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

Bootstrapped Regtested on aarch64-none-linux-gnu,
arm-none-linux-gnueabihf, x86_64-pc-linux-gnu
-m32, -m64 and no issues.

Any feedback?

Thanks,
Tamar

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 --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 
0000000000000000000000000000000000000000..9129f82cffe5e0028bbd6b7f0a9ae434388331e3
--- /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 
ab850de024bf41ea7635ce7381bcc6acd8fe0c28..8c71865aa0b1c2db7f0b0167dc7ed1db6c6da260
 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


-- 
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 0000000000000000000000000000000000000000..9129f82cffe5e0028bbd6b7f0a9ae434388331e3
--- /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 ab850de024bf41ea7635ce7381bcc6acd8fe0c28..8c71865aa0b1c2db7f0b0167dc7ed1db6c6da260 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