OSDN Git Service

* inclhack.def: Avoid changing NULL on C++ friendly systems.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-alias.c
index a344384..9dab4c6 100644 (file)
@@ -39,7 +39,6 @@ Boston, MA 02111-1307, USA.  */
 #include "tree-gimple.h"
 #include "tree-flow.h"
 #include "tree-inline.h"
-#include "tree-alias-common.h"
 #include "tree-pass.h"
 #include "convert.h"
 #include "params.h"
@@ -125,8 +124,6 @@ struct alias_stats_d
   unsigned int simple_resolved;
   unsigned int tbaa_queries;
   unsigned int tbaa_resolved;
-  unsigned int pta_queries;
-  unsigned int pta_resolved;
 };
 
 
@@ -150,7 +147,6 @@ static void setup_pointers_and_addressables (struct alias_info *);
 static bool collect_points_to_info_r (tree, tree, void *);
 static bool is_escape_site (tree, size_t *);
 static void add_pointed_to_var (struct alias_info *, tree, tree);
-static void add_pointed_to_expr (tree, tree);
 static void create_global_var (void);
 static void collect_points_to_info_for (struct alias_info *, tree);
 static bool ptr_is_dereferenced_by (tree, tree, bool *);
@@ -354,12 +350,13 @@ struct tree_opt_pass pass_may_alias =
   NULL,                                        /* next */
   0,                                   /* static_pass_number */
   TV_TREE_MAY_ALIAS,                   /* tv_id */
-  PROP_cfg | PROP_ssa | PROP_pta,      /* properties_required */
+  PROP_cfg | PROP_ssa,                 /* properties_required */
   PROP_alias,                          /* properties_provided */
   0,                                   /* properties_destroyed */
   0,                                   /* todo_flags_start */
   TODO_dump_func | TODO_rename_vars
-    | TODO_ggc_collect | TODO_verify_ssa  /* todo_flags_finish */
+    | TODO_ggc_collect | TODO_verify_ssa,  /* todo_flags_finish */
+  0                                    /* letter */
 };
 
 
@@ -384,10 +381,11 @@ init_alias_info (void)
   if (aliases_computed_p)
     {
       size_t i;
+      bitmap_iterator bi;
 
       /* Clear the call-clobbered set.  We are going to re-discover
          call-clobbered variables.  */
-      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
+      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
        {
          tree var = referenced_var (i);
 
@@ -396,7 +394,7 @@ init_alias_info (void)
             code, so we can't remove them from CALL_CLOBBERED_VARS.  */
          if (!is_call_clobbered (var))
            bitmap_clear_bit (call_clobbered_vars, var_ann (var)->uid);
-       });
+       }
 
       /* Similarly, clear the set of addressable variables.  In this
         case, we can just clear the set because addressability is
@@ -416,7 +414,7 @@ init_alias_info (void)
        {
          tree name = ssa_name (i);
 
-         if (!POINTER_TYPE_P (TREE_TYPE (name)))
+         if (!name || !POINTER_TYPE_P (TREE_TYPE (name)))
            continue;
 
          if (SSA_NAME_PTR_INFO (name))
@@ -485,10 +483,7 @@ delete_alias_info (struct alias_info *ai)
 static void
 collect_points_to_info_for (struct alias_info *ai, tree ptr)
 {
-#if defined ENABLE_CHECKING
-  if (!POINTER_TYPE_P (TREE_TYPE (ptr)))
-    abort ();
-#endif
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
 
   if (!bitmap_bit_p (ai->ssa_names_visited, SSA_NAME_VERSION (ptr)))
     {
@@ -500,14 +495,14 @@ collect_points_to_info_for (struct alias_info *ai, tree ptr)
 
 
 /* Helper for ptr_is_dereferenced_by.  Called by walk_tree to look for
-   INDIRECT_REF nodes for the pointer passed in DATA.  */
+   (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA.  */
 
 static tree
 find_ptr_dereference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
 {
   tree ptr = (tree) data;
 
-  if (TREE_CODE (*tp) == INDIRECT_REF
+  if (INDIRECT_REF_P (*tp)
       && TREE_OPERAND (*tp, 0) == ptr)
     return *tp;
 
@@ -515,8 +510,9 @@ find_ptr_dereference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
 }
 
 
-/* Return true if STMT contains INDIRECT_REF <PTR>.  *IS_STORE is set
-   to 'true' if the dereference is on the LHS of an assignment.  */
+/* Return true if STMT contains (ALIGN/MISALIGNED_)INDIRECT_REF <PTR>.  
+   *IS_STORE is set to 'true' if the dereference is on the LHS of an 
+   assignment.  */
 
 static bool
 ptr_is_dereferenced_by (tree ptr, tree stmt, bool *is_store)
@@ -576,6 +572,8 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
 {
   basic_block bb;
   size_t i;
+  tree op;
+  ssa_op_iter iter;
 
   timevar_push (TV_TREE_PTA);
 
@@ -586,14 +584,10 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
 
       for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
        {
-         use_optype uses;
-         def_optype defs;
-         v_may_def_optype v_may_defs;
-         v_must_def_optype v_must_defs;
-         stmt_ann_t ann;
          bitmap addr_taken;
          tree stmt = bsi_stmt (si);
          bool stmt_escapes_p = is_escape_site (stmt, &ai->num_calls_found);
+         bitmap_iterator bi;
 
          /* Mark all the variables whose address are taken by the
             statement.  Note that this will miss all the addresses taken
@@ -602,13 +596,13 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
          get_stmt_operands (stmt);
          addr_taken = addresses_taken (stmt);
          if (addr_taken)
-           EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i,
-               {
-                 tree var = referenced_var (i);
-                 bitmap_set_bit (ai->addresses_needed, var_ann (var)->uid);
-                 if (stmt_escapes_p)
-                   mark_call_clobbered (var);
-               });
+           EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
+             {
+               tree var = referenced_var (i);
+               bitmap_set_bit (ai->addresses_needed, var_ann (var)->uid);
+               if (stmt_escapes_p)
+                 mark_call_clobbered (var);
+             }
 
          if (stmt_escapes_p)
            block_ann->has_escape_site = 1;
@@ -623,17 +617,14 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
          if (addr_taken
              && TREE_CODE (stmt) == MODIFY_EXPR
              && !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 0))))
-           EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i,
-               {
-                 tree var = referenced_var (i);
-                 mark_call_clobbered (var);
-               });
+           EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
+             {
+               tree var = referenced_var (i);
+               mark_call_clobbered (var);
+             }
 
-         ann = stmt_ann (stmt);
-         uses = USE_OPS (ann);
-         for (i = 0; i < NUM_USES (uses); i++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
            {
-             tree op = USE_OP (uses, i);
              var_ann_t v_ann = var_ann (SSA_NAME_VAR (op));
              struct ptr_info_def *pi;
              bool is_store;
@@ -653,16 +644,14 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
 
              collect_points_to_info_for (ai, op);
 
-             pi =  SSA_NAME_PTR_INFO (op);
+             pi = SSA_NAME_PTR_INFO (op);
              if (ptr_is_dereferenced_by (op, stmt, &is_store))
                {
-                 /* If we found OP to point to a set of variables or
-                    malloc, then mark it as being 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.  */
-                 if (pi->pt_malloc || pi->pt_vars)
-                   pi->is_dereferenced = 1;
+                 /* 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.  Again, we don't need to grow
@@ -700,37 +689,26 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
          /* Update reference counter for definitions to any
             potentially aliased variable.  This is used in the alias
             grouping heuristics.  */
-         defs = DEF_OPS (ann);
-         for (i = 0; i < NUM_DEFS (defs); i++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
            {
-             tree op = DEF_OP (defs, i);
              tree var = SSA_NAME_VAR (op);
              var_ann_t ann = var_ann (var);
              bitmap_set_bit (ai->written_vars, ann->uid);
              if (may_be_aliased (var))
                (VARRAY_UINT (ai->num_references, ann->uid))++;
+
+             if (POINTER_TYPE_P (TREE_TYPE (op)))
+               collect_points_to_info_for (ai, op);
            }
 
          /* Mark variables in V_MAY_DEF operands as being written to.  */
-         v_may_defs = V_MAY_DEF_OPS (ann);
-         for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
            {
-             tree op = V_MAY_DEF_OP (v_may_defs, i);
              tree var = SSA_NAME_VAR (op);
              var_ann_t ann = var_ann (var);
              bitmap_set_bit (ai->written_vars, ann->uid);
            }
            
-         /* Mark variables in V_MUST_DEF operands as being written to.  */
-         v_must_defs = V_MUST_DEF_OPS (ann);
-         for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
-           {
-             tree op = V_MUST_DEF_OP (v_must_defs, i);
-             tree var = SSA_NAME_VAR (op);
-             var_ann_t ann = var_ann (var);
-             bitmap_set_bit (ai->written_vars, ann->uid);
-           }
-
          /* 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
@@ -762,15 +740,16 @@ create_name_tags (struct alias_info *ai)
       tree ptr = VARRAY_TREE (ai->processed_ptrs, i);
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
 
-      if (!pi->is_dereferenced)
+      if (pi->pt_anything || !pi->is_dereferenced)
        {
          /* No name tags for pointers that have not been
-            dereferenced.  */
+            dereferenced or point to an arbitrary location.  */
          pi->name_mem_tag = NULL_TREE;
          continue;
        }
 
-      if (pi->pt_vars)
+      if (pi->pt_vars
+         && bitmap_first_set_bit (pi->pt_vars) >= 0)
        {
          size_t j;
          tree old_name_tag = pi->name_mem_tag;
@@ -827,6 +806,9 @@ create_name_tags (struct alias_info *ai)
          continue;
        }
 
+      TREE_THIS_VOLATILE (pi->name_mem_tag)
+         |= TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
+
       /* Mark the new name tag for renaming.  */
       bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
     }
@@ -855,52 +837,33 @@ compute_flow_sensitive_aliasing (struct alias_info *ai)
       tree ptr = VARRAY_TREE (ai->processed_ptrs, i);
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
       var_ann_t v_ann = var_ann (SSA_NAME_VAR (ptr));
+      bitmap_iterator bi;
 
       if (pi->value_escapes_p || pi->pt_anything)
        {
          /* If PTR escapes or may point to anything, then its associated
-            memory tags are call-clobbered.  */
+            memory tags and pointed-to variables are call-clobbered.  */
          if (pi->name_mem_tag)
            mark_call_clobbered (pi->name_mem_tag);
 
          if (v_ann->type_mem_tag)
            mark_call_clobbered (v_ann->type_mem_tag);
 
-         /* If PTR may point to anything, mark call-clobbered all the
-            addressables with the same alias set as the type pointed-to by
-            PTR.  */
-         if (pi->pt_anything)
-           {
-             HOST_WIDE_INT ptr_set;
-             ptr_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
-             for (j = 0; j < ai->num_addressable_vars; j++)
-               {
-                 struct alias_map_d *alias_map = ai->addressable_vars[j];
-                 if (alias_map->set == ptr_set)
-                   mark_call_clobbered (alias_map->var);
-               }
-           }
-
-         /* If PTR's value may escape and PTR is never dereferenced, we
-            need to mark all the variables PTR points-to as
-            call-clobbered.  Note that we only need do this it PTR is
-            never dereferenced.  If PTR is dereferenced, it will have a
-            name memory tag, which will have been marked call-clobbered.
-            This will in turn mark the pointed-to variables as
-            call-clobbered when we call add_may_alias below.  */
-         if (pi->value_escapes_p
-             && pi->name_mem_tag == NULL_TREE
-             && pi->pt_vars)
-           EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j,
-               mark_call_clobbered (referenced_var (j)));
+         if (pi->pt_vars)
+           EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j, bi)
+             {
+               mark_call_clobbered (referenced_var (j));
+             }
        }
 
       /* Set up aliasing information for PTR's name memory tag (if it has
         one).  Note that only pointers that have been dereferenced will
         have a name memory tag.  */
       if (pi->name_mem_tag && pi->pt_vars)
-       EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j,
-           add_may_alias (pi->name_mem_tag, referenced_var (j)));
+       EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j, bi)
+         {
+           add_may_alias (pi->name_mem_tag, referenced_var (j));
+         }
 
       /* If the name tag is call clobbered, so is the type tag
         associated with the base VAR_DECL.  */
@@ -925,6 +888,7 @@ static void
 compute_flow_insensitive_aliasing (struct alias_info *ai)
 {
   size_t i;
+  sbitmap res;
 
   /* Initialize counter for the total number of virtual operands that
      aliasing will introduce.  When AI->TOTAL_ALIAS_VOPS goes beyond the
@@ -993,6 +957,72 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
        }
     }
 
+  /* Since this analysis is based exclusively on symbols, it fails to
+     handle cases where two pointers P and Q have different memory
+     tags with conflicting alias set numbers but no aliased symbols in
+     common.
+
+     For example, suppose that we have two memory tags TMT.1 and TMT.2
+     such that
+     
+               may-aliases (TMT.1) = { a }
+               may-aliases (TMT.2) = { b }
+
+     and the alias set number of TMT.1 conflicts with that of TMT.2.
+     Since they don't have symbols in common, loads and stores from
+     TMT.1 and TMT.2 will seem independent of each other, which will
+     lead to the optimizers making invalid transformations (see
+     testsuite/gcc.c-torture/execute/pr15262-[12].c).
+
+     To avoid this problem, we do a final traversal of AI->POINTERS
+     looking for pairs of pointers that have no aliased symbols in
+     common and yet have conflicting alias set numbers.  */
+  res = sbitmap_alloc (num_referenced_vars);
+
+  for (i = 0; i < ai->num_pointers; i++)
+    {
+      size_t j;
+      struct alias_map_d *p_map1 = ai->pointers[i];
+      tree tag1 = var_ann (p_map1->var)->type_mem_tag;
+      sbitmap may_aliases1 = p_map1->may_aliases;
+
+      for (j = i + 1; j < ai->num_pointers; j++)
+       {
+         struct alias_map_d *p_map2 = ai->pointers[j];
+         tree tag2 = var_ann (p_map2->var)->type_mem_tag;
+         sbitmap may_aliases2 = p_map2->may_aliases;
+
+         /* If the pointers may not point to each other, do nothing.  */
+         if (!may_alias_p (p_map1->var, p_map1->set, p_map2->var, p_map2->set))
+           continue;
+
+         /* The two pointers may alias each other.  If they already have
+            symbols in common, do nothing.  */
+         sbitmap_a_and_b (res, may_aliases1, may_aliases2);
+         if (sbitmap_first_set_bit (res) >= 0)
+           continue;
+
+         if (sbitmap_first_set_bit (may_aliases2) >= 0)
+           {
+             size_t k;
+
+             /* Add all the aliases for TAG2 into TAG1's alias set.
+                FIXME, update grouping heuristic counters.  */
+             EXECUTE_IF_SET_IN_SBITMAP (may_aliases2, 0, k,
+                 add_may_alias (tag1, referenced_var (k)));
+             sbitmap_a_or_b (may_aliases1, may_aliases1, may_aliases2);
+           }
+         else
+           {
+             /* Since TAG2 does not have any aliases of its own, add
+                TAG2 itself to the alias set of TAG1.  */
+             add_may_alias (tag1, tag2);
+           }
+       }
+    }
+
+  sbitmap_free (res);
+
   if (dump_file)
     fprintf (dump_file, "%s: Total number of aliased vops: %ld\n",
             get_name (current_function_decl),
@@ -1226,10 +1256,8 @@ group_aliases (struct alias_info *ai)
            {
              tree new_alias;
 
-#if defined ENABLE_CHECKING
-             if (VARRAY_ACTIVE_SIZE (ann->may_aliases) != 1)
-               abort ();
-#endif
+             gcc_assert (VARRAY_ACTIVE_SIZE (ann->may_aliases) == 1);
+
              new_alias = VARRAY_TREE (ann->may_aliases, 0);
              replace_may_alias (name_tag, j, new_alias);
            }
@@ -1314,8 +1342,9 @@ setup_pointers_and_addressables (struct alias_info *ai)
 
       /* Name memory tags already have flow-sensitive aliasing
         information, so they need not be processed by
-        compute_may_aliases.  Similarly, type memory tags are already
-        accounted for when we process their associated pointer.  */
+        compute_flow_insensitive_aliasing.  Similarly, type memory
+        tags are already accounted for when we process their
+        associated pointer.  */
       if (v_ann->mem_tag_kind != NOT_A_TAG)
        continue;
 
@@ -1328,6 +1357,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
        {
          if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid)
              && v_ann->mem_tag_kind == NOT_A_TAG
+             && TREE_CODE (var) != RESULT_DECL
              && !is_global_var (var))
            {
              /* The address of VAR is not needed, remove the
@@ -1419,41 +1449,6 @@ setup_pointers_and_addressables (struct alias_info *ai)
            }
        }
     }
-
-  /* If we found no addressable variables, but we have more than one
-     pointer, we will need to check for conflicts between the
-     pointers.  Otherwise, we would miss alias relations as in
-     testsuite/gcc.dg/tree-ssa/20040319-1.c:
-
-               struct bar { int count;  int *arr;};
-
-               void foo (struct bar *b)
-               {
-                 b->count = 0;
-                 *(b->arr) = 2;
-                 if (b->count == 0)
-                   abort ();
-               }
-
-     b->count and *(b->arr) could be aliased if b->arr == &b->count.
-     To do this, we add all the memory tags for the pointers in
-     AI->POINTERS to AI->ADDRESSABLE_VARS, so that
-     compute_flow_insensitive_aliasing will naturally compare every
-     pointer to every type tag.  */
-  if (ai->num_addressable_vars == 0
-      && ai->num_pointers > 1)
-    {
-      free (ai->addressable_vars);
-      ai->addressable_vars = xcalloc (ai->num_pointers,
-                                     sizeof (struct alias_map_d *));
-      ai->num_addressable_vars = 0;
-      for (i = 0; i < ai->num_pointers; i++)
-       {
-         struct alias_map_d *p = ai->pointers[i];
-         tree tag = var_ann (p->var)->type_mem_tag;
-         create_alias_map_for (tag, ai);
-       }
-    }
 }
 
 
@@ -1488,13 +1483,17 @@ static void
 maybe_create_global_var (struct alias_info *ai)
 {
   size_t i, n_clobbered;
+  bitmap_iterator bi;
   
   /* No need to create it, if we have one already.  */
   if (global_var == NULL_TREE)
     {
       /* Count all the call-clobbered variables.  */
       n_clobbered = 0;
-      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, n_clobbered++);
+      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
+       {
+         n_clobbered++;
+       }
 
       /* Create .GLOBAL_VAR if we have too many call-clobbered
         variables.  We also create .GLOBAL_VAR when there no
@@ -1522,7 +1521,7 @@ maybe_create_global_var (struct alias_info *ai)
   /* If the function has calls to clobbering functions and .GLOBAL_VAR has
      been created, make it an alias for all call-clobbered variables.  */
   if (global_var)
-    EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
+    EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
       {
        tree var = referenced_var (i);
        if (var != global_var)
@@ -1530,7 +1529,7 @@ maybe_create_global_var (struct alias_info *ai)
             add_may_alias (var, global_var);
             bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
          }
-      });
+      }
 }
 
 
@@ -1565,10 +1564,7 @@ may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
   v_ann = var_ann (var);
   m_ann = var_ann (mem);
 
-#if defined ENABLE_CHECKING
-  if (m_ann->mem_tag_kind != TYPE_TAG)
-    abort ();
-#endif
+  gcc_assert (m_ann->mem_tag_kind == TYPE_TAG);
 
   alias_stats.tbaa_queries++;
 
@@ -1577,7 +1573,8 @@ may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
      for PTR's alias set here, not its pointed-to type.  We also can't
      do this check with relaxed aliasing enabled.  */
   if (POINTER_TYPE_P (TREE_TYPE (var))
-      && var_alias_set != 0)
+      && var_alias_set != 0
+      && mem_alias_set != 0)
     {
       HOST_WIDE_INT ptr_alias_set = get_alias_set (ptr);
       if (ptr_alias_set == var_alias_set)
@@ -1591,69 +1588,8 @@ may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
   /* If the alias sets don't conflict then MEM cannot alias VAR.  */
   if (!alias_sets_conflict_p (mem_alias_set, var_alias_set))
     {
-      /* Handle aliases to structure fields.  If either VAR or MEM are
-        aggregate types, they may not have conflicting types, but one of
-        the structures could contain a pointer to the other one.
-
-        For instance, given
-
-               MEM -> struct P *p;
-               VAR -> struct Q *q;
-
-        It may happen that '*p' and '*q' can't alias because 'struct P'
-        and 'struct Q' have non-conflicting alias sets.  However, it could
-        happen that one of the fields in 'struct P' is a 'struct Q *' or
-        vice-versa.
-
-        Therefore, we also need to check if 'struct P' aliases 'struct Q *'
-        or 'struct Q' aliases 'struct P *'.  Notice, that since GIMPLE
-        does not have more than one-level pointers, we don't need to
-        recurse into the structures.  */
-      if (AGGREGATE_TYPE_P (TREE_TYPE (mem))
-         || AGGREGATE_TYPE_P (TREE_TYPE (var)))
-       {
-         tree ptr_to_var;
-         
-         if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
-           ptr_to_var = TYPE_POINTER_TO (TREE_TYPE (TREE_TYPE (var)));
-         else
-           ptr_to_var = TYPE_POINTER_TO (TREE_TYPE (var));
-
-         /* If no pointer-to VAR exists, then MEM can't alias VAR.  */
-         if (ptr_to_var == NULL_TREE)
-           {
-             alias_stats.alias_noalias++;
-             alias_stats.tbaa_resolved++;
-             return false;
-           }
-
-         /* If MEM doesn't alias a pointer to VAR and VAR doesn't alias
-            PTR, then PTR can't alias VAR.  */
-         if (!alias_sets_conflict_p (mem_alias_set, get_alias_set (ptr_to_var))
-             && !alias_sets_conflict_p (var_alias_set, get_alias_set (ptr)))
-           {
-             alias_stats.alias_noalias++;
-             alias_stats.tbaa_resolved++;
-             return false;
-           }
-       }
-      else
-       {
-         alias_stats.alias_noalias++;
-         alias_stats.tbaa_resolved++;
-         return false;
-       }
-    }
-
-  if (flag_tree_points_to != PTA_NONE)
-      alias_stats.pta_queries++;
-
-  /* If -ftree-points-to is given, check if PTR may point to VAR.  */
-  if (flag_tree_points_to == PTA_ANDERSEN
-      && !ptr_may_alias_var (ptr, var))
-    {
       alias_stats.alias_noalias++;
-      alias_stats.pta_resolved++;
+      alias_stats.tbaa_resolved++;
       return false;
     }
 
@@ -1671,10 +1607,7 @@ add_may_alias (tree var, tree alias)
   var_ann_t v_ann = get_var_ann (var);
   var_ann_t a_ann = get_var_ann (alias);
 
-#if defined ENABLE_CHECKING
-  if (var == alias)
-    abort ();
-#endif
+  gcc_assert (var != alias);
 
   if (v_ann->may_aliases == NULL)
     VARRAY_TREE_INIT (v_ann->may_aliases, 2, "aliases");
@@ -1684,7 +1617,9 @@ add_may_alias (tree var, tree alias)
     if (alias == VARRAY_TREE (v_ann->may_aliases, i))
       return;
 
-  /* If VAR is a call-clobbered variable, so is its new ALIAS.  */
+  /* If VAR is a call-clobbered variable, so is its new ALIAS.
+     FIXME, call-clobbering should only depend on whether an address
+     escapes.  It should be independent of aliasing.  */
   if (is_call_clobbered (var))
     mark_call_clobbered (alias);
 
@@ -1705,7 +1640,9 @@ replace_may_alias (tree var, size_t i, tree new_alias)
   var_ann_t v_ann = var_ann (var);
   VARRAY_TREE (v_ann->may_aliases, i) = new_alias;
 
-  /* If VAR is a call-clobbered variable, so is NEW_ALIAS.  */
+  /* If VAR is a call-clobbered variable, so is NEW_ALIAS.
+     FIXME, call-clobbering should only depend on whether an address
+     escapes.  It should be independent of aliasing.  */
   if (is_call_clobbered (var))
     mark_call_clobbered (new_alias);
 
@@ -1724,8 +1661,6 @@ set_pt_anything (tree ptr)
 
   pi->pt_anything = 1;
   pi->pt_malloc = 0;
-  pi->pt_vars = NULL;
-  pi->is_dereferenced = 0;
 
   /* The pointer used to have a name tag, but we now found it pointing
      to an arbitrary location.  The name tag needs to be renamed and
@@ -1746,7 +1681,7 @@ set_pt_malloc (tree ptr)
   struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
 
   /* If the pointer has already been found to point to arbitrary
-     memory locations, it is unsafe to mark it as pointing to malloc. */
+     memory locations, it is unsafe to mark it as pointing to malloc.  */
   if (pi->pt_anything)
     return;
 
@@ -1812,47 +1747,83 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
                           orig_pi->pt_vars);
        }
     }
+  else
+    set_pt_anything (dest);
 }
 
 
-/* Add VALUE to the list of expressions pointed-to by PTR.  */
+/* Add EXPR to the list of expressions pointed-to by PTR.  */
 
 static void
-add_pointed_to_expr (tree ptr, tree value)
+add_pointed_to_expr (struct alias_info *ai, tree ptr, tree expr)
 {
-  if (TREE_CODE (value) == WITH_SIZE_EXPR)
-    value = TREE_OPERAND (value, 0);
-
-#if defined ENABLE_CHECKING
-  /* Pointer variables should have been handled by merge_pointed_to_info.  */
-  if (TREE_CODE (value) == SSA_NAME
-      && POINTER_TYPE_P (TREE_TYPE (value)))
-    abort ();
-#endif
+  if (TREE_CODE (expr) == WITH_SIZE_EXPR)
+    expr = TREE_OPERAND (expr, 0);
 
   get_ptr_info (ptr);
 
-  /* If VALUE is the result of a malloc-like call, then the area pointed to
-     PTR is guaranteed to not alias with anything else.  */
-  if (TREE_CODE (value) == CALL_EXPR
-      && (call_expr_flags (value) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
-    set_pt_malloc (ptr);
-  else
-    set_pt_anything (ptr);
-
-  if (dump_file)
+  if (TREE_CODE (expr) == CALL_EXPR
+      && (call_expr_flags (expr) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
     {
-      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+      /* If EXPR is a malloc-like call, then the area pointed to PTR
+        is guaranteed to not alias with anything else.  */
+      set_pt_malloc (ptr);
+    }
+  else if (TREE_CODE (expr) == ADDR_EXPR)
+    {
+      /* Found P_i = ADDR_EXPR  */
+      add_pointed_to_var (ai, ptr, expr);
+    }
+  else if (TREE_CODE (expr) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (expr)))
+    {
+      /* Found P_i = Q_j.  */
+      merge_pointed_to_info (ai, ptr, expr);
+    }
+  else if (TREE_CODE (expr) == PLUS_EXPR || TREE_CODE (expr) == MINUS_EXPR)
+    {
+      /* Found P_i = PLUS_EXPR or P_i = MINUS_EXPR  */
+      tree op0 = TREE_OPERAND (expr, 0);
+      tree op1 = TREE_OPERAND (expr, 1);
 
-      fprintf (dump_file, "Pointer ");
-      print_generic_expr (dump_file, ptr, dump_flags);
-      fprintf (dump_file, " points to ");
-      if (pi->pt_malloc)
-       fprintf (dump_file, "malloc space: ");
-      else
-       fprintf (dump_file, "an arbitrary address: ");
-      print_generic_expr (dump_file, value, dump_flags);
-      fprintf (dump_file, "\n");
+      /* Both operands may be of pointer type.  FIXME: Shouldn't
+        we just expect PTR + OFFSET always?  */
+      if (POINTER_TYPE_P (TREE_TYPE (op0))
+         && TREE_CODE (op0) != INTEGER_CST)
+       {
+         if (TREE_CODE (op0) == SSA_NAME)
+           merge_pointed_to_info (ai, ptr, op0);
+         else if (TREE_CODE (op0) == ADDR_EXPR)
+           add_pointed_to_var (ai, ptr, op0);
+         else
+           set_pt_anything (ptr);
+       }
+
+      if (POINTER_TYPE_P (TREE_TYPE (op1))
+         && TREE_CODE (op1) != INTEGER_CST)
+       {
+         if (TREE_CODE (op1) == SSA_NAME)
+           merge_pointed_to_info (ai, ptr, op1);
+         else if (TREE_CODE (op1) == ADDR_EXPR)
+           add_pointed_to_var (ai, ptr, op1);
+         else
+           set_pt_anything (ptr);
+       }
+
+      /* Neither operand is a pointer?  VAR can be pointing anywhere.
+        FIXME: Shouldn't we abort here?  If we get here, we found
+        PTR = INT_CST + INT_CST, which should not be a valid pointer
+        expression.  */
+      if (!(POINTER_TYPE_P (TREE_TYPE (op0))
+           && TREE_CODE (op0) != INTEGER_CST)
+         && !(POINTER_TYPE_P (TREE_TYPE (op1))
+              && TREE_CODE (op1) != INTEGER_CST))
+       set_pt_anything (ptr);
+    }
+  else
+    {
+      /* If we can't recognize the expression, assume that PTR may
+        point anywhere.  */
+      set_pt_anything (ptr);
     }
 }
 
@@ -1868,13 +1839,10 @@ add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
   tree pt_var;
   size_t uid;
 
-#if defined ENABLE_CHECKING
-  if (TREE_CODE (value) != ADDR_EXPR)
-    abort ();
-#endif
+  gcc_assert (TREE_CODE (value) == ADDR_EXPR);
 
   pt_var = TREE_OPERAND (value, 0);
-  if (TREE_CODE_CLASS (TREE_CODE (pt_var)) == 'r')
+  if (REFERENCE_CLASS_P (pt_var))
     pt_var = get_base_address (pt_var);
 
   if (pt_var && SSA_VAR_P (pt_var))
@@ -1882,14 +1850,14 @@ add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
       uid = var_ann (pt_var)->uid;
       bitmap_set_bit (ai->addresses_needed, uid);
 
-      /* If PTR has already been found to point anywhere, don't
-        add the variable to PTR's points-to set.  */
-      if (!pi->pt_anything)
-       {
-         if (pi->pt_vars == NULL)
-           pi->pt_vars = BITMAP_GGC_ALLOC ();
-         bitmap_set_bit (pi->pt_vars, uid);
-       }
+      if (pi->pt_vars == NULL)
+       pi->pt_vars = BITMAP_GGC_ALLOC ();
+      bitmap_set_bit (pi->pt_vars, uid);
+
+      /* If the variable is a global, mark the pointer as pointing to
+        global memory (which will make its tag a global variable).  */
+      if (is_global_var (pt_var))
+       pi->pt_global_mem = 1;
     }
 }
 
@@ -1916,84 +1884,69 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
       fprintf (dump_file, "\n");
     }
 
-  if (TREE_CODE (stmt) == MODIFY_EXPR)
+  switch (TREE_CODE (stmt))
     {
-      tree rhs = TREE_OPERAND (stmt, 1);
-      STRIP_NOPS (rhs);
+    case RETURN_EXPR:
+      if (TREE_CODE (TREE_OPERAND (stmt, 0)) != MODIFY_EXPR)
+       abort ();
+      stmt = TREE_OPERAND (stmt, 0);
+      /* FALLTHRU  */
 
-      /* Found P_i = ADDR_EXPR  */
-      if (TREE_CODE (rhs) == ADDR_EXPR)
-       add_pointed_to_var (ai, var, rhs);
+    case MODIFY_EXPR:
+      {
+       tree rhs = TREE_OPERAND (stmt, 1);
+       STRIP_NOPS (rhs);
+       add_pointed_to_expr (ai, var, rhs);
+       break;
+      }
 
-      /* Found P_i = Q_j.  */
-      else if (TREE_CODE (rhs) == SSA_NAME
-              && POINTER_TYPE_P (TREE_TYPE (rhs)))
-       merge_pointed_to_info (ai, var, rhs);
+    case ASM_EXPR:
+      /* Pointers defined by __asm__ statements can point anywhere.  */
+      set_pt_anything (var);
+      break;
 
-      /* Found P_i = PLUS_EXPR or P_i = MINUS_EXPR  */
-      else if (TREE_CODE (rhs) == PLUS_EXPR
-              || TREE_CODE (rhs) == MINUS_EXPR)
+    case NOP_EXPR:
+      if (IS_EMPTY_STMT (stmt))
        {
-         tree op0 = TREE_OPERAND (rhs, 0);
-         tree op1 = TREE_OPERAND (rhs, 1);
-
-         if (TREE_CODE (op0) == SSA_NAME
-             && POINTER_TYPE_P (TREE_TYPE (op0)))
-           merge_pointed_to_info (ai, var, op0);
-         else if (TREE_CODE (op1) == SSA_NAME
-                  && POINTER_TYPE_P (TREE_TYPE (op1)))
-           merge_pointed_to_info (ai, var, op1);
-         else if (TREE_CODE (op0) == ADDR_EXPR)
-           add_pointed_to_var (ai, var, op0);
-         else if (TREE_CODE (op1) == ADDR_EXPR)
-           add_pointed_to_var (ai, var, op1);
+         tree decl = SSA_NAME_VAR (var);
+         
+         if (TREE_CODE (decl) == PARM_DECL)
+           add_pointed_to_expr (ai, var, decl);
+         else if (DECL_INITIAL (decl))
+           add_pointed_to_expr (ai, var, DECL_INITIAL (decl));
          else
-           add_pointed_to_expr (var, rhs);
+           add_pointed_to_expr (ai, var, decl);
        }
+      break;
 
-      /* Something else.  */
-      else
-       add_pointed_to_expr (var, rhs);
-    }
-  else if (TREE_CODE (stmt) == ASM_EXPR)
-    {
-      /* Pointers defined by __asm__ statements can point anywhere.  */
-      set_pt_anything (var);
-    }
-  else if (IS_EMPTY_STMT (stmt))
-    {
-      tree decl = SSA_NAME_VAR (var);
-
-      if (TREE_CODE (decl) == PARM_DECL)
-       add_pointed_to_expr (var, decl);
-      else if (DECL_INITIAL (decl))
-       add_pointed_to_var (ai, var, DECL_INITIAL (decl));
-      else
-       add_pointed_to_expr (var, decl);
-    }
-  else if (TREE_CODE (stmt) == PHI_NODE)
-    {
-      /* It STMT is a PHI node, then VAR is one of its arguments.  The
-        variable that we are analyzing is the LHS of the PHI node.  */
-      tree lhs = PHI_RESULT (stmt);
+    case PHI_NODE:
+      {
+        /* It STMT is a PHI node, then VAR is one of its arguments.  The
+          variable that we are analyzing is the LHS of the PHI node.  */
+       tree lhs = PHI_RESULT (stmt);
 
-      if (TREE_CODE (var) == ADDR_EXPR)
-       add_pointed_to_var (ai, lhs, var);
-      else if (TREE_CODE (var) == SSA_NAME)
-       {
-         if (bitmap_bit_p (ai->ssa_names_visited, SSA_NAME_VERSION (var)))
+       switch (TREE_CODE (var))
+         {
+         case ADDR_EXPR:
+           add_pointed_to_var (ai, lhs, var);
+           break;
+           
+         case SSA_NAME:
            merge_pointed_to_info (ai, lhs, var);
-         else
-           set_pt_anything (lhs);
-       }
-      else if (is_gimple_min_invariant (var))
-       add_pointed_to_expr (lhs, var);
-      else
-       abort ();
-    }
-  else
-    abort ();
+           break;
+           
+         default:
+           gcc_assert (is_gimple_min_invariant (var));
+           add_pointed_to_expr (ai, lhs, var);
+           break;
+         }
+       break;
+      }
 
+    default:
+      gcc_unreachable ();
+    }
+  
   return false;
 }
 
@@ -2073,9 +2026,6 @@ create_memory_tag (tree type, bool is_type_tag)
      determine whether they should be considered globals.  */
   DECL_CONTEXT (tag) = current_function_decl;
 
-  /* If the pointed-to type is volatile, so is the tag.  */
-  TREE_THIS_VOLATILE (tag) = TREE_THIS_VOLATILE (type);
-
   /* Memory tags are by definition addressable.  This also prevents
      is_gimple_ref frome confusing memory tags with optimizable
      variables.  */
@@ -2106,13 +2056,11 @@ get_nmt_for (tree ptr)
   if (tag == NULL_TREE)
     tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
 
-  /* If PTR is a PARM_DECL, its memory tag should be considered a global
-     variable.  */
-  if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL)
-    mark_call_clobbered (tag);
-
-  /* Similarly, if PTR points to malloc, then TAG is a global.  */
-  if (pi->pt_malloc)
+  /* If PTR is a PARM_DECL, it points to a global variable or malloc,
+     then its name tag should be considered a global variable.  */
+  if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL
+      || pi->pt_malloc
+      || pi->pt_global_mem)
     mark_call_clobbered (tag);
 
   return tag;
@@ -2146,9 +2094,7 @@ get_tmt_for (tree ptr, struct alias_info *ai)
   for (i = 0, tag = NULL_TREE; i < ai->num_pointers; i++)
     {
       struct alias_map_d *curr = ai->pointers[i];
-      if (tag_set == curr->set 
-         && (flag_tree_points_to == PTA_NONE 
-             || same_points_to_set (curr->var, ptr)))
+      if (tag_set == curr->set)
        {
          tag = var_ann (curr->var)->type_mem_tag;
          break;
@@ -2178,13 +2124,12 @@ get_tmt_for (tree ptr, struct alias_info *ai)
       ai->pointers[ai->num_pointers++] = alias_map;
     }
 
-#if defined ENABLE_CHECKING
+  /* If the pointed-to type is volatile, so is the tag.  */
+  TREE_THIS_VOLATILE (tag) |= TREE_THIS_VOLATILE (tag_type);
+
   /* Make sure that the type tag has the same alias set as the
      pointed-to type.  */
-  if (tag_set != get_alias_set (tag))
-    abort ();
-#endif
-
+  gcc_assert (tag_set == get_alias_set (tag));
 
   return tag;
 }
@@ -2234,10 +2179,6 @@ dump_alias_stats (FILE *file)
           alias_stats.tbaa_queries);
   fprintf (file, "Total TBAA resolved:\t%u\n",
           alias_stats.tbaa_resolved);
-  fprintf (file, "Total PTA queries:\t%u\n",
-          alias_stats.pta_queries);
-  fprintf (file, "Total PTA resolved:\t%u\n",
-          alias_stats.pta_resolved);
 }
   
 
@@ -2284,7 +2225,12 @@ dump_alias_info (FILE *file)
   for (i = 1; i < num_ssa_names; i++)
     {
       tree ptr = ssa_name (i);
-      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+      struct ptr_info_def *pi;
+      
+      if (ptr == NULL_TREE)
+       continue;
+
+      pi = SSA_NAME_PTR_INFO (ptr);
       if (!SSA_NAME_IN_FREE_LIST (ptr)
          && pi
          && pi->name_mem_tag)
@@ -2321,10 +2267,7 @@ get_ptr_info (tree t)
 {
   struct ptr_info_def *pi;
 
-#if defined ENABLE_CHECKING
-  if (!POINTER_TYPE_P (TREE_TYPE (t)))
-    abort ();
-#endif
+  gcc_assert (POINTER_TYPE_P (TREE_TYPE (t)));
 
   pi = SSA_NAME_PTR_INFO (t);
   if (pi == NULL)
@@ -2370,13 +2313,14 @@ dump_points_to_info_for (FILE *file, tree ptr)
       if (pi->pt_vars)
        {
          unsigned ix;
+         bitmap_iterator bi;
 
          fprintf (file, ", points-to vars: { ");
-         EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix,
-             {
-               print_generic_expr (file, referenced_var (ix), dump_flags);
-               fprintf (file, " ");
-             });
+         EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi)
+           {
+             print_generic_expr (file, referenced_var (ix), dump_flags);
+             fprintf (file, " ");
+           }
          fprintf (file, "}");
        }
     }
@@ -2403,6 +2347,7 @@ dump_points_to_info (FILE *file)
   basic_block bb;
   block_stmt_iterator si;
   size_t i;
+  ssa_op_iter iter;
   const char *fname =
     lang_hooks.decl_printable_name (current_function_decl, 2);
 
@@ -2436,12 +2381,11 @@ dump_points_to_info (FILE *file)
 
        for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
          {
-           stmt_ann_t ann = stmt_ann (bsi_stmt (si));
-           def_optype defs = DEF_OPS (ann);
-           if (defs)
-             for (i = 0; i < NUM_DEFS (defs); i++)
-               if (POINTER_TYPE_P (TREE_TYPE (DEF_OP (defs, i))))
-                 dump_points_to_info_for (file, DEF_OP (defs, i));
+           tree stmt = bsi_stmt (si);
+           tree def;
+           FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+             if (POINTER_TYPE_P (TREE_TYPE (def)))
+               dump_points_to_info_for (file, def);
          }
     }
 
@@ -2499,15 +2443,17 @@ may_be_aliased (tree var)
   if (TREE_ADDRESSABLE (var))
     return true;
 
-  /* Automatic variables can't have their addresses escape any other way.  */
-  if (!TREE_STATIC (var))
-    return false;
-
   /* Globally visible variables can have their addresses taken by other
      translation units.  */
   if (DECL_EXTERNAL (var) || TREE_PUBLIC (var))
     return true;
 
+  /* Automatic variables can't have their addresses escape any other way.
+     This must be after the check for global variables, as extern declarations
+     do not have TREE_STATIC set.  */
+  if (!TREE_STATIC (var))
+    return false;
+
   /* If we're in unit-at-a-time mode, then we must have seen all occurrences
      of address-of operators, and so we can trust TREE_ADDRESSABLE.  Otherwise
      we can only be sure the variable isn't addressable if it's local to the