[gcc r15-7881] vect: Enforce dr_with_seg_len::align precondition [PR116125]
Richard Sandiford
rsandifo@gcc.gnu.org
Fri Mar 7 10:18:52 GMT 2025
https://gcc.gnu.org/g:e8651b80aeb86da935035e218747a6b41b611497
commit r15-7881-ge8651b80aeb86da935035e218747a6b41b611497
Author: Richard Sandiford <richard.sandiford@arm.com>
Date: Fri Mar 7 10:18:35 2025 +0000
vect: Enforce dr_with_seg_len::align precondition [PR116125]
tree-data-refs.cc uses alignment information to try to optimise
the code generated for alias checks. The assumption for "normal"
non-grouped, full-width scalar accesses was that the access size
would be a multiple of the alignment. As Richi notes in the PR,
this is a documented precondition of dr_with_seg_len:
/* The minimum common alignment of DR's start address, SEG_LEN and
ACCESS_SIZE. */
unsigned int align;
PR115192 was a case in which this assumption didn't hold. The access
was part of an aligned 4-element group, but only the first 2 elements
of the group were accessed. The alignment was therefore double the
access size.
In r15-820-ga0fe4fb1c8d78045 I'd "fixed" that by capping the
alignment in one of the output routines. But I think that was
misconceived. The precondition means that we should cap the
alignment at source instead.
Failure to do that caused a similar wrong code bug in this PR,
where the alignment comes from a short bitfield access rather
than from a group access.
gcc/
PR tree-optimization/116125
* tree-vect-data-refs.cc (vect_prune_runtime_alias_test_list): Make
the dr_with_seg_len alignment fields describe tha access sizes as
well as the pointer alignment.
* tree-data-ref.cc (create_intersect_range_checks): Don't compensate
for invalid alignment fields here.
gcc/testsuite/
PR tree-optimization/116125
* gcc.dg/vect/pr116125.c: New test.
Diff:
---
gcc/testsuite/gcc.dg/vect/pr116125.c | 30 ++++++++++++++++++++++++++++++
gcc/tree-data-ref.cc | 2 --
gcc/tree-vect-data-refs.cc | 9 ++++++++-
3 files changed, 38 insertions(+), 3 deletions(-)
diff --git a/gcc/testsuite/gcc.dg/vect/pr116125.c b/gcc/testsuite/gcc.dg/vect/pr116125.c
new file mode 100644
index 000000000000..eab9efdc061b
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vect/pr116125.c
@@ -0,0 +1,30 @@
+#include "tree-vect.h"
+
+struct st
+{
+ unsigned int num : 8;
+};
+
+void __attribute__((noipa))
+mem_overlap (struct st *a, struct st *b)
+{
+ for (int i = 0; i < 9; i++)
+ a[i].num = b[i].num + 1;
+}
+
+int
+main (void)
+{
+ check_vect ();
+
+ struct st a[9] = {};
+
+ // input a = 0, 0, 0, 0, 0, 0, 0, 0, 0
+ mem_overlap (&a[1], a);
+
+ // output a = 0, 1, 2, 3, 4, 5, 6, 7, 8
+ if (a[2].num == 2)
+ return 0;
+ else
+ __builtin_abort ();
+}
diff --git a/gcc/tree-data-ref.cc b/gcc/tree-data-ref.cc
index 5decfb1abf51..18d9f0fa7660 100644
--- a/gcc/tree-data-ref.cc
+++ b/gcc/tree-data-ref.cc
@@ -2647,8 +2647,6 @@ create_intersect_range_checks (class loop *loop, tree *cond_expr,
if the maximum value of one segment is equal to the minimum
value of the other. */
min_align = std::min (dr_a.align, dr_b.align);
- min_align = std::min (min_align, known_alignment (dr_a.access_size));
- min_align = std::min (min_align, known_alignment (dr_b.access_size));
cmp_code = LT_EXPR;
}
diff --git a/gcc/tree-vect-data-refs.cc b/gcc/tree-vect-data-refs.cc
index 6d5854ac7c7a..eb43526094bc 100644
--- a/gcc/tree-vect-data-refs.cc
+++ b/gcc/tree-vect-data-refs.cc
@@ -4074,7 +4074,7 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
poly_uint64 lower_bound;
tree segment_length_a, segment_length_b;
unsigned HOST_WIDE_INT access_size_a, access_size_b;
- unsigned int align_a, align_b;
+ unsigned HOST_WIDE_INT align_a, align_b;
/* Ignore the alias if the VF we chose ended up being no greater
than the dependence distance. */
@@ -4231,6 +4231,13 @@ vect_prune_runtime_alias_test_list (loop_vec_info loop_vinfo)
stmt_info_b->stmt);
}
+ /* dr_with_seg_len requires the alignment to apply to the segment length
+ and access size, not just the start address. The access size can be
+ smaller than the pointer alignment for grouped accesses and bitfield
+ references; see PR115192 and PR116125 respectively. */
+ align_a = std::min (align_a, least_bit_hwi (access_size_a));
+ align_b = std::min (align_b, least_bit_hwi (access_size_b));
+
dr_with_seg_len dr_a (dr_info_a->dr, segment_length_a,
access_size_a, align_a);
dr_with_seg_len dr_b (dr_info_b->dr, segment_length_b,
More information about the Gcc-cvs
mailing list