https://gcc.gnu.org/g:a96792693e1fb8c1a8f36cf9c293bf9c329e82b0

commit r13-9839-ga96792693e1fb8c1a8f36cf9c293bf9c329e82b0
Author: Pengfei Li <pengfei....@arm.com>
Date:   Thu Aug 14 13:59:48 2025 +0000

    AArch64: Fix invalid immediate offsets in SVE gather/scatter [PR121449]
    
    This patch fixes incorrect constraints in RTL patterns for AArch64 SVE
    gather/scatter with type widening/narrowing and vector-plus-immediate
    addressing. The bug leads to below "immediate offset out of range"
    errors during assembly, eventually causing compilation failures.
    
    /tmp/ccsVqBp1.s: Assembler messages:
    /tmp/ccsVqBp1.s:54: Error: immediate offset out of range 0 to 31 at operand 
3 -- `ld1b z1.d,p0/z,[z1.d,#64]'
    
    Current RTL patterns for such instructions incorrectly use vgw or vgd
    constraints for the immediate operand, base on the vector element type
    in Z registers (zN.s or zN.d). However, for gather/scatter with type
    conversions, the immediate range for vector-plus-immediate addressing is
    determined by the element type in memory, which differs from that in
    vector registers. Using the wrong constraint can produce out-of-range
    offset values that cannot be encoded in the instruction.
    
    This patch corrects the constraints used in these patterns. A test case
    that reproduces the issue is also included.
    
    Bootstrapped and regression-tested on aarch64-linux-gnu.
    
    gcc/ChangeLog:
            PR target/121449
            * config/aarch64/aarch64-sve.md
            (mask_gather_load<mode><v_int_container>): Use vg<Vesize>
            constraints for alternatives with immediate offset.
            (mask_scatter_store<mode><v_int_container>): Likewise.
    
    gcc/testsuite/ChangeLog:
            PR target/121449
            * g++.target/aarch64/sve/pr121449.C: New test.

Diff:
---
 gcc/config/aarch64/aarch64-sve.md               |  8 ++---
 gcc/testsuite/g++.target/aarch64/sve/pr121449.C | 44 +++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 4 deletions(-)

diff --git a/gcc/config/aarch64/aarch64-sve.md 
b/gcc/config/aarch64/aarch64-sve.md
index 9cb09187c620..89f4e6d3b75c 100644
--- a/gcc/config/aarch64/aarch64-sve.md
+++ b/gcc/config/aarch64/aarch64-sve.md
@@ -1421,7 +1421,7 @@
   [(set (match_operand:SVE_4 0 "register_operand" "=w, w, w, w, w, w")
        (unspec:SVE_4
          [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, 
Upl")
-          (match_operand:DI 1 "aarch64_sve_gather_offset_<Vesize>" "Z, vgw, 
rk, rk, rk, rk")
+          (match_operand:DI 1 "aarch64_sve_gather_offset_<Vesize>" "Z, 
vg<Vesize>, rk, rk, rk, rk")
           (match_operand:VNx4SI 2 "register_operand" "w, w, w, w, w, w")
           (match_operand:DI 3 "const_int_operand" "Ui1, Ui1, Z, Ui1, Z, Ui1")
           (match_operand:DI 4 "aarch64_gather_scale_operand_<Vesize>" "Ui1, 
Ui1, Ui1, Ui1, i, i")
@@ -1443,7 +1443,7 @@
   [(set (match_operand:SVE_2 0 "register_operand" "=w, w, w, w")
        (unspec:SVE_2
          [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl")
-          (match_operand:DI 1 "aarch64_sve_gather_offset_<Vesize>" "Z, vgd, 
rk, rk")
+          (match_operand:DI 1 "aarch64_sve_gather_offset_<Vesize>" "Z, 
vg<Vesize>, rk, rk")
           (match_operand:VNx2DI 2 "register_operand" "w, w, w, w")
           (match_operand:DI 3 "const_int_operand")
           (match_operand:DI 4 "aarch64_gather_scale_operand_<Vesize>" "Ui1, 
Ui1, Ui1, i")
@@ -2254,7 +2254,7 @@
   [(set (mem:BLK (scratch))
        (unspec:BLK
          [(match_operand:VNx4BI 5 "register_operand" "Upl, Upl, Upl, Upl, Upl, 
Upl")
-          (match_operand:DI 0 "aarch64_sve_gather_offset_<Vesize>" "Z, vgw, 
rk, rk, rk, rk")
+          (match_operand:DI 0 "aarch64_sve_gather_offset_<Vesize>" "Z, 
vg<Vesize>, rk, rk, rk, rk")
           (match_operand:VNx4SI 1 "register_operand" "w, w, w, w, w, w")
           (match_operand:DI 2 "const_int_operand" "Ui1, Ui1, Z, Ui1, Z, Ui1")
           (match_operand:DI 3 "aarch64_gather_scale_operand_<Vesize>" "Ui1, 
Ui1, Ui1, Ui1, i, i")
@@ -2276,7 +2276,7 @@
   [(set (mem:BLK (scratch))
        (unspec:BLK
          [(match_operand:VNx2BI 5 "register_operand" "Upl, Upl, Upl, Upl")
-          (match_operand:DI 0 "aarch64_sve_gather_offset_<Vesize>" "Z, vgd, 
rk, rk")
+          (match_operand:DI 0 "aarch64_sve_gather_offset_<Vesize>" "Z, 
vg<Vesize>, rk, rk")
           (match_operand:VNx2DI 1 "register_operand" "w, w, w, w")
           (match_operand:DI 2 "const_int_operand")
           (match_operand:DI 3 "aarch64_gather_scale_operand_<Vesize>" "Ui1, 
Ui1, Ui1, i")
diff --git a/gcc/testsuite/g++.target/aarch64/sve/pr121449.C 
b/gcc/testsuite/g++.target/aarch64/sve/pr121449.C
new file mode 100644
index 000000000000..b2e13765dfa8
--- /dev/null
+++ b/gcc/testsuite/g++.target/aarch64/sve/pr121449.C
@@ -0,0 +1,44 @@
+/* PR target/121449 */
+/* { dg-do assemble { target aarch64_asm_sve_ok } } */
+/* { dg-options "-O3 -save-temps" } */
+
+struct example;
+
+struct array {
+  unsigned length();
+  example *operator[](unsigned i) {
+    example **data = reinterpret_cast<example **>(this);
+    return data[i];
+  }
+};
+
+struct example {
+  int a[16];
+  bool is_even;
+  int version;
+  int count() { return is_even ? 2 : 1; }
+  void fun1(int, long);
+  void fun2(unsigned, unsigned);
+  void process(array &, array &);
+};
+
+bool found;
+
+void example::process(array &a, array &b) {
+  for (unsigned i = 1; a.length(); i++) {
+    long total = 0;
+    for (unsigned k = 0; k <= i; k++) {
+      total += a[k]->count();
+    }
+    for (unsigned j = 0; j < i; j++) {
+      int major = b[j]->version;
+      if (found)
+        major += i;
+      fun1(i + 1, total);
+      fun2(j, major);
+    }
+  }
+}
+
+/* { dg-final { scan-assembler-not {\tld1b\t(z[0-9]+)\.d, p[0-7]/z, 
\[(z[0-9]+)\.d, #64\]} } } */
+

Reply via email to