On Thu, Aug 28, 2025 at 4:25 AM Richard Biener
<[email protected]> wrote:
>
> On Wed, Aug 27, 2025 at 6:12 PM Andrew Pinski
> <[email protected]> wrote:
> >
> > Currently the code rejects:
> > ```
> > tmp = *a;
> > *b = tmp;
> > ```
> > (unless *a == *b). This can be improved such that if a and b are known to
> > share the same base, then only reject it if they overlap; that is the
> > difference of the offsets (from the base) is maybe less than the size.
> >
> > This fixes the testcase in comment #0 of PR 107051.
> >
> > PR tree-optimization/107051
> >
> > gcc/ChangeLog:
> >
> > * tree-ssa-forwprop.cc (optimize_agr_copyprop_1): Allow for
> > memory sharing the same base if they known not to overlap over
> > the size.
> >
> > gcc/testsuite/ChangeLog:
> >
> > * gcc.dg/tree-ssa/copy-prop-aggregate-union-1.c: New test.
> >
> > Signed-off-by: Andrew Pinski <[email protected]>
> > ---
> > .../tree-ssa/copy-prop-aggregate-union-1.c | 24 +++++++++++++++++
> > gcc/tree-ssa-forwprop.cc | 27 ++++++++++++++++++-
> > 2 files changed, 50 insertions(+), 1 deletion(-)
> > create mode 100644
> > gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-union-1.c
> >
> > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-union-1.c
> > b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-union-1.c
> > new file mode 100644
> > index 00000000000..206f6e1be55
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tree-ssa/copy-prop-aggregate-union-1.c
> > @@ -0,0 +1,24 @@
> > +/* { dg-do compile } */
> > +/* { dg-options "-O1 -fdump-tree-forwprop1-details" } */
> > +/* PR tree-optimization/107051 */
> > +
> > +
> > +union U2 {
> > + unsigned f0;
> > + char * f1;
> > +};
> > +
> > +/* Since g_284[0] and g_284[1] are known not overlap,
> > + copy prop can happen. */
> > +union U2 g_284[2] = {{0UL},{0xC2488F72L}};
> > +
> > +int e;
> > +void func_1() {
> > + union U2 c = {7};
> > + int *d[2];
> > + for (; e;)
> > + *d[1] = 0;
> > + g_284[0] = c = g_284[1];
> > +}
> > +
> > +/* { dg-final { scan-tree-dump-times "after previous" 1 "forwprop1" } } */
> > diff --git a/gcc/tree-ssa-forwprop.cc b/gcc/tree-ssa-forwprop.cc
> > index e0f25a12f34..82344f4020d 100644
> > --- a/gcc/tree-ssa-forwprop.cc
> > +++ b/gcc/tree-ssa-forwprop.cc
> > @@ -1455,7 +1455,32 @@ optimize_agr_copyprop_1 (gimple *stmt, gimple
> > *use_stmt,
> > */
> > if (!operand_equal_p (dest2, src, 0)
> > && !DECL_P (dest2) && !DECL_P (src))
> > - return false;
> > + {
> > + /* If *a and *b have the same base see if
> > + the offset between the two is greater than
> > + or equal to the size of the type. */
> > + poly_int64 offset1, offset2;
> > + tree len = TYPE_SIZE_UNIT (TREE_TYPE (src));
> > + if (len == NULL_TREE
> > + || !tree_fits_poly_int64_p (len))
> > + return false;
> > + tree base1 = get_addr_base_and_unit_offset (dest2, &offset1);
> > + if (!base1)
> > + return false;
> > + tree base2 = get_addr_base_and_unit_offset (src, &offset2);
> > + if (!base2)
> > + return false;
> > + if (!operand_equal_p (base1, base2))
>
> I'll note that exact overlap, thus
>
> b = a;
> tmp = *a;
> *b = tmp;
>
> is fine. VN uses alignment as additional non-partial overlap test,
> so when !operand_equal_p here you could see whether
> get_object_alignment () for both is > size (mostly interesting for
> small sizes, of course). With -fstrict-aliasing if both have the
> same type then partial overlaps also cannot happen (but this
> condition is a bit difficult to apply I think).
Actually the same type is exactly when we need to reject it.
We have:
```
struct s D.3029;
struct s * q.2_1;
struct s * p.3_3;
<bb 2> [local count: 1073741824]:
q.2_1 = q;
p.3_3 = p;
D.3029 = *p.3_3;
*q.2_1 = D.3029;
```
A load from `p.3_3` and then a store to `q.2_1`. They have exactly the
same type but different bases in the IR. Note `q.2_1` is equal to
`p.3_3 + 4B` due to the union.
So in summary with -fstrict-aliasing, we still can't figure out it
since then we will be using a memcpy (during expansion) for
overlapping copy. we could in theory change it over to a memmove but
then we lose aliasing information.
I have a new patch which I am testing and will submit soon.
Thanks,
Andrew Pinski
>
> > + return false;
> > + poly_int64 size = tree_to_poly_int64 (len);
> > + /* Make sure [offset1, offset1 + len - 1] does
> > + not overlap with [offset2, offset2 + len - 1]
> > + or overlaps fully. */
>
> There's ranges_may_overlap_p you might want to use here.
>
> Richard.
>
> > + if (!known_eq (offset2, offset1)
> > + && !known_ge (offset2 - offset1, size)
> > + && !known_ge (offset1 - offset2, size))
> > + return false;
> > + }
> >
> > if (dump_file && (dump_flags & TDF_DETAILS))
> > {
> > --
> > 2.43.0
> >