]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
RISC-V: Use splitter to generate zicond in another case
authorPhilipp Tomsich <philipp.tomsich@vrull.eu>
Tue, 29 Aug 2023 22:48:24 +0000 (16:48 -0600)
committerJeff Law <jlaw@ventanamicro.com>
Tue, 29 Aug 2023 22:59:19 +0000 (16:59 -0600)
So in analyzing Ventana's internal tree against the trunk it became apparent
that the current zicond code is missing a case that helps coremark's bitwise
CRC implementation.

Here's a minimized testcase:

long xor1(long crc, long poly)
{
  if (crc & 1)
    crc ^= poly;

  return crc;
}

ie, it's just a conditional xor.

We generate this:

        andi    a5,a0,1
        neg     a5,a5
        and     a5,a5,a1
        xor     a0,a5,a0
        ret

But we should instead generate:

        andi    a5,a0,1
        czero.eqz       a5,a1,a5
        xor     a0,a5,a0
        ret

Combine wants to generate:

Trying 7, 8 -> 9:
    7: r140:DI=r137:DI&0x1
    8: r141:DI=-r140:DI
      REG_DEAD r140:DI
    9: r142:DI=r141:DI&r144:DI
      REG_DEAD r144:DI
      REG_DEAD r141:DI
Failed to match this instruction:
(set (reg:DI 142)
    (and:DI (sign_extract:DI (reg/v:DI 137 [ crc ])
            (const_int 1 [0x1])
            (const_int 0 [0]))
        (reg:DI 144)))

A splitter can rewrite the above into a suitable if-then-else construct and
squeeze an instruction out of that pesky CRC loop.  Sadly it doesn't really
help anything else.

The patch includes two variants.  One that uses ZBS, the other uses an ANDI
logical to produce the input condition.

gcc/
* config/riscv/zicond.md: New splitters to rewrite single bit
sign extension as the condition to a czero in the desired form.

gcc/testsuite
* gcc.target/riscv/zicond-xor-01.c: New test.

Co-authored-by: Jeff Law <jlaw@ventanamicro.com>
gcc/config/riscv/zicond.md
gcc/testsuite/gcc.target/riscv/zicond-xor-01.c [new file with mode: 0644]

index 25f21d33487e1b9f1ae47bad4268d77f465f14da..4619220ef8acca99c58592f4eab44399387f13ff 100644 (file)
   "TARGET_ZICOND && rtx_equal_p (operands[1], operands[3])"
   "czero.nez\t%0,%2,%1"
 )
+
+;; Combine creates this form in some cases (particularly the coremark
+;; CRC loop.
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (sign_extract:X (match_operand:X 1 "register_operand")
+                              (const_int 1)
+                              (match_operand 2 "immediate_operand"))
+              (match_operand:X 3 "register_operand")))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND && TARGET_ZBS"
+  [(set (match_dup 4) (zero_extract:X (match_dup 1) (const_int 1) (match_dup 2)))
+   (set (match_dup 0) (if_then_else:X (eq:X (match_dup 4) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 3)))])
+
+(define_split
+  [(set (match_operand:X 0 "register_operand")
+       (and:X (sign_extract:X (match_operand:X 1 "register_operand")
+                              (const_int 1)
+                              (match_operand 2 "immediate_operand"))
+              (match_operand:X 3 "register_operand")))
+   (clobber (match_operand:X 4 "register_operand"))]
+  "TARGET_ZICOND && !TARGET_ZBS && (UINTVAL (operands[2]) < 11)"
+  [(set (match_dup 4) (and:X (match_dup 1) (match_dup 2)))
+   (set (match_dup 0) (if_then_else:X (eq:X (match_dup 4) (const_int 0))
+                                     (const_int 0)
+                                     (match_dup 3)))]
+{
+  operands[2] = GEN_INT (1 << UINTVAL(operands[2]));
+})
diff --git a/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c
new file mode 100644 (file)
index 0000000..8362ffa
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zicond -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" "-Os" "-Oz" } } */
+
+long xor1(long crc, long poly)
+{
+  if (crc & 1)
+    crc ^= poly;
+
+  return crc;
+}
+
+/* { dg-final { scan-assembler-times "czero.eqz\t" 1 } } */
+/* { dg-final { scan-assembler-times "xor\t" 1 } } */