On 5/24/24 2:41 AM, Mariam Arutunian wrote:
If the target is ZBC or ZBKC, it uses clmul instruction for the CRC calculation.
Otherwise, if the target is ZBKB, generates table-based CRC,
but for reversing inputs and the output uses bswap and brev8 instructions.
Add new tests to check CRC generation for ZBC, ZBKC and ZBKB targets.

   gcc/

      * expr.cc (gf2n_poly_long_div_quotient): New function.
      (reflect): Likewise.
      * expr.h (gf2n_poly_long_div_quotient): New function declaration.
      (reflect): Likewise.

   gcc/config/riscv/

     * bitmanip.md (crc_rev<ANYI1:mode><ANYI:mode>4): New expander for reversed CRC.
      (crc<SUBX1:mode><SUBX:mode>4): New expander for bit-forward CRC.
      (SUBX1, ANYI1): New iterators.
     * riscv-protos.h (generate_reflecting_code_using_brev): New function declaration.
      (expand_crc_using_clmul): Likewise.
      (expand_reversed_crc_using_clmul): Likewise.
      * riscv.cc (generate_reflecting_code_using_brev): New function.
      (expand_crc_using_clmul): Likewise.
      (expand_reversed_crc_using_clmul): Likewise.
      * riscv.md (UNSPEC_CRC, UNSPEC_CRC_REV):  New unspecs.

   gcc/testsuite/gcc.target/riscv/

         * crc-1-zbc.c: New test.
         * crc-10-zbc.c: Likewise.
         * crc-12-zbc.c: Likewise.
         * crc-13-zbc.c: Likewise.
         * crc-14-zbc.c: Likewise.
         * crc-17-zbc.c: Likewise.
         * crc-18-zbc.c: Likewise.
         * crc-21-zbc.c: Likewise.
         * crc-22-rv64-zbc.c: Likewise.
         * crc-22-zbkb.c: Likewise.
         * crc-23-zbc.c: Likewise.
         * crc-4-zbc.c: Likewise.
         * crc-5-zbc.c: Likewise.
         * crc-5-zbkb.c: Likewise.
         * crc-6-zbc.c: Likewise.
         * crc-7-zbc.c: Likewise.
         * crc-8-zbc.c: Likewise.
         * crc-8-zbkb.c: Likewise.
         * crc-9-zbc.c: Likewise.
         * crc-CCIT-data16-zbc.c: Likewise.
         * crc-CCIT-data8-zbc.c: Likewise.
         * crc-coremark-16bitdata-zbc.c: Likewise.

Signed-off-by: Mariam Arutunian <mariamarutun...@gmail.com <mailto:mariamarutun...@gmail.com>>
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index 8769a6b818b..c98d451f404 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -973,3 +973,66 @@
   "TARGET_ZBC"
   "clmulr\t%0,%1,%2"
   [(set_attr "type" "clmul")])
+
+
+;; Iterator for hardware integer modes narrower than XLEN, same as SUBX
+(define_mode_iterator SUBX1 [QI HI (SI "TARGET_64BIT")])
+
+;; Iterator for hardware integer modes narrower than XLEN, same as ANYI
+(define_mode_iterator ANYI1 [QI HI SI (DI "TARGET_64BIT")])
If these iterators are the same as existing ones, let's just using the existing ones. unless we need both SUBX and SUBX1 in the same pattern or ANYI/ANYI1.



+
+;; Reversed CRC 8, 16, 32 for TARGET_64
+(define_expand "crc_rev<ANYI1:mode><ANYI:mode>4"
+       ;; return value (calculated CRC)
+  [(set (match_operand:ANYI 0 "register_operand" "=r")
+                     ;; initial CRC
+       (unspec:ANYI [(match_operand:ANYI 1 "register_operand" "r")
+                     ;; data
+                     (match_operand:ANYI1 2 "register_operand" "r")
+                     ;; polynomial without leading 1
+                     (match_operand:ANYI 3)]
+                     UNSPEC_CRC_REV))]
So the preferred formatting for .md files has operands of a given operator at the same indention level. So in this case SET is the operator, with two operands (destination/source). Indent the source and destination at the same level. so

  [(set (match_operand:ANYI 0 ...0)
        (unspec: ANYI ...)

Similarly for the reversed expander.


diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc
index 85df5b7ab49..123695033a6 100644
--- a/gcc/config/riscv/riscv.cc
+++ b/gcc/config/riscv/riscv.cc
@@ -11394,7 +11394,7 @@ riscv_expand_usadd (rtx dest, rtx x, rtx y)
   if (mode == HImode || mode == QImode)
     {
       int shift_bits = GET_MODE_BITSIZE (Xmode)
-       - GET_MODE_BITSIZE (mode).to_constant ();
+                      - GET_MODE_BITSIZE (mode).to_constant ();
gcc_assert (shift_bits > 0);
Looks like an unrelated spurious change.  Drop.


@@ -11415,6 +11415,188 @@ riscv_expand_usadd (rtx dest, rtx x, rtx y)
   emit_move_insn (dest, gen_lowpart (mode, xmode_dest));
 }
+/* Generate instruction sequence
+   which reflects the value of the OP using bswap and brev8 instructions.
+   OP's mode may be less than word_mode, to get the correct number,
+   after reflecting we shift right the value by SHIFT_VAL.
+   E.g. we have 1111 0001, after reflection (target 32-bit) we will get
+   1000 1111 0000 0000, if we shift-out 16 bits,
+   we will get the desired one: 1000 1111.  */
+
+void
+generate_reflecting_code_using_brev (rtx *op, int shift_val)
+{
+
+  riscv_expand_op (BSWAP, word_mode, *op, *op, *op);
+  riscv_expand_op (LSHIFTRT, word_mode, *op, *op,
+                  gen_int_mode (shift_val, word_mode));
Formatting nit with the gen_int_mode (...) argument. It should line up with the LSHIFTRT argument.



+
+void
+expand_crc_using_clmul (rtx *operands)
+{
+  /* Check and keep arguments.  */
+  gcc_assert (!CONST_INT_P (operands[0]));
+  gcc_assert (CONST_INT_P (operands[3]));
+  unsigned HOST_WIDE_INT
+      crc_size = GET_MODE_BITSIZE (GET_MODE (operands[0])).to_constant ();
+  gcc_assert (crc_size <= 32);
+  unsigned HOST_WIDE_INT
+      data_size = GET_MODE_BITSIZE (GET_MODE (operands[2])).to_constant ();
+
+  /* Calculate the quotient.  */
+  unsigned HOST_WIDE_INT
+      q = gf2n_poly_long_div_quotient (UINTVAL (operands[3]), crc_size + 1);
+
+  rtx crc_extended = gen_rtx_ZERO_EXTEND (word_mode, operands[1]);
+  rtx crc = gen_reg_rtx (word_mode);
+  if (crc_size > data_size)
+    riscv_expand_op (LSHIFTRT, word_mode, crc, crc_extended,
+                    gen_int_mode (crc_size - data_size, word_mode));
+  else
+    crc = gen_rtx_ZERO_EXTEND (word_mode, operands[1]);
+  rtx t0 = gen_reg_rtx (word_mode);
+  riscv_emit_move (t0, gen_int_mode (q, word_mode));
+  rtx t1 = gen_reg_rtx (word_mode);
+  riscv_emit_move (t1, operands[3]);
+
+  rtx a0 = gen_reg_rtx (word_mode);
+  rtx data = gen_rtx_ZERO_EXTEND (word_mode, operands[2]);
+  riscv_expand_op (XOR, word_mode, a0, crc, data);
+
+  if (TARGET_64BIT)
+    emit_insn (gen_riscv_clmul_di (a0, a0, t0));
+  else
+    emit_insn (gen_riscv_clmul_si (a0, a0, t0));
+
+  riscv_expand_op (LSHIFTRT, word_mode, a0, a0, gen_int_mode (crc_size,
+                                                             word_mode));
Formatting nit on word_size argument.


+
+  if (crc_size == 32 && word_mode == DImode)
Rather than hard coding these cases, would it be better to check if crc_size < GET_MODE_BITSIZE (word_mode)? Similarly for the reversed case.

Overall it looks pretty good as well. Please repost after fixing the minor issues noted above.

Thanks,
jeff


Reply via email to