On Tue, 7 Jul 2026, Tamar Christina wrote:

> 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?

OK.

Richard.

> 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
> 
> 
> 

-- 
Richard Biener <[email protected]>
SUSE Software Solutions Germany GmbH,
Frankenstrasse 146, 90461 Nuernberg, Germany;
GF: Jochen Jaser, Andrew McDonald; (HRB 36809, AG Nuernberg)

Reply via email to