On Fri, 1 Jul 2022, Martin Jambor wrote: > Hi, > > As the testcase in PR 105860 shows, the code that tries to re-use the > handled_component chains in SRA can be horribly confused by unions, > where it thinks it has found a compatible structure under which it can > chain the references, but in fact it found the type it was looking > for elsewhere in a union and generated a write to a completely wrong > part of an aggregate. > > I don't remember whether the plan was to support unions at all in > build_reconstructed_reference but it can work, to an extent, if we > make sure that we start the search only outside the outermost union, > which is what the patch does (and the extra testcase verifies). > > Bootstrapped and tested on x86_64-linux. OK for trunk and then for > release branches?
OK, but I'm wondering if the same problem can arise when the handled_component_p includes VIEW_CONVERTs or BIT_FIELD_REFs both of which may pun to a type already seen in a more inner referece. Thus, is the actual problem that build_reconstructed_reference searches for the outermost match of the type rather than the innermost match? So should it search inner-to-outer instead (or for the last match in the current way of searching?) Thanks, Richard. > Thanks, > > Martin > > > gcc/ChangeLog: > > 2022-07-01 Martin Jambor <mjam...@suse.cz> > > PR tree-optimization/105860 > * tree-sra.cc (build_reconstructed_reference): Start expr > traversal only just below the outermost union. > > gcc/testsuite/ChangeLog: > > 2022-07-01 Martin Jambor <mjam...@suse.cz> > > PR tree-optimization/105860 > * gcc.dg/tree-ssa/alias-access-path-13.c: New test. > * gcc.dg/tree-ssa/pr105860.c: Likewise. > --- > .../gcc.dg/tree-ssa/alias-access-path-13.c | 31 +++++++++ > gcc/testsuite/gcc.dg/tree-ssa/pr105860.c | 63 +++++++++++++++++++ > gcc/tree-sra.cc | 13 +++- > 3 files changed, 106 insertions(+), 1 deletion(-) > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-13.c > create mode 100644 gcc/testsuite/gcc.dg/tree-ssa/pr105860.c > > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-13.c > b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-13.c > new file mode 100644 > index 00000000000..e502a97bc75 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/alias-access-path-13.c > @@ -0,0 +1,31 @@ > +/* { dg-do compile } */ > +/* { dg-options "-O2 -fdump-tree-fre1" } */ > + > +struct inn > +{ > + int val; > +}; > + > +union foo > +{ > + struct inn inn; > + long int baz; > +} *fooptr; > + > +struct bar > +{ > + union foo foo; > + int val2; > +} *barptr; > + > +int > +test () > +{ > + union foo foo; > + foo.inn.val = 0; > + barptr->val2 = 123; > + *fooptr = foo; > + return barptr->val2; > +} > + > +/* { dg-final { scan-tree-dump-times "return 123" 1 "fre1"} } */ > diff --git a/gcc/testsuite/gcc.dg/tree-ssa/pr105860.c > b/gcc/testsuite/gcc.dg/tree-ssa/pr105860.c > new file mode 100644 > index 00000000000..77bcb4a6739 > --- /dev/null > +++ b/gcc/testsuite/gcc.dg/tree-ssa/pr105860.c > @@ -0,0 +1,63 @@ > +/* { dg-do run } */ > +/* { dg-options "-O1" } */ > + > +struct S1 { > + unsigned int _0; > + unsigned int _1; > +} ; > +struct S2 { > + struct S1 _s1; > + unsigned long _x2; > +} ; > + > +struct ufld_type1 { > + unsigned int _u1t; > + struct S2 _s2; > +} ; > + > +struct ufld_type2 { > + unsigned int _u2t; > + struct S1 _s1; > +} ; > +struct parm_type { > + union { > + struct ufld_type1 var_1; > + struct ufld_type2 var_2; > + } U; > +}; > + > +struct parm_type bad_function( struct parm_type arg0 ) > +{ > + struct parm_type rv; > + struct S2 var4; > + switch( arg0.U.var_2._u2t ) { > + case 4294967041: > + var4._s1 = arg0.U.var_1._s2._s1; > + rv.U.var_1._u1t = 4294967041; > + rv.U.var_1._s2 = var4; > + break; > + case 4294967043: > + rv.U.var_2._u2t = 4294967043; > + rv.U.var_2._s1 = arg0.U.var_2._s1; > + break; > + default: > + break; > + } > + return rv; > +} > + > +int main() { > + struct parm_type val; > + struct parm_type out; > + val.U.var_2._u2t = 4294967043; > + val.U.var_2._s1._0 = 0x01010101; > + val.U.var_2._s1._1 = 0x02020202; > + out = bad_function(val); > + if (val.U.var_2._u2t != 4294967043) > + __builtin_abort (); > + if (out.U.var_2._s1._0 != 0x01010101) > + __builtin_abort (); > + if (val.U.var_2._s1._1 != 0x02020202 ) > + __builtin_abort (); > + return 0; > +} > diff --git a/gcc/tree-sra.cc b/gcc/tree-sra.cc > index 081c51b58a4..099e8dbe873 100644 > --- a/gcc/tree-sra.cc > +++ b/gcc/tree-sra.cc > @@ -1667,7 +1667,18 @@ build_ref_for_offset (location_t loc, tree base, > poly_int64 offset, > static tree > build_reconstructed_reference (location_t, tree base, struct access *model) > { > - tree expr = model->expr, prev_expr = NULL; > + tree expr = model->expr; > + /* We have to make sure to start just below the outermost union. */ > + tree start_expr = expr; > + while (handled_component_p (expr)) > + { > + if (TREE_CODE (TREE_TYPE (TREE_OPERAND (expr, 0))) == UNION_TYPE) > + start_expr = expr; > + expr = TREE_OPERAND (expr, 0); > + } > + > + expr = start_expr; > + tree prev_expr = NULL_TREE; > while (!types_compatible_p (TREE_TYPE (expr), TREE_TYPE (base))) > { > if (!handled_component_p (expr)) > -- Richard Biener <rguent...@suse.de> SUSE Software Solutions Germany GmbH, Frankenstra