https://gcc.gnu.org/g:31eb899f30c51f03e9dcae76ff92c53928345d7c
commit r17-5663-g31eb899f30c51f03e9dcae76ff92c53928345d7c Author: Jeff Law <[email protected]> Date: Wed Oct 28 07:11:44 2026 -0600 [RISC-V] Fix multiple small RISC-V bugs discovered during LLM review And yesterday's set of fixes inspired by LLM review of the RISC-V machine description. For ior/xor synthesis, two issues. First we can trigger undefined behavior with a shift by the size of the object. It never results in incorrect code, but it's best avoided. Second, there's an off-by-1 error which caused us to fail to synthesize the rotate variants in one class of cases. The LLM generated a test for the missed optimization. For and synthesis, we could generate an unrecognizable insn if B is off, but Zbkb was on. It's an unlikely combination, but clearly wrong. The LLM generated a testcase for this problem too. In the overflow expanders and divmod expanders, we can write the output before the inputs are consumed. This is actually safe in practice for these expanders, but wrong from a design standpoint. I don't have the md.texi or rtl.texi passage handy, but the expanders are responsible for ensuring the inputs are fully consumed before outputs are written. make_safe_from handles that nicely. Given it's 100% latent, no testcase. There's a unnamed define_insn_and_split that shifted 1, potentially by 32 or more bits. That's bad. HOST_WIDE_INT_1U fixes that. Didn't bother asking for a testcase from the LLM Regression tested on riscv32-elf and riscv64-elf. Bootstrapped and regression tested on the K3 and c920. K1 is in flight. gcc/ * config/riscv/riscv.cc (synthesize_xor): Avoid undefined shift when using rotate to get key bits into useful position. Fix off-by-one error causing missed optimization in rotate case. (synthesize_and): Do not use zext.h if ZBB is not enabled. * config/riscv/riscv.md (addv<mode>4): Use make_safe_from to ensure inputs are not overwritten by early assignments to the output. (uaddv<mode>4, subv<mode>4, usubv<mode>4, <u>divmod<mode>4): Likewise. (addition with masked shift splitter): Use HOST_WIDE_INT_1U rather than 1. gcc/testsuite/ * gcc.target/riscv/xor-synthesis-5.c: New test. * gcc.target/riscv/zbkb-zext.c: New test. Diff: --- gcc/config/riscv/riscv.cc | 14 ++++++++++---- gcc/config/riscv/riscv.md | 10 +++++++++- gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c | 10 ++++++++++ gcc/testsuite/gcc.target/riscv/zbkb-zext.c | 3 +++ 4 files changed, 32 insertions(+), 5 deletions(-) diff --git a/gcc/config/riscv/riscv.cc b/gcc/config/riscv/riscv.cc index cc96cc0ad8bf..bed695ccae4b 100644 --- a/gcc/config/riscv/riscv.cc +++ b/gcc/config/riscv/riscv.cc @@ -16270,12 +16270,18 @@ synthesize_ior_xor (rtx_code code, rtx operands[3]) of leading zeros after masking off all but the low 11 bits. */ int rotcount = clz_hwi (ival & 0x7ff) - (BITS_PER_WORD - 11); - /* Rotate the constant left by MSB bits. */ - ival = (ival << rotcount) | (ival >> (BITS_PER_WORD - rotcount)); + /* Rotate the constant left by MSB bits. Avoid undefined behavior if + rotcount is zero. A rotcount of zero means there's no room to rotate + in bits. We can just set ival to all ones so is rejected later with + the msb - lsb check. */ + if (rotcount != 0) + ival = (ival << rotcount) | (ival >> (BITS_PER_WORD - rotcount)); + else + ival = HOST_WIDE_INT_M1U; /* Now we can do the same tests as before. */ lsb = ctz_hwi (ival); - msb = BITS_PER_WORD - clz_hwi (ival); + msb = BITS_PER_WORD - 1 - clz_hwi (ival); if ((INTVAL (operands[2]) & HOST_WIDE_INT_UC (0x7ff)) != 0 && msb - lsb + 1 <= 11) { @@ -16524,7 +16530,7 @@ synthesize_and (rtx operands[3]) && budget >= 3 && consecutive_bits_operand (GEN_INT (~t), word_mode) && ((TARGET_ZBA && popcount_hwi (t) == 32) - || popcount_hwi (t) == 16 + || (TARGET_ZBB && popcount_hwi (t) == 16) || popcount_hwi (t) <= 11)) { /* First rotate the relevant bits into the low position. */ diff --git a/gcc/config/riscv/riscv.md b/gcc/config/riscv/riscv.md index 76a566520ff5..a913660d9511 100644 --- a/gcc/config/riscv/riscv.md +++ b/gcc/config/riscv/riscv.md @@ -811,6 +811,8 @@ rtx t3 = gen_reg_rtx (<MODE>mode); rtx t4 = gen_reg_rtx (<MODE>mode); + operands[1] = make_safe_from (operands[1], operands[0]); + operands[2] = make_safe_from (operands[2], operands[0]); emit_insn (gen_add3_insn (operands[0], operands[1], operands[2])); rtx cmp1 = gen_rtx_LT (<MODE>mode, operands[2], const0_rtx); emit_insn (gen_cstore<mode>4 (t3, cmp1, operands[2], const0_rtx)); @@ -845,6 +847,7 @@ } else { + operands[1] = make_safe_from (operands[1], operands[0]); emit_insn (gen_add3_insn (operands[0], operands[1], operands[2])); riscv_expand_conditional_branch (operands[3], LTU, operands[0], operands[1]); @@ -993,6 +996,8 @@ rtx t3 = gen_reg_rtx (<MODE>mode); rtx t4 = gen_reg_rtx (<MODE>mode); + operands[1] = make_safe_from (operands[1], operands[0]); + operands[2] = make_safe_from (operands[2], operands[0]); emit_insn (gen_sub3_insn (operands[0], operands[1], operands[2])); rtx cmp1 = gen_rtx_LT (<MODE>mode, operands[2], const0_rtx); @@ -1030,6 +1035,7 @@ } else { + operands[1] = make_safe_from (operands[1], operands[0]); emit_insn (gen_sub3_insn (operands[0], operands[1], operands[2])); riscv_expand_conditional_branch (operands[3], LTU, operands[1], operands[0]); @@ -1451,6 +1457,8 @@ "TARGET_DIV && riscv_use_divmod_expander ()" { rtx tmp = gen_reg_rtx (<MODE>mode); + operands[1] = make_safe_from (operands[1], operands[0]); + operands[2] = make_safe_from (operands[2], operands[0]); emit_insn (gen_<u>div<GPR:mode>3 (operands[0], operands[1], operands[2])); emit_insn (gen_mul<GPR:mode>3 (tmp, operands[0], operands[2])); emit_insn (gen_sub<GPR:mode>3 (operands[3], operands[1], tmp)); @@ -4962,7 +4970,7 @@ (match_operand:SI 4 "register_operand" "r")))) (clobber (match_scratch:DI 5 "=&r"))] "TARGET_64BIT - && (INTVAL (operands[3]) | ((1 << INTVAL (operands[2])) - 1)) == 0xffffffff" + && (INTVAL (operands[3]) | ((HOST_WIDE_INT_1U << INTVAL (operands[2])) - 1)) == 0xffffffff" "#" "&& reload_completed" [(set (match_dup 5) (ashift:DI (match_dup 1) (match_dup 2))) diff --git a/gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c b/gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c new file mode 100644 index 000000000000..02ef91a22bc6 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/xor-synthesis-5.c @@ -0,0 +1,10 @@ +/* { dg-do compile { target rv64 } } */ +/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */ +/* { dg-options "-march=rv64gc_zbkb -mabi=lp64d" } */ + +unsigned long f_or (unsigned long x) { return x | 0xF80000000000003Ful; } +unsigned long f_xor (unsigned long x) { return x ^ 0xF80000000000003Ful; } + +/* { dg-final { scan-assembler-times "\tori\t\[a-z0-9\]+,\[a-z0-9\]+,2047" 1 } } */ +/* { dg-final { scan-assembler-times "\txori\t\[a-z0-9\]+,\[a-z0-9\]+,2047" 1 } } */ +/* { dg-final { scan-assembler-times "\trori\t" 4 } } */ diff --git a/gcc/testsuite/gcc.target/riscv/zbkb-zext.c b/gcc/testsuite/gcc.target/riscv/zbkb-zext.c new file mode 100644 index 000000000000..b856adf37837 --- /dev/null +++ b/gcc/testsuite/gcc.target/riscv/zbkb-zext.c @@ -0,0 +1,3 @@ +/* { dg-do compile } */ +/* { dg-options "-march=rv64gc_zbkb -mabi=lp64" } */ +unsigned long f(unsigned long x){ return x & 0xFF000000000000FFul; }
