From patchwork Tue Jun 27 14:09:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "juzhe.zhong@rivai.ai" X-Patchwork-Id: 113438 Return-Path: Delivered-To: ouuuleilei@gmail.com Received: by 2002:a59:994d:0:b0:3d9:f83d:47d9 with SMTP id k13csp8226857vqr; Tue, 27 Jun 2023 07:10:16 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7OAS9zIxUoZ+moCWo6RIbKEoz/Aii9ZqIeY67tLVK75otu3Tb/L4tVB0CttRiD/eBG/mGx X-Received: by 2002:a17:907:b12:b0:991:e3c4:c131 with SMTP id h18-20020a1709070b1200b00991e3c4c131mr3800171ejl.6.1687875015762; Tue, 27 Jun 2023 07:10:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687875015; cv=none; d=google.com; s=arc-20160816; b=pNvvqvXMUIVqsYz1Z/GkXS1dWecfTKugnbf4sezix3ODn6/moc6ix6Bm61x1C577Aj BygTK1NcdPDwzGSEeVjV6ugQ2lp4uN8bSDd95KJhmgous/H0E0hL9giwv3PHMapulD0A RoQq2s1i5vBUXxmjnqnR8q6NxzYxmP6hU9+BFS+HoFdZt0CL3lWKhiybiFeYNjWNm3BM xlYcvy50y+Xvi12wwWHOh0xfUm9FP4ElZ8MXa1piCK3wVSw1KtDmIay4zQ17r/UE2N8/ kkvFH5OntguAXxFTHh5Jl7j2JskrYNz4GfifqRW2uVFIbsRoU233oYSQzJ6zUNr5FA/R YWVg== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=sender:errors-to:list-subscribe:list-help:list-post:list-archive :list-unsubscribe:list-id:precedence:feedback-id :content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:dmarc-filter:delivered-to; bh=HWC19hdWIjegh+jVJC+Vt7O93egop3AgFtu3E5mUP6E=; fh=wJQXjlF2pzwEVBXObiUXCE1/GsELYeDpatHPYmXU/Wc=; b=VkLNgc0T6e9MPDDmKy1onJj/oA79lt3PdxL5uEIeOKlwCmsuY+uBkUJDo4jaHKfTH1 jNYAHPGi3I//bI4x4HtsdWXLpo7K/aKWAqE3oVJbrbt+2JC+Lx5prJ13I06FN1SZViAG 2u/xUdGTw4UAaIUU42w6qO6YmOrlIJO/xTctzXP9WyZpw5jifo/5iCD4eS8zgipGHVJI 8s0K4pWIGhBswD7XHGabga5yWtcja8rtw2jOqpvd3yoBW+yjTSshY95BhX1NFfLsn+Dr hvAcDIoTYK2qhWxjbUjLB68AtCSU43KKt6A34sqv0GVjTnxBglaKB05PPOzzsxKuBtnZ Fo9w== ARC-Authentication-Results: i=1; mx.google.com; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from sourceware.org (server2.sourceware.org. [2620:52:3:1:0:246e:9693:128c]) by mx.google.com with ESMTPS id t15-20020a170906948f00b009887f2dbee9si4188522ejx.612.2023.06.27.07.10.15 for (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 27 Jun 2023 07:10:15 -0700 (PDT) Received-SPF: pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) client-ip=2620:52:3:1:0:246e:9693:128c; Authentication-Results: mx.google.com; spf=pass (google.com: domain of gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org designates 2620:52:3:1:0:246e:9693:128c as permitted sender) smtp.mailfrom="gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org" Received: from server2.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 74F283858000 for ; Tue, 27 Jun 2023 14:10:07 +0000 (GMT) X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from smtpbgeu2.qq.com (smtpbgeu2.qq.com [18.194.254.142]) by sourceware.org (Postfix) with ESMTPS id 24A343858D33 for ; Tue, 27 Jun 2023 14:09:34 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 24A343858D33 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=rivai.ai Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=rivai.ai X-QQ-mid: bizesmtp76t1687874969tsm7r6cv Received: from server1.localdomain ( [58.60.1.22]) by bizesmtp.qq.com (ESMTP) with id ; Tue, 27 Jun 2023 22:09:28 +0800 (CST) X-QQ-SSF: 01400000000000G0S000000A0000000 X-QQ-FEAT: mRz6/7wsmIhJgu60V6RiI9V1ugCNoa2B6kZZBcO/Cdj7rj/26BfPvq7MrgHsx Co/Wj0OUwF0b/JwwvOq963UIFra3PpibSIAUJJWSIrIE+yb8FZopxxVxEyvDmcsGN4qohwu YBJMibyuqbmVz7tStPXoRoGKMnO8Gii2HEtNOpifHgT4ugm854Glqhaoc5TTRqGxzGHZ5Wq P8c4SFsW/VIBV3MzLu7bIQJPNCE2JBJ3+Gcxl/9whtpmtNYx0UwwByGSzbGL5YyfG7TH6Gu OjPxR577u3JCJjl6bCxbyz9moYgTGcGwISzPCEjatN0Gvt+g3x2SCo+3Wp4bKiACLFDHqoT u8aXZgHbdfgMM8raLCmBbz4ZpRQ5hIPYwUZODdJdWfN5QxZWwd0rzn78hzINCHYSkq4+TO2 izt+eRBovli5o5LsV7DdbkKvleXouRLi X-QQ-GoodBg: 2 X-BIZMAIL-ID: 297917611693782008 From: Juzhe-Zhong To: gcc-patches@gcc.gnu.org Cc: kito.cheng@gmail.com, kito.cheng@sifive.com, palmer@dabbelt.com, palmer@rivosinc.com, jeffreyalaw@gmail.com, rdapp.gcc@gmail.com, Juzhe-Zhong Subject: [PATCH] RISC-V: Fix bug of pre-calculated const vector mask Date: Tue, 27 Jun 2023 22:09:24 +0800 Message-Id: <20230627140924.33604-1-juzhe.zhong@rivai.ai> X-Mailer: git-send-email 2.36.1 MIME-Version: 1.0 X-QQ-SENDSIZE: 520 Feedback-ID: bizesmtp:rivai.ai:qybglogicsvrgz:qybglogicsvrgz7a-one-0 X-Spam-Status: No, score=-8.8 required=5.0 tests=BAYES_00, GIT_PATCH_0, KAM_DMARC_STATUS, KAM_SHORT, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, RCVD_IN_MSPIKE_H3, RCVD_IN_MSPIKE_WL, SCC_10_SHORT_WORD_LINES, SCC_20_SHORT_WORD_LINES, SCC_5_SHORT_WORD_LINES, SPF_PASS, TXREP, T_SCC_BODY_TEXT_LINE, T_SPF_HELO_TEMPERROR autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces+ouuuleilei=gmail.com@gcc.gnu.org Sender: "Gcc-patches" X-getmail-retrieved-from-mailbox: =?utf-8?q?INBOX?= X-GMAIL-THRID: =?utf-8?q?1769865232525532891?= X-GMAIL-MSGID: =?utf-8?q?1769865232525532891?= GCC doesn't known RVV is using compact mask model. Consider this following case: #define N 16 int main () { int8_t mask[N] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; int8_t out[N] = {0}; for (int8_t i = 0; i < N; ++i) if (mask[i]) out[i] = i; for (int8_t i = 0; i < N; ++i) { if (mask[i]) assert (out[i] == i); else assert (out[i] == 0); } } Before this patch, the pre-calculated mask in constant memory pool: .LC1: .byte 68 ====> 0b01000100 This is incorrect, such case failed in execution. After this patch: .LC1: .byte 10 ====> 0b1010 Pass on exection. gcc/ChangeLog: * config/riscv/riscv-v.cc (rvv_builder::compact_mask): New function. (expand_const_vector): Fix bug. * config/riscv/riscv.cc (riscv_const_insns): Ditto. gcc/testsuite/ChangeLog: * gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-1.c: New test. * gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-2.c: New test. * gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-3.c: New test. * gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-4.c: New test. * gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-5.c: New test. * gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-6.c: New test. * gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-7.c: New test. --- gcc/config/riscv/riscv-v.cc | 61 +++++++++++++++++-- gcc/config/riscv/riscv.cc | 6 ++ .../riscv/rvv/autovec/vls-vlmax/bitmask-1.c | 23 +++++++ .../riscv/rvv/autovec/vls-vlmax/bitmask-2.c | 23 +++++++ .../riscv/rvv/autovec/vls-vlmax/bitmask-3.c | 23 +++++++ .../riscv/rvv/autovec/vls-vlmax/bitmask-4.c | 23 +++++++ .../riscv/rvv/autovec/vls-vlmax/bitmask-5.c | 25 ++++++++ .../riscv/rvv/autovec/vls-vlmax/bitmask-6.c | 27 ++++++++ .../riscv/rvv/autovec/vls-vlmax/bitmask-7.c | 30 +++++++++ 9 files changed, 236 insertions(+), 5 deletions(-) create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-1.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-2.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-3.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-4.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-5.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-6.c create mode 100644 gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-7.c diff --git a/gcc/config/riscv/riscv-v.cc b/gcc/config/riscv/riscv-v.cc index adb8d7d36a5..54d1904bbe8 100644 --- a/gcc/config/riscv/riscv-v.cc +++ b/gcc/config/riscv/riscv-v.cc @@ -291,6 +291,7 @@ public: bool single_step_npatterns_p () const; bool npatterns_all_equal_p () const; + rtx compact_mask () const; machine_mode new_mode () const { return m_new_mode; } scalar_mode inner_mode () const { return m_inner_mode; } @@ -505,6 +506,44 @@ rvv_builder::npatterns_all_equal_p () const return true; } +/* Generate the compact mask. + + E.g: mask = { 0, -1 }, mode = VNx2BI, bitsize = 128bits. + + GCC by default will generate the mask = 0b00000001xxxxx. + + However, it's not expected mask for RVV since RVV + prefers the compact mask = 0b10xxxxx. +*/ +rtx +rvv_builder::compact_mask () const +{ + /* Use the container mode with SEW = 8 and LMUL = 1. */ + unsigned container_size + = MAX (CEIL (npatterns (), 8), BYTES_PER_RISCV_VECTOR.to_constant () / 8); + machine_mode container_mode + = get_vector_mode (QImode, container_size).require (); + + unsigned nunits = GET_MODE_NUNITS (container_mode).to_constant (); + rtvec v = rtvec_alloc (nunits); + for (unsigned i = 0; i < nunits; i++) + RTVEC_ELT (v, i) = const0_rtx; + + unsigned char b = 0; + for (unsigned i = 0; i < npatterns (); i++) + { + if (INTVAL (elt (i))) + b = b | (1 << (i % 8)); + + if ((i > 0 && (i % 8) == 7) || (i == (npatterns () - 1))) + { + RTVEC_ELT (v, ((i + 7) / 8) - 1) = gen_int_mode (b, QImode); + b = 0; + } + } + return gen_rtx_CONST_VECTOR (container_mode, v); +} + static unsigned get_sew (machine_mode mode) { @@ -1141,11 +1180,23 @@ expand_const_vector (rtx target, rtx src) if (GET_MODE_CLASS (mode) == MODE_VECTOR_BOOL) { rtx elt; - gcc_assert ( - const_vec_duplicate_p (src, &elt) - && (rtx_equal_p (elt, const0_rtx) || rtx_equal_p (elt, const1_rtx))); - rtx ops[] = {target, src}; - emit_vlmax_insn (code_for_pred_mov (mode), RVV_UNOP, ops); + unsigned int nelts; + if (const_vec_duplicate_p (src, &elt)) + { + rtx ops[] = {target, src}; + emit_vlmax_insn (code_for_pred_mov (mode), RVV_UNOP, ops); + } + else if (GET_MODE_NUNITS (mode).is_constant (&nelts)) + { + rvv_builder builder (mode, nelts, 1); + for (unsigned int i = 0; i < nelts; i++) + builder.quick_push (CONST_VECTOR_ELT (src, i)); + rtx mask = builder.compact_mask (); + rtx mem = validize_mem (force_const_mem (GET_MODE (mask), mask)); + emit_move_insn (target, gen_rtx_MEM (mode, XEXP (mem, 0))); + } + else + gcc_unreachable (); return; } diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 280aa0b33b9..86c83f0906d 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -1323,6 +1323,12 @@ riscv_const_insns (rtx x) return 1 + 4; /*vmv.v.x + memory access. */ } } + + /* GCC doesn't known RVV is using compact model of mask, + we should by default handle mask in mov pattern. */ + if (GET_MODE_CLASS (GET_MODE (x)) == MODE_VECTOR_BOOL) + /* TODO: We can adjust it according real cost model of vlm.v. */ + return 1; } /* TODO: We may support more const vector in the future. */ diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-1.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-1.c new file mode 100644 index 00000000000..81229fd62b9 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-1.c @@ -0,0 +1,23 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "--param riscv-autovec-preference=fixed-vlmax -O3" } */ + +#include +#include +#define N 16 + +int +main () +{ + int mask[N] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + int64_t out[N] = {0}; + for (int i = 0; i < N; ++i) + if (mask[i]) + out[i] = i; + for (int i = 0; i < N; ++i) + { + if (mask[i]) + assert (out[i] == i); + else + assert (out[i] == 0); + } +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-2.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-2.c new file mode 100644 index 00000000000..a23e47171bc --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-2.c @@ -0,0 +1,23 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "--param riscv-autovec-preference=fixed-vlmax -O3" } */ + +#include +#include +#define N 16 + +int +main () +{ + int mask[N] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + int out[N] = {0}; + for (int i = 0; i < N; ++i) + if (mask[i]) + out[i] = i; + for (int i = 0; i < N; ++i) + { + if (mask[i]) + assert (out[i] == i); + else + assert (out[i] == 0); + } +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-3.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-3.c new file mode 100644 index 00000000000..6ea8fdd89c0 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-3.c @@ -0,0 +1,23 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "--param riscv-autovec-preference=fixed-vlmax -O3" } */ + +#include +#include +#define N 16 + +int +main () +{ + int16_t mask[N] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + int16_t out[N] = {0}; + for (int16_t i = 0; i < N; ++i) + if (mask[i]) + out[i] = i; + for (int16_t i = 0; i < N; ++i) + { + if (mask[i]) + assert (out[i] == i); + else + assert (out[i] == 0); + } +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-4.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-4.c new file mode 100644 index 00000000000..2d97c26abfd --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-4.c @@ -0,0 +1,23 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "--param riscv-autovec-preference=fixed-vlmax -O3" } */ + +#include +#include +#define N 16 + +int +main () +{ + int8_t mask[N] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + int8_t out[N] = {0}; + for (int8_t i = 0; i < N; ++i) + if (mask[i]) + out[i] = i; + for (int8_t i = 0; i < N; ++i) + { + if (mask[i]) + assert (out[i] == i); + else + assert (out[i] == 0); + } +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-5.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-5.c new file mode 100644 index 00000000000..b89b70e99a6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-5.c @@ -0,0 +1,25 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "--param riscv-autovec-preference=fixed-vlmax --param riscv-autovec-lmul=m2 -O3" } */ + +#include +#include + +#define N 32 + +int +main () +{ + int8_t mask[N] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + int8_t out[N] = {0}; + for (int8_t i = 0; i < N; ++i) + if (mask[i]) + out[i] = i; + for (int8_t i = 0; i < N; ++i) + { + if (mask[i]) + assert (out[i] == i); + else + assert (out[i] == 0); + } +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-6.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-6.c new file mode 100644 index 00000000000..ac8d91e793b --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-6.c @@ -0,0 +1,27 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "--param riscv-autovec-preference=fixed-vlmax --param riscv-autovec-lmul=m4 -O3" } */ + +#include +#include + +#define N 64 + +int +main () +{ + int8_t mask[N] = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + int8_t out[N] = {0}; + for (int8_t i = 0; i < N; ++i) + if (mask[i]) + out[i] = i; + for (int8_t i = 0; i < N; ++i) + { + if (mask[i]) + assert (out[i] == i); + else + assert (out[i] == 0); + } +} diff --git a/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-7.c b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-7.c new file mode 100644 index 00000000000..f538db23b1d --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/rvv/autovec/vls-vlmax/bitmask-7.c @@ -0,0 +1,30 @@ +/* { dg-do run { target { riscv_vector } } } */ +/* { dg-options "--param riscv-autovec-preference=fixed-vlmax --param riscv-autovec-lmul=m8 -O3" } */ + +#include +#include + +#define N 128 + +int +main () +{ + uint8_t mask[N] + = {0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, + 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1, 0, 1}; + uint8_t out[N] = {0}; + for (uint8_t i = 0; i < N; ++i) + if (mask[i]) + out[i] = i; + for (uint8_t i = 0; i < N; ++i) + { + if (mask[i]) + assert (out[i] == i); + else + assert (out[i] == 0); + } +}