https://gcc.gnu.org/g:09021961ea027196cafca0d0308fd7c5e997bff8

commit r17-2213-g09021961ea027196cafca0d0308fd7c5e997bff8
Author: Tamar Christina <[email protected]>
Date:   Wed Jul 8 08:35:45 2026 +0100

    vect: unshare header computation for more CSE
    
    The example loop
    
    #define N 512
    #define START 1
    #define END 505
    
    int x[N] __attribute__((aligned(32)));
    
    int __attribute__((noipa))
    foo (void)
    {
      for (int *p = x + START; p < x + END; ++p)
        if (*p == 0)
          return START;
    
      return -1;
    }
    
    shows that when we vectorize we generate the following pre-header when doing
    peeling for alignment:
    
      _22 = (unsigned long) &MEM <int[512]> [(void *)&x + 4B];
      _23 = _22 & POLY_INT_CST [15, 16];
      _24 = _23 >> 2;
      _26 = 1 - _24;
      _27 = _26 * 4;
      vectp_x.6_25 = &x + _27;
      _36 = 504 + _24;
      max_mask_37 = .WHILE_ULT (0, _36, { 0, ... });
      _38 = .WHILE_ULT (0, _24, { 0, ... });
      _39 = ~_38;
      _40 = max_mask_37 & _39;
    
    notice how _22 and and the actual vector pointer vectp_x.6_25 start at the
    same offset but have a different base.  This happens because in
    vect_create_addr_base_for_vector_ref we fold the offset into the base very
    early and so we can't form or share the address computation anymore with the
    scalar address which needs to be there for the alignment checks.
    
    The patch delays this and forms an explicit base + offset and keeping base 
as
    a separate value.  This allows VN at the end of vect to share the 
computations
    and we get
    
      _22 = (unsigned long) &MEM <int[512]> [(void *)&x + 4B];
      _23 = _22 & POLY_INT_CST [15, 16];
      _24 = _23 >> 2;
      _27 = _24 * 4;
      _28 = -_27;
      vectp_x.6_26 = &MEM <int[512]> [(void *)&x + 4B] + _28;
      _37 = 504 + _24;
      max_mask_38 = .WHILE_ULT (0, _37, { 0, ... });
      _39 = .WHILE_ULT (0, _24, { 0, ... });
      _40 = ~_39;
      _41 = max_mask_38 & _40;
    
    Notice how they now share the same base address.  This drops two 
instructions
    off the loop pre-header:
    
    from
    
    foo:
            cntb    x0
            sub     x3, x0, #1
            cmp     x0, 4096
            and     x0, x0, x3
            ccmp    x0, 0, 0, ls
            bne     .L7
            adrp    x4, .LANCHOR0
            add     x4, x4, :lo12:.LANCHOR0
            add     x1, x4, 4
            mov     w2, 1
            and     x1, x1, x3
            mov     w0, 0
            cntw    x3
            lsr     x1, x1, 2
            whilelo p15.s, xzr, x1
            sub     x2, x2, x1
            add     x1, x1, 504
            whilelo p7.s, xzr, x1
            not     p7.b, p7/z, p15.b
            add     x2, x4, x2, lsl 2
            b       .L4
    
    to
    
    foo:
            cntb    x0
            sub     x1, x0, #1
            cmp     x0, 4096
            and     x0, x0, x1
            adrp    x2, .LANCHOR0
            ccmp    x0, 0, 0, ls
            add     x2, x2, :lo12:.LANCHOR0
            bne     .L7
            add     x2, x2, 4
            mov     w0, 0
            and     x1, x2, x1
            cntw    x3
            sub     x2, x2, x1
            lsr     x1, x1, 2
            whilelo p15.s, xzr, x1
            add     x1, x1, 504
            whilelo p7.s, xzr, x1
            not     p7.b, p7/z, p15.b
            b       .L4
    
    gcc/ChangeLog:
    
            * tree-vect-data-refs.cc (vect_create_addr_base_for_vector_ref):
            Restructure computations to force separate base.
    
    gcc/testsuite/ChangeLog:
    
            * gcc.target/aarch64/sve/vect-early-break-cbranch_18.c: New test.

Diff:
---
 .../aarch64/sve/vect-early-break-cbranch_18.c      | 22 ++++++++++++++++
 gcc/tree-vect-data-refs.cc                         | 30 ++++++++++++++++++++--
 2 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_18.c 
b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_18.c
new file mode 100644
index 000000000000..9129f82cffe5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/sve/vect-early-break-cbranch_18.c
@@ -0,0 +1,22 @@
+/* { dg-do compile } */
+/* { dg-options "-Ofast -msve-vector-bits=256 -mautovec-preference=sve-only 
-fdump-tree-vect-details" } */
+
+#define N 512
+#define START 1
+#define END 505
+
+int x[N] __attribute__((aligned(32)));
+
+int __attribute__((noipa))
+foo (void)
+{
+  for (int *p = x + START; p < x + END; ++p)
+    if (*p == 0)
+      return START;
+
+  return -1;
+}
+
+/* { dg-final { scan-tree-dump "Alignment of access forced using peeling" 
"vect" } } */
+/* { dg-final { scan-tree-dump-times {Value numbering stmt = 
vectp_x\.[0-9]+_[0-9]+ = &x \+ 4;} 1 "vect" } } */
+/* { dg-final { scan-tree-dump-times {Value numbering stmt = 
vectp_x\.[0-9]+_[0-9]+ = vectp_x\.[0-9]+_[0-9]+ \+ 18446744073709551612;} 1 
"vect" } } */
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index 80f7539614c2..0e0754769ae4 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -5729,7 +5729,13 @@ vect_create_addr_base_for_vector_ref (vec_info *vinfo, 
stmt_vec_info stmt_info,
   innermost_loop_behavior *drb = vect_dr_behavior (vinfo, dr_info);
 
   tree data_ref_base = unshare_expr (drb->base_address);
-  tree base_offset = unshare_expr (get_dr_vinfo_offset (vinfo, dr_info, true));
+  tree vector_offset = NULL_TREE;
+  if (loop_vinfo && dr_info->offset)
+    vector_offset = unshare_expr (dr_info->offset);
+  tree base_offset = unshare_expr (vector_offset
+                                  ? drb->offset
+                                  : get_dr_vinfo_offset (vinfo, dr_info,
+                                                         true));
   tree init = unshare_expr (drb->init);
 
   if (loop_vinfo)
@@ -5767,7 +5773,27 @@ vect_create_addr_base_for_vector_ref (vec_info *vinfo, 
stmt_vec_info stmt_info,
 
   vect_ptr_type = build_pointer_type (TREE_TYPE (DR_REF (dr)));
   dest = vect_get_new_vect_var (vect_ptr_type, vect_pointer_var, base_name);
-  addr_base = force_gimple_operand (addr_base, &seq, true, dest);
+
+  /* Keep vectorizer-added offsets separate from the original scalar access
+     address.  Forming "base + scalar offset" first gives the target a better
+     chance of sharing it with other address calculations, such as the
+     misalignment check used for masked alignment peeling.  */
+  if (vector_offset)
+    {
+      tree scalar_dest = vect_get_new_vect_var (vect_ptr_type,
+                                               vect_pointer_var, base_name);
+      gimple_seq addr_seq = NULL;
+      addr_base = force_gimple_operand (addr_base, &addr_seq, true,
+                                       scalar_dest);
+      gimple_seq_add_seq (&seq, addr_seq);
+      addr_base = fold_build_pointer_plus (addr_base,
+                                          fold_convert (sizetype,
+                                                        vector_offset));
+    }
+
+  gimple_seq addr_seq = NULL;
+  addr_base = force_gimple_operand (addr_base, &addr_seq, true, dest);
+  gimple_seq_add_seq (&seq, addr_seq);
   gimple_seq_add_seq (new_stmt_list, seq);
 
   if (TREE_CODE (addr_base) == SSA_NAME

Reply via email to