The following fixes a bug in PTA that caused const/pure calls and
calls with fn spec attribute to have mishandled return solutions
or CALLCLOBBERED solutions.

Bootstrapped and tested on x86_64-unknown-linux-gnu, no testcase
for the reported issue (I failed to massage the three-file fortran
testcase).

Richard.

2016-09-21  Richard Biener  <rguent...@suse.de>

        PR tree-optimization/77648
        * tree-ssa-structalias.c (process_constraint): Handle all DEREF
        with complex RHS.
        (make_transitive_closure_constraints): Adjust comment.
        (make_any_offset_constraints): New function.
        (handle_rhs_call): Make sure to first expand a pointer to all
        subfields before transitively closing it.
        (handle_const_call): Likewise.  Properly expand returned
        pointers as well.
        (handle_pure_call): Likewise.

        * gcc.dg/torture/pr77648-1.c: New testcase.
        * gcc.dg/torture/pr77648-2.c: Likewise.


Index: gcc/tree-ssa-structalias.c
===================================================================
*** gcc/tree-ssa-structalias.c  (revision 240255)
--- gcc/tree-ssa-structalias.c  (working copy)
*************** process_constraint (constraint_t t)
*** 3010,3016 ****
        process_constraint (new_constraint (tmplhs, rhs));
        process_constraint (new_constraint (lhs, tmplhs));
      }
!   else if (rhs.type == ADDRESSOF && lhs.type == DEREF)
      {
        /* Split into tmp = &rhs, *lhs = tmp */
        struct constraint_expr tmplhs;
--- 3010,3016 ----
        process_constraint (new_constraint (tmplhs, rhs));
        process_constraint (new_constraint (lhs, tmplhs));
      }
!   else if ((rhs.type != SCALAR || rhs.offset != 0) && lhs.type == DEREF)
      {
        /* Split into tmp = &rhs, *lhs = tmp */
        struct constraint_expr tmplhs;
*************** make_transitive_closure_constraints (var
*** 3747,3753 ****
  {
    struct constraint_expr lhs, rhs;
  
!   /* VAR = *VAR;  */
    lhs.type = SCALAR;
    lhs.var = vi->id;
    lhs.offset = 0;
--- 3747,3753 ----
  {
    struct constraint_expr lhs, rhs;
  
!   /* VAR = *(VAR + UNKNOWN);  */
    lhs.type = SCALAR;
    lhs.var = vi->id;
    lhs.offset = 0;
*************** make_transitive_closure_constraints (var
*** 3757,3762 ****
--- 3757,3779 ----
    process_constraint (new_constraint (lhs, rhs));
  }
  
+ /* Add constraints to that the solution of VI has all subvariables added.  */
+ 
+ static void
+ make_any_offset_constraints (varinfo_t vi)
+ {
+   struct constraint_expr lhs, rhs;
+ 
+   /* VAR = VAR + UNKNOWN;  */
+   lhs.type = SCALAR;
+   lhs.var = vi->id;
+   lhs.offset = 0;
+   rhs.type = SCALAR;
+   rhs.var = vi->id;
+   rhs.offset = UNKNOWN_OFFSET;
+   process_constraint (new_constraint (lhs, rhs));
+ }
+ 
  /* Temporary storage for fake var decls.  */
  struct obstack fake_var_decl_obstack;
  
*************** handle_rhs_call (gcall *stmt, vec<ce_s>
*** 3902,3916 ****
           && (flags & EAF_NOESCAPE))
        {
          varinfo_t uses = get_call_use_vi (stmt);
          if (!(flags & EAF_DIRECT))
!           {
!             varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
!             make_constraint_to (tem->id, arg);
!             make_transitive_closure_constraints (tem);
!             make_copy_constraint (uses, tem->id);
!           }
!         else
!           make_constraint_to (uses->id, arg);
          returns_uses = true;
        }
        else if (flags & EAF_NOESCAPE)
--- 3919,3930 ----
           && (flags & EAF_NOESCAPE))
        {
          varinfo_t uses = get_call_use_vi (stmt);
+         varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
+         make_constraint_to (tem->id, arg);
+         make_any_offset_constraints (tem);
          if (!(flags & EAF_DIRECT))
!           make_transitive_closure_constraints (tem);
!         make_copy_constraint (uses, tem->id);
          returns_uses = true;
        }
        else if (flags & EAF_NOESCAPE)
*************** handle_rhs_call (gcall *stmt, vec<ce_s>
*** 3920,3925 ****
--- 3934,3940 ----
          varinfo_t clobbers = get_call_clobber_vi (stmt);
          varinfo_t tem = new_var_info (NULL_TREE, "callarg", true);
          make_constraint_to (tem->id, arg);
+         make_any_offset_constraints (tem);
          if (!(flags & EAF_DIRECT))
            make_transitive_closure_constraints (tem);
          make_copy_constraint (uses, tem->id);
*************** handle_rhs_call (gcall *stmt, vec<ce_s>
*** 3945,3951 ****
    if (returns_uses)
      {
        rhsc.var = get_call_use_vi (stmt)->id;
!       rhsc.offset = 0;
        rhsc.type = SCALAR;
        results->safe_push (rhsc);
      }
--- 3960,3966 ----
    if (returns_uses)
      {
        rhsc.var = get_call_use_vi (stmt)->id;
!       rhsc.offset = UNKNOWN_OFFSET;
        rhsc.type = SCALAR;
        results->safe_push (rhsc);
      }
*************** handle_const_call (gcall *stmt, vec<ce_s
*** 4054,4059 ****
--- 4069,4075 ----
    if (gimple_call_chain (stmt))
      {
        varinfo_t uses = get_call_use_vi (stmt);
+       make_any_offset_constraints (uses);
        make_transitive_closure_constraints (uses);
        make_constraint_to (uses->id, gimple_call_chain (stmt));
        rhsc.var = uses->id;
*************** handle_const_call (gcall *stmt, vec<ce_s
*** 4062,4077 ****
        results->safe_push (rhsc);
      }
  
!   /* May return arguments.  */
    for (k = 0; k < gimple_call_num_args (stmt); ++k)
      {
        tree arg = gimple_call_arg (stmt, k);
        auto_vec<ce_s> argc;
-       unsigned i;
-       struct constraint_expr *argp;
        get_constraint_for_rhs (arg, &argc);
!       FOR_EACH_VEC_ELT (argc, i, argp)
!       results->safe_push (*argp);
      }
  
    /* May return addresses of globals.  */
--- 4078,4101 ----
        results->safe_push (rhsc);
      }
  
!   /* May return offsetted arguments.  */
!   varinfo_t tem = NULL;
!   if (gimple_call_num_args (stmt) != 0)
!     tem = new_var_info (NULL_TREE, "callarg", true);
    for (k = 0; k < gimple_call_num_args (stmt); ++k)
      {
        tree arg = gimple_call_arg (stmt, k);
        auto_vec<ce_s> argc;
        get_constraint_for_rhs (arg, &argc);
!       make_constraints_to (tem->id, argc);
!     }
!   if (tem)
!     {
!       ce_s ce;
!       ce.type = SCALAR;
!       ce.var = tem->id;
!       ce.offset = UNKNOWN_OFFSET;
!       results->safe_push (ce);
      }
  
    /* May return addresses of globals.  */
*************** handle_pure_call (gcall *stmt, vec<ce_s>
*** 4098,4103 ****
--- 4122,4128 ----
        if (!uses)
        {
          uses = get_call_use_vi (stmt);
+         make_any_offset_constraints (uses);
          make_transitive_closure_constraints (uses);
        }
        make_constraint_to (uses->id, arg);
*************** handle_pure_call (gcall *stmt, vec<ce_s>
*** 4109,4114 ****
--- 4134,4140 ----
        if (!uses)
        {
          uses = get_call_use_vi (stmt);
+         make_any_offset_constraints (uses);
          make_transitive_closure_constraints (uses);
        }
        make_constraint_to (uses->id, gimple_call_chain (stmt));
Index: gcc/testsuite/gcc.dg/torture/pr77648-1.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr77648-1.c    (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr77648-1.c    (working copy)
***************
*** 0 ****
--- 1,24 ----
+ /* { dg-do run } */
+ 
+ struct S { int *p; int *q; };
+ 
+ int **__attribute__((noinline,noclone,pure)) foo (struct S *s)
+ {
+   int tem;
+   __asm__ ("" : "=g" (tem) : "g" (s->p));
+   return &s->q;
+ }
+ 
+ int main()
+ {
+   struct S s;
+   int i = 1, j = 2;
+   int **x;
+   s.p = &i;
+   s.q = &j;
+   x = foo (&s);
+   **x = 7;
+   if (j != 7)
+     __builtin_abort ();
+   return 0;
+ }
Index: gcc/testsuite/gcc.dg/torture/pr77648-2.c
===================================================================
*** gcc/testsuite/gcc.dg/torture/pr77648-2.c    (revision 0)
--- gcc/testsuite/gcc.dg/torture/pr77648-2.c    (working copy)
***************
*** 0 ****
--- 1,22 ----
+ /* { dg-do run } */
+ 
+ struct S { int *p; int *q; };
+ 
+ int **__attribute__((noinline,noclone,const)) foo (struct S *s)
+ {
+   return &s->q;
+ }
+ 
+ int main()
+ {
+   struct S s;
+   int i = 1, j = 2;
+   int **x;
+   s.p = &i;
+   s.q = &j;
+   x = foo (&s);
+   **x = 7;
+   if (j != 7)
+     __builtin_abort ();
+   return 0;
+ }

Reply via email to