re PR tree-optimization/36400 (points-to results wrong)
authorRichard Guenther <rguenther@suse.de>
Fri, 27 Jun 2008 18:53:43 +0000 (18:53 +0000)
committerRichard Biener <rguenth@gcc.gnu.org>
Fri, 27 Jun 2008 18:53:43 +0000 (18:53 +0000)
2008-06-27  Richard Guenther  <rguenther@suse.de>

PR tree-optimization/36400
PR tree-optimization/36373
PR tree-optimization/36344
* tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
var_nonlocal, nonlocal_tree, nonlocal_id): New globals
(update_alias_info): Remove call clobbering code.
(make_constraint_to): New helper function.
(make_escape_constraint): Likewise.
(handle_rhs_call): Use it on all pointer containing arguments.
Also mark the static chain escaped.
(handle_lhs_call): Make constraints from NONLOCAL and ESCAPED
instead of ANYTHING.
(make_constraint_from): New helper split out from ...
(make_constraint_from_anything): ... here.
(find_func_aliases): Add constraints for escape sites.
(intra_create_variable_infos): Make constraints from NONLOCAL
for parameters.
(find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same
as ANYTHING.
(clobber_what_p_points_to): Remove.
(clobber_what_escaped): New function.
(init_base_vars): Init NONLOCAL and ESCAPED.
(do_sd_constraint): Do not propagate the solution from ESCAPED
but use ESCAPED as a placeholder.
(solve_graph): Likewise.
* tree-flow.h (clobber_what_p_points_to): Remove.
(clobber_what_escaped): Declare.
* tree-ssa-alias.c (set_initial_properties): Call it.
Remove code clobbering escaped pointers.

* gcc.dg/torture/pr36373-1.c: New testcase.
* gcc.dg/torture/pr36373-2.c: Likewise.
* gcc.dg/torture/pr36373-3.c: Likewise.
* gcc.dg/torture/pr36373-4.c: Likewise.
* gcc.dg/torture/pr36373-5.c: Likewise.
* gcc.dg/torture/pr36373-6.c: Likewise.
* gcc.dg/torture/pr36373-7.c: Likewise.
* gcc.dg/torture/pr36373-8.c: Likewise.
* gcc.dg/torture/pr36373-9.c: Likewise.
* gcc.dg/torture/pr36373-10.c: Likewise.
* gcc.dg/torture/pr36400.c: Likewise.
* gcc.c-torture/execute/pta-field-1.c: Likewise.
* gcc.c-torture/execute/pta-field-2.c: Likewise.
* gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL.
* gcc.dg/tree-ssa/pr24287.c: XFAIL.

From-SVN: r137197

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/tree-ssa/loadpre8.c
gcc/testsuite/gcc.dg/tree-ssa/pr24287.c
gcc/tree-flow.h
gcc/tree-ssa-alias.c
gcc/tree-ssa-structalias.c

index c8ddda0b721b062d2e13e26d898c1efaa6570e67..f1279f8b7af05d833538187ef57e8191d2796209 100644 (file)
@@ -1,3 +1,35 @@
+2008-06-27  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/36400
+       PR tree-optimization/36373
+       PR tree-optimization/36344
+       * tree-ssa-structalias.c (var_escaped, escaped_tree, escaped_id,
+       var_nonlocal, nonlocal_tree, nonlocal_id): New globals
+       (update_alias_info): Remove call clobbering code.
+       (make_constraint_to): New helper function.
+       (make_escape_constraint): Likewise.
+       (handle_rhs_call): Use it on all pointer containing arguments.
+       Also mark the static chain escaped.
+       (handle_lhs_call): Make constraints from NONLOCAL and ESCAPED
+       instead of ANYTHING.
+       (make_constraint_from): New helper split out from ...
+       (make_constraint_from_anything): ... here.
+       (find_func_aliases): Add constraints for escape sites.
+       (intra_create_variable_infos): Make constraints from NONLOCAL
+       for parameters.
+       (find_what_p_points_to): Interpret NONLOCAL and ESCAPED the same
+       as ANYTHING.
+       (clobber_what_p_points_to): Remove.
+       (clobber_what_escaped): New function.
+       (init_base_vars): Init NONLOCAL and ESCAPED.
+       (do_sd_constraint): Do not propagate the solution from ESCAPED
+       but use ESCAPED as a placeholder.
+       (solve_graph): Likewise.
+       * tree-flow.h (clobber_what_p_points_to): Remove.
+       (clobber_what_escaped): Declare.
+       * tree-ssa-alias.c (set_initial_properties): Call it.
+       Remove code clobbering escaped pointers.
+
 2008-06-27  Richard Sandiford  <rdsandiford@googlemail.com>
 
        * function.c (allocate_struct_function): Only allocate a unique
index 64384d5621afc09d634310b992d02cb429af3e4c..086345b87ca3f00b787f579b314d861484ba0ef2 100644 (file)
@@ -1,3 +1,24 @@
+2008-06-27  Richard Guenther  <rguenther@suse.de>
+
+       PR tree-optimization/36400
+       PR tree-optimization/36373
+       PR tree-optimization/36344
+       * gcc.dg/torture/pr36373-1.c: New testcase.
+       * gcc.dg/torture/pr36373-2.c: Likewise.
+       * gcc.dg/torture/pr36373-3.c: Likewise.
+       * gcc.dg/torture/pr36373-4.c: Likewise.
+       * gcc.dg/torture/pr36373-5.c: Likewise.
+       * gcc.dg/torture/pr36373-6.c: Likewise.
+       * gcc.dg/torture/pr36373-7.c: Likewise.
+       * gcc.dg/torture/pr36373-8.c: Likewise.
+       * gcc.dg/torture/pr36373-9.c: Likewise.
+       * gcc.dg/torture/pr36373-10.c: Likewise.
+       * gcc.dg/torture/pr36400.c: Likewise.
+       * gcc.c-torture/execute/pta-field-1.c: Likewise.
+       * gcc.c-torture/execute/pta-field-2.c: Likewise.
+       * gcc.dg/tree-ssa/loadpre8.c: Remove XFAIL.
+       * gcc.dg/tree-ssa/pr24287.c: XFAIL.
+
 2008-06-27  Eric Botcazou  <ebotcazou@adacore.com>
 
        * gnat.dg/aggr9.ad[sb]: New test.
index 6be2b3ec7fd798af57e7d00cc2a46a323fc0a092..056c3fd635404fe79584050b81c7468346d814a1 100644 (file)
@@ -93,5 +93,5 @@ rewrite_add_phi_arguments (basic_block bb)
          get_reaching_def ((get_def_from_ptr (get_phi_result_ptr (phi)))->ssa_name.var);
     }
 }
-/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" { xfail *-*-* } } } */
+/* { dg-final { scan-tree-dump-times "Eliminated: 1" 1 "pre" } } */
 /* { dg-final { cleanup-tree-dump "pre" } } */
index 8e7f18691dc75ff576d66c671764bdc037c0b259..c4b172295b4fdf07e52fe5b7b8aa93e26a43fcde 100644 (file)
@@ -21,5 +21,5 @@ int g(void)
     link_error ();
   return t2 == 2;
 }
-/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized"} } */
+/* { dg-final { scan-tree-dump-times "link_error" 0 "optimized" { xfail *-*-* } } } */
 /* { dg-final { cleanup-tree-dump "optimized" } } */
index 855f0807951028874775287e55d1ee498020d38e..15329ac002ec9400ddb2b0e76eb2aa5d18146431 100644 (file)
@@ -1173,7 +1173,7 @@ tree gimple_fold_indirect_ref (tree);
 
 /* In tree-ssa-structalias.c */
 bool find_what_p_points_to (tree);
-bool clobber_what_p_points_to (tree);
+bool clobber_what_escaped (void);
 
 /* In tree-ssa-live.c */
 extern void remove_unused_locals (void);
index 748ff31684e88e8749021939a83e5ef43543f0fb..7c24739e407ab960fcebec00a079938b22cabd01 100644 (file)
@@ -537,6 +537,12 @@ set_initial_properties (struct alias_info *ai)
        }
     }
 
+  if (!clobber_what_escaped ())
+    {
+      any_pt_anything = true;
+      pt_anything_mask |= ESCAPE_TO_CALL;
+    }
+
   for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
     {
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
@@ -557,18 +563,6 @@ set_initial_properties (struct alias_info *ai)
 
          if (tag)
            mark_call_clobbered (tag, pi->escape_mask);
-
-         /* Defer to points-to analysis if possible, otherwise
-            clobber all addressable variables.  Parameters cannot
-            point to local memory though.
-            ???  Properly tracking which pointers point to non-local
-            memory only would make a big difference here.  */
-         if (!clobber_what_p_points_to (ptr)
-             && !(pi->escape_mask & ESCAPE_IS_PARM))
-           {
-             any_pt_anything = true;
-             pt_anything_mask |= pi->escape_mask;
-           }
        }
 
       /* If the name tag is call clobbered, so is the symbol tag
@@ -2906,6 +2900,12 @@ is_escape_site (tree stmt)
       if (TREE_CODE (lhs) == SSA_NAME)
        return NO_ESCAPE;
 
+      /* If the LHS is a non-global decl, it isn't a non-local memory store.
+        If the LHS escapes, the RHS escape is dealt with in the PTA solver.  */
+      if (DECL_P (lhs)
+         && !is_global_var (lhs))
+       return NO_ESCAPE;
+
       /* FIXME: LHS is not an SSA_NAME.  Even if it's an assignment to a
         local variables we cannot be sure if it will escape, because we
         don't have information about objects not in SSA form.  Need to
index a9eaa97c52cbeb0647b3ac5c68d2f96d22dc9d2c..2b6c56fa1a706a98df98543133f8db9a093198aa 100644 (file)
@@ -294,26 +294,34 @@ get_varinfo_fc (unsigned int n)
   return v;
 }
 
+/* Static IDs for the special variables.  */
+enum { nothing_id = 0, anything_id = 1, readonly_id = 2,
+       escaped_id = 3, nonlocal_id = 4, integer_id = 5 };
+
 /* Variable that represents the unknown pointer.  */
 static varinfo_t var_anything;
 static tree anything_tree;
-static unsigned int anything_id;
 
 /* Variable that represents the NULL pointer.  */
 static varinfo_t var_nothing;
 static tree nothing_tree;
-static unsigned int nothing_id;
 
 /* Variable that represents read only memory.  */
 static varinfo_t var_readonly;
 static tree readonly_tree;
-static unsigned int readonly_id;
+
+/* Variable that represents escaped memory.  */
+static varinfo_t var_escaped;
+static tree escaped_tree;
+
+/* Variable that represents nonlocal memory.  */
+static varinfo_t var_nonlocal;
+static tree nonlocal_tree;
 
 /* Variable that represents integers.  This is used for when people do things
    like &0->a.b.  */
 static varinfo_t var_integer;
 static tree integer_tree;
-static unsigned int integer_id;
 
 /* Lookup a heap var for FROM, and return it if we find one.  */
 
@@ -1399,6 +1407,7 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
        bitmap_set_bit (sol, anything_id);
      goto done;
    }
+
   /* For each variable j in delta (Sol(y)), add
      an edge in the graph from j to x, and union Sol(j) into Sol(x).  */
   EXECUTE_IF_SET_IN_BITMAP (delta, 0, j, bi)
@@ -1417,8 +1426,16 @@ do_sd_constraint (constraint_graph_t graph, constraint_t c,
 
          /* Adding edges from the special vars is pointless.
             They don't have sets that can change.  */
-         if (get_varinfo (t) ->is_special_var)
+         if (get_varinfo (t)->is_special_var)
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
+         /* Merging the solution from ESCAPED needlessly increases
+            the set.  Use ESCAPED as representative instead.  */
+         else if (get_varinfo (t)->id == escaped_id
+                  && !bitmap_bit_p (sol, get_varinfo (t)->id))
+           {
+             bitmap_set_bit (sol, escaped_id);
+             flag = true;
+           }
          else if (add_graph_edge (graph, lhs, t))
            flag |= bitmap_ior_into (sol, get_varinfo (t)->solution);
        }
@@ -2351,7 +2368,9 @@ solve_graph (constraint_graph_t graph)
 
              solution_empty = bitmap_empty_p (solution);
 
-             if (!solution_empty)
+             if (!solution_empty
+                 /* Do not propagate the ESCAPED solution.  */
+                 && i != escaped_id)
                {
                  bitmap_iterator bi;
 
@@ -3271,24 +3290,7 @@ update_alias_info (tree stmt, struct alias_info *ai)
   /* Mark all the variables whose address are taken by the statement.  */
   addr_taken = addresses_taken (stmt);
   if (addr_taken)
-    {
-      bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
-
-      /* If STMT is an escape point, all the addresses taken by it are
-        call-clobbered.  */
-      if (stmt_escape_type != NO_ESCAPE)
-       {
-         bitmap_iterator bi;
-         unsigned i;
-
-         EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
-           {
-             tree rvar = referenced_var (i);
-             if (!unmodifiable_var_p (rvar))
-               mark_call_clobbered (rvar, stmt_escape_type);
-           }
-       }
-    }
+    bitmap_ior_into (gimple_addressable_vars (cfun), addr_taken);
 
   /* Process each operand use.  For pointers, determine whether they
      are dereferenced by the statement, or whether their value
@@ -3573,6 +3575,34 @@ handle_ptr_arith (VEC (ce_s, heap) *lhsc, tree expr)
   return true;
 }
 
+/* Create a constraint ID = OP.  */
+
+static void
+make_constraint_to (unsigned id, tree op)
+{
+  VEC(ce_s, heap) *rhsc = NULL;
+  struct constraint_expr *c;
+  struct constraint_expr includes;
+  unsigned int j;
+
+  includes.var = id;
+  includes.offset = 0;
+  includes.type = SCALAR;
+
+  get_constraint_for (op, &rhsc);
+  for (j = 0; VEC_iterate (ce_s, rhsc, j, c); j++)
+    process_constraint_1 (new_constraint (includes, *c), true);
+  VEC_free (ce_s, heap, rhsc);
+}
+
+/* Make constraints necessary to make OP escape.  */
+
+static void
+make_escape_constraint (tree op)
+{
+  make_constraint_to (escaped_id, op);
+}
+
 /* For non-IPA mode, generate constraints necessary for a call on the
    RHS.  */
 
@@ -3581,35 +3611,21 @@ handle_rhs_call  (tree rhs)
 {
   tree arg;
   call_expr_arg_iterator iter;
-  struct constraint_expr rhsc;
-
-  rhsc.var = anything_id;
-  rhsc.offset = 0;
-  rhsc.type = ADDRESSOF;
 
   FOR_EACH_CALL_EXPR_ARG (arg, iter, rhs)
-    {
-      VEC(ce_s, heap) *lhsc = NULL;
-
-      /* Find those pointers being passed, and make sure they end up
-        pointing to anything.  */
-      if (POINTER_TYPE_P (TREE_TYPE (arg)))
-       {
-         unsigned int j;
-         struct constraint_expr *lhsp;
-
-         get_constraint_for (arg, &lhsc);
-         do_deref (&lhsc);
-         for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
-           process_constraint_1 (new_constraint (*lhsp, rhsc), true);
-         VEC_free (ce_s, heap, lhsc);
-       }
-    }
+    /* Find those pointers being passed, and make sure they end up
+       pointing to anything.  */
+    if (could_have_pointers (arg))
+      make_escape_constraint (arg);
+
+  /* The static chain escapes as well.  */
+  if (CALL_EXPR_STATIC_CHAIN (rhs))
+    make_escape_constraint (CALL_EXPR_STATIC_CHAIN (rhs));
 }
 
 /* For non-IPA mode, generate constraints necessary for a call
    that returns a pointer and assigns it to LHS.  This simply makes
-   the LHS point to anything.  */
+   the LHS point to global and escaped variables.  */
 
 static void
 handle_lhs_call (tree lhs)
@@ -3619,12 +3635,70 @@ handle_lhs_call (tree lhs)
   unsigned int j;
   struct constraint_expr *lhsp;
 
-  rhsc.var = anything_id;
+  get_constraint_for (lhs, &lhsc);
+  rhsc.var = nonlocal_id;
+  rhsc.offset = 0;
+  rhsc.type = ADDRESSOF;
+  for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+    process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+  rhsc.var = escaped_id;
   rhsc.offset = 0;
   rhsc.type = ADDRESSOF;
+  for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+    process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+  VEC_free (ce_s, heap, lhsc);
+}
+
+/* For non-IPA mode, generate constraints necessary for a call of a
+   const function that returns a pointer in the statement STMT.  */
+
+static void
+handle_const_call (tree stmt)
+{
+  tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
+  tree call = get_call_expr_in (stmt);
+  VEC(ce_s, heap) *lhsc = NULL;
+  struct constraint_expr rhsc;
+  unsigned int j;
+  struct constraint_expr *lhsp;
+  tree arg;
+  call_expr_arg_iterator iter;
+
   get_constraint_for (lhs, &lhsc);
+
+  /* If this is a nested function then it can return anything.  */
+  if (CALL_EXPR_STATIC_CHAIN (call))
+    {
+      rhsc.var = anything_id;
+      rhsc.offset = 0;
+      rhsc.type = ADDRESSOF;
+      for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+       process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+      VEC_free (ce_s, heap, lhsc);
+      return;
+    }
+
+  /* May return addresses of globals.  */
+  rhsc.var = nonlocal_id;
+  rhsc.offset = 0;
+  rhsc.type = ADDRESSOF;
   for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
     process_constraint_1 (new_constraint (*lhsp, rhsc), true);
+
+  /* May return arguments.  */
+  FOR_EACH_CALL_EXPR_ARG (arg, iter, call)
+    if (could_have_pointers (arg))
+      {
+       VEC(ce_s, heap) *argc = NULL;
+       struct constraint_expr *argp;
+       int i;
+       get_constraint_for (arg, &argc);
+       for (i = 0; VEC_iterate (ce_s, argc, i, argp); i++)
+         for (j = 0; VEC_iterate (ce_s, lhsc, j, lhsp); j++)
+           process_constraint_1 (new_constraint (*lhsp, *argp), true);
+       VEC_free (ce_s, heap, argc);
+      }
+
   VEC_free (ce_s, heap, lhsc);
 }
 
@@ -3636,10 +3710,12 @@ handle_lhs_call (tree lhs)
 static void
 find_func_aliases (tree origt)
 {
-  tree t = origt;
+  tree call, t = origt;
   VEC(ce_s, heap) *lhsc = NULL;
   VEC(ce_s, heap) *rhsc = NULL;
   struct constraint_expr *c;
+  enum escape_type stmt_escape_type;
+  int flags;
 
   if (TREE_CODE (t) == RETURN_EXPR && TREE_OPERAND (t, 0))
     t = TREE_OPERAND (t, 0);
@@ -3688,17 +3764,26 @@ find_func_aliases (tree origt)
 
      In non-ipa mode, we need to generate constraints for each
      pointer passed by address.  */
-  else if (((TREE_CODE (t) == GIMPLE_MODIFY_STMT
-            && TREE_CODE (GIMPLE_STMT_OPERAND (t, 1)) == CALL_EXPR
-            && !(call_expr_flags (GIMPLE_STMT_OPERAND (t, 1))
-                 & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
-           || (TREE_CODE (t) == CALL_EXPR
-               && !(call_expr_flags (t)
-                    & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))))
+  else if ((call = get_call_expr_in (t)) != NULL_TREE
+          && !((flags = call_expr_flags (call))
+               & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
     {
       if (!in_ipa_mode)
        {
-         if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
+         /* Const functions can return their arguments and addresses
+            of global memory but not of escaped memory.  */
+         if (flags & ECF_CONST)
+           {
+             if (TREE_CODE (t) == GIMPLE_MODIFY_STMT
+                 && could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
+               handle_const_call (t);
+           }
+         /* Pure functions can return addresses in and of memory
+            reachable from their arguments, but they are not an escape
+            point for reachable memory of their arguments.  But as we
+            do not compute call-used memory separately we cannot do
+            something special here.  */
+         else if (TREE_CODE (t) == GIMPLE_MODIFY_STMT)
            {
              handle_rhs_call (GIMPLE_STMT_OPERAND (t, 1));
              if (could_have_pointers (GIMPLE_STMT_OPERAND (t, 1)))
@@ -3893,6 +3978,57 @@ find_func_aliases (tree origt)
        get_varinfo (c->var)->no_tbaa_pruning = true;
     }
 
+  stmt_escape_type = is_escape_site (t);
+  if (stmt_escape_type == ESCAPE_STORED_IN_GLOBAL)
+    {
+      tree rhs;
+      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+      rhs = GIMPLE_STMT_OPERAND (t, 1);
+      if (TREE_CODE (rhs) == ADDR_EXPR)
+       {
+         tree base = get_base_address (TREE_OPERAND (rhs, 0));
+         if (base
+             && (!DECL_P (base)
+                 || !is_global_var (base)))
+           make_escape_constraint (rhs);
+       }
+      else if (TREE_CODE (rhs) == SSA_NAME
+              && POINTER_TYPE_P (TREE_TYPE (rhs)))
+       make_escape_constraint (rhs);
+      else if (could_have_pointers (rhs))
+       make_escape_constraint (rhs);
+    }
+  else if (stmt_escape_type == ESCAPE_BAD_CAST)
+    {
+      tree rhs;
+      gcc_assert (TREE_CODE (t) == GIMPLE_MODIFY_STMT);
+      rhs = GIMPLE_STMT_OPERAND (t, 1);
+      gcc_assert (CONVERT_EXPR_P (rhs)
+                 || TREE_CODE (rhs) == VIEW_CONVERT_EXPR);
+      rhs = TREE_OPERAND (rhs, 0);
+      make_escape_constraint (rhs);
+    }
+  else if (stmt_escape_type == ESCAPE_TO_ASM)
+    {
+      tree link;
+      int i;
+      for (i = 0, link = ASM_OUTPUTS (t); link; i++, link = TREE_CHAIN (link))
+       {
+         tree op = TREE_VALUE (link);
+         if (op && could_have_pointers (op))
+           /* Strictly we'd only need the constraints from ESCAPED and
+              NONLOCAL.  */
+           make_escape_constraint (op);
+       }
+      for (i = 0, link = ASM_INPUTS (t); link; i++, link = TREE_CHAIN (link))
+       {
+         tree op = TREE_VALUE (link);
+         if (op && could_have_pointers (op))
+           /* Strictly we'd only need the constraint to ESCAPED.  */
+           make_escape_constraint (op);
+       }
+    }
+
   /* After promoting variables and computing aliasing we will
      need to re-scan most statements.  FIXME: Try to minimize the
      number of statements re-scanned.  It's not really necessary to
@@ -4118,9 +4254,10 @@ push_fields_onto_fieldstack (tree type, VEC(fieldoff_s,heap) **fieldstack,
   return count;
 }
 
-/* Create a constraint from ANYTHING variable to VI.  */
+/* Create a constraint ID = &FROM.  */
+
 static void
-make_constraint_from_anything (varinfo_t vi)
+make_constraint_from (varinfo_t vi, int from)
 {
   struct constraint_expr lhs, rhs;
 
@@ -4128,12 +4265,19 @@ make_constraint_from_anything (varinfo_t vi)
   lhs.offset = 0;
   lhs.type = SCALAR;
 
-  rhs.var = anything_id;
+  rhs.var = from;
   rhs.offset = 0;
   rhs.type = ADDRESSOF;
   process_constraint (new_constraint (lhs, rhs));
 }
 
+/* Create a constraint from ANYTHING variable to VI.  */
+static void
+make_constraint_from_anything (varinfo_t vi)
+{
+  make_constraint_from (vi, anything_id);
+}
+
 /* Count the number of arguments DECL has, and set IS_VARARGS to true
    if it is a varargs function.  */
 
@@ -4478,7 +4622,7 @@ intra_create_variable_infos (void)
   struct constraint_expr lhs, rhs;
 
   /* For each incoming pointer argument arg, create the constraint ARG
-     = ANYTHING or a dummy variable if flag_argument_noalias is set.  */
+     = NONLOCAL or a dummy variable if flag_argument_noalias is set.  */
   for (t = DECL_ARGUMENTS (current_function_decl); t; t = TREE_CHAIN (t))
     {
       varinfo_t p;
@@ -4539,7 +4683,7 @@ intra_create_variable_infos (void)
          varinfo_t arg_vi = get_vi_for_tree (t);
 
          for (p = arg_vi; p; p = p->next)
-           make_constraint_from_anything (p);
+           make_constraint_from (p, nonlocal_id);
        }
     }
 }
@@ -4794,7 +4938,9 @@ find_what_p_points_to (tree p)
                     aliases.  */
                  if (vi->id == nothing_id)
                    pi->pt_null = 1;
-                 else if (vi->id == anything_id)
+                 else if (vi->id == anything_id
+                          || vi->id == nonlocal_id
+                          || vi->id == escaped_id)
                    was_pt_anything = 1;
                  else if (vi->id == readonly_id)
                    was_pt_anything = 1;
@@ -4843,42 +4989,23 @@ find_what_p_points_to (tree p)
   return false;
 }
 
-/* Mark everything that p points to as call clobbered.  Returns true
-   if everything is done and false if all addressable variables need to
-   be clobbered because p points to anything.  */
+/* Mark the ESCAPED solution as call clobbered.  Returns false if
+   pt_anything escaped which needs all locals that have their address
+   taken marked call clobbered as well.  */
 
 bool
-clobber_what_p_points_to (tree p)
+clobber_what_escaped (void)
 {
-  tree lookup_p = p;
   varinfo_t vi;
-  struct ptr_info_def *pi;
   unsigned int i;
   bitmap_iterator bi;
 
   if (!have_alias_info)
     return false;
 
-  /* For parameters, get at the points-to set for the actual parm
-     decl.  */
-  if (TREE_CODE (p) == SSA_NAME
-      && TREE_CODE (SSA_NAME_VAR (p)) == PARM_DECL
-      && SSA_NAME_IS_DEFAULT_DEF (p))
-    lookup_p = SSA_NAME_VAR (p);
-
-  vi = lookup_vi_for_tree (lookup_p);
-  if (!vi)
-    return false;
-
-  /* We are asking for the points-to solution of pointers.  */
-  gcc_assert (!vi->is_artificial_var
-             && vi->size == vi->fullsize);
-
-  pi = get_ptr_info (p);
-
   /* This variable may have been collapsed, let's get the real
-     variable.  */
-  vi = get_varinfo (find (vi->id));
+     variable for escaped_id.  */
+  vi = get_varinfo (find (escaped_id));
 
   /* Mark variables in the solution call-clobbered.  */
   EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
@@ -4903,12 +5030,13 @@ clobber_what_p_points_to (tree p)
           || TREE_CODE (vi->decl) == PARM_DECL
           || TREE_CODE (vi->decl) == RESULT_DECL)
          && !unmodifiable_var_p (vi->decl))
-       mark_call_clobbered (vi->decl, pi->escape_mask);
+       mark_call_clobbered (vi->decl, ESCAPE_TO_CALL);
     }
 
   return true;
 }
 
+
 /* Dump points-to information to OUTFILE.  */
 
 void
@@ -4959,20 +5087,19 @@ init_base_vars (void)
   /* Create the NULL variable, used to represent that a variable points
      to NULL.  */
   nothing_tree = create_tmp_var_raw (void_type_node, "NULL");
-  var_nothing = new_var_info (nothing_tree, 0, "NULL");
+  var_nothing = new_var_info (nothing_tree, nothing_id, "NULL");
   insert_vi_for_tree (nothing_tree, var_nothing);
   var_nothing->is_artificial_var = 1;
   var_nothing->offset = 0;
   var_nothing->size = ~0;
   var_nothing->fullsize = ~0;
   var_nothing->is_special_var = 1;
-  nothing_id = 0;
   VEC_safe_push (varinfo_t, heap, varmap, var_nothing);
 
   /* Create the ANYTHING variable, used to represent that a variable
      points to some unknown piece of memory.  */
   anything_tree = create_tmp_var_raw (void_type_node, "ANYTHING");
-  var_anything = new_var_info (anything_tree, 1, "ANYTHING");
+  var_anything = new_var_info (anything_tree, anything_id, "ANYTHING");
   insert_vi_for_tree (anything_tree, var_anything);
   var_anything->is_artificial_var = 1;
   var_anything->size = ~0;
@@ -4980,7 +5107,6 @@ init_base_vars (void)
   var_anything->next = NULL;
   var_anything->fullsize = ~0;
   var_anything->is_special_var = 1;
-  anything_id = 1;
 
   /* Anything points to anything.  This makes deref constraints just
      work in the presence of linked list and other p = *p type loops,
@@ -5001,7 +5127,7 @@ init_base_vars (void)
   /* Create the READONLY variable, used to represent that a variable
      points to readonly memory.  */
   readonly_tree = create_tmp_var_raw (void_type_node, "READONLY");
-  var_readonly = new_var_info (readonly_tree, 2, "READONLY");
+  var_readonly = new_var_info (readonly_tree, readonly_id, "READONLY");
   var_readonly->is_artificial_var = 1;
   var_readonly->offset = 0;
   var_readonly->size = ~0;
@@ -5009,7 +5135,6 @@ init_base_vars (void)
   var_readonly->next = NULL;
   var_readonly->is_special_var = 1;
   insert_vi_for_tree (readonly_tree, var_readonly);
-  readonly_id = 2;
   VEC_safe_push (varinfo_t, heap, varmap, var_readonly);
 
   /* readonly memory points to anything, in order to make deref
@@ -5020,15 +5145,58 @@ init_base_vars (void)
   lhs.var = readonly_id;
   lhs.offset = 0;
   rhs.type = ADDRESSOF;
-  rhs.var = anything_id;
+  rhs.var = readonly_id;  /* FIXME */
   rhs.offset = 0;
+  process_constraint (new_constraint (lhs, rhs));
 
+  /* Create the ESCAPED variable, used to represent the set of escaped
+     memory.  */
+  escaped_tree = create_tmp_var_raw (void_type_node, "ESCAPED");
+  var_escaped = new_var_info (escaped_tree, escaped_id, "ESCAPED");
+  insert_vi_for_tree (escaped_tree, var_escaped);
+  var_escaped->is_artificial_var = 1;
+  var_escaped->offset = 0;
+  var_escaped->size = ~0;
+  var_escaped->fullsize = ~0;
+  var_escaped->is_special_var = 0;
+  VEC_safe_push (varinfo_t, heap, varmap, var_escaped);
+  gcc_assert (VEC_index (varinfo_t, varmap, 3) == var_escaped);
+
+  /* ESCAPED = *ESCAPED, because escaped is may-deref'd at calls, etc.  */
+  lhs.type = SCALAR;
+  lhs.var = escaped_id;
+  lhs.offset = 0;
+  rhs.type = DEREF;
+  rhs.var = escaped_id;
+  rhs.offset = 0;
+  process_constraint_1 (new_constraint (lhs, rhs), true);
+
+  /* Create the NONLOCAL variable, used to represent the set of nonlocal
+     memory.  */
+  nonlocal_tree = create_tmp_var_raw (void_type_node, "NONLOCAL");
+  var_nonlocal = new_var_info (nonlocal_tree, nonlocal_id, "NONLOCAL");
+  insert_vi_for_tree (nonlocal_tree, var_nonlocal);
+  var_nonlocal->is_artificial_var = 1;
+  var_nonlocal->offset = 0;
+  var_nonlocal->size = ~0;
+  var_nonlocal->fullsize = ~0;
+  var_nonlocal->is_special_var = 1;
+  VEC_safe_push (varinfo_t, heap, varmap, var_nonlocal);
+
+  /* Nonlocal memory points to escaped (which includes nonlocal),
+     in order to make deref easier.  */
+  lhs.type = SCALAR;
+  lhs.var = nonlocal_id;
+  lhs.offset = 0;
+  rhs.type = ADDRESSOF;
+  rhs.var = escaped_id;
+  rhs.offset = 0;
   process_constraint (new_constraint (lhs, rhs));
 
   /* Create the INTEGER variable, used to represent that a variable points
      to an INTEGER.  */
   integer_tree = create_tmp_var_raw (void_type_node, "INTEGER");
-  var_integer = new_var_info (integer_tree, 3, "INTEGER");
+  var_integer = new_var_info (integer_tree, integer_id, "INTEGER");
   insert_vi_for_tree (integer_tree, var_integer);
   var_integer->is_artificial_var = 1;
   var_integer->size = ~0;
@@ -5036,7 +5204,6 @@ init_base_vars (void)
   var_integer->offset = 0;
   var_integer->next = NULL;
   var_integer->is_special_var = 1;
-  integer_id = 3;
   VEC_safe_push (varinfo_t, heap, varmap, var_integer);
 
   /* INTEGER = ANYTHING, because we don't know where a dereference of
@@ -5048,6 +5215,26 @@ init_base_vars (void)
   rhs.var = anything_id;
   rhs.offset = 0;
   process_constraint (new_constraint (lhs, rhs));
+
+  /* *ESCAPED = &ESCAPED.  This is true because we have to assume
+     everything pointed to by escaped can also point to escaped. */
+  lhs.type = DEREF;
+  lhs.var = escaped_id;
+  lhs.offset = 0;
+  rhs.type = ADDRESSOF;
+  rhs.var = escaped_id;
+  rhs.offset = 0;
+  process_constraint_1 (new_constraint (lhs, rhs), true);
+
+  /* *ESCAPED = &NONLOCAL.  This is true because we have to assume
+     everything pointed to by escaped can also point to nonlocal. */
+  lhs.type = DEREF;
+  lhs.var = escaped_id;
+  lhs.offset = 0;
+  rhs.type = ADDRESSOF;
+  rhs.var = nonlocal_id;
+  rhs.offset = 0;
+  process_constraint_1 (new_constraint (lhs, rhs), true);
 }
 
 /* Initialize things necessary to perform PTA */