From: Jeff Law Date: Fri, 3 Jul 2026 04:36:47 +0000 (-0600) Subject: [RISC-V] Improve IOR/XOR synthesis for expensive constant cases X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=e07e140680c717cfc59a11bf2287ff6433ebddd2;p=thirdparty%2Fgcc.git [RISC-V] Improve IOR/XOR synthesis for expensive constant cases So much like the changes to add_synthesis, this adjusts xor/ior synthesis to use riscv_integer_cost rather than riscv_const_insns. For those that didn't read the add_synthesis patch, what happens is riscv_const_insns returns 0 for constants requiring more than 3 insns to synthesize. So imagine if the original constant had cost 5, it's bit inversion has cost 4. Both get converted to "0" because they're over the maximal value and thus we can't distinguish between them and we fail to use C' with XNOR, ORN or ANDN to improve the resulting code. The constants here were actually from the AND cases, but given the common ISA capability and GCC structure I suspected the AND cases would apply to IOR/XOR, and they do. Tested without regression on riscv32-elf and riscv64-elf, also bootstrapped and regression tested on the k3 and c920. I'll obviously be waiting for pre-commit CI to do its thing before moving forward. gcc/ * config/riscv/riscv.cc (synthesize_ior_xor): Use riscv_integer_cost rather than riscv_const_insns. gcc/testsuite * gcc.target/riscv/xor-synthesis-4.c: New test. --- diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index 09dc41930aa..d31d4a8aeab 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -15687,7 +15687,7 @@ synthesize_ior_xor (rtx_code code, rtx operands[3]) execution and fusion in the constant synthesis those would naturally decrease the budget. It also does not account for the IOR/XOR at the end of the sequence which would increase the budget. */ - int budget = (TARGET_ZBS ? riscv_const_insns (operands[2], true) : -1); + int budget = (TARGET_ZBS ? riscv_integer_cost (INTVAL (operands[2]), true) : -1); int original_budget = budget; /* Bits we need to set in operands[0]. As we synthesize the operation, @@ -15751,7 +15751,7 @@ synthesize_ior_xor (rtx_code code, rtx operands[3]) if ((TARGET_ZBB || TARGET_XTHEADBB || TARGET_ZBKB) && budget < 0 && popcount_hwi (INTVAL (operands[2])) <= 11 - && riscv_const_insns (operands[2], true) >= 3) + && riscv_integer_cost (INTVAL (operands[2]), true) >= 3) { ival = INTVAL (operands[2]); /* First see if the constant trivially fits into 11 bits in the LSB. */ @@ -15840,9 +15840,8 @@ synthesize_ior_xor (rtx_code code, rtx operands[3]) we have Zbb, then we have XNOR and ORN. So if the inverted constant is cheaper, invert it and use XNOR/ORN. */ if (TARGET_ZBB - && riscv_const_insns (GEN_INT (~UINTVAL (operands[2])), true) > 0 - && (riscv_const_insns (operands[2], true) - > riscv_const_insns (GEN_INT (~UINTVAL (operands[2])), true))) + && (riscv_integer_cost (INTVAL (operands[2]), true) + > riscv_integer_cost (~UINTVAL (operands[2]), true))) { rtx x = force_reg (word_mode, GEN_INT (~UINTVAL (operands[2]))); diff --git a/gcc/testsuite/gcc.target/riscv/xor-synthesis-4.c b/gcc/testsuite/gcc.target/riscv/xor-synthesis-4.c new file mode 100644 index 00000000000..4fc6c526faf --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xor-synthesis-4.c @@ -0,0 +1,19 @@ +/* { dg-do compile { target rv64 } } */ +/* { dg-options "-march=rv64gcb -mabi=lp64d" } */ + + + +#define T(X) long xnor##X(long x) { return x ^ X; } + +T(0x000200c3233fffffUL) +T(0x300000000003ffffUL) +T(0x00004f10000a0fffUL) +T(0x0000c7f3801fefffUL) +T(0xe00000000000fc00UL) +T(0x0eef7ffffffbbfffUL) +T(0xff0000000000ff00UL) + +/* Each test above is better handled by inverting the constant + and using xnor. */ + +/* { dg-final { scan-assembler-times "\\txnor\\t" 7 } } */