Assuming we have the following variables:
unsigned long long a0, a1;
unsigned int a2;
For the expression:
a0 = (a0 << 50) >> 49; // slli a0, a0, 50 + srli a0, a0, 49
a2 = a1 + a0; // addw a2, a1, a0 + slli a2, a2, 32 + srli a2, a2, 32
In the optimization process of ZBA (combine pass), it would be optimized to:
a2 = a0 << 1 + a1; // sh1add a2, a0, a1 + zext.w a2, a2
This is clearly incorrect, as it overlooks the fact that a0=a0&0x7ffe, meaning
that the bits a0[32:14] are set to zero.
gcc/ChangeLog:
* config/riscv/bitmanip.md: The optimization can only be applied if
the high bit of operands[3] is set to 1.
gcc/testsuite/ChangeLog:
* gcc.target/riscv/zba-shNadd-09.c: New test.
* gcc.target/riscv/zba-shNadd-10.c: New test.
---
gcc/config/riscv/bitmanip.md | 3 ++-
.../gcc.target/riscv/zba-shNadd-09.c | 12 +++++++++++
.../gcc.target/riscv/zba-shNadd-10.c | 20 +++++++++++++++++++
3 files changed, 34 insertions(+), 1 deletion(-)
create mode 100644 gcc/testsuite/gcc.target/riscv/zba-shNadd-09.c
create mode 100644 gcc/testsuite/gcc.target/riscv/zba-shNadd-10.c
diff --git a/gcc/config/riscv/bitmanip.md b/gcc/config/riscv/bitmanip.md
index b29c127bcb8..9091c48b106 100644
--- a/gcc/config/riscv/bitmanip.md
+++ b/gcc/config/riscv/bitmanip.md
@@ -80,7 +80,8 @@ (define_split
(match_operand:DI 3
"consecutive_bits_operand")) 0)
(subreg:SI (match_operand:DI 4
"register_operand") 0))))]
"TARGET_64BIT && TARGET_ZBA
- && riscv_shamt_matches_mask_p (INTVAL (operands[2]), INTVAL (operands[3]))"
+ && riscv_shamt_matches_mask_p (INTVAL (operands[2]), INTVAL (operands[3]))
+ && ((INTVAL (operands[3]) & (1 << 31)) != 0)"
[(set (match_dup 0) (plus:DI (ashift:DI (match_dup 1) (match_dup 2))
(match_dup 4)))
(set (match_dup 0) (zero_extend:DI (subreg:SI (match_dup 0) 0)))])
diff --git a/gcc/testsuite/gcc.target/riscv/zba-shNadd-09.c
b/gcc/testsuite/gcc.target/riscv/zba-shNadd-09.c
new file mode 100644
index 00000000000..303f3cbb863
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zba-shNadd-09.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-march=rv64gc_zba -mabi=lp64" } */
+/* { dg-skip-if "" { *-*-* } { "-O0" "-Og" } } */
+
+long long sub (unsigned long long a, unsigned long long b)
+{
+ b = (b << 50) >> 49;
+ unsigned int x = a + b;
+ return x;
+}
+
+/* { dg-final { scan-assembler-not {\msh1add} } } */
diff --git a/gcc/testsuite/gcc.target/riscv/zba-shNadd-10.c
b/gcc/testsuite/gcc.target/riscv/zba-shNadd-10.c
new file mode 100644
index 00000000000..bec0260d625
--- /dev/null
+++ b/gcc/testsuite/gcc.target/riscv/zba-shNadd-10.c
@@ -0,0 +1,20 @@
+/* { dg-do run { target { rv64 } } } */
+/* { dg-options "-march=rv64gc_zba -mabi=lp64d -O2" } */
+
+#include <stdio.h>
+struct {
+ unsigned a : 14;
+ unsigned b : 3;
+} c;
+unsigned long long d;
+void e(unsigned long long *f, long p2) { *f = p2; }
+signed g;
+long i;
+int main() {
+ c.b = 4;
+ i = -(-c.a - (3023282U + c.a + g));
+ e(&d, i);
+ printf("%llu\n", d);
+}
+
+/* { dg-output "3023282\r\n" } */
--
2.25.1