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