Hi,

On Mon, Jul 04 2022, Richard Biener wrote:
> 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.

SRA already refuses to operate at all on any anything that is accessed
with a reference where a V_C_E is not the outermost handled_component.
Outermost V_C_Es are skipped and the pass works with the underlying
expr.  BIT_FIELD_REFs have to be outermost and they are treated
similarly.  So that should be safe.

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

I don't think so.  In the testcase it found a match where there should
have been none (meaning a crude MEM_REF should be created), any
certainly correct match must be outside of a union COMPONENT_REF and
there should never be more than one.

Thanks,

Martin

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

Reply via email to