From: Philipp Tomsich Date: Tue, 29 Aug 2023 22:48:24 +0000 (-0600) Subject: RISC-V: Use splitter to generate zicond in another case X-Git-Tag: basepoints/gcc-15~6582 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=94b950df6f8c46925799f642e5c44f42638f2b5e;p=thirdparty%2Fgcc.git RISC-V: Use splitter to generate zicond in another case 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 --- diff --git a/gcc/config/riscv/zicond.md b/gcc/config/riscv/zicond.md index 25f21d33487e..4619220ef8ac 100644 --- a/gcc/config/riscv/zicond.md +++ b/gcc/config/riscv/zicond.md @@ -62,3 +62,34 @@ "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 index 000000000000..8362ffaf5ab1 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zicond-xor-01.c @@ -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 } } */