OSDN Git Service

2005-07-07 Daniel Berlin <dberlin@dberlin.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-structalias.c
index 25c2a44..6f89799 100644 (file)
@@ -16,7 +16,7 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GCC; if not, write to the Free Software
-Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */
 
 #include "config.h"
@@ -26,7 +26,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #include "ggc.h"
 #include "obstack.h"
 #include "bitmap.h"
-#include "tree-ssa-structalias.h"
 #include "flags.h"
 #include "rtl.h"
 #include "tm_p.h"
@@ -34,7 +33,6 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #include "basic-block.h"
 #include "output.h"
 #include "errors.h"
-#include "expr.h"
 #include "diagnostic.h"
 #include "tree.h"
 #include "c-common.h"
@@ -50,6 +48,7 @@ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 #include "timevar.h"
 #include "alloc-pool.h"
 #include "splay-tree.h"
+#include "tree-ssa-structalias.h"
 
 /* The idea behind this analyzer is to generate set constraints from the
    program, then solve the resulting constraints in order to generate the
@@ -168,7 +167,7 @@ static void build_constraint_graph (void);
 static bitmap_obstack ptabitmap_obstack;
 static bitmap_obstack iteration_obstack;
 DEF_VEC_P(constraint_t);
-DEF_VEC_ALLOC_P(constraint_t,gc);
+DEF_VEC_ALLOC_P(constraint_t,heap);
 
 static struct constraint_stats
 {
@@ -224,6 +223,9 @@ struct variable_info
   /* True for variables that have unions somewhere in them.  */
   unsigned int has_union:1;
 
+  /* True if this is a heap variable.  */
+  unsigned int is_heap_var:1;
+
   /* Points-to set for this variable.  */
   bitmap solution;
 
@@ -232,7 +234,7 @@ struct variable_info
 
   /* Vector of complex constraints for this node.  Complex
      constraints are those involving dereferences.  */
-  VEC(constraint_t,gc) *complex;
+  VEC(constraint_t,heap) *complex;
 };
 typedef struct variable_info *varinfo_t;
 
@@ -243,11 +245,11 @@ static alloc_pool variable_info_pool;
 
 DEF_VEC_P(varinfo_t);
 
-DEF_VEC_ALLOC_P(varinfo_t, gc);
+DEF_VEC_ALLOC_P(varinfo_t, heap);
 
 /* Table of variable info structures for constraint variables.  Indexed directly
    by variable info id.  */
-static VEC(varinfo_t,gc) *varmap;
+static VEC(varinfo_t,heap) *varmap;
 #define get_varinfo(n) VEC_index(varinfo_t, varmap, n)
 
 /* Variable that represents the unknown pointer.  */
@@ -271,6 +273,12 @@ static varinfo_t var_integer;
 static tree integer_tree;
 static unsigned int integer_id;
 
+/* Variable that represents arbitrary offsets into an object.  Used to
+   represent pointer arithmetic, which may not legally escape the
+   bounds of an object.  */
+static varinfo_t var_anyoffset;
+static tree anyoffset_tree;
+static unsigned int anyoffset_id;
 
 /* Return a new variable info structure consisting for a variable
    named NAME, and using constraint graph node NODE.  */
@@ -287,6 +295,7 @@ new_var_info (tree t, unsigned int id, const char *name, unsigned int node)
   ret->address_taken = false;
   ret->indirect_target = false;
   ret->is_artificial_var = false;
+  ret->is_heap_var = false;
   ret->is_unknown_size_var = false;
   ret->solution = BITMAP_ALLOC (&ptabitmap_obstack);
   bitmap_clear (ret->solution);
@@ -333,7 +342,7 @@ struct constraint
 
 /* List of constraints that we use to build the constraint graph from.  */
 
-static VEC(constraint_t,gc) *constraints;
+static VEC(constraint_t,heap) *constraints;
 static alloc_pool constraint_pool;
 
 /* An edge in the constraint graph.  We technically have no use for
@@ -365,7 +374,7 @@ new_constraint_edge (unsigned int src, unsigned int dest)
 }
 
 DEF_VEC_P(constraint_edge_t);
-DEF_VEC_ALLOC_P(constraint_edge_t,gc);
+DEF_VEC_ALLOC_P(constraint_edge_t,heap);
 
 
 /* The constraint graph is simply a set of adjacency vectors, one per
@@ -374,12 +383,12 @@ DEF_VEC_ALLOC_P(constraint_edge_t,gc);
    IOW, all edges are "forward" edges, which is not like our CFG.  
    So remember that
    preds[x]->src == x, and
-   succs[x]->src == x*/
+   succs[x]->src == x.  */
 
 struct constraint_graph
 {
-  VEC(constraint_edge_t,gc) **succs;
-  VEC(constraint_edge_t,gc) **preds;
+  VEC(constraint_edge_t,heap) **succs;
+  VEC(constraint_edge_t,heap) **preds;
 };
 
 typedef struct constraint_graph *constraint_graph_t;
@@ -532,7 +541,7 @@ constraint_equal (struct constraint a, struct constraint b)
 /* Find a constraint LOOKFOR in the sorted constraint vector VEC */
 
 static constraint_t
-constraint_vec_find (VEC(constraint_t,gc) *vec,
+constraint_vec_find (VEC(constraint_t,heap) *vec,
                     struct constraint lookfor)
 {
   unsigned int place;  
@@ -553,8 +562,8 @@ constraint_vec_find (VEC(constraint_t,gc) *vec,
 /* Union two constraint vectors, TO and FROM.  Put the result in TO.  */
 
 static void
-constraint_set_union (VEC(constraint_t,gc) **to,
-                     VEC(constraint_t,gc) **from)
+constraint_set_union (VEC(constraint_t,heap) **to,
+                     VEC(constraint_t,heap) **from)
 {
   int i;
   constraint_t c;
@@ -565,7 +574,7 @@ constraint_set_union (VEC(constraint_t,gc) **to,
        {
          unsigned int place = VEC_lower_bound (constraint_t, *to, c,
                                                constraint_less);
-         VEC_safe_insert (constraint_t, gc, *to, place, c);
+         VEC_safe_insert (constraint_t, heap, *to, place, c);
        }
     }
 }
@@ -633,7 +642,7 @@ insert_into_complex (unsigned int var, constraint_t c)
   varinfo_t vi = get_varinfo (var);
   unsigned int place = VEC_lower_bound (constraint_t, vi->complex, c,
                                        constraint_less);
-  VEC_safe_insert (constraint_t, gc, vi->complex, place, c);
+  VEC_safe_insert (constraint_t, heap, vi->complex, place, c);
 }
 
 
@@ -662,7 +671,7 @@ constraint_edge_less (const constraint_edge_t a, const constraint_edge_t b)
    Return the edge, if found, NULL otherwise.  */
 
 static constraint_edge_t 
-constraint_edge_vec_find (VEC(constraint_edge_t,gc) *vec, 
+constraint_edge_vec_find (VEC(constraint_edge_t,heap) *vec, 
                          struct constraint_edge lookfor)
 {
   unsigned int place;  
@@ -710,6 +719,7 @@ condense_varmap_nodes (unsigned int to, unsigned int src)
        c->lhs.var = to;
     }
   constraint_set_union (&tovi->complex, &srcvi->complex);
+  VEC_free (constraint_t, heap, srcvi->complex);
   srcvi->complex = NULL;
 }
 
@@ -719,8 +729,8 @@ condense_varmap_nodes (unsigned int to, unsigned int src)
 static void
 erase_graph_self_edge (constraint_graph_t graph, struct constraint_edge edge)
 {
-  VEC(constraint_edge_t,gc) *predvec = graph->preds[edge.src];
-  VEC(constraint_edge_t,gc) *succvec = graph->succs[edge.dest];
+  VEC(constraint_edge_t,heap) *predvec = graph->preds[edge.src];
+  VEC(constraint_edge_t,heap) *succvec = graph->succs[edge.dest];
   unsigned int place;
   gcc_assert (edge.src == edge.dest);
 
@@ -756,8 +766,8 @@ erase_graph_self_edge (constraint_graph_t graph, struct constraint_edge edge)
 static void
 clear_edges_for_node (constraint_graph_t graph, unsigned int node)
 {
-  VEC(constraint_edge_t,gc) *succvec = graph->succs[node];
-  VEC(constraint_edge_t,gc) *predvec = graph->preds[node];
+  VEC(constraint_edge_t,heap) *succvec = graph->succs[node];
+  VEC(constraint_edge_t,heap) *predvec = graph->preds[node];
   constraint_edge_t c;
   int i;
   
@@ -786,6 +796,8 @@ clear_edges_for_node (constraint_graph_t graph, unsigned int node)
        VEC_ordered_remove (constraint_edge_t, graph->succs[c->dest], place);
       }    
   
+  VEC_free (constraint_edge_t, heap, graph->preds[node]);
+  VEC_free (constraint_edge_t, heap, graph->succs[node]);
   graph->preds[node] = NULL;
   graph->succs[node] = NULL;
 }
@@ -800,7 +812,7 @@ add_graph_edge (constraint_graph_t graph, struct constraint_edge newe)
   unsigned int place;
   unsigned int src = newe.src;
   unsigned int dest = newe.dest;
-  VEC(constraint_edge_t,gc) *vec;
+  VEC(constraint_edge_t,heap) *vec;
 
   vec = graph->preds[src];
   place = VEC_lower_bound (constraint_edge_t, vec, &newe, 
@@ -813,13 +825,13 @@ add_graph_edge (constraint_graph_t graph, struct constraint_edge newe)
 
       weightbitmap = BITMAP_ALLOC (&ptabitmap_obstack);
       edge->weights = weightbitmap;
-      VEC_safe_insert (constraint_edge_t, gc, graph->preds[edge->src], 
+      VEC_safe_insert (constraint_edge_t, heap, graph->preds[edge->src], 
                       place, edge);
       edge = new_constraint_edge (dest, src);
       edge->weights = weightbitmap;
       place = VEC_lower_bound (constraint_edge_t, graph->succs[edge->src],
                               edge, constraint_edge_less);
-      VEC_safe_insert (constraint_edge_t, gc, graph->succs[edge->src], 
+      VEC_safe_insert (constraint_edge_t, heap, graph->succs[edge->src], 
                       place, edge);
       edge_added = true;
       return true;
@@ -836,7 +848,7 @@ get_graph_weights (constraint_graph_t graph, struct constraint_edge lookfor)
 {
   constraint_edge_t edge;
   unsigned int src = lookfor.src;
-  VEC(constraint_edge_t,gc) *vec;
+  VEC(constraint_edge_t,heap) *vec;
   vec = graph->preds[src];
   edge = constraint_edge_vec_find (vec, lookfor);
   gcc_assert (edge != NULL);
@@ -850,8 +862,8 @@ static void
 merge_graph_nodes (constraint_graph_t graph, unsigned int to, 
                   unsigned int from)
 {
-  VEC(constraint_edge_t,gc) *succvec = graph->succs[from];
-  VEC(constraint_edge_t,gc) *predvec = graph->preds[from];
+  VEC(constraint_edge_t,heap) *succvec = graph->succs[from];
+  VEC(constraint_edge_t,heap) *predvec = graph->preds[from];
   int i;
   constraint_edge_t c;
   
@@ -941,9 +953,12 @@ build_constraint_graph (void)
   int i = 0;
   constraint_t c;
 
-  graph = ggc_alloc (sizeof (struct constraint_graph));
-  graph->succs = ggc_alloc_cleared (VEC_length (varinfo_t, varmap) * sizeof (*graph->succs));
-  graph->preds = ggc_alloc_cleared (VEC_length (varinfo_t, varmap) * sizeof (*graph->preds));
+  graph = xmalloc (sizeof (struct constraint_graph));
+  graph->succs = xcalloc (VEC_length (varinfo_t, varmap),
+                         sizeof (*graph->succs));
+  graph->preds = xcalloc (VEC_length (varinfo_t, varmap),
+                         sizeof (*graph->preds));
+
   for (i = 0; VEC_iterate (constraint_t, constraints, i, c); i++)
     {
       struct constraint_expr lhs = c->lhs;
@@ -984,12 +999,14 @@ build_constraint_graph (void)
        }
     }
 }
+
+
 /* Changed variables on the last iteration.  */
 static unsigned int changed_count;
 static sbitmap changed;
 
-DEF_VEC_I(uint);
-DEF_VEC_ALLOC_I(uint,heap);
+DEF_VEC_I(unsigned);
+DEF_VEC_ALLOC_I(unsigned,heap);
 
 
 /* Strongly Connected Component visitation info.  */
@@ -1000,8 +1017,8 @@ struct scc_info
   sbitmap in_component;
   int current_index;
   unsigned int *visited_index;
-  VEC(uint,heap) *scc_stack;
-  VEC(uint,heap) *unification_queue;
+  VEC(unsigned,heap) *scc_stack;
+  VEC(unsigned,heap) *unification_queue;
 };
 
 
@@ -1051,18 +1068,18 @@ scc_visit (constraint_graph_t graph, struct scc_info *si, unsigned int n)
     {
       unsigned int t = si->visited_index[n];
       SET_BIT (si->in_component, n);
-      while (VEC_length (uint, si->scc_stack) != 0 
-            && t < si->visited_index[VEC_last (uint, si->scc_stack)])
+      while (VEC_length (unsigned, si->scc_stack) != 0 
+            && t < si->visited_index[VEC_last (unsigned, si->scc_stack)])
        {
-         unsigned int w = VEC_pop (uint, si->scc_stack);
+         unsigned int w = VEC_pop (unsigned, si->scc_stack);
          get_varinfo (w)->node = n;
          SET_BIT (si->in_component, w);
          /* Mark this node for collapsing.  */
-         VEC_safe_push (uint, heap, si->unification_queue, w);
+         VEC_safe_push (unsigned, heap, si->unification_queue, w);
        } 
     }
   else
-    VEC_safe_push (uint, heap, si->scc_stack, n);
+    VEC_safe_push (unsigned, heap, si->scc_stack, n);
 }
 
 
@@ -1132,9 +1149,9 @@ process_unification_queue (constraint_graph_t graph, struct scc_info *si,
        changed rep's solution.
        
        Delete any 0 weighted self-edges we now have for rep.  */
-  while (i != VEC_length (uint, si->unification_queue))
+  while (i != VEC_length (unsigned, si->unification_queue))
     {
-      unsigned int tounify = VEC_index (uint, si->unification_queue, i);
+      unsigned int tounify = VEC_index (unsigned, si->unification_queue, i);
       unsigned int n = get_varinfo (tounify)->node;
 
       if (dump_file && (dump_flags & TDF_DETAILS))
@@ -1167,8 +1184,8 @@ process_unification_queue (constraint_graph_t graph, struct scc_info *si,
       /* If we've either finished processing the entire queue, or
         finished processing all nodes for component n, update the solution for
         n.  */
-      if (i == VEC_length (uint, si->unification_queue)
-         || get_varinfo (VEC_index (uint, si->unification_queue, i))->node != n)
+      if (i == VEC_length (unsigned, si->unification_queue)
+         || get_varinfo (VEC_index (unsigned, si->unification_queue, i))->node != n)
        {
          struct constraint_edge edge;
 
@@ -1206,7 +1223,7 @@ struct topo_info
   sbitmap visited;
   /* Array that stores the topological order of the graph, *in
      reverse*.  */
-  VEC(uint,heap) *topo_order;
+  VEC(unsigned,heap) *topo_order;
 };
 
 
@@ -1219,7 +1236,7 @@ init_topo_info (void)
   struct topo_info *ti = xmalloc (sizeof (struct topo_info));
   ti->visited = sbitmap_alloc (size);
   sbitmap_zero (ti->visited);
-  ti->topo_order = VEC_alloc (uint, heap, 1);
+  ti->topo_order = VEC_alloc (unsigned, heap, 1);
   return ti;
 }
 
@@ -1230,7 +1247,7 @@ static void
 free_topo_info (struct topo_info *ti)
 {
   sbitmap_free (ti->visited);
-  VEC_free (uint, heap, ti->topo_order);
+  VEC_free (unsigned, heap, ti->topo_order);
   free (ti);
 }
 
@@ -1241,7 +1258,7 @@ static void
 topo_visit (constraint_graph_t graph, struct topo_info *ti,
            unsigned int n)
 {
-  VEC(constraint_edge_t,gc) *succs = graph->succs[n];
+  VEC(constraint_edge_t,heap) *succs = graph->succs[n];
   constraint_edge_t c;
   int i;
   SET_BIT (ti->visited, n);
@@ -1250,7 +1267,7 @@ topo_visit (constraint_graph_t graph, struct topo_info *ti,
       if (!TEST_BIT (ti->visited, c->dest))
        topo_visit (graph, ti, c->dest);
     }
-  VEC_safe_push (uint, heap, ti->topo_order, n);
+  VEC_safe_push (unsigned, heap, ti->topo_order, n);
 }
 
 /* Return true if variable N + OFFSET is a legal field of N.  */
@@ -1447,8 +1464,8 @@ init_scc_info (void)
   si->in_component = sbitmap_alloc (size);
   sbitmap_ones (si->in_component);
   si->visited_index = xcalloc (sizeof (unsigned int), size + 1);
-  si->scc_stack = VEC_alloc (uint, heap, 1);
-  si->unification_queue = VEC_alloc (uint, heap, 1);
+  si->scc_stack = VEC_alloc (unsigned, heap, 1);
+  si->unification_queue = VEC_alloc (unsigned, heap, 1);
   return si;
 }
 
@@ -1460,8 +1477,8 @@ free_scc_info (struct scc_info *si)
   sbitmap_free (si->visited);
   sbitmap_free (si->in_component);
   free (si->visited_index);
-  VEC_free (uint, heap, si->scc_stack);
-  VEC_free (uint, heap, si->unification_queue);
+  VEC_free (unsigned, heap, si->scc_stack);
+  VEC_free (unsigned, heap, si->unification_queue);
   free(si); 
 }
 
@@ -1534,14 +1551,14 @@ perform_var_substitution (constraint_graph_t graph)
      node in topological order.  */
   compute_topo_order (graph, ti);
  
-  while (VEC_length (uint, ti->topo_order) != 0)
+  while (VEC_length (unsigned, ti->topo_order) != 0)
     {
-      unsigned int i = VEC_pop (uint, ti->topo_order);
+      unsigned int i = VEC_pop (unsigned, ti->topo_order);
       unsigned int pred;
       varinfo_t vi = get_varinfo (i);
       bool okay_to_elim = false;
       unsigned int root = VEC_length (varinfo_t, varmap);
-      VEC(constraint_edge_t,gc) *predvec = graph->preds[i];
+      VEC(constraint_edge_t,heap) *predvec = graph->preds[i];
       constraint_edge_t ce;
       bitmap tmp;
 
@@ -1660,9 +1677,9 @@ solve_graph (constraint_graph_t graph)
 
       compute_topo_order (graph, ti);
 
-      while (VEC_length (uint, ti->topo_order) != 0)
+      while (VEC_length (unsigned, ti->topo_order) != 0)
        {
-         i = VEC_pop (uint, ti->topo_order);
+         i = VEC_pop (unsigned, ti->topo_order);
          gcc_assert (get_varinfo (i)->node == i);
 
          /* If the node has changed, we need to process the
@@ -1673,8 +1690,8 @@ solve_graph (constraint_graph_t graph)
              constraint_t c;
              constraint_edge_t e;
              bitmap solution;
-             VEC(constraint_t,gc) *complex = get_varinfo (i)->complex;
-             VEC(constraint_edge_t,gc) *succs;
+             VEC(constraint_t,heap) *complex = get_varinfo (i)->complex;
+             VEC(constraint_edge_t,heap) *succs;
 
              RESET_BIT (changed, i);
              changed_count--;
@@ -1850,13 +1867,14 @@ get_constraint_exp_from_ssa_var (tree t)
 
   cexpr.type = SCALAR;
   
-  if (TREE_READONLY (t))
+  cexpr.var = get_id_for_tree (t);
+  /* If we determine the result is "anything", and we know this is readonly,
+     say it points to readonly memory instead.  */
+  if (cexpr.var == anything_id && TREE_READONLY (t))
     {
       cexpr.type = ADDRESSOF;
       cexpr.var = readonly_id;
     }
-  else
-    cexpr.var = get_id_for_tree (t);    
     
   cexpr.offset = 0;
   return cexpr;
@@ -1913,13 +1931,13 @@ process_constraint (constraint_t t)
       for (vi = get_varinfo (rhs.var); vi != NULL; vi = vi->next)
        vi->address_taken = true;
 
-      VEC_safe_push (constraint_t, gc, constraints, t);
+      VEC_safe_push (constraint_t, heap, constraints, t);
     }
   else
     {
       if (lhs.type != DEREF && rhs.type == DEREF)
        get_varinfo (lhs.var)->indirect_target = true;
-      VEC_safe_push (constraint_t, gc, constraints, t);
+      VEC_safe_push (constraint_t, heap, constraints, t);
     }
 }
 
@@ -1940,6 +1958,25 @@ bitpos_of_field (const tree fdecl)
 }
 
 
+/* Return true if an access to [ACCESSPOS, ACCESSSIZE]
+   overlaps with a field at [FIELDPOS, FIELDSIZE] */
+
+static bool
+offset_overlaps_with_access (const unsigned HOST_WIDE_INT fieldpos,
+                            const unsigned HOST_WIDE_INT fieldsize,
+                            const unsigned HOST_WIDE_INT accesspos,
+                            const unsigned HOST_WIDE_INT accesssize)
+{
+  if (fieldpos == accesspos && fieldsize == accesssize)
+    return true;
+  if (accesspos >= fieldpos && accesspos < (fieldpos + fieldsize))
+    return true;
+  if (accesspos < fieldpos && (accesspos + accesssize > fieldpos))
+    return true;
+  
+  return false;
+}
+
 /* Given a COMPONENT_REF T, return the constraint_expr for it.  */
 
 static struct constraint_expr
@@ -2000,8 +2037,27 @@ get_constraint_for_component_ref (tree t)
         we may have to do something cute here.  */
       
       if (result.offset < get_varinfo (result.var)->fullsize)  
-       result.var = first_vi_for_offset (get_varinfo (result.var), 
-                                         result.offset)->id;
+       {
+         /* It's also not true that the constraint will actually start at the
+            right offset, it may start in some padding.  We only care about
+            setting the constraint to the first actual field it touches, so
+            walk to find it.  */ 
+         varinfo_t curr;
+         for (curr = get_varinfo (result.var); curr; curr = curr->next)
+           {
+             if (offset_overlaps_with_access (curr->offset, curr->size,
+                                              result.offset, bitsize))
+               {
+                 result.var = curr->id;
+                 break;
+
+               }
+           }
+         /* assert that we found *some* field there. The user couldn't be
+            accessing *only* padding.  */
+            
+         gcc_assert (curr);
+       }
       else
        if (dump_file && (dump_flags & TDF_DETAILS))
          fprintf (dump_file, "Access to past the end of variable, ignoring\n");
@@ -2099,11 +2155,18 @@ get_constraint_for (tree t)
               &ANYTHING added.  */
            if (call_expr_flags (t) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA))
              {
-               tree heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
+               varinfo_t vi;
+               tree heapvar;
+               
+               heapvar = create_tmp_var_raw (ptr_type_node, "HEAP");
+               DECL_EXTERNAL (heapvar) = 1;
+               add_referenced_tmp_var (heapvar);
                temp.var = create_variable_info_for (heapvar,
                                                     alias_get_name (heapvar));
                
-               get_varinfo (temp.var)->is_artificial_var = 1;
+               vi = get_varinfo (temp.var);
+               vi->is_artificial_var = 1;
+               vi->is_heap_var = 1;
                temp.type = ADDRESSOF;
                temp.offset = 0;
                return temp;
@@ -2153,9 +2216,11 @@ get_constraint_for (tree t)
              
              /* Cast from non-pointer to pointers are bad news for us.
                 Anything else, we see through */
-             if (!(POINTER_TYPE_P (TREE_TYPE (t))  &&
-                   ! POINTER_TYPE_P (TREE_TYPE (op))))
+             if (!(POINTER_TYPE_P (TREE_TYPE (t))
+                   && ! POINTER_TYPE_P (TREE_TYPE (op))))
                return get_constraint_for (op);
+
+             /* FALLTHRU  */
            }
          default:
            {
@@ -2210,8 +2275,7 @@ do_simple_structure_copy (const struct constraint_expr lhs,
                          const unsigned HOST_WIDE_INT size)
 {
   varinfo_t p = get_varinfo (lhs.var);
-  unsigned HOST_WIDE_INT pstart,last;
-
+  unsigned HOST_WIDE_INT pstart, last;
   pstart = p->offset;
   last = p->offset + size;
   for (; p && p->offset < last; p = p->next)
@@ -2321,8 +2385,6 @@ do_structure_copy (tree lhsop, tree rhsop)
   unsigned HOST_WIDE_INT lhssize;
   unsigned HOST_WIDE_INT rhssize;
 
-  lhssize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (lhsop)));
-  rhssize = TREE_INT_CST_LOW (TYPE_SIZE (TREE_TYPE (rhsop)));
   lhs = get_constraint_for (lhsop);  
   rhs = get_constraint_for (rhsop);
   
@@ -2334,8 +2396,18 @@ do_structure_copy (tree lhsop, tree rhsop)
       rhs = tmp;
     }
   
-  /* If the RHS is a special var, set all the LHS fields to that
-     special var.  */
+  /*  This is fairly conservative for the RHS == ADDRESSOF case, in that it's
+      possible it's something we could handle.  However, most cases falling
+      into this are dealing with transparent unions, which are slightly
+      weird. */
+  if (rhs.type == ADDRESSOF && rhs.var > integer_id)
+    {
+      rhs.type = ADDRESSOF;
+      rhs.var = anything_id;
+    }
+
+  /* If the RHS is a special var, or an addressof, set all the LHS fields to
+     that special var.  */
   if (rhs.var <= integer_id)
     {
       for (p = get_varinfo (lhs.var); p; p = p->next)
@@ -2351,6 +2423,41 @@ do_structure_copy (tree lhsop, tree rhsop)
     }
   else
     {
+      tree rhstype = TREE_TYPE (rhsop);
+      tree lhstype = TREE_TYPE (lhsop);
+      tree rhstypesize = TYPE_SIZE (rhstype);
+      tree lhstypesize = TYPE_SIZE (lhstype);
+
+      /* If we have a variably sized types on the rhs or lhs, and a deref
+        constraint, add the constraint, lhsconstraint = &ANYTHING.
+        This is conservatively correct because either the lhs is an unknown
+        sized var (if the constraint is SCALAR), or the lhs is a DEREF
+        constraint, and every variable it can point to must be unknown sized
+        anyway, so we don't need to worry about fields at all.  */
+      if ((rhs.type == DEREF && TREE_CODE (rhstypesize) != INTEGER_CST)
+         || (lhs.type == DEREF && TREE_CODE (lhstypesize) != INTEGER_CST))
+       {
+         rhs.var = anything_id;
+         rhs.type = ADDRESSOF;
+         rhs.offset = 0;
+         process_constraint (new_constraint (lhs, rhs));
+         return;
+       }
+
+      /* The size only really matters insofar as we don't set more or less of
+        the variable.  If we hit an unknown size var, the size should be the
+        whole darn thing.  */
+      if (get_varinfo (rhs.var)->is_unknown_size_var)
+       rhssize = ~0;
+      else
+       rhssize = TREE_INT_CST_LOW (rhstypesize);
+
+      if (get_varinfo (lhs.var)->is_unknown_size_var)
+       lhssize = ~0;
+      else
+       lhssize = TREE_INT_CST_LOW (lhstypesize);
+
+  
       if (rhs.type == SCALAR && lhs.type == SCALAR)  
        do_simple_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
       else if (lhs.type != DEREF && rhs.type == DEREF)
@@ -2359,17 +2466,13 @@ do_structure_copy (tree lhsop, tree rhsop)
        do_lhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
       else
        {
-         tree rhsdecl = get_varinfo (rhs.var)->decl;
-         tree pointertype = TREE_TYPE (rhsdecl);
-         tree pointedtotype = TREE_TYPE (pointertype);
-         tree tmpvar;
+         tree pointedtotype = lhstype;
+         tree tmpvar;  
+
          gcc_assert (rhs.type == DEREF && lhs.type == DEREF);
          tmpvar = create_tmp_var_raw (pointedtotype, "structcopydereftmp");
-         lhs = get_constraint_for (tmpvar);
-         do_rhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
-         rhs = lhs;
-         lhs = get_constraint_for (lhsop);
-         do_lhs_deref_structure_copy (lhs, rhs, MIN (lhssize, rhssize));
+         do_structure_copy (tmpvar, rhsop);
+         do_structure_copy (lhsop, tmpvar);
        }
     }
 }
@@ -2391,81 +2494,311 @@ ref_contains_indirect_ref (tree ref)
 }
 
 
-/*  Tree walker that is the heart of the aliasing infrastructure.
-    TP is a pointer to the current tree.
-    WALK_SUBTREES specifies whether to continue traversing subtrees or
-    not.
-    Returns NULL_TREE when we should stop.
-    
-    This function is the main part of the constraint builder. It
-    walks the trees, calling the appropriate building functions
-    to process various statements.  */
+/* Update related alias information kept in AI.  This is used when
+   building name tags, alias sets and deciding grouping heuristics.
+   STMT is the statement to process.  This function also updates
+   ADDRESSABLE_VARS.  */
 
 static void
-find_func_aliases (tree t)
+update_alias_info (tree stmt, struct alias_info *ai)
+{
+  bitmap addr_taken;
+  use_operand_p use_p;
+  ssa_op_iter iter;
+  bool stmt_escapes_p = is_escape_site (stmt, ai);
+  tree op;
+
+  /* Mark all the variables whose address are taken by the statement.  */
+  addr_taken = addresses_taken (stmt);
+  if (addr_taken)
+    {
+      bitmap_ior_into (addressable_vars, addr_taken);
+
+      /* If STMT is an escape point, all the addresses taken by it are
+        call-clobbered.  */
+      if (stmt_escapes_p)
+       {
+         bitmap_iterator bi;
+         unsigned i;
+
+         EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
+           mark_call_clobbered (referenced_var (i));
+       }
+    }
+
+  /* Process each operand use.  If an operand may be aliased, keep
+     track of how many times it's being used.  For pointers, determine
+     whether they are dereferenced by the statement, or whether their
+     value escapes, etc.  */
+  FOR_EACH_PHI_OR_STMT_USE (use_p, stmt, iter, SSA_OP_USE)
+    {
+      tree op, var;
+      var_ann_t v_ann;
+      struct ptr_info_def *pi;
+      bool is_store;
+      unsigned num_uses, num_derefs;
+
+      op = USE_FROM_PTR (use_p);
+
+      /* If STMT is a PHI node, OP may be an ADDR_EXPR.  If so, add it
+        to the set of addressable variables.  */
+      if (TREE_CODE (op) == ADDR_EXPR)
+       {
+         gcc_assert (TREE_CODE (stmt) == PHI_NODE);
+
+         /* PHI nodes don't have annotations for pinning the set
+            of addresses taken, so we collect them here.
+
+            FIXME, should we allow PHI nodes to have annotations
+            so that they can be treated like regular statements?
+            Currently, they are treated as second-class
+            statements.  */
+         add_to_addressable_set (TREE_OPERAND (op, 0), &addressable_vars);
+         continue;
+       }
+
+      /* Ignore constants.  */
+      if (TREE_CODE (op) != SSA_NAME)
+       continue;
+
+      var = SSA_NAME_VAR (op);
+      v_ann = var_ann (var);
+
+      /* If the operand's variable may be aliased, keep track of how
+        many times we've referenced it.  This is used for alias
+        grouping in compute_flow_insensitive_aliasing.  */
+      if (may_be_aliased (var))
+       NUM_REFERENCES_INC (v_ann);
+
+      /* We are only interested in pointers.  */
+      if (!POINTER_TYPE_P (TREE_TYPE (op)))
+       continue;
+
+      pi = get_ptr_info (op);
+
+      /* Add OP to AI->PROCESSED_PTRS, if it's not there already.  */
+      if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op)))
+       {
+         SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (op));
+         VARRAY_PUSH_TREE (ai->processed_ptrs, op);
+       }
+
+      /* If STMT is a PHI node, then it will not have pointer
+        dereferences and it will not be an escape point.  */
+      if (TREE_CODE (stmt) == PHI_NODE)
+       continue;
+
+      /* Determine whether OP is a dereferenced pointer, and if STMT
+        is an escape point, whether OP escapes.  */
+      count_uses_and_derefs (op, stmt, &num_uses, &num_derefs, &is_store);
+
+      if (num_derefs > 0)
+       {
+         /* Mark OP as dereferenced.  In a subsequent pass,
+            dereferenced pointers that point to a set of
+            variables will be assigned a name tag to alias
+            all the variables OP points to.  */
+         pi->is_dereferenced = 1;
+
+         /* Keep track of how many time we've dereferenced each
+            pointer.  */
+         NUM_REFERENCES_INC (v_ann);
+
+         /* If this is a store operation, mark OP as being
+            dereferenced to store, otherwise mark it as being
+            dereferenced to load.  */
+         if (is_store)
+           bitmap_set_bit (ai->dereferenced_ptrs_store, DECL_UID (var));
+         else
+           bitmap_set_bit (ai->dereferenced_ptrs_load, DECL_UID (var));
+       }
+
+      if (stmt_escapes_p && num_derefs < num_uses)
+       {
+         /* If STMT is an escape point and STMT contains at
+            least one direct use of OP, then the value of OP
+            escapes and so the pointed-to variables need to
+            be marked call-clobbered.  */
+         pi->value_escapes_p = 1;
+
+         /* If the statement makes a function call, assume
+            that pointer OP will be dereferenced in a store
+            operation inside the called function.  */
+         if (get_call_expr_in (stmt))
+           {
+             bitmap_set_bit (ai->dereferenced_ptrs_store, DECL_UID (var));
+             pi->is_dereferenced = 1;
+           }
+       }
+    }
+
+  if (TREE_CODE (stmt) == PHI_NODE)
+    return;
+
+  /* Update reference counter for definitions to any
+     potentially aliased variable.  This is used in the alias
+     grouping heuristics.  */
+  FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
+    {
+      tree var = SSA_NAME_VAR (op);
+      var_ann_t ann = var_ann (var);
+      bitmap_set_bit (ai->written_vars, DECL_UID (var));
+      if (may_be_aliased (var))
+       NUM_REFERENCES_INC (ann);
+      
+    }
+  
+  /* Mark variables in V_MAY_DEF operands as being written to.  */
+  FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
+    {
+      tree var = DECL_P (op) ? op : SSA_NAME_VAR (op);
+      bitmap_set_bit (ai->written_vars, DECL_UID (var));
+    }
+}
+
+
+/* Handle pointer arithmetic EXPR when creating aliasing constraints.
+   Expressions of the type PTR + CST can be handled in two ways:
+
+   1- If the constraint for PTR is ADDRESSOF for a non-structure
+      variable, then we can use it directly because adding or
+      subtracting a constant may not alter the original ADDRESSOF
+      constraing (i.e., pointer arithmetic may not legally go outside
+      an object's boundaries).
+
+   2- If the constraint for PTR is ADDRESSOF for a structure variable,
+      then if CST is a compile-time constant that can be used as an
+      offset, we can determine which sub-variable will be pointed-to
+      by the expression.
+
+   Return true if the expression is handled.  For any other kind of
+   expression, return false so that each operand can be added as a
+   separate constraint by the caller.  */
+
+static bool
+handle_ptr_arith (struct constraint_expr lhs, tree expr)
+{
+  tree op0, op1;
+  struct constraint_expr base, offset;
+
+  if (TREE_CODE (expr) != PLUS_EXPR)
+    return false;
+
+  op0 = TREE_OPERAND (expr, 0);
+  op1 = TREE_OPERAND (expr, 1);
+
+  base = get_constraint_for (op0);
+
+  offset.var = anyoffset_id;
+  offset.type = ADDRESSOF;
+  offset.offset = 0;
+
+  process_constraint (new_constraint (lhs, base));
+  process_constraint (new_constraint (lhs, offset));
+
+  return true;
+}
+
+
+/* Walk statement T setting up aliasing constraints according to the
+   references found in T.  This function is the main part of the
+   constraint builder.  AI points to auxiliary alias information used
+   when building alias sets and computing alias grouping heuristics.  */
+
+static void
+find_func_aliases (tree t, struct alias_info *ai)
 {
   struct constraint_expr lhs, rhs;
-  switch (TREE_CODE (t))
-    {      
-    case PHI_NODE:
-      {
-       int i;
 
-       /* Only care about pointers and structures containing
-          pointers.  */
-       if (POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (t)))
-           || AGGREGATE_TYPE_P (TREE_TYPE (PHI_RESULT (t))))
-         {
-           lhs = get_constraint_for (PHI_RESULT (t));
-           for (i = 0; i < PHI_NUM_ARGS (t); i++)
-             {
-               rhs = get_constraint_for (PHI_ARG_DEF (t, i));
-               process_constraint (new_constraint (lhs, rhs));
-             }
-         }
-      }
-      break;
+  /* Update various related attributes like escaped addresses, pointer
+     dereferences for loads and stores.  This is used when creating
+     name tags and alias sets.  */
+  update_alias_info (t, ai);
 
-    case MODIFY_EXPR:
-      {
-       tree lhsop = TREE_OPERAND (t, 0);
-       tree rhsop = TREE_OPERAND (t, 1);
-       int i;  
+  /* Now build constraints expressions.  */
+  if (TREE_CODE (t) == PHI_NODE)
+    {
+      /* Only care about pointers and structures containing
+        pointers.  */
+      if (POINTER_TYPE_P (TREE_TYPE (PHI_RESULT (t)))
+         || AGGREGATE_TYPE_P (TREE_TYPE (PHI_RESULT (t))))
+       {
+         int i;
 
-       if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)) 
-           && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
-         {
-           do_structure_copy (lhsop, rhsop);
-         }
-       else
-         {
-           /* Only care about operations with pointers, structures
-              containing pointers, dereferences, and call
-              expressions.  */
-           if (POINTER_TYPE_P (TREE_TYPE (lhsop))
-               || AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
-               || ref_contains_indirect_ref (lhsop)
-               || TREE_CODE (rhsop) == CALL_EXPR)
-             {
-               lhs = get_constraint_for (lhsop);
-               switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
-                 {
-                   /* RHS that consist of unary operations,
-                      exceptional types, or bare decls/constants, get
-                      handled directly by get_constraint_for.  */ 
+         lhs = get_constraint_for (PHI_RESULT (t));
+         for (i = 0; i < PHI_NUM_ARGS (t); i++)
+           {
+             rhs = get_constraint_for (PHI_ARG_DEF (t, i));
+             process_constraint (new_constraint (lhs, rhs));
+           }
+       }
+    }
+  else if (TREE_CODE (t) == MODIFY_EXPR)
+    {
+      tree lhsop = TREE_OPERAND (t, 0);
+      tree rhsop = TREE_OPERAND (t, 1);
+      int i;   
+
+      if (AGGREGATE_TYPE_P (TREE_TYPE (lhsop)) 
+         && AGGREGATE_TYPE_P (TREE_TYPE (rhsop)))
+       {
+         do_structure_copy (lhsop, rhsop);
+       }
+      else
+       {
+         /* Only care about operations with pointers, structures
+            containing pointers, dereferences, and call expressions.  */
+         if (POINTER_TYPE_P (TREE_TYPE (lhsop))
+             || AGGREGATE_TYPE_P (TREE_TYPE (lhsop))
+             || ref_contains_indirect_ref (lhsop)
+             || TREE_CODE (rhsop) == CALL_EXPR)
+           {
+             lhs = get_constraint_for (lhsop);
+             switch (TREE_CODE_CLASS (TREE_CODE (rhsop)))
+               {
+                 /* RHS that consist of unary operations,
+                    exceptional types, or bare decls/constants, get
+                    handled directly by get_constraint_for.  */ 
                  case tcc_reference:
                  case tcc_declaration:
                  case tcc_constant:
                  case tcc_exceptional:
                  case tcc_expression:
                  case tcc_unary:
-                   {
-                     rhs = get_constraint_for (rhsop);
-                     process_constraint (new_constraint (lhs, rhs));
-                   }
+                     {
+                       rhs = get_constraint_for (rhsop);
+                       process_constraint (new_constraint (lhs, rhs));
+
+                       /* When taking the address of an aggregate
+                          type, from the LHS we can access any field
+                          of the RHS.  */
+                       if (rhs.type == ADDRESSOF
+                           && rhs.var > anything_id
+                           && AGGREGATE_TYPE_P (TREE_TYPE (TREE_TYPE (rhsop))))
+                         {
+                           rhs.var = anyoffset_id;
+                           rhs.type = ADDRESSOF;
+                           rhs.offset = 0;
+                           process_constraint (new_constraint (lhs, rhs));
+                         }
+                     }
                    break;
 
-                   /* Otherwise, walk each operand.  */
+                 case tcc_binary:
+                     {
+                       /* For pointer arithmetic of the form
+                          PTR + CST, we can simply use PTR's
+                          constraint because pointer arithmetic is
+                          not allowed to go out of bounds.  */
+                       if (handle_ptr_arith (lhs, rhsop))
+                         break;
+                     }
+                   /* FALLTHRU  */
+
+                 /* Otherwise, walk each operand.  Notice that we
+                    can't use the operand interface because we need
+                    to process expressions other than simple operands
+                    (e.g. INDIRECT_REF, ADDR_EXPR, CALL_EXPR).  */
                  default:
                    for (i = 0; i < TREE_CODE_LENGTH (TREE_CODE (rhsop)); i++)
                      {
@@ -2473,15 +2806,16 @@ find_func_aliases (tree t)
                        rhs = get_constraint_for (op);
                        process_constraint (new_constraint (lhs, rhs));
                      }
-                 }      
-             }
-         }
-      }
-      break;
-
-    default:
-      break;
+               }      
+           }
+       }
     }
+
+  /* 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
+     re-scan *all* statements.  */
+  mark_stmt_modified (t);
 }
 
 
@@ -2642,12 +2976,12 @@ create_variable_info_for (tree decl, const char *name)
   tree decltype = TREE_TYPE (decl);
   bool notokay = false;
   bool hasunion;
-  subvar_t svars;
   bool is_global = DECL_P (decl) ? is_global_var (decl) : false;
   VEC (fieldoff_s,heap) *fieldstack = NULL;
   
 
-  hasunion = TREE_CODE (decltype) == UNION_TYPE || TREE_CODE (decltype) == QUAL_UNION_TYPE;
+  hasunion = TREE_CODE (decltype) == UNION_TYPE
+             || TREE_CODE (decltype) == QUAL_UNION_TYPE;
   if (var_can_have_subvars (decl) && use_field_sensitive && !hasunion)
     {
       push_fields_onto_fieldstack (decltype, &fieldstack, 0, &hasunion);
@@ -2657,62 +2991,6 @@ create_variable_info_for (tree decl, const char *name)
          notokay = true;
        }        
     }
-
-  /* If this variable already has subvars, just create the variables for the
-     subvars and we are done.
-     NOTE: This assumes things haven't generated uses of previously
-     unused structure fields.  */
-  if (use_field_sensitive 
-      && !notokay 
-      && var_can_have_subvars (decl) 
-      && var_ann (decl)      
-      && (svars = get_subvars_for_var (decl)))
-    {
-      subvar_t sv;
-      varinfo_t base = NULL;
-      unsigned int firstindex = index;
-
-      for (sv = svars; sv; sv = sv->next)
-       {
-         /* For debugging purposes, this will print the names of the
-            fields as "<var>.<offset>.<size>"
-            This is only for debugging purposes.  */
-#define PRINT_LONG_NAMES
-#ifdef PRINT_LONG_NAMES
-         char *tempname;
-         const char *newname;
-
-         asprintf (&tempname,
-                   "%s." HOST_WIDE_INT_PRINT_DEC "." HOST_WIDE_INT_PRINT_DEC,
-                   alias_get_name (decl), sv->offset, sv->size);
-         newname = ggc_strdup (tempname);
-         free (tempname);
-         vi = new_var_info (sv->var, index, newname, index);
-#else
-         vi = new_var_info (sv->var, index, alias_get_name (sv->var), index);
-#endif
-         vi->decl = sv->var;
-         vi->fullsize = TREE_INT_CST_LOW (TYPE_SIZE (decltype));
-         vi->size = sv->size;
-         vi->offset = sv->offset;
-         if (!base)
-           {
-             base = vi;
-             insert_id_for_tree (decl, index);
-           }
-         else
-           {
-             insert_into_field_list (base, vi);
-           }
-         insert_id_for_tree (sv->var, index);  
-         VEC_safe_push (varinfo_t, gc, varmap, vi);
-         if (is_global)
-           make_constraint_to_anything (vi);
-         index++;
-         
-       }
-      return firstindex;
-    }
   
 
   /* If the variable doesn't have subvars, we may end up needing to
@@ -2723,7 +3001,7 @@ create_variable_info_for (tree decl, const char *name)
   vi->offset = 0;
   vi->has_union = hasunion;
   if (!TYPE_SIZE (decltype) 
-      || TREE_CODE (TYPE_SIZE  (decltype)) != INTEGER_CST
+      || TREE_CODE (TYPE_SIZE (decltype)) != INTEGER_CST
       || TREE_CODE (decltype) == ARRAY_TYPE
       || TREE_CODE (decltype) == UNION_TYPE
       || TREE_CODE (decltype) == QUAL_UNION_TYPE)
@@ -2739,7 +3017,7 @@ create_variable_info_for (tree decl, const char *name)
     }
   
   insert_id_for_tree (vi->decl, index);  
-  VEC_safe_push (varinfo_t, gc, varmap, vi);
+  VEC_safe_push (varinfo_t, heap, varmap, vi);
   if (is_global)
     make_constraint_to_anything (vi);
 
@@ -2786,7 +3064,6 @@ create_variable_info_for (tree decl, const char *name)
        }
       
       field = fo->field;
-      gcc_assert (bitpos_of_field (field) == 0);
       vi->size = TREE_INT_CST_LOW (DECL_SIZE (field));
       for (i = 1; VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
        {
@@ -2804,7 +3081,7 @@ create_variable_info_for (tree decl, const char *name)
          newvi->size = TREE_INT_CST_LOW (DECL_SIZE (field));
          newvi->fullsize = vi->fullsize;
          insert_into_field_list (vi, newvi);
-         VEC_safe_push (varinfo_t, gc, varmap, newvi);
+         VEC_safe_push (varinfo_t, heap, varmap, newvi);
          if (is_global)
            make_constraint_to_anything (newvi);
 
@@ -2824,10 +3101,10 @@ dump_solution_for_var (FILE *file, unsigned int var)
   unsigned int i;
   bitmap_iterator bi; 
   
-  fprintf (file, "%s = {", vi->name);
+  fprintf (file, "%s = { ", vi->name);
   EXECUTE_IF_SET_IN_BITMAP (get_varinfo (vi->node)->solution, 0, i, bi)
     {
-      fprintf (file, "%s,", get_varinfo (i)->name);
+      fprintf (file, "%s ", get_varinfo (i)->name);
     }
   fprintf (file, "}\n");
 }
@@ -2860,7 +3137,6 @@ intra_create_variable_infos (void)
       lhs.type = SCALAR;
       lhs.var  = create_variable_info_for (t, alias_get_name (t));
       
-      get_varinfo (lhs.var)->is_artificial_var = true;
       rhs.var = anything_id;
       rhs.type = ADDRESSOF;
       rhs.offset = 0;
@@ -2883,30 +3159,67 @@ set_uids_in_ptset (bitmap into, bitmap from)
 {
   unsigned int i;
   bitmap_iterator bi;
+  bool found_anyoffset = false;
+  subvar_t sv;
 
   EXECUTE_IF_SET_IN_BITMAP (from, 0, i, bi)
     {
       varinfo_t vi = get_varinfo (i);
+
+      /* If we find ANYOFFSET in the solution and the solution
+        includes SFTs for some structure, then all the SFTs in that
+        structure will need to be added to the alias set.  */
+      if (vi->id == anyoffset_id)
+       {
+         found_anyoffset = true;
+         continue;
+       }
+
+      /* The only artificial variables that are allowed in a may-alias
+        set are heap variables.  */
+      if (vi->is_artificial_var && !vi->is_heap_var)
+       continue;
       
-      /* Variables containing unions may need to be converted to their 
-        SFT's, because SFT's can have unions and we cannot.  */
       if (vi->has_union && get_subvars_for_var (vi->decl) != NULL)
        {
-         subvar_t svars = get_subvars_for_var (vi->decl);
-         subvar_t sv;
-         for (sv = svars; sv; sv = sv->next)
-           bitmap_set_bit (into, var_ann (sv->var)->uid);    
+         /* Variables containing unions may need to be converted to
+            their SFT's, because SFT's can have unions and we cannot.  */
+         for (sv = get_subvars_for_var (vi->decl); sv; sv = sv->next)
+           bitmap_set_bit (into, DECL_UID (sv->var));
        }
-      /* We may end up with labels in the points-to set because people
-        take their address, and they are _DECL's.  */
       else if (TREE_CODE (vi->decl) == VAR_DECL 
-         || TREE_CODE (vi->decl) == PARM_DECL)
-       bitmap_set_bit (into, var_ann (vi->decl)->uid);
-
-         
+              || TREE_CODE (vi->decl) == PARM_DECL)
+       {
+         if (found_anyoffset
+             && var_can_have_subvars (vi->decl)
+             && get_subvars_for_var (vi->decl))
+           {
+             /* If ANYOFFSET is in the solution set and VI->DECL is
+                an aggregate variable with sub-variables, then any of
+                the SFTs inside VI->DECL may have been accessed.  Add
+                all the sub-vars for VI->DECL.  */
+             for (sv = get_subvars_for_var (vi->decl); sv; sv = sv->next)
+               bitmap_set_bit (into, DECL_UID (sv->var));
+           }
+         else if (var_can_have_subvars (vi->decl)
+                  && get_subvars_for_var (vi->decl))
+           {
+             /* If VI->DECL is an aggregate for which we created
+                SFTs, add the SFT corresponding to VI->OFFSET.  */
+             tree sft = get_subvar_at (vi->decl, vi->offset);
+             bitmap_set_bit (into, DECL_UID (sft));
+           }
+         else
+           {
+             /* Otherwise, just add VI->DECL to the alias set.  */
+             bitmap_set_bit (into, DECL_UID (vi->decl));
+           }
+       }
     }
 }
-static int have_alias_info = false;
+
+
+static bool have_alias_info = false;
 
 /* Given a pointer variable P, fill in its points-to set, or return
    false if we can't.  */
@@ -2915,8 +3228,10 @@ bool
 find_what_p_points_to (tree p)
 {
   unsigned int id = 0;
+
   if (!have_alias_info)
     return false;
+
   if (lookup_id_for_tree (p, &id))
     {
       varinfo_t vi = get_varinfo (id);
@@ -2924,14 +3239,15 @@ find_what_p_points_to (tree p)
       if (vi->is_artificial_var)
        return false;
 
-      /* See if this is a field or a structure */
+      /* See if this is a field or a structure */
       if (vi->size != vi->fullsize)
        {
+         /* Nothing currently asks about structure fields directly,
+            but when they do, we need code here to hand back the
+            points-to set.  */
          if (!var_can_have_subvars (vi->decl)
              || get_subvars_for_var (vi->decl) == NULL)
            return false;
-         /* Nothing currently asks about structure fields directly, but when
-            they do, we need code here to hand back the points-to set.  */
        } 
       else
        {
@@ -2943,24 +3259,49 @@ find_what_p_points_to (tree p)
             variable.  */
          vi = get_varinfo (vi->node);
          
-         /* Make sure there aren't any artificial vars in the points to set.
-             XXX: Note that we need to translate our heap variables to
-             something.  */
+         /* Translate artificial variables into SSA_NAME_PTR_INFO
+            attributes.  */
          EXECUTE_IF_SET_IN_BITMAP (vi->solution, 0, i, bi)
            {
-             if (get_varinfo (i)->is_artificial_var)
-               return false;
+             varinfo_t vi = get_varinfo (i);
+
+             if (vi->is_artificial_var)
+               {
+                 /* FIXME.  READONLY should be handled better so that
+                    flow insensitive aliasing can disregard writeable
+                    aliases.  */
+                 if (vi->id == nothing_id)
+                   pi->pt_null = 1;
+                 else if (vi->id == anything_id)
+                   pi->pt_anything = 1;
+                 else if (vi->id == readonly_id)
+                   pi->pt_anything = 1;
+                 else if (vi->id == integer_id)
+                   pi->pt_anything = 1;
+                 else if (vi->is_heap_var)
+                   pi->pt_global_mem = 1;
+               }
            }
-         pi->pt_anything = false;
+
+         if (pi->pt_anything)
+           return false;
+
          if (!pi->pt_vars)
            pi->pt_vars = BITMAP_GGC_ALLOC ();
+
          set_uids_in_ptset (pi->pt_vars, vi->solution);
+
+         if (bitmap_empty_p (pi->pt_vars))
+           pi->pt_vars = NULL;
+
          return true;
        }
     }
+
   return false;
 }
 
+
 /* Initialize things necessary to perform PTA */
 
 static void
@@ -2969,27 +3310,42 @@ init_alias_vars (void)
   bitmap_obstack_initialize (&ptabitmap_obstack);
 }
 
-/* Dump the points-to information to OUTFILE.  */
 
-static void
+/* Dump points-to information to OUTFILE.  */
+
+void
 dump_sa_points_to_info (FILE *outfile)
 {
-  
   unsigned int i;
+
+  fprintf (outfile, "\nPoints-to sets\n\n");
+
   if (dump_flags & TDF_STATS)
     {
       fprintf (outfile, "Stats:\n");
-      fprintf (outfile, "Total vars:%d\n", stats.total_vars);
-      fprintf (outfile, "Statically unified vars:%d\n", stats.unified_vars_static);
-      fprintf (outfile, "Collapsed vars:%d\n", stats.collapsed_vars);
-      fprintf (outfile, "Dynamically unified vars:%d\n", stats.unified_vars_dynamic);
-      fprintf (outfile, "Iterations:%d\n", stats.iterations);
+      fprintf (outfile, "Total vars:               %d\n", stats.total_vars);
+      fprintf (outfile, "Statically unified vars:  %d\n",
+              stats.unified_vars_static);
+      fprintf (outfile, "Collapsed vars:           %d\n", stats.collapsed_vars);
+      fprintf (outfile, "Dynamically unified vars: %d\n",
+              stats.unified_vars_dynamic);
+      fprintf (outfile, "Iterations:               %d\n", stats.iterations);
     }
+
   for (i = 0; i < VEC_length (varinfo_t, varmap); i++)
     dump_solution_for_var (outfile, i);
 }
 
 
+/* Debug points-to information to stderr.  */
+
+void
+debug_sa_points_to_info (void)
+{
+  dump_sa_points_to_info (stderr);
+}
+
+
 /* Initialize the always-existing constraint variables for NULL
    ANYTHING, READONLY, and INTEGER */
 
@@ -3008,7 +3364,7 @@ init_base_vars (void)
   var_nothing->size = ~0;
   var_nothing->fullsize = ~0;
   nothing_id = 0;
-  VEC_safe_push (varinfo_t, gc, varmap, var_nothing);
+  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.  */
@@ -3025,7 +3381,7 @@ init_base_vars (void)
   /* Anything points to anything.  This makes deref constraints just
      work in the presence of linked list and other p = *p type loops, 
      by saying that *ANYTHING = ANYTHING. */
-  VEC_safe_push (varinfo_t, gc, varmap, var_anything);
+  VEC_safe_push (varinfo_t, heap, varmap, var_anything);
   lhs.type = SCALAR;
   lhs.var = anything_id;
   lhs.offset = 0;
@@ -3033,8 +3389,11 @@ init_base_vars (void)
   rhs.var = anything_id;
   rhs.offset = 0;
   var_anything->address_taken = true;
-  process_constraint (new_constraint (lhs, rhs));
 
+  /* This specifically does not use process_constraint because
+     process_constraint ignores all anything = anything constraints, since all
+     but this one are redundant.  */
+  VEC_safe_push (constraint_t, heap, constraints, new_constraint (lhs, rhs));
   
   /* Create the READONLY variable, used to represent that a variable
      points to readonly memory.  */
@@ -3047,7 +3406,7 @@ init_base_vars (void)
   var_readonly->next = NULL;
   insert_id_for_tree (readonly_tree, 2);
   readonly_id = 2;
-  VEC_safe_push (varinfo_t, gc, varmap, var_readonly);
+  VEC_safe_push (varinfo_t, heap, varmap, var_readonly);
 
   /* readonly memory points to anything, in order to make deref
      easier.  In reality, it points to anything the particular
@@ -3059,7 +3418,6 @@ init_base_vars (void)
   rhs.type = ADDRESSOF;
   rhs.var = anything_id;
   rhs.offset = 0;
-  var_readonly->address_taken = true;
   
   process_constraint (new_constraint (lhs, rhs));
   
@@ -3074,19 +3432,55 @@ init_base_vars (void)
   var_integer->offset = 0;
   var_integer->next = NULL;
   integer_id = 3;
-  VEC_safe_push (varinfo_t, gc, varmap, var_integer);
+  VEC_safe_push (varinfo_t, heap, varmap, var_integer);
+
+  /* *INTEGER = ANYTHING, because we don't know where a dereference of a random
+     integer will point to.  */
+  lhs.type = SCALAR;
+  lhs.var = integer_id;
+  lhs.offset = 0;
+  rhs.type = ADDRESSOF;
+  rhs.var = anything_id;
+  rhs.offset = 0;
+  process_constraint (new_constraint (lhs, rhs));
+
+  /* Create the ANYOFFSET variable, used to represent an arbitrary offset
+     inside an object.  This is similar to ANYTHING, but less drastic.
+     It means that the pointer can point anywhere inside an object,
+     but not outside of it.  */
+  anyoffset_tree = create_tmp_var_raw (void_type_node, "ANYOFFSET");
+  anyoffset_id = 4;
+  var_anyoffset = new_var_info (anyoffset_tree, anyoffset_id, "ANYOFFSET",
+                                anyoffset_id); 
+  insert_id_for_tree (anyoffset_tree, anyoffset_id);
+  var_anyoffset->is_artificial_var = 1;
+  var_anyoffset->size = ~0;
+  var_anyoffset->offset = 0;
+  var_anyoffset->next = NULL;
+  var_anyoffset->fullsize = ~0;
+  VEC_safe_push (varinfo_t, heap, varmap, var_anyoffset);
+
+  /* ANYOFFSET points to ANYOFFSET.  */
+  lhs.type = SCALAR;
+  lhs.var = anyoffset_id;
+  lhs.offset = 0;
+  rhs.type = ADDRESSOF;
+  rhs.var = anyoffset_id;
+  rhs.offset = 0;
+  process_constraint (new_constraint (lhs, rhs));
 }  
 
 
 /* Create points-to sets for the current function.  See the comments
    at the start of the file for an algorithmic overview.  */
 
-static void
-create_alias_vars (void)
+void
+compute_points_to_sets (struct alias_info *ai)
 {
   basic_block bb;
 
-  
+  timevar_push (TV_TREE_PTA);
+
   init_alias_vars ();
 
   constraint_pool = create_alloc_pool ("Constraint pool", 
@@ -3096,11 +3490,11 @@ create_alias_vars (void)
   constraint_edge_pool = create_alloc_pool ("Constraint edges",
                                            sizeof (struct constraint_edge), 30);
   
-  constraints = VEC_alloc (constraint_t, gc, 8);
-  varmap = VEC_alloc (varinfo_t, gc, 8);
+  constraints = VEC_alloc (constraint_t, heap, 8);
+  varmap = VEC_alloc (varinfo_t, heap, 8);
   id_for_tree = htab_create (10, tree_id_hash, tree_id_eq, free);
   memset (&stats, 0, sizeof (stats));
-  
+
   init_base_vars ();
 
   intra_create_variable_infos ();
@@ -3113,28 +3507,29 @@ create_alias_vars (void)
 
       for (phi = phi_nodes (bb); phi; phi = TREE_CHAIN (phi))
        if (is_gimple_reg (PHI_RESULT (phi)))
-         find_func_aliases (phi);
+         find_func_aliases (phi, ai);
 
       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       find_func_aliases (bsi_stmt (bsi));
+       find_func_aliases (bsi_stmt (bsi), ai);
     }
 
   build_constraint_graph ();
 
   if (dump_file)
     {
-      fprintf (dump_file, "Constraints:\n");
+      fprintf (dump_file, "Points-to analysis\n\nConstraints:\n\n");
       dump_constraints (dump_file);
     }
 
   if (dump_file)
-    fprintf (dump_file, "Collapsing static cycles and doing variable substitution:\n");
+    fprintf (dump_file, "\nCollapsing static cycles and doing variable "
+                       "substitution:\n");
 
   find_and_collapse_graph_cycles (graph, false);
   perform_var_substitution (graph);
 
   if (dump_file)
-    fprintf (dump_file, "Solving graph:\n");
+    fprintf (dump_file, "\nSolving graph:\n");
 
   solve_graph (graph);
 
@@ -3142,52 +3537,37 @@ create_alias_vars (void)
     dump_sa_points_to_info (dump_file);
   
   have_alias_info = true;
+
+  timevar_pop (TV_TREE_PTA);
 }
 
-struct tree_opt_pass pass_build_pta = 
-{
-  "pta",                               /* name */
-  NULL,                                        /* gate */
-  create_alias_vars,                   /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_TREE_PTA,                         /* tv_id */
-  PROP_cfg,                            /* properties_required */
-  PROP_pta,                            /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                    /* letter */
-};
 
 /* Delete created points-to sets.  */
 
-static void
-delete_alias_vars (void)
+void
+delete_points_to_sets (void)
 {
+  varinfo_t v;
+  int i;
+
   htab_delete (id_for_tree);
+  bitmap_obstack_release (&ptabitmap_obstack);
+  VEC_free (constraint_t, heap, constraints);
+  
+  for (i = 0; VEC_iterate (varinfo_t, varmap, i, v); i++)
+    {
+      VEC_free (constraint_edge_t, heap, graph->succs[i]);
+      VEC_free (constraint_edge_t, heap, graph->preds[i]);
+      VEC_free (constraint_t, heap, v->complex);
+    }
+  free (graph->succs);
+  free (graph->preds);
+  free (graph);
+
+  VEC_free (varinfo_t, heap, varmap);
   free_alloc_pool (variable_info_pool);
   free_alloc_pool (constraint_pool); 
   free_alloc_pool (constraint_edge_pool);
-  bitmap_obstack_release (&ptabitmap_obstack);
+
   have_alias_info = false;
 }
-
-struct tree_opt_pass pass_del_pta = 
-{
-  NULL,                                 /* name */
-  NULL,                                        /* gate */
-  delete_alias_vars,                   /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_TREE_PTA,                         /* tv_id */
-  PROP_pta,                            /* properties_required */
-  0,                                   /* properties_provided */
-  PROP_pta,                            /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  0,                                    /* todo_flags_finish */
-  0                                    /* letter */
-};