tree-ssa-alias.c (compute_flow_insensitive_aliasing): If type memory tag is call...
[gcc.git] / gcc / tree-ssa-alias.c
index 9da01676f43488575705c6966985ffd9a9fd6d24..4bd438b94397317e45bb4993aa8f872dba8d6105 100644 (file)
@@ -141,6 +141,7 @@ static tree create_memory_tag (tree type, bool is_type_tag);
 static tree get_tmt_for (tree, struct alias_info *);
 static tree get_nmt_for (tree);
 static void add_may_alias (tree, tree);
+static void replace_may_alias (tree, size_t, tree);
 static struct alias_info *init_alias_info (void);
 static void delete_alias_info (struct alias_info *);
 static void compute_points_to_and_addr_escape (struct alias_info *);
@@ -156,6 +157,8 @@ static bool ptr_is_dereferenced_by (tree, tree, bool *);
 static void maybe_create_global_var (struct alias_info *ai);
 static void group_aliases (struct alias_info *);
 static struct ptr_info_def *get_ptr_info (tree t);
+static void set_pt_anything (tree ptr);
+static void set_pt_malloc (tree ptr);
 
 /* Global declarations.  */
 
@@ -172,13 +175,6 @@ bitmap call_clobbered_vars;
    variable).  */
 bitmap addressable_vars;
 
-/* 'true' after aliases have been computed (see compute_may_aliases).  This
-   is used by get_stmt_operands and its helpers to determine what to do
-   when scanning an operand for a variable that may be aliased.  If
-   may-alias information is still not available, the statement is marked as
-   having volatile operands.  */
-bool aliases_computed_p;
-
 /* When the program has too many call-clobbered variables and call-sites,
    this variable is used to represent the clobbering effects of function
    calls.  In these cases, all the call clobbered variables in the program
@@ -347,9 +343,6 @@ compute_may_aliases (void)
 
   /* Deallocate memory used by aliasing data structures.  */
   delete_alias_info (ai);
-
-  /* Indicate that may-alias information is now available.  */
-  aliases_computed_p = true;
 }
 
 struct tree_opt_pass pass_may_alias = 
@@ -362,11 +355,12 @@ struct tree_opt_pass pass_may_alias =
   0,                                   /* static_pass_number */
   TV_TREE_MAY_ALIAS,                   /* tv_id */
   PROP_cfg | PROP_ssa | PROP_pta,      /* properties_required */
-  0,                                   /* properties_provided */
+  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 */
 };
 
 
@@ -376,6 +370,7 @@ static struct alias_info *
 init_alias_info (void)
 {
   struct alias_info *ai;
+  static bool aliases_computed_p = false;
 
   ai = xcalloc (1, sizeof (struct alias_info));
   ai->ssa_names_visited = BITMAP_XMALLOC ();
@@ -386,6 +381,67 @@ init_alias_info (void)
   ai->dereferenced_ptrs_store = BITMAP_XMALLOC ();
   ai->dereferenced_ptrs_load = BITMAP_XMALLOC ();
 
+  /* If aliases have been computed before, clear existing information.  */
+  if (aliases_computed_p)
+    {
+      size_t i;
+
+      /* Clear the call-clobbered set.  We are going to re-discover
+         call-clobbered variables.  */
+      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
+       {
+         tree var = referenced_var (i);
+
+         /* Variables that are intrinsically call-clobbered (globals,
+            local statics, etc) will not be marked by the aliasing
+            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
+        only computed here.  */
+      bitmap_clear (addressable_vars);
+
+      /* Clear flow-insensitive alias information from each symbol.  */
+      for (i = 0; i < num_referenced_vars; i++)
+       {
+         var_ann_t ann = var_ann (referenced_var (i));
+         ann->is_alias_tag = 0;
+         ann->may_aliases = NULL;
+       }
+
+      /* Clear flow-sensitive points-to information from each SSA name.  */
+      for (i = 1; i < num_ssa_names; i++)
+       {
+         tree name = ssa_name (i);
+
+         if (!POINTER_TYPE_P (TREE_TYPE (name)))
+           continue;
+
+         if (SSA_NAME_PTR_INFO (name))
+           {
+             struct ptr_info_def *pi = SSA_NAME_PTR_INFO (name);
+
+             /* Clear all the flags but keep the name tag to
+                avoid creating new temporaries unnecessarily.  If
+                this pointer is found to point to a subset or
+                superset of its former points-to set, then a new
+                tag will need to be created in create_name_tags.  */
+             pi->pt_anything = 0;
+             pi->pt_malloc = 0;
+             pi->value_escapes_p = 0;
+             pi->is_dereferenced = 0;
+             if (pi->pt_vars)
+               bitmap_clear (pi->pt_vars);
+           }
+       }
+    }
+
+  /* Next time, we will need to reset alias information.  */
+  aliases_computed_p = true;
+
   return ai;
 }
 
@@ -438,7 +494,7 @@ collect_points_to_info_for (struct alias_info *ai, tree ptr)
   if (!bitmap_bit_p (ai->ssa_names_visited, SSA_NAME_VERSION (ptr)))
     {
       bitmap_set_bit (ai->ssa_names_visited, SSA_NAME_VERSION (ptr));
-      walk_use_def_chains (ptr, collect_points_to_info_r, ai);
+      walk_use_def_chains (ptr, collect_points_to_info_r, ai, true);
       VARRAY_PUSH_TREE (ai->processed_ptrs, ptr);
     }
 }
@@ -521,6 +577,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);
 
@@ -531,11 +589,6 @@ 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);
@@ -574,11 +627,8 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
                  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;
@@ -598,16 +648,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
@@ -635,17 +683,18 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
                     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, v_ann->uid);
+                   {
+                     bitmap_set_bit (ai->dereferenced_ptrs_store, v_ann->uid);
+                     pi->is_dereferenced = 1;
+                   }
                }
            }
 
          /* 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);
@@ -654,25 +703,13 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
            }
 
          /* 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
@@ -704,22 +741,19 @@ 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 we could not determine where PTR was pointing to, clear
-        all the other points-to flags.  */
-      pi = SSA_NAME_PTR_INFO (ptr);
-      if (pi->pt_anything)
+      if (pi->pt_anything || !pi->is_dereferenced)
        {
-         pi->pt_malloc = 0;
-         pi->pt_vars = NULL;
-         pi->is_dereferenced = 0;
+         /* No name tags for pointers that have not been
+            dereferenced or point to an arbitrary location.  */
+         pi->name_mem_tag = NULL_TREE;
+         continue;
        }
 
-      if (!pi->is_dereferenced)
-       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;
 
          /* If PTR points to a set of variables, check if we don't
             have another pointer Q with the same points-to set before
@@ -732,7 +766,6 @@ create_name_tags (struct alias_info *ai)
             problems if they both had different name tags because
             they would have different SSA version numbers (which
             would force us to take the name tags in and out of SSA).  */
-         pi->name_mem_tag = NULL_TREE;
          for (j = 0; j < i; j++)
            {
              tree q = VARRAY_TREE (ai->processed_ptrs, j);
@@ -748,8 +781,17 @@ create_name_tags (struct alias_info *ai)
                }
            }
 
+         /* If we didn't find a pointer with the same points-to set
+            as PTR, create a new name tag if needed.  */
          if (pi->name_mem_tag == NULL_TREE)
            pi->name_mem_tag = get_nmt_for (ptr);
+
+         /* If the new name tag computed for PTR is different than
+            the old name tag that it used to have, then the old tag
+            needs to be removed from the IL, so we mark it for
+            renaming.  */
+         if (old_name_tag && old_name_tag != pi->name_mem_tag)
+           bitmap_set_bit (vars_to_rename, var_ann (old_name_tag)->uid);
        }
       else if (pi->pt_malloc)
        {
@@ -761,7 +803,8 @@ create_name_tags (struct alias_info *ai)
          /* Only pointers that may point to malloc or other variables
             may receive a name tag.  If the pointer does not point to
             a known spot, we should use type tags.  */
-         abort ();
+         set_pt_anything (ptr);
+         continue;
        }
 
       /* Mark the new name tag for renaming.  */
@@ -796,38 +839,14 @@ compute_flow_sensitive_aliasing (struct alias_info *ai)
       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)
+         if (pi->pt_vars)
            EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j,
                mark_call_clobbered (referenced_var (j)));
        }
@@ -911,6 +930,10 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
              num_tag_refs = VARRAY_UINT (ai->num_references, tag_ann->uid);
              num_var_refs = VARRAY_UINT (ai->num_references, v_ann->uid);
 
+             /* If TAG is call clobbered, so is VAR.  */
+             if (is_call_clobbered (tag))
+               mark_call_clobbered (var);
+
              /* Add VAR to TAG's may-aliases set.  */
              add_may_alias (tag, var);
 
@@ -1103,8 +1126,29 @@ group_aliases (struct alias_info *ai)
          sbitmap_a_and_b (res, tag1_aliases, tag2_aliases);
          if (sbitmap_first_set_bit (res) >= 0)
            {
+             size_t k;
+
              tree tag2 = var_ann (ai->pointers[j]->var)->type_mem_tag;
 
+             if (!is_call_clobbered (tag1) && is_call_clobbered (tag2))
+               {
+                 mark_call_clobbered (tag1);
+                 EXECUTE_IF_SET_IN_SBITMAP (tag1_aliases, 0, k,
+                   {
+                     tree var = referenced_var (k);
+                     mark_call_clobbered (var);
+                   });
+               }
+             else if (is_call_clobbered (tag1) && !is_call_clobbered (tag2))
+               {
+                 mark_call_clobbered (tag2);
+                 EXECUTE_IF_SET_IN_SBITMAP (tag2_aliases, 0, k,
+                   {
+                     tree var = referenced_var (k);
+                     mark_call_clobbered (var);
+                   });
+               }
+
              sbitmap_a_or_b (tag1_aliases, tag1_aliases, tag2_aliases);
 
              /* TAG2 does not need its aliases anymore.  */
@@ -1158,13 +1202,17 @@ group_aliases (struct alias_info *ai)
        {
          tree alias = VARRAY_TREE (aliases, j);
          var_ann_t ann = var_ann (alias);
-         if (ann->may_aliases)
+
+         if (ann->mem_tag_kind == NOT_A_TAG && ann->may_aliases)
            {
+             tree new_alias;
+
 #if defined ENABLE_CHECKING
              if (VARRAY_ACTIVE_SIZE (ann->may_aliases) != 1)
                abort ();
 #endif
-             VARRAY_TREE (aliases, j) = VARRAY_TREE (ann->may_aliases, 0);
+             new_alias = VARRAY_TREE (ann->may_aliases, 0);
+             replace_may_alias (name_tag, j, new_alias);
            }
        }
     }
@@ -1188,11 +1236,7 @@ create_alias_map_for (tree var, struct alias_info *ai)
   struct alias_map_d *alias_map;
   alias_map = xcalloc (1, sizeof (*alias_map));
   alias_map->var = var;
-
-  if (TREE_CODE (TREE_TYPE (var)) == ARRAY_TYPE)
-    alias_map->set = get_alias_set (TREE_TYPE (TREE_TYPE (var)));
-  else
-    alias_map->set = get_alias_set (var);
+  alias_map->set = get_alias_set (var);
   ai->addressable_vars[ai->num_addressable_vars++] = alias_map;
 }
 
@@ -1219,12 +1263,10 @@ setup_pointers_and_addressables (struct alias_info *ai)
 
       if (POINTER_TYPE_P (TREE_TYPE (var)))
        {
-         /* Since we don't keep track of volatile variables nor
-            variables with hidden uses, assume that these pointers
-            are used in indirect store operations.  */
-         var_ann_t ann = var_ann (var);
-         if (TREE_THIS_VOLATILE (var) || ann->has_hidden_use)
-           bitmap_set_bit (ai->dereferenced_ptrs_store, ann->uid);
+         /* Since we don't keep track of volatile variables, assume that
+            these pointers are used in indirect store operations.  */
+         if (TREE_THIS_VOLATILE (var))
+           bitmap_set_bit (ai->dereferenced_ptrs_store, var_ann (var)->uid);
 
          num_pointers++;
        }
@@ -1266,9 +1308,8 @@ setup_pointers_and_addressables (struct alias_info *ai)
       if (TREE_ADDRESSABLE (var))
        {
          if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid)
-             && !v_ann->has_hidden_use
              && v_ann->mem_tag_kind == NOT_A_TAG
-             && !needs_to_live_in_memory (var))
+             && !is_global_var (var))
            {
              /* The address of VAR is not needed, remove the
                 addressable bit, so that it can be optimized as a
@@ -1299,48 +1340,64 @@ setup_pointers_and_addressables (struct alias_info *ai)
 
       /* Add pointer variables that have been dereferenced to the POINTERS
          array and create a type memory tag for them.  */
-      if (POINTER_TYPE_P (TREE_TYPE (var))
-         && (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid)
-             || bitmap_bit_p (ai->dereferenced_ptrs_load, v_ann->uid)))
+      if (POINTER_TYPE_P (TREE_TYPE (var)))
        {
-         tree tag = v_ann->type_mem_tag;
-         var_ann_t t_ann;
-
-         /* If pointer VAR still doesn't have a memory tag associated
-            with it, create it now or re-use an existing one.  */
-         if (tag == NULL_TREE)
-           tag = get_tmt_for (var, ai);
-         t_ann = var_ann (tag);
-
-         /* The type tag will need to be renamed into SSA afterwards.
-            Note that we cannot do this inside get_tmt_for because
-            aliasing may run multiple times and we only create type
-            tags the first time.  */
-         bitmap_set_bit (vars_to_rename, t_ann->uid);
-
-         /* Associate the tag with pointer VAR.  */
-         v_ann->type_mem_tag = tag;
-
-         /* If pointer VAR has been used in a store operation, then its
-            memory tag must be marked as written-to.  */
-         if (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid))
-           bitmap_set_bit (ai->written_vars, t_ann->uid);
-
-         /* If pointer VAR is a global variable or a PARM_DECL, then its
-            memory tag should be considered a global variable.  */
-         if (TREE_CODE (var) == PARM_DECL || needs_to_live_in_memory (var))
-           mark_call_clobbered (tag);
-
-         /* All the dereferences of pointer VAR count as references of
-            TAG.  Since TAG can be associated with several pointers, add
-            the dereferences of VAR to the TAG.  We may need to grow
-            AI->NUM_REFERENCES because we have been adding name and
-            type tags.  */
-         if (t_ann->uid >= VARRAY_SIZE (ai->num_references))
-           VARRAY_GROW (ai->num_references, t_ann->uid + 10);
-
-         VARRAY_UINT (ai->num_references, t_ann->uid)
-             += VARRAY_UINT (ai->num_references, v_ann->uid);
+         if ((bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid)
+               || bitmap_bit_p (ai->dereferenced_ptrs_load, v_ann->uid)))
+           {
+             tree tag;
+             var_ann_t t_ann;
+
+             /* If pointer VAR still doesn't have a memory tag
+                associated with it, create it now or re-use an
+                existing one.  */
+             tag = get_tmt_for (var, ai);
+             t_ann = var_ann (tag);
+
+             /* The type tag will need to be renamed into SSA
+                afterwards. Note that we cannot do this inside
+                get_tmt_for because aliasing may run multiple times
+                and we only create type tags the first time.  */
+             bitmap_set_bit (vars_to_rename, t_ann->uid);
+
+             /* Associate the tag with pointer VAR.  */
+             v_ann->type_mem_tag = tag;
+
+             /* If pointer VAR has been used in a store operation,
+                then its memory tag must be marked as written-to.  */
+             if (bitmap_bit_p (ai->dereferenced_ptrs_store, v_ann->uid))
+               bitmap_set_bit (ai->written_vars, t_ann->uid);
+
+             /* If pointer VAR is a global variable or a PARM_DECL,
+                then its memory tag should be considered a global
+                variable.  */
+             if (TREE_CODE (var) == PARM_DECL || is_global_var (var))
+               mark_call_clobbered (tag);
+
+             /* All the dereferences of pointer VAR count as
+                references of TAG.  Since TAG can be associated with
+                several pointers, add the dereferences of VAR to the
+                TAG.  We may need to grow AI->NUM_REFERENCES because
+                we have been adding name and type tags.  */
+             if (t_ann->uid >= VARRAY_SIZE (ai->num_references))
+               VARRAY_GROW (ai->num_references, t_ann->uid + 10);
+
+             VARRAY_UINT (ai->num_references, t_ann->uid)
+               += VARRAY_UINT (ai->num_references, v_ann->uid);
+           }
+         else
+           {
+             /* The pointer has not been dereferenced.  If it had a
+                type memory tag, remove it and mark the old tag for
+                renaming to remove it out of the IL.  */
+             var_ann_t ann = var_ann (var);
+             tree tag = ann->type_mem_tag;
+             if (tag)
+               {
+                 bitmap_set_bit (vars_to_rename, var_ann (tag)->uid);
+                 ann->type_mem_tag = NULL_TREE;
+               }
+           }
        }
     }
 
@@ -1413,30 +1470,35 @@ maybe_create_global_var (struct alias_info *ai)
 {
   size_t i, n_clobbered;
   
-  /* Count all the call-clobbered variables.  */
-  n_clobbered = 0;
-  EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, n_clobbered++);
+  /* 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++);
 
-  /* Create .GLOBAL_VAR if we have too many call-clobbered variables.
-     We also create .GLOBAL_VAR when there no call-clobbered variables
-     to prevent code motion transformations from re-arranging function
-     calls that may have side effects.  For instance,
+      /* Create .GLOBAL_VAR if we have too many call-clobbered
+        variables.  We also create .GLOBAL_VAR when there no
+        call-clobbered variables to prevent code motion
+        transformations from re-arranging function calls that may
+        have side effects.  For instance,
 
-               foo ()
+               foo ()
                {
                  int a = f ();
                  g ();
                  h (a);
                }
 
-     There are no call-clobbered variables in foo(), so it would be
-     entirely possible for a pass to want to move the call to f()
-     after the call to g().  If f() has side effects, that would be
-     wrong.  Creating .GLOBAL_VAR in this case will insert VDEFs for
-     it and prevent such transformations.  */
-  if (n_clobbered == 0
-      || ai->num_calls_found * n_clobbered >= (size_t) GLOBAL_VAR_THRESHOLD)
-    create_global_var ();
+        There are no call-clobbered variables in foo(), so it would
+        be entirely possible for a pass to want to move the call to
+        f() after the call to g().  If f() has side effects, that
+        would be wrong.  Creating .GLOBAL_VAR in this case will
+        insert VDEFs for it and prevent such transformations.  */
+      if (n_clobbered == 0
+         || ai->num_calls_found * n_clobbered >= (size_t) GLOBAL_VAR_THRESHOLD)
+       create_global_var ();
+    }
 
   /* If the function has calls to clobbering functions and .GLOBAL_VAR has
      been created, make it an alias for all call-clobbered variables.  */
@@ -1603,19 +1665,58 @@ 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 (is_call_clobbered (var))
-    mark_call_clobbered (alias);
-
-  /* Likewise.  If ALIAS is call-clobbered, so is VAR.  */
-  else if (is_call_clobbered (alias))
-    mark_call_clobbered (var);
-
   VARRAY_PUSH_TREE (v_ann->may_aliases, alias);
   a_ann->is_alias_tag = 1;
 }
 
 
+/* Replace alias I in the alias sets of VAR with NEW_ALIAS.  */
+
+static void
+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;
+}
+
+
+/* Mark pointer PTR as pointing to an arbitrary memory location.  */
+
+static void
+set_pt_anything (tree ptr)
+{
+  struct ptr_info_def *pi = get_ptr_info (ptr);
+
+  pi->pt_anything = 1;
+  pi->pt_malloc = 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
+     disassociated from PTR.  */
+  if (pi->name_mem_tag)
+    {
+      bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
+      pi->name_mem_tag = NULL_TREE;
+    }
+}
+
+
+/* Mark pointer PTR as pointing to a malloc'd memory area.  */
+
+static void
+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.  */
+  if (pi->pt_anything)
+    return;
+
+  pi->pt_malloc = 1;
+}
+
+
 /* Given two pointers DEST and ORIG.  Merge the points-to information in
    ORIG into DEST.  AI is as in collect_points_to_info.  */
 
@@ -1632,7 +1733,7 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
 
   if (orig_pi)
     {
-      dest_pi->pt_anything |= orig_pi->pt_anything;
+      dest_pi->pt_global_mem |= orig_pi->pt_global_mem;
 
       /* Notice that we never merge PT_MALLOC.  This attribute is only
         true if the pointer is the result of a malloc() call.
@@ -1657,10 +1758,13 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
         malloc call.  Copy propagation before aliasing should cure
         this.  */
       dest_pi->pt_malloc = 0;
-      if (orig_pi->pt_malloc)
-       dest_pi->pt_anything = 1;
 
-      if (orig_pi->pt_vars)
+      if (orig_pi->pt_malloc || orig_pi->pt_anything)
+       set_pt_anything (dest);
+
+      if (!dest_pi->pt_anything
+         && orig_pi->pt_vars
+         && bitmap_first_set_bit (orig_pi->pt_vars) >= 0)
        {
          if (dest_pi->pt_vars == NULL)
            {
@@ -1673,6 +1777,8 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
                           orig_pi->pt_vars);
        }
     }
+  else
+    set_pt_anything (dest);
 }
 
 
@@ -1681,7 +1787,8 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
 static void
 add_pointed_to_expr (tree ptr, tree value)
 {
-  struct ptr_info_def *pi;
+  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.  */
@@ -1690,18 +1797,20 @@ add_pointed_to_expr (tree ptr, tree value)
     abort ();
 #endif
 
-  pi = get_ptr_info (ptr);
+  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)))
-    pi->pt_malloc = 1;
+    set_pt_malloc (ptr);
   else
-    pi->pt_anything = 1;
+    set_pt_anything (ptr);
 
   if (dump_file)
     {
+      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+
       fprintf (dump_file, "Pointer ");
       print_generic_expr (dump_file, ptr, dump_flags);
       fprintf (dump_file, " points to ");
@@ -1722,30 +1831,33 @@ add_pointed_to_expr (tree ptr, tree value)
 static void
 add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
 {
-  if (TREE_CODE (value) == ADDR_EXPR)
+  struct ptr_info_def *pi = get_ptr_info (ptr);
+  tree pt_var;
+  size_t uid;
+
+#if defined ENABLE_CHECKING
+  if (TREE_CODE (value) != ADDR_EXPR)
+    abort ();
+#endif
+
+  pt_var = TREE_OPERAND (value, 0);
+  if (TREE_CODE_CLASS (TREE_CODE (pt_var)) == 'r')
+    pt_var = get_base_address (pt_var);
+
+  if (pt_var && SSA_VAR_P (pt_var))
     {
-      tree pt_var;
-      struct ptr_info_def *pi;
-      size_t uid;
+      uid = var_ann (pt_var)->uid;
+      bitmap_set_bit (ai->addresses_needed, uid);
 
-      pt_var = TREE_OPERAND (value, 0);
-      if (TREE_CODE_CLASS (TREE_CODE (pt_var)) == 'r')
-       pt_var = get_base_address (pt_var);
+      if (pi->pt_vars == NULL)
+       pi->pt_vars = BITMAP_GGC_ALLOC ();
+      bitmap_set_bit (pi->pt_vars, uid);
 
-      if (pt_var && SSA_VAR_P (pt_var))
-       {
-         pi = get_ptr_info (ptr);
-         uid = var_ann (pt_var)->uid;
-         if (pi->pt_vars == NULL)
-           pi->pt_vars = BITMAP_GGC_ALLOC ();
-         bitmap_set_bit (pi->pt_vars, uid);
-         bitmap_set_bit (ai->addresses_needed, uid);
-       }
-      else
-       add_pointed_to_expr (ptr, value);
+      /* 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;
     }
-  else
-    add_pointed_to_expr (ptr, value);
 }
 
 
@@ -1776,8 +1888,8 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
       tree rhs = TREE_OPERAND (stmt, 1);
       STRIP_NOPS (rhs);
 
-      /* Found P_i = CONST.  */
-      if (is_gimple_min_invariant (rhs))
+      /* Found P_i = ADDR_EXPR  */
+      if (TREE_CODE (rhs) == ADDR_EXPR)
        add_pointed_to_var (ai, var, rhs);
 
       /* Found P_i = Q_j.  */
@@ -1792,17 +1904,33 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
          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 (is_gimple_min_invariant (op0))
-           add_pointed_to_var (ai, var, op0);
-         else if (is_gimple_min_invariant (op1))
-           add_pointed_to_var (ai, var, op1);
-         else
+         /* Both operands may be of pointer type.  FIXME: Shouldn't
+            we just expect PTR + OFFSET always?  */
+         if (POINTER_TYPE_P (TREE_TYPE (op0)))
+           {
+             if (TREE_CODE (op0) == SSA_NAME)
+               merge_pointed_to_info (ai, var, op0);
+             else if (TREE_CODE (op0) == ADDR_EXPR)
+               add_pointed_to_var (ai, var, op0);
+             else
+               add_pointed_to_expr (var, op0);
+           }
+
+         if (POINTER_TYPE_P (TREE_TYPE (op1)))
+           {
+             if (TREE_CODE (op1) == SSA_NAME)
+               merge_pointed_to_info (ai, var, op1);
+             else if (TREE_CODE (op1) == ADDR_EXPR)
+               add_pointed_to_var (ai, var, op1);
+             else
+               add_pointed_to_expr (var, op1);
+           }
+
+         /* Neither operand is a pointer?  VAR can be pointing
+            anywhere.   FIXME: Is this right?  If we get here, we
+            found PTR = INT_CST + INT_CST.  */
+         if (!POINTER_TYPE_P (TREE_TYPE (op0))
+             && !POINTER_TYPE_P (TREE_TYPE (op1)))
            add_pointed_to_expr (var, rhs);
        }
 
@@ -1813,7 +1941,7 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
   else if (TREE_CODE (stmt) == ASM_EXPR)
     {
       /* Pointers defined by __asm__ statements can point anywhere.  */
-      get_ptr_info (var)->pt_anything = 1;
+      set_pt_anything (var);
     }
   else if (IS_EMPTY_STMT (stmt))
     {
@@ -1828,12 +1956,16 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
     }
   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);
 
-      if (is_gimple_min_invariant (var))
+      if (TREE_CODE (var) == ADDR_EXPR)
        add_pointed_to_var (ai, lhs, var);
       else if (TREE_CODE (var) == SSA_NAME)
        merge_pointed_to_info (ai, lhs, var);
+      else if (is_gimple_min_invariant (var))
+       add_pointed_to_expr (lhs, var);
       else
        abort ();
     }
@@ -1950,18 +2082,14 @@ get_nmt_for (tree ptr)
   tree tag = pi->name_mem_tag;
 
   if (tag == NULL_TREE)
-    {
-      tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
+    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)
-       mark_call_clobbered (tag);
-    }
+  /* 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;
 }
@@ -2009,9 +2137,13 @@ get_tmt_for (tree ptr, struct alias_info *ai)
     {
       struct alias_map_d *alias_map;
 
-      /* Create a new MT.* artificial variable representing the memory
-        location pointed-to by PTR.  */
-      tag = create_memory_tag (tag_type, true);
+      /* If PTR did not have a type tag already, create a new TMT.*
+        artificial variable representing the memory location
+        pointed-to by PTR.  */
+      if (var_ann (ptr)->type_mem_tag == NULL_TREE)
+       tag = create_memory_tag (tag_type, true);
+      else
+       tag = var_ann (ptr)->type_mem_tag;
 
       /* Add PTR to the POINTERS array.  Note that we are not interested in
         PTR's alias set.  Instead, we cache the alias set for the memory that
@@ -2022,6 +2154,14 @@ get_tmt_for (tree ptr, struct alias_info *ai)
       ai->pointers[ai->num_pointers++] = alias_map;
     }
 
+#if defined ENABLE_CHECKING
+  /* 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
+
+
   return tag;
 }
 
@@ -2037,7 +2177,7 @@ create_global_var (void)
                            size_type_node);
   DECL_ARTIFICIAL (global_var) = 1;
   TREE_READONLY (global_var) = 0;
-  DECL_EXTERNAL (global_var) = 0;
+  DECL_EXTERNAL (global_var) = 1;
   TREE_STATIC (global_var) = 1;
   TREE_USED (global_var) = 1;
   DECL_CONTEXT (global_var) = NULL_TREE;
@@ -2086,16 +2226,53 @@ dump_alias_info (FILE *file)
   const char *funcname
     = lang_hooks.decl_printable_name (current_function_decl, 2);
 
-  fprintf (file, "\nAlias information for %s\n\n", funcname);
+  fprintf (file, "\nFlow-insensitive alias information for %s\n\n", funcname);
+
+  fprintf (file, "Aliased symbols\n\n");
+  for (i = 0; i < num_referenced_vars; i++)
+    {
+      tree var = referenced_var (i);
+      if (may_be_aliased (var))
+       dump_variable (file, var);
+    }
 
+  fprintf (file, "\nDereferenced pointers\n\n");
   for (i = 0; i < num_referenced_vars; i++)
     {
       tree var = referenced_var (i);
       var_ann_t ann = var_ann (var);
-      if (ann->may_aliases
-         || ann->type_mem_tag
-         || ann->is_alias_tag
-         || ann->mem_tag_kind != NOT_A_TAG)
+      if (ann->type_mem_tag)
+       dump_variable (file, var);
+    }
+
+  fprintf (file, "\nType memory tags\n\n");
+  for (i = 0; i < num_referenced_vars; i++)
+    {
+      tree var = referenced_var (i);
+      var_ann_t ann = var_ann (var);
+      if (ann->mem_tag_kind == TYPE_TAG)
+       dump_variable (file, var);
+    }
+
+  fprintf (file, "\n\nFlow-sensitive alias information for %s\n\n", funcname);
+
+  fprintf (file, "SSA_NAME pointers\n\n");
+  for (i = 1; i < num_ssa_names; i++)
+    {
+      tree ptr = ssa_name (i);
+      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+      if (!SSA_NAME_IN_FREE_LIST (ptr)
+         && pi
+         && pi->name_mem_tag)
+       dump_points_to_info_for (file, ptr);
+    }
+
+  fprintf (file, "\nName memory tags\n\n");
+  for (i = 0; i < num_referenced_vars; i++)
+    {
+      tree var = referenced_var (i);
+      var_ann_t ann = var_ann (var);
+      if (ann->mem_tag_kind == NAME_TAG)
        dump_variable (file, var);
     }
 
@@ -2144,7 +2321,6 @@ dump_points_to_info_for (FILE *file, tree ptr)
 {
   struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
 
-  fprintf (file, "Pointer ");
   print_generic_expr (file, ptr, dump_flags);
 
   if (pi)
@@ -2203,6 +2379,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);
 
@@ -2236,12 +2413,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);
          }
     }
 
@@ -2289,3 +2465,36 @@ debug_may_aliases_for (tree var)
 {
   dump_may_aliases_for (stderr, var);
 }
+
+/* Return true if VAR may be aliased.  */
+
+bool
+may_be_aliased (tree var)
+{
+  /* Obviously.  */
+  if (TREE_ADDRESSABLE (var))
+    return true;
+
+  /* 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
+     current function.  */
+  if (flag_unit_at_a_time)
+    return false;
+  if (decl_function_context (var) == current_function_decl)
+    return false;
+
+  return true;
+}
+