This patch introduces a new RTL pattern for bset + sext + or and
Test cases for this pattern.

The patch does not fully resolve the bug itself, but only one
specific case of it. The pattern is written this way because
the issue only occurs with the bset + sext sequence when
the output is a 64-bit value, where the upper 32bits are lost
during the sext instruction.

Example:
dest = 0xFFFFFFFF00000001
a = 29

In the initial implementation, we get:
0xFFFFFFFF00000001 | 0x0000000020000000

which results in:
0xFFFFFFFF20000001

However, with the bset + sext sequence, the behavior is incorrect:
after bset : 0xFFFFFFFF20000001
after sext : 0x0000000020000001

So the sign extension is performed incorrectly, causing the upper 32 bits to
be discarded and leading to an incorrect final result.

The issue is that both long and int cases currently share the same RTL in the
combine pass when our pattern matches, so at the moment I do not have a clear
 way to distinguish between them. As a result, GCC also generates bset + sext + 
or
for the int case, where it should generate only bset + sext.

Regression testing on RISC-V trunk completed with no new failures.

2026-05-07  Milan Tripkovic  <[email protected]>

gcc/ChangeLog:

      * config/riscv/bitmanip.md (bset_sextw_or): new pattern for bset

gcc/testsuite/ChangeLog:

      * gcc.target/riscv/pr123884-c.c: New test for new pattern






CONFIDENTIALITY: The contents of this e-mail are confidential and intended only 
for the above addressee(s). If you are not the intended recipient, or the 
person responsible for delivering it to the intended recipient, copying or 
delivering it to anyone else or using it in any unauthorized manner is 
prohibited and may be unlawful. If you receive this e-mail by mistake, please 
notify the sender and the systems administrator at [email protected] 
immediately.
---
 gcc/config/riscv/bitmanip.md                | 26 +++++++++++++++++++++
 gcc/testsuite/gcc.target/riscv/pr123884-c.c | 17 ++++++++++++++
 2 files changed, 43 insertions(+)
 create mode 100644 gcc/testsuite/gcc.target/riscv/pr123884-c.c

diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index a0ee29439..e2e71e700 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -740,6 +740,32 @@
   { operands[2] = GEN_INT (INTVAL (operands[2]) & 0x1f); }
   [(set_attr "type" "bitmanip")])
 
+;;Pattern for bset with sign_extend
+(define_insn_and_split "bset_sextw_or"
+       [(set (match_operand:DI 0 "register_operand" "=r")
+                               (ior:DI
+                                       (sign_extend:DI
+                                               (ashift:SI
+                                                       (const_int 1)
+                                                               (subreg:QI
+                                                                       
(match_operand:DI 1 "register_operand" "r") 0)))
+                                       (match_operand:DI 2 "register_operand" 
"r")))]
+       "TARGET_64BIT && TARGET_ZBS"
+       "#"
+       "&& !reload_completed"
+       [
+               (set (match_dup 3)
+                                       (ashift:DI (const_int 1)
+                                                                       
(subreg:QI (match_dup 1) 0)))
+               (set (match_dup 3)
+                                       (sign_extend:DI (subreg:SI (match_dup 
3) 0)))
+               (set (match_dup 0)
+                                       (ior:DI (match_dup 2) (match_dup 3)))
+       ]
+       {
+               operands[3] = gen_reg_rtx (DImode);
+       }
+)
 ;; Similarly two patterns for AND generating bclr to
 ;; manipulate a bit in a register
 (define_insn_and_split ""
diff --git a/gcc/testsuite/gcc.target/riscv/pr123884-c.c 
b/gcc/testsuite/gcc.target/riscv/pr123884-c.c
new file mode 100644
index 000000000..61f5756bc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/pr123884-c.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zbs -mabi=lp64d -O2" } */
+ 
+int foo2(int dst, int a)
+{
+    dst |= (1 << a);
+    return dst;
+}
+
+long  foo(long dst, int a)
+{
+    return dst | (1 << a);
+}
+ 
+/* { dg-final { scan-assembler-times "\tbset\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tsext.w\t" 2 } } */
+/* { dg-final { scan-assembler-times "\tor\t" 2 } } */
\ No newline at end of file
-- 
2.34.1

Reply via email to