On 4/1/25 12:20 AM, Jin Ma wrote:
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)))])
So I would add a comment to that new condition.  Something like
/* Ensure the mask includes all the bits in SImode.  */

We need to be careful with constants like 1 << 31.  Something like
(HOST_WIDE_INT_1U << 31) would be better from a type safety standpoint (INTVAL returns a HOST_WIDE_INT object).






+#include <stdio.h>
In general, avoid #includes if you can in tests. Remove the <stdio.h> include.



+  printf("%llu\n", d);
Instead of a printf and using dg-output, the standard way we test for correctness is by either aborting or calling exit (0). So rather than the printf use

  if (d != 3023282)
    __builtin_abort ();
  __builtin_exit (0);

And drop the dg-output line.


With those changes this patch is probably OK. We'd want to post the V2 so that the pre-commit tester can chew on it.

Thanks!
Jeff

Reply via email to