OSDN Git Service

PR rtl-optimization/42621
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-alias.c
index e3fe52a..cbb43b5 100644 (file)
@@ -1,12 +1,13 @@
 /* Alias analysis for trees.
-   Copyright (C) 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009
+   Free Software Foundation, Inc.
    Contributed by Diego Novillo <dnovillo@redhat.com>
 
 This file is part of GCC.
 
 GCC is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
-the Free Software Foundation; either version 2, or (at your option)
+the Free Software Foundation; either version 3, or (at your option)
 any later version.
 
 GCC is distributed in the hope that it will be useful,
@@ -15,9 +16,8 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
-along with GCC; see the file COPYING.  If not, write to
-the Free Software Foundation, 51 Franklin Street, Fifth Floor,
-Boston, MA 02110-1301, USA.  */
+along with GCC; see the file COPYING3.  If not see
+<http://www.gnu.org/licenses/>.  */
 
 #include "config.h"
 #include "system.h"
@@ -36,11 +36,10 @@ Boston, MA 02110-1301, USA.  */
 #include "function.h"
 #include "diagnostic.h"
 #include "tree-dump.h"
-#include "tree-gimple.h"
+#include "gimple.h"
 #include "tree-flow.h"
 #include "tree-inline.h"
 #include "tree-pass.h"
-#include "tree-ssa-structalias.h"
 #include "convert.h"
 #include "params.h"
 #include "ipa-type-escape.h"
@@ -48,2276 +47,270 @@ Boston, MA 02110-1301, USA.  */
 #include "bitmap.h"
 #include "vecprim.h"
 #include "pointer-set.h"
+#include "alloc-pool.h"
+#include "tree-ssa-alias.h"
 
-/* Structure to map a variable to its alias set.  */
-struct alias_map_d
-{
-  /* Variable and its alias set.  */
-  tree var;
-  HOST_WIDE_INT set;
-};
-
-
-/* Data structures used for computing memory partitions.  */
-
-struct mp_info_def
-{
-  /* Symbol or memory tag.  */
-  tree var;
-
-  /* Number of virtual operators needed to represent references to VAR.  */
-  long num_vops;
-};
-
-typedef struct mp_info_def *mp_info_t;
-DEF_VEC_P(mp_info_t);
-DEF_VEC_ALLOC_P(mp_info_t, heap);
-
-/* Counters used to display statistics on alias analysis.  */
-struct alias_stats_d
-{
-  unsigned int alias_queries;
-  unsigned int alias_mayalias;
-  unsigned int alias_noalias;
-  unsigned int simple_queries;
-  unsigned int simple_resolved;
-  unsigned int tbaa_queries;
-  unsigned int tbaa_resolved;
-  unsigned int structnoaddress_queries;
-  unsigned int structnoaddress_resolved;
-};
-
-
-/* Local variables.  */
-static struct alias_stats_d alias_stats;
-static bitmap_obstack alias_bitmap_obstack;
-
-/* Local functions.  */
-static void compute_flow_insensitive_aliasing (struct alias_info *);
-static void finalize_ref_all_pointers (struct alias_info *);
-static void dump_alias_stats (FILE *);
-static bool may_alias_p (tree, HOST_WIDE_INT, tree, HOST_WIDE_INT, bool);
-static tree create_memory_tag (tree type, bool is_type_tag);
-static tree get_smt_for (tree, struct alias_info *);
-static tree get_nmt_for (tree);
-static void add_may_alias (tree, tree);
-static struct alias_info *init_alias_info (void);
-static void delete_alias_info (struct alias_info *);
-static void compute_flow_sensitive_aliasing (struct alias_info *);
-static void setup_pointers_and_addressables (struct alias_info *);
-static void create_global_var (void);
-static void maybe_create_global_var (struct alias_info *ai);
-static void set_pt_anything (tree ptr);
-
-void dump_mp_info (FILE *, VEC(mp_info_t,heap) *mp_info_t);
-void debug_mp_info (VEC(mp_info_t,heap) *mp_info_t);
-
-/* Global declarations.  */
-
-/* Mark variable VAR as being non-addressable.  */
-
-static void
-mark_non_addressable (tree var)
-{
-  tree mpt;
-
-  if (!TREE_ADDRESSABLE (var))
-    return;
-
-  mpt = memory_partition (var);
-
-  if (!MTAG_P (var))
-    var_ann (var)->call_clobbered = false;
-
-  bitmap_clear_bit (gimple_call_clobbered_vars (cfun), DECL_UID (var));
-  TREE_ADDRESSABLE (var) = 0;
-
-  if (mpt)
-    {
-      bitmap_clear_bit (MPT_SYMBOLS (mpt), DECL_UID (var));
-      set_memory_partition (var, NULL_TREE);
-    }
-}
-
-
-/* qsort comparison function to sort type/name tags by DECL_UID.  */
-
-static int
-sort_tags_by_id (const void *pa, const void *pb)
-{
-  tree a = *(tree *)pa;
-  tree b = *(tree *)pb;
-  return DECL_UID (a) - DECL_UID (b);
-}
-
-/* Initialize WORKLIST to contain those memory tags that are marked call
-   clobbered.  Initialized WORKLIST2 to contain the reasons these
-   memory tags escaped.  */
-
-static void
-init_transitive_clobber_worklist (VEC (tree, heap) **worklist,
-                                 VEC (int, heap) **worklist2)
-{
-  referenced_var_iterator rvi;
-  tree curr;
-
-  FOR_EACH_REFERENCED_VAR (curr, rvi)
-    {
-      if (MTAG_P (curr) && is_call_clobbered (curr))
-       {
-         VEC_safe_push (tree, heap, *worklist, curr);
-         VEC_safe_push (int, heap, *worklist2, var_ann (curr)->escape_mask);
-       }
-    }
-}
-
-/* Add ALIAS to WORKLIST (and the reason for escaping REASON to WORKLIST2) if
-   ALIAS is not already marked call clobbered, and is a memory
-   tag.  */
-
-static void
-add_to_worklist (tree alias, VEC (tree, heap) **worklist,
-                VEC (int, heap) **worklist2,
-                int reason)
-{
-  if (MTAG_P (alias) && !is_call_clobbered (alias))
-    {
-      VEC_safe_push (tree, heap, *worklist, alias);
-      VEC_safe_push (int, heap, *worklist2, reason);
-    }
-}
-
-/* Mark aliases of TAG as call clobbered, and place any tags on the
-   alias list that were not already call clobbered on WORKLIST.  */
-
-static void
-mark_aliases_call_clobbered (tree tag, VEC (tree, heap) **worklist,
-                            VEC (int, heap) **worklist2)
-{
-  bitmap aliases;
-  bitmap_iterator bi;
-  unsigned int i;
-  tree entry;
-  var_ann_t ta = var_ann (tag);
-
-  if (!MTAG_P (tag))
-    return;
-  aliases = may_aliases (tag);
-  if (!aliases)
-    return;
-
-  EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
-    {
-      entry = referenced_var (i);
-      if (!unmodifiable_var_p (entry))
-       {
-         add_to_worklist (entry, worklist, worklist2, ta->escape_mask);
-         mark_call_clobbered (entry, ta->escape_mask);
-       }
-    }
-}
-
-/* Tags containing global vars need to be marked as global.
-   Tags containing call clobbered vars need to be marked as call
-   clobbered. */
-
-static void
-compute_tag_properties (void)
-{
-  referenced_var_iterator rvi;
-  tree tag;
-  bool changed = true;
-  VEC (tree, heap) *taglist = NULL;
-
-  FOR_EACH_REFERENCED_VAR (tag, rvi)
-    {
-      if (!MTAG_P (tag) || TREE_CODE (tag) == STRUCT_FIELD_TAG)
-       continue;
-      VEC_safe_push (tree, heap, taglist, tag);
-    }
-
-  /* We sort the taglist by DECL_UID, for two reasons.
-     1. To get a sequential ordering to make the bitmap accesses
-     faster.
-     2. Because of the way we compute aliases, it's more likely that
-     an earlier tag is included in a later tag, and this will reduce
-     the number of iterations.
-
-     If we had a real tag graph, we would just topo-order it and be
-     done with it.  */
-  qsort (VEC_address (tree, taglist),
-        VEC_length (tree, taglist),
-        sizeof (tree),
-        sort_tags_by_id);
-
-  /* Go through each tag not marked as global, and if it aliases
-     global vars, mark it global. 
-     
-     If the tag contains call clobbered vars, mark it call
-     clobbered.  
-
-     This loop iterates because tags may appear in the may-aliases
-     list of other tags when we group.  */
-
-  while (changed)
-    {
-      unsigned int k;
-
-      changed = false;      
-      for (k = 0; VEC_iterate (tree, taglist, k, tag); k++)
-       {
-         bitmap ma;
-         bitmap_iterator bi;
-         unsigned int i;
-         tree entry;
-         bool tagcc = is_call_clobbered (tag);
-         bool tagglobal = MTAG_GLOBAL (tag);
-         
-         if (tagcc && tagglobal)
-           continue;
-         
-         ma = may_aliases (tag);
-         if (!ma)
-           continue;
-
-         EXECUTE_IF_SET_IN_BITMAP (ma, 0, i, bi)
-           {
-             entry = referenced_var (i);
-             /* Call clobbered entries cause the tag to be marked
-                call clobbered.  */
-             if (!tagcc && is_call_clobbered (entry))
-               {
-                 mark_call_clobbered (tag, var_ann (entry)->escape_mask);
-                 tagcc = true;
-                 changed = true;
-               }
-
-             /* Global vars cause the tag to be marked global.  */
-             if (!tagglobal && is_global_var (entry))
-               {
-                 MTAG_GLOBAL (tag) = true;
-                 changed = true;
-                 tagglobal = true;
-               }
-
-             /* Early exit once both global and cc are set, since the
-                loop can't do any more than that.  */
-             if (tagcc && tagglobal)
-               break;
-           }
-       }
-    }
-  VEC_free (tree, heap, taglist);
-}
-
-/* Set up the initial variable clobbers and globalness.
-   When this function completes, only tags whose aliases need to be
-   clobbered will be set clobbered.  Tags clobbered because they   
-   contain call clobbered vars are handled in compute_tag_properties.  */
-
-static void
-set_initial_properties (struct alias_info *ai)
-{
-  unsigned int i;
-  referenced_var_iterator rvi;
-  tree var;
-  tree ptr;
-
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    {
-      if (is_global_var (var) 
-         && (!var_can_have_subvars (var)
-             || get_subvars_for_var (var) == NULL))
-       {
-         if (!unmodifiable_var_p (var))
-           mark_call_clobbered (var, ESCAPE_IS_GLOBAL);
-       }
-      else if (TREE_CODE (var) == PARM_DECL
-              && gimple_default_def (cfun, var)
-              && POINTER_TYPE_P (TREE_TYPE (var)))
-       {
-         tree def = gimple_default_def (cfun, var);
-         get_ptr_info (def)->value_escapes_p = 1;
-         get_ptr_info (def)->escape_mask |= ESCAPE_IS_PARM;      
-       }
-    }
-
-  for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
-    {
-      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
-      tree tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
-      
-      if (pi->value_escapes_p)
-       {
-         /* If PTR escapes then its associated memory tags and
-            pointed-to variables are call-clobbered.  */
-         if (pi->name_mem_tag)
-           mark_call_clobbered (pi->name_mem_tag, pi->escape_mask);
-
-         if (tag)
-           mark_call_clobbered (tag, pi->escape_mask);
-
-         if (pi->pt_vars)
-           {
-             bitmap_iterator bi;
-             unsigned int j;         
-             EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j, bi)
-               if (!unmodifiable_var_p (referenced_var (j)))
-                 mark_call_clobbered (referenced_var (j), pi->escape_mask);
-           }
-       }
-
-      /* If the name tag is call clobbered, so is the symbol tag
-        associated with the base VAR_DECL.  */
-      if (pi->name_mem_tag
-         && tag
-         && is_call_clobbered (pi->name_mem_tag))
-       mark_call_clobbered (tag, pi->escape_mask);
-
-      /* Name tags and symbol tags that we don't know where they point
-        to, might point to global memory, and thus, are clobbered.
-
-         FIXME:  This is not quite right.  They should only be
-         clobbered if value_escapes_p is true, regardless of whether
-         they point to global memory or not.
-         So removing this code and fixing all the bugs would be nice.
-         It is the cause of a bunch of clobbering.  */
-      if ((pi->pt_global_mem || pi->pt_anything) 
-         && pi->is_dereferenced && pi->name_mem_tag)
-       {
-         mark_call_clobbered (pi->name_mem_tag, ESCAPE_IS_GLOBAL);
-         MTAG_GLOBAL (pi->name_mem_tag) = true;
-       }
-      
-      if ((pi->pt_global_mem || pi->pt_anything) 
-         && pi->is_dereferenced
-         && tag)
-       {
-         mark_call_clobbered (tag, ESCAPE_IS_GLOBAL);
-         MTAG_GLOBAL (tag) = true;
-       }
-    }
-}
-
-/* Compute which variables need to be marked call clobbered because
-   their tag is call clobbered, and which tags need to be marked
-   global because they contain global variables.  */
-
-static void
-compute_call_clobbered (struct alias_info *ai)
-{
-  VEC (tree, heap) *worklist = NULL;
-  VEC(int,heap) *worklist2 = NULL;
-  
-  set_initial_properties (ai);
-  init_transitive_clobber_worklist (&worklist, &worklist2);
-  while (VEC_length (tree, worklist) != 0)
-    {
-      tree curr = VEC_pop (tree, worklist);
-      int reason = VEC_pop (int, worklist2);
-      
-      mark_call_clobbered (curr, reason);
-      mark_aliases_call_clobbered (curr, &worklist, &worklist2);
-    }
-  VEC_free (tree, heap, worklist);
-  VEC_free (int, heap, worklist2);
-  compute_tag_properties ();
-}
-
-/* Dump the MP_INFO array to FILE.  */
-
-void
-dump_mp_info (FILE *file, VEC(mp_info_t,heap) *mp_info)
-{
-  unsigned i;
-  mp_info_t mp_p;
-
-  for (i = 0; VEC_iterate (mp_info_t, mp_info, i, mp_p); i++)
-    {
-      fprintf (file, "%6lu\t", mp_p->num_vops);
-      if (mp_p->var == NULL_TREE)
-       {
-         fprintf (file, "CALL-CLOBBERED SYMBOLS: ");
-         dump_decl_set (file, gimple_call_clobbered_vars (cfun));
-       }
-      else
-       dump_variable (file, mp_p->var);
-    }
-}
-
-
-/* Dump the MP_INFO array to stderr.  */
-
-void
-debug_mp_info (VEC(mp_info_t,heap) *mp_info)
-{
-  dump_mp_info (stderr, mp_info);
-}
-
-
-/* Comparison function for qsort used in sort_mp_info.  */
-
-static int
-mp_info_cmp (const void *p, const void *q)
-{
-  mp_info_t e1 = *((const mp_info_t *) p);
-  mp_info_t e2 = *((const mp_info_t *) q);
-
-  /* We want to sort in decreasing order.  */
-  if (e1->num_vops < e2->num_vops)
-    return 1;
-  else if (e1->num_vops > e2->num_vops)
-    return -1;
-  else
-    return 0;
-}
-
-
-/* Sort the array of reference counts used to compute memory partitions.
-   Elements are sorted in descending order of virtual operators needed.  */
-
-static inline void
-sort_mp_info (VEC(mp_info_t,heap) *list)
-{
-  unsigned num = VEC_length (mp_info_t, list);
-
-  if (num < 2)
-    return;
-
-  if (num == 2)
-    {
-      if (VEC_index (mp_info_t, list, 0)->num_vops
-         < VEC_index (mp_info_t, list, 1)->num_vops)
-       {  
-         /* Swap elements if they are in the wrong order.  */
-         mp_info_t tmp = VEC_index (mp_info_t, list, 0);
-         VEC_replace (mp_info_t, list, 0, VEC_index (mp_info_t, list, 1));
-         VEC_replace (mp_info_t, list, 1, tmp);
-       }
-
-      return;
-    }
-
-  /* There are 3 or more elements, call qsort.  */
-  qsort (VEC_address (mp_info_t, list), VEC_length (mp_info_t, list), 
-        sizeof (mp_info_t), mp_info_cmp);
-}
-
-
-/* Create a new partition to hold all the symbols aliased with
-   MP_P->VAR.  If MP_P->VAR is NULL, it partitions the call-clobbered
-   variables. Only symbols that are not already in another partition
-   are added to the new partition created for MP_P->VAR.  */
-
-static void
-create_partition_for (mp_info_t mp_p)
-{
-  bitmap_iterator bi;
-  tree mpt, sym;
-  bitmap aliases;
-  unsigned i;
-
-  if (mp_p->num_vops <= (long) MAX_ALIASED_VOPS)
-    return;
-
-  if (mp_p->var == NULL_TREE)
-    {
-      bitmap_iterator bi;
-      bitmap tmp;
-
-      /* Since the partitions we create for call-clobbered variables
-        will also be marked call-clobbered, make a copy of the
-        original set to avoid confusing the iterator.  */
-      tmp = BITMAP_ALLOC (NULL);
-      bitmap_copy (tmp, gimple_call_clobbered_vars (cfun));
-
-      /* Process call-clobbered symbols when no MP_P->VAR is given.  */
-      mpt = NULL_TREE;
-      EXECUTE_IF_SET_IN_BITMAP (tmp, 0, i, bi)
-       {
-         tree sym = referenced_var (i);
-         if (memory_partition (sym) == NULL_TREE)
-           {
-             if (mpt == NULL_TREE)
-               {
-                 mpt = get_mpt_for (sym);
-                 mp_p->num_vops++;
-               }
-
-             mark_sym_for_renaming (mpt);
-             mark_sym_for_renaming (sym);
-             set_memory_partition (sym, mpt);
-           }
-
-         mp_p->num_vops--;
-
-         /* If we have already grouped enough, stop.  */
-         if (mp_p->num_vops <= (long) MAX_ALIASED_VOPS)
-           break;
-       }
-
-      BITMAP_FREE (tmp);
-    }
-  else
-    {
-      aliases = may_aliases (mp_p->var);
-      gcc_assert (!bitmap_empty_p (aliases));
-
-      mpt = NULL_TREE;
-      EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
-       {
-         sym = referenced_var (i);
-         /* Only set the memory partition for aliased symbol SYM if
-            SYM does not belong to another partition.  */
-         if (memory_partition (sym) == NULL_TREE)
-           {
-             if (mpt == NULL_TREE)
-               {
-                 mpt = get_mpt_for (mp_p->var);
-                 mp_p->num_vops++;
-               }
-
-             mark_sym_for_renaming (mpt);
-             mark_sym_for_renaming (sym);
-             set_memory_partition (sym, mpt);
-           }
-
-         mp_p->num_vops--;
-
-         /* If we have already grouped enough, stop.  */
-         if (mp_p->num_vops <= (long) MAX_ALIASED_VOPS)
-           break;
-       }
-
-      if (mpt)
-       mark_call_clobbered (mpt, ESCAPE_UNKNOWN);
-    }
-}
-
-
-/* Rewrite the alias set for TAG to use the newly created partitions.
-   If TAG is NULL, rewrite the set of call-clobbered variables.
-   NEW_ALIASES is a scratch bitmap to build the new set of aliases for
-   TAG.  */
-
-static void
-rewrite_alias_set_for (tree tag, bitmap new_aliases)
-{
-  bitmap_iterator bi;
-  unsigned i;
-  tree mpt, sym;
-
-  if (tag == NULL_TREE)
-    {
-      /* Do not rewrite CALL_CLOBBERED_VARS.  If a symbol S is taken
-        out of this set, the optimizers will no longer consider S as
-        call-clobbered, and that may lead to wrong transformations
-        (e.g., pass_tail_calls explicitly examines all the symbols in
-        the function to determine if it should enable tail-call
-        marking).  */
-      return;
-    }
-  else
-    {
-      /* Create a new alias set for TAG with the new partitions.  */
-
-      EXECUTE_IF_SET_IN_BITMAP (MTAG_ALIASES (tag), 0, i, bi)
-       {
-         sym = referenced_var (i);
-         mpt = memory_partition (sym);
-         if (mpt)
-           bitmap_set_bit (new_aliases, DECL_UID (mpt));
-         else
-           bitmap_set_bit (new_aliases, DECL_UID (sym));
-       }
-
-      /* Rebuild the may-alias array for TAG.  */
-      bitmap_copy (MTAG_ALIASES (tag), new_aliases);
-    }
-}
-
-
-/* Compute memory partitions.
-
-   The partitioning is straightforward:
-   
-   1- All the memory tags and call-clobbered that cause virtual
-      operators are collected into the MP_INFO table together with the
-      number of virtual operands that would be needed to represent all
-      the members in the alias set.
-
-   2- MP_INFO is sorted in decreasing order of virtual operators.
-
-   3- For every memory tag T in MP_INFO, a new partition MP is created.  
-
-   4- All the symbols S in T's alias set are examined.  If S is not
-      already in another partition then S is added to partition MP.
-
-   6- The estimate of VOPS is updated, if it falls below
-      MAX_ALIASED_VOPS, we stop.  */
-
-static void
-compute_memory_partitions (void)
-{
-  referenced_var_iterator rvi;
-  tree var;
-  unsigned i;
-  struct mp_info_def mp;
-  mp_info_t mp_p;
-  VEC(mp_info_t,heap) *mp_info;
-  long max_num_vops = 0;
-  bitmap new_aliases;
-
-  timevar_push (TV_MEMORY_PARTITIONING);
-
-  mp_info = NULL;
-  max_num_vops = 0;
-
-  /* Add reference counts for all the call-clobbered variables.  */
-  if (!bitmap_empty_p (gimple_call_clobbered_vars (cfun)))
-    {
-      mp.var = NULL_TREE;
-      mp.num_vops = bitmap_count_bits (gimple_call_clobbered_vars (cfun));
-      max_num_vops = mp.num_vops;
-      mp_p = xcalloc (1, sizeof (*mp_p));
-      *mp_p = mp;
-      VEC_safe_push (mp_info_t, heap, mp_info, mp_p);
-    }
-
-  /* Add reference counts for all the symbol tags.  */
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    {
-      if (TREE_CODE (var) != SYMBOL_MEMORY_TAG
-         && TREE_CODE (var) != NAME_MEMORY_TAG)
-       continue;
-
-      /* Each reference to VAR will produce as many VOPs as elements
-        exist in its alias set.  */
-      mp.var = var;
-      if (!may_aliases (var))
-       mp.num_vops = 0;
-      else
-       mp.num_vops = bitmap_count_bits (may_aliases (var));
-
-      /* No point grouping singleton alias sets.  */
-      if (mp.num_vops <= 1)
-       continue;
-
-      mp_p = xcalloc (1, sizeof (*mp_p));
-      *mp_p = mp;
-      VEC_safe_push (mp_info_t, heap, mp_info, mp_p);
-
-      if (mp.num_vops > max_num_vops)
-       max_num_vops = mp.num_vops;
-    }
-
-  if (dump_file)
-    {
-      fprintf (dump_file, "\n%s: Maximum number of VOPS needed per statement: "
-              "%ld\n", get_name (current_function_decl), max_num_vops);
-    }
-
-  /* No partitions required if we are below the threshold.  */
-  if (max_num_vops <= (long) MAX_ALIASED_VOPS)
-    goto done;
-
-  /* Sort the MP_INFO array in order of decreasing number of
-     virtual operands.  */
-  sort_mp_info (mp_info);
-
-  if (dump_file)
-    {
-      fprintf (dump_file, "\nVOPS generated by pointer dereferences "
-                         "before partitioning:\n");
-      dump_mp_info (dump_file, mp_info);
-    }
-
-  /* Now that we have all the VOP generating tags in the MP_INFO array
-     sorted by decreasing number of VOPS, create memory partitions and
-     group aliased symbols into those partitions.  */
-  for (i = 0; VEC_iterate (mp_info_t, mp_info, i, mp_p); i++)
-    {
-      /* Stop processing if we are already below the threshold.  */
-      if (mp_p->num_vops <= (long) MAX_ALIASED_VOPS)
-       break;
-
-      create_partition_for (mp_p);
-    }
-
-  /* After partitions have been created, rewrite alias sets to use
-     them instead of the original symbols.  This way, if the alias set
-     was computed as { a b c d e f }, and the subset { b e f } was
-     grouped into partition MPT.3, then the new alias set for the tag
-     will be  { a c d MPT.3 }.  */
-  new_aliases = BITMAP_ALLOC (NULL);
-
-  for (i = 0; VEC_iterate (mp_info_t, mp_info, i, mp_p); i++)
-    {
-      rewrite_alias_set_for (mp_p->var, new_aliases);
-      bitmap_clear (new_aliases);
-    }
-
-  BITMAP_FREE (new_aliases);
-
-  if (dump_file)
-    {
-      fprintf (dump_file, "\nVOPS generated by pointer dereferences "
-                         "after partitioning:\n");
-      dump_mp_info (dump_file, mp_info);
-    }
-
-done:
-  /* Free allocated memory.  */
-  for (i = 0; VEC_iterate (mp_info_t, mp_info, i, mp_p); i++)
-    free (mp_p);
-  VEC_free (mp_info_t, heap, mp_info);
-
-  timevar_pop (TV_MEMORY_PARTITIONING);
-}
-
-/* This function computes the value of the is_aliased bit for
-   variables.  is_aliased is true for any variable that is in an
-   alias bitmap.  */
-
-static void
-compute_is_aliased (void)
-{
-  referenced_var_iterator rvi;
-  tree tag;
-  bitmap aliased_vars = BITMAP_ALLOC (NULL);
-  bitmap_iterator bi;
-  unsigned int i;
-  
-  /* Add is_aliased for all vars pointed to by the symbol tags.  */
-  FOR_EACH_REFERENCED_VAR (tag, rvi)
-    {
-      bitmap aliases;
-      if (TREE_CODE (tag) != SYMBOL_MEMORY_TAG
-         && TREE_CODE (tag) != NAME_MEMORY_TAG)
-       continue;
-      aliases = MTAG_ALIASES (tag);
-      if (!aliases)
-       continue;
-      
-      bitmap_ior_into (aliased_vars, aliases);   
-    }
-  
-  EXECUTE_IF_SET_IN_BITMAP (aliased_vars, 0, i, bi)
-    {
-      tree var = referenced_var (i);
-      
-      var_ann (var)->is_aliased = true;
-    }
-  
-  BITMAP_FREE (aliased_vars);
-}
-
-
-/* Compute may-alias information for every variable referenced in function
-   FNDECL.
-
-   Alias analysis proceeds in 3 main phases:
-
-   1- Points-to and escape analysis.
-
-   This phase walks the use-def chains in the SSA web looking for three
-   things:
-
-       * Assignments of the form P_i = &VAR
-       * Assignments of the form P_i = malloc()
-       * Pointers and ADDR_EXPR that escape the current function.
-
-   The concept of 'escaping' is the same one used in the Java world.  When
-   a pointer or an ADDR_EXPR escapes, it means that it has been exposed
-   outside of the current function.  So, assignment to global variables,
-   function arguments and returning a pointer are all escape sites, as are
-   conversions between pointers and integers.
-
-   This is where we are currently limited.  Since not everything is renamed
-   into SSA, we lose track of escape properties when a pointer is stashed
-   inside a field in a structure, for instance.  In those cases, we are
-   assuming that the pointer does escape.
-
-   We use escape analysis to determine whether a variable is
-   call-clobbered.  Simply put, if an ADDR_EXPR escapes, then the variable
-   is call-clobbered.  If a pointer P_i escapes, then all the variables
-   pointed-to by P_i (and its memory tag) also escape.
-
-   2- Compute flow-sensitive aliases
-
-   We have two classes of memory tags.  Memory tags associated with the
-   pointed-to data type of the pointers in the program.  These tags are
-   called "symbol memory tag" (SMT).  The other class are those associated
-   with SSA_NAMEs, called "name memory tag" (NMT). The basic idea is that
-   when adding operands for an INDIRECT_REF *P_i, we will first check
-   whether P_i has a name tag, if it does we use it, because that will have
-   more precise aliasing information.  Otherwise, we use the standard symbol
-   tag.
-
-   In this phase, we go through all the pointers we found in points-to
-   analysis and create alias sets for the name memory tags associated with
-   each pointer P_i.  If P_i escapes, we mark call-clobbered the variables
-   it points to and its tag.
-
-
-   3- Compute flow-insensitive aliases
-
-   This pass will compare the alias set of every symbol memory tag and
-   every addressable variable found in the program.  Given a symbol
-   memory tag SMT and an addressable variable V.  If the alias sets of
-   SMT and V conflict (as computed by may_alias_p), then V is marked
-   as an alias tag and added to the alias set of SMT.
-
-   For instance, consider the following function:
-
-           foo (int i)
-           {
-             int *p, a, b;
-           
-             if (i > 10)
-               p = &a;
-             else
-               p = &b;
-           
-             *p = 3;
-             a = b + 2;
-             return *p;
-           }
-
-   After aliasing analysis has finished, the symbol memory tag for pointer
-   'p' will have two aliases, namely variables 'a' and 'b'.  Every time
-   pointer 'p' is dereferenced, we want to mark the operation as a
-   potential reference to 'a' and 'b'.
-
-           foo (int i)
-           {
-             int *p, a, b;
-
-             if (i_2 > 10)
-               p_4 = &a;
-             else
-               p_6 = &b;
-             # p_1 = PHI <p_4(1), p_6(2)>;
-
-             # a_7 = VDEF <a_3>;
-             # b_8 = VDEF <b_5>;
-             *p_1 = 3;
-
-             # a_9 = VDEF <a_7>
-             # VUSE <b_8>
-             a_9 = b_8 + 2;
-
-             # VUSE <a_9>;
-             # VUSE <b_8>;
-             return *p_1;
-           }
-
-   In certain cases, the list of may aliases for a pointer may grow too
-   large.  This may cause an explosion in the number of virtual operands
-   inserted in the code.  Resulting in increased memory consumption and
-   compilation time.
-
-   When the number of virtual operands needed to represent aliased
-   loads and stores grows too large (configurable with @option{--param
-   max-aliased-vops}), alias sets are grouped to avoid severe
-   compile-time slow downs and memory consumption.  See group_aliases.  */
-
-static unsigned int
-compute_may_aliases (void)
-{
-  struct alias_info *ai;
-  
-  memset (&alias_stats, 0, sizeof (alias_stats));
-
-  /* Initialize aliasing information.  */
-  ai = init_alias_info ();
-
-  /* For each pointer P_i, determine the sets of variables that P_i may
-     point-to.  For every addressable variable V, determine whether the
-     address of V escapes the current function, making V call-clobbered
-     (i.e., whether &V is stored in a global variable or if its passed as a
-     function call argument).  */
-  compute_points_to_sets (ai);
-
-  /* Collect all pointers and addressable variables, compute alias sets,
-     create memory tags for pointers and promote variables whose address is
-     not needed anymore.  */
-  setup_pointers_and_addressables (ai);
-
-  /* Compute type-based flow-insensitive aliasing for all the type
-     memory tags.  */
-  compute_flow_insensitive_aliasing (ai);
-
-  /* Compute flow-sensitive, points-to based aliasing for all the name
-     memory tags.  */
-  compute_flow_sensitive_aliasing (ai);
-  
-  /* Compute call clobbering information.  */
-  compute_call_clobbered (ai);
-
-  /* If the program makes no reference to global variables, but it
-     contains a mixture of pure and non-pure functions, then we need
-     to create use-def and def-def links between these functions to
-     avoid invalid transformations on them.  */
-  maybe_create_global_var (ai);
-
-  /* If the program contains ref-all pointers, finalize may-alias information
-     for them.  This pass needs to be run after call-clobbering information
-     has been computed.  */
-  if (ai->ref_all_symbol_mem_tag)
-    finalize_ref_all_pointers (ai);
-
-  /* Compute memory partitions for every memory variable.  */
-  compute_memory_partitions ();
-
-  /* Debugging dumps.  */
-  if (dump_file)
-    {
-      dump_referenced_vars (dump_file);
-      if (dump_flags & TDF_STATS)
-       dump_alias_stats (dump_file);
-      dump_points_to_info (dump_file);
-      dump_alias_info (dump_file);
-    }
-
-  /* Set up is_aliased flags. */
-  compute_is_aliased ();
-  
-  /* Deallocate memory used by aliasing data structures.  */
-  delete_alias_info (ai);
-
-  {
-    block_stmt_iterator bsi;
-    basic_block bb;
-    FOR_EACH_BB (bb)
-      {
-        for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-          {
-            update_stmt_if_modified (bsi_stmt (bsi));
-          }
-      }
-  }
-  return 0;
-}
-
-
-struct tree_opt_pass pass_may_alias = 
-{
-  "alias",                             /* name */
-  NULL,                                        /* gate */
-  compute_may_aliases,                 /* execute */
-  NULL,                                        /* sub */
-  NULL,                                        /* next */
-  0,                                   /* static_pass_number */
-  TV_TREE_MAY_ALIAS,                   /* tv_id */
-  PROP_cfg | PROP_ssa,                 /* properties_required */
-  PROP_alias,                          /* properties_provided */
-  0,                                   /* properties_destroyed */
-  0,                                   /* todo_flags_start */
-  TODO_dump_func | TODO_update_ssa
-    | TODO_ggc_collect | TODO_verify_ssa
-    | TODO_verify_stmts,               /* todo_flags_finish */
-  0                                    /* letter */
-};
-
-
-/* Data structure used to count the number of dereferences to PTR
-   inside an expression.  */
-struct count_ptr_d
-{
-  tree ptr;
-  unsigned count;
-};
-
-
-/* Helper for count_uses_and_derefs.  Called by walk_tree to look for
-   (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA.  */
-
-static tree
-count_ptr_derefs (tree *tp, int *walk_subtrees, void *data)
-{
-  struct count_ptr_d *count_p = (struct count_ptr_d *) data;
-
-  /* Do not walk inside ADDR_EXPR nodes.  In the expression &ptr->fld,
-     pointer 'ptr' is *not* dereferenced, it is simply used to compute
-     the address of 'fld' as 'ptr + offsetof(fld)'.  */
-  if (TREE_CODE (*tp) == ADDR_EXPR)
-    {
-      *walk_subtrees = 0;
-      return NULL_TREE;
-    }
-
-  if (INDIRECT_REF_P (*tp) && TREE_OPERAND (*tp, 0) == count_p->ptr)
-    count_p->count++;
-
-  return NULL_TREE;
-}
-
-
-/* Count the number of direct and indirect uses for pointer PTR in
-   statement STMT.  The two counts are stored in *NUM_USES_P and
-   *NUM_DEREFS_P respectively.  *IS_STORE_P is set to 'true' if at
-   least one of those dereferences is a store operation.  */
-
-void
-count_uses_and_derefs (tree ptr, tree stmt, unsigned *num_uses_p,
-                      unsigned *num_derefs_p, bool *is_store)
-{
-  ssa_op_iter i;
-  tree use;
-
-  *num_uses_p = 0;
-  *num_derefs_p = 0;
-  *is_store = false;
-
-  /* Find out the total number of uses of PTR in STMT.  */
-  FOR_EACH_SSA_TREE_OPERAND (use, stmt, i, SSA_OP_USE)
-    if (use == ptr)
-      (*num_uses_p)++;
-
-  /* Now count the number of indirect references to PTR.  This is
-     truly awful, but we don't have much choice.  There are no parent
-     pointers inside INDIRECT_REFs, so an expression like
-     '*x_1 = foo (x_1, *x_1)' needs to be traversed piece by piece to
-     find all the indirect and direct uses of x_1 inside.  The only
-     shortcut we can take is the fact that GIMPLE only allows
-     INDIRECT_REFs inside the expressions below.  */
-  if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT
-      || (TREE_CODE (stmt) == RETURN_EXPR
-         && TREE_CODE (TREE_OPERAND (stmt, 0)) == GIMPLE_MODIFY_STMT)
-      || TREE_CODE (stmt) == ASM_EXPR
-      || TREE_CODE (stmt) == CALL_EXPR)
-    {
-      tree lhs, rhs;
-
-      if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
-       {
-         lhs = GIMPLE_STMT_OPERAND (stmt, 0);
-         rhs = GIMPLE_STMT_OPERAND (stmt, 1);
-       }
-      else if (TREE_CODE (stmt) == RETURN_EXPR)
-       {
-         tree e = TREE_OPERAND (stmt, 0);
-         lhs = GIMPLE_STMT_OPERAND (e, 0);
-         rhs = GIMPLE_STMT_OPERAND (e, 1);
-       }
-      else if (TREE_CODE (stmt) == ASM_EXPR)
-       {
-         lhs = ASM_OUTPUTS (stmt);
-         rhs = ASM_INPUTS (stmt);
-       }
-      else
-       {
-         lhs = NULL_TREE;
-         rhs = stmt;
-       }
-
-      if (lhs && (TREE_CODE (lhs) == TREE_LIST
-                 || EXPR_P (lhs) || GIMPLE_STMT_P (lhs)))
-       {
-         struct count_ptr_d count;
-         count.ptr = ptr;
-         count.count = 0;
-         walk_tree (&lhs, count_ptr_derefs, &count, NULL);
-         *is_store = true;
-         *num_derefs_p = count.count;
-       }
-
-      if (rhs && (TREE_CODE (rhs) == TREE_LIST
-                 || EXPR_P (rhs) || GIMPLE_STMT_P (rhs)))
-       {
-         struct count_ptr_d count;
-         count.ptr = ptr;
-         count.count = 0;
-         walk_tree (&rhs, count_ptr_derefs, &count, NULL);
-         *num_derefs_p += count.count;
-       }
-    }
-
-  gcc_assert (*num_uses_p >= *num_derefs_p);
-}
-
-/* Initialize the data structures used for alias analysis.  */
-
-static struct alias_info *
-init_alias_info (void)
-{
-  struct alias_info *ai;
-  referenced_var_iterator rvi;
-  tree var;
-
-  ai = XCNEW (struct alias_info);
-  ai->ssa_names_visited = sbitmap_alloc (num_ssa_names);
-  sbitmap_zero (ai->ssa_names_visited);
-  ai->processed_ptrs = VEC_alloc (tree, heap, 50);
-  ai->written_vars = pointer_set_create ();
-  ai->dereferenced_ptrs_store = pointer_set_create ();
-  ai->dereferenced_ptrs_load = pointer_set_create ();
-
-  /* If aliases have been computed before, clear existing information.  */
-  if (gimple_aliases_computed_p (cfun))
-    {
-      unsigned i;
-      
-      bitmap_obstack_release (&alias_bitmap_obstack);
-      
-      /* Similarly, clear the set of addressable variables.  In this
-        case, we can just clear the set because addressability is
-        only computed here.  */
-      bitmap_clear (gimple_addressable_vars (cfun));
-
-      /* Clear flow-insensitive alias information from each symbol.  */
-      FOR_EACH_REFERENCED_VAR (var, rvi)
-       {
-         var_ann_t ann = var_ann (var);
-         
-         ann->is_aliased = 0;
-
-         if (MTAG_P (var))
-           MTAG_ALIASES (var) = NULL;
-
-         /* Since we are about to re-discover call-clobbered
-            variables, clear the call-clobbered flag.  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.  
-
-            NB: STRUCT_FIELDS are still call clobbered if they are for
-            a global variable, so we *don't* clear their call clobberedness
-            just because they are tags, though we will clear it if they
-            aren't for global variables.  */
-         if (TREE_CODE (var) == NAME_MEMORY_TAG
-             || TREE_CODE (var) == SYMBOL_MEMORY_TAG
-             || !is_global_var (var))
-           clear_call_clobbered (var);
-       }
-
-      /* Clear flow-sensitive points-to information from each SSA name.  */
-      for (i = 1; i < num_ssa_names; i++)
-       {
-         tree name = ssa_name (i);
-
-         if (!name || !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_null = 0;
-             pi->value_escapes_p = 0;
-             pi->is_dereferenced = 0;
-             if (pi->pt_vars)
-               bitmap_clear (pi->pt_vars);
-           }
-       }
-    }
-  else
-    {
-      /* If this is the first time we compute aliasing information,
-        every non-register symbol will need to be put into SSA form
-        (the initial SSA form only operates on GIMPLE registers).  */
-      FOR_EACH_REFERENCED_VAR (var, rvi)
-       if (!is_gimple_reg (var))
-         mark_sym_for_renaming (var);
-    }
-
-  /* Next time, we will need to reset alias information.  */
-  cfun->gimple_df->aliases_computed_p = true;
-  bitmap_obstack_initialize (&alias_bitmap_obstack);
-
-  return ai;
-}
-
-
-/* Deallocate memory used by alias analysis.  */
-
-static void
-delete_alias_info (struct alias_info *ai)
-{
-  size_t i;
-
-  sbitmap_free (ai->ssa_names_visited);
-
-  VEC_free (tree, heap, ai->processed_ptrs);
-
-  for (i = 0; i < ai->num_addressable_vars; i++)
-    free (ai->addressable_vars[i]);
-  free (ai->addressable_vars);
-  
-  for (i = 0; i < ai->num_pointers; i++)
-    free (ai->pointers[i]);
-  free (ai->pointers);
-
-  pointer_set_destroy (ai->written_vars);
-  pointer_set_destroy (ai->dereferenced_ptrs_store);
-  pointer_set_destroy (ai->dereferenced_ptrs_load);
-  free (ai);
-
-  delete_points_to_sets ();
-}
-
-/* Used for hashing to identify pointer infos with identical
-   pt_vars bitmaps.  */
-static int
-eq_ptr_info (const void *p1, const void *p2)
-{
-  const struct ptr_info_def *n1 = (const struct ptr_info_def *) p1;
-  const struct ptr_info_def *n2 = (const struct ptr_info_def *) p2;
-  return bitmap_equal_p (n1->pt_vars, n2->pt_vars);
-}
-
-static hashval_t
-ptr_info_hash (const void *p)
-{
-  const struct ptr_info_def *n = (const struct ptr_info_def *) p;
-  return bitmap_hash (n->pt_vars);
-}
-
-/* Create name tags for all the pointers that have been dereferenced.
-   We only create a name tag for a pointer P if P is found to point to
-   a set of variables (so that we can alias them to *P) or if it is
-   the result of a call to malloc (which means that P cannot point to
-   anything else nor alias any other variable).
-
-   If two pointers P and Q point to the same set of variables, they
-   are assigned the same name tag.  */
-
-static void
-create_name_tags (void)
-{
-  size_t i;
-  VEC (tree, heap) *with_ptvars = NULL;
-  tree ptr;
-  htab_t ptr_hash;
-
-  /* Collect the list of pointers with a non-empty points to set.  */
-  for (i = 1; i < num_ssa_names; i++)
-    {
-      tree ptr = ssa_name (i);
-      struct ptr_info_def *pi;
-
-      if (!ptr
-         || !POINTER_TYPE_P (TREE_TYPE (ptr))
-         || !SSA_NAME_PTR_INFO (ptr))
-       continue;
-
-      pi = SSA_NAME_PTR_INFO (ptr);
-
-      if (pi->pt_anything || !pi->is_dereferenced)
-       {
-         /* No name tags for pointers that have not been
-            dereferenced or point to an arbitrary location.  */
-         pi->name_mem_tag = NULL_TREE;
-         continue;
-       }
-
-      /* Set pt_anything on the pointers without pt_vars filled in so
-        that they are assigned a symbol tag.  */
-      if (pi->pt_vars && !bitmap_empty_p (pi->pt_vars))        
-       VEC_safe_push (tree, heap, with_ptvars, ptr);
-      else
-       set_pt_anything (ptr);
-    }
-  
-  /* If we didn't find any pointers with pt_vars set, we're done.  */
-  if (!with_ptvars)
-    return;
-
-  ptr_hash = htab_create (10, ptr_info_hash, eq_ptr_info, NULL);
-  /* Now go through the pointers with pt_vars, and find a name tag
-     with the same pt_vars as this pointer, or create one if one
-     doesn't exist.  */
-  for (i = 0; VEC_iterate (tree, with_ptvars, i, ptr); i++)
-    {
-      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
-      tree old_name_tag = pi->name_mem_tag;
-      struct ptr_info_def **slot;
-      
-      /* If PTR points to a set of variables, check if we don't
-        have another pointer Q with the same points-to set before
-        creating a tag.  If so, use Q's tag instead of creating a
-        new one.
-        
-        This is important for not creating unnecessary symbols
-        and also for copy propagation.  If we ever need to
-        propagate PTR into Q or vice-versa, we would run into
-        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).  */
-
-      slot = (struct ptr_info_def **) htab_find_slot (ptr_hash, pi, INSERT);
-      if (*slot)
-        pi->name_mem_tag = (*slot)->name_mem_tag;
-      else
-       {
-         *slot = pi;
-         /* 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)
-       mark_sym_for_renaming (old_name_tag);
-      
-      TREE_THIS_VOLATILE (pi->name_mem_tag)
-       |= TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
-      
-      /* Mark the new name tag for renaming.  */
-      mark_sym_for_renaming (pi->name_mem_tag);
-    }
-  htab_delete (ptr_hash);
-
-  VEC_free (tree, heap, with_ptvars);
-}
-
-/* Union the alias set SET into the may-aliases for TAG */
-
-static void
-union_alias_set_into (tree tag, bitmap set)
-{
-  bitmap ma = MTAG_ALIASES (tag);
-  
-  if (bitmap_empty_p (set))
-    return;
-  
-  if (!ma)
-    ma = MTAG_ALIASES (tag) = BITMAP_ALLOC (&alias_bitmap_obstack);
-  bitmap_ior_into (ma, set);
-}
-
-
-/* For every pointer P_i in AI->PROCESSED_PTRS, create may-alias sets for
-   the name memory tag (NMT) associated with P_i.  If P_i escapes, then its
-   name tag and the variables it points-to are call-clobbered.  Finally, if
-   P_i escapes and we could not determine where it points to, then all the
-   variables in the same alias set as *P_i are marked call-clobbered.  This
-   is necessary because we must assume that P_i may take the address of any
-   variable in the same alias set.  */
-
-static void
-compute_flow_sensitive_aliasing (struct alias_info *ai)
-{
-  size_t i;
-  tree ptr;
-  
-  set_used_smts ();
-  
-  for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
-    {
-      if (!find_what_p_points_to (ptr))
-       set_pt_anything (ptr);
-    }
-
-  create_name_tags ();
-
-  for (i = 0; VEC_iterate (tree, ai->processed_ptrs, i, ptr); i++)
-    {
-      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
-      tree tag = symbol_mem_tag (SSA_NAME_VAR (ptr));
-
-      /* 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)
-       {
-         if (!bitmap_empty_p (pi->pt_vars))
-           {
-             union_alias_set_into (pi->name_mem_tag, pi->pt_vars);
-             union_alias_set_into (tag, pi->pt_vars);
-             bitmap_clear_bit (MTAG_ALIASES (tag), DECL_UID (tag));
-           
-             /* It may be the case that this the tag uid was the only
-                bit we had set in the aliases list, and in this case,
-                we don't want to keep an empty bitmap, as this
-                asserts in tree-ssa-operands.c .  */
-             if (bitmap_empty_p (MTAG_ALIASES (tag)))
-               BITMAP_FREE (MTAG_ALIASES (tag));
-           }
-       }
-    }
-}
-
-
-/* Return TRUE if at least one symbol in TAG2's alias set is also
-   present in TAG1's alias set.  */
-
-static bool
-have_common_aliases_p (bitmap tag1aliases, bitmap tag2aliases)
-{
-
-  /* This is the old behavior of have_common_aliases_p, which is to
-     return false if both sets are empty, or one set is and the other
-     isn't.  */
-     if ((tag1aliases == NULL && tag2aliases != NULL)
-      || (tag2aliases == NULL && tag1aliases != NULL)
-      || (tag1aliases == NULL && tag2aliases == NULL))
-    return false;
-
-  return bitmap_intersect_p (tag1aliases, tag2aliases);
-}
-
-/* Compute type-based alias sets.  Traverse all the pointers and
-   addressable variables found in setup_pointers_and_addressables.
-   
-   For every pointer P in AI->POINTERS and addressable variable V in
-   AI->ADDRESSABLE_VARS, add V to the may-alias sets of P's symbol
-   memory tag (SMT) if their alias sets conflict.  V is then marked as
-   an aliased symbol so that the operand scanner knows that statements
-   containing V have aliased operands.  */
-
-static void
-compute_flow_insensitive_aliasing (struct alias_info *ai)
-{
-  size_t i;
-
-  /* For every pointer P, determine which addressable variables may alias
-     with P's symbol memory tag.  */
-  for (i = 0; i < ai->num_pointers; i++)
-    {
-      size_t j;
-      struct alias_map_d *p_map = ai->pointers[i];
-      tree tag = symbol_mem_tag (p_map->var);
-      tree var;
-
-      /* Call-clobbering information is not finalized yet at this point.  */
-      if (PTR_IS_REF_ALL (p_map->var))
-       continue;
-
-      for (j = 0; j < ai->num_addressable_vars; j++)
-       {
-         struct alias_map_d *v_map;
-         var_ann_t v_ann;
-         bool tag_stored_p, var_stored_p;
-         
-         v_map = ai->addressable_vars[j];
-         var = v_map->var;
-         v_ann = var_ann (var);
-
-         /* Skip memory tags and variables that have never been
-            written to.  We also need to check if the variables are
-            call-clobbered because they may be overwritten by
-            function calls.  */
-         tag_stored_p = pointer_set_contains (ai->written_vars, tag)
-                        || is_call_clobbered (tag);
-         var_stored_p = pointer_set_contains (ai->written_vars, var)
-                        || is_call_clobbered (var);
-         if (!tag_stored_p && !var_stored_p)
-           continue;
-            
-         if (may_alias_p (p_map->var, p_map->set, var, v_map->set, false))
-           {
-             /* We should never have a var with subvars here, because
-                they shouldn't get into the set of addressable vars */
-             gcc_assert (!var_can_have_subvars (var)
-                         || get_subvars_for_var (var) == NULL);
-
-             /* Add VAR to TAG's may-aliases set.  */
-             add_may_alias (tag, var);
-           }
-       }
-    }
-
-  /* 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 SMT.1 and SMT.2
-     such that
-     
-               may-aliases (SMT.1) = { a }
-               may-aliases (SMT.2) = { b }
-
-     and the alias set number of SMT.1 conflicts with that of SMT.2.
-     Since they don't have symbols in common, loads and stores from
-     SMT.1 and SMT.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.  */
-  for (i = 0; i < ai->num_pointers; i++)
-    {
-      size_t j;
-      struct alias_map_d *p_map1 = ai->pointers[i];
-      tree tag1 = symbol_mem_tag (p_map1->var);
-      bitmap may_aliases1 = MTAG_ALIASES (tag1);
-
-      if (PTR_IS_REF_ALL (p_map1->var))
-       continue;
-
-      for (j = i + 1; j < ai->num_pointers; j++)
-       {
-         struct alias_map_d *p_map2 = ai->pointers[j];
-         tree tag2 = symbol_mem_tag (p_map2->var);
-         bitmap may_aliases2 = may_aliases (tag2);
-
-         if (PTR_IS_REF_ALL (p_map2->var))
-           continue;
-
-         /* If the pointers may not point to each other, do nothing.  */
-         if (!may_alias_p (p_map1->var, p_map1->set, tag2, p_map2->set, true))
-           continue;
-
-         /* The two pointers may alias each other.  If they already have
-            symbols in common, do nothing.  */
-         if (have_common_aliases_p (may_aliases1, may_aliases2))
-           continue;
+/* Broad overview of how alias analysis on gimple works:
 
-         if (may_aliases2 && !bitmap_empty_p (may_aliases2))
-           {
-             union_alias_set_into (tag1, 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);
-           }
-       }
-
-    }
-}
-
-
-/* Finalize may-alias information for ref-all pointers.  Traverse all
-   the addressable variables found in setup_pointers_and_addressables.
-
-   If flow-sensitive alias analysis has attached a name memory tag to
-   a ref-all pointer, we will use it for the dereferences because that
-   will have more precise aliasing information.  But if there is no
-   name tag, we will use a special symbol tag that aliases all the
-   call-clobbered addressable variables.  */
-
-static void
-finalize_ref_all_pointers (struct alias_info *ai)
-{
-  size_t i;
-
-  /* First add the real call-clobbered variables.  */
-  for (i = 0; i < ai->num_addressable_vars; i++)
-    {
-      tree var = ai->addressable_vars[i]->var;
-      if (is_call_clobbered (var))
-       add_may_alias (ai->ref_all_symbol_mem_tag, var);
-    }
-
-  /* Then add the call-clobbered pointer memory tags.  See
-     compute_flow_insensitive_aliasing for the rationale.  */
-  for (i = 0; i < ai->num_pointers; i++)
-    {
-      tree ptr = ai->pointers[i]->var, tag;
-      if (PTR_IS_REF_ALL (ptr))
-       continue;
-      tag = symbol_mem_tag (ptr);
-      if (is_call_clobbered (tag))
-       add_may_alias (ai->ref_all_symbol_mem_tag, tag);
-    }
-
-}
+   Statements clobbering or using memory are linked through the
+   virtual operand factored use-def chain.  The virtual operand
+   is unique per function, its symbol is accessible via gimple_vop (cfun).
+   Virtual operands are used for efficiently walking memory statements
+   in the gimple IL and are useful for things like value-numbering as
+   a generation count for memory references.
 
+   SSA_NAME pointers may have associated points-to information
+   accessible via the SSA_NAME_PTR_INFO macro.  Flow-insensitive
+   points-to information is (re-)computed by the TODO_rebuild_alias
+   pass manager todo.  Points-to information is also used for more
+   precise tracking of call-clobbered and call-used variables and
+   related disambiguations.
 
-/* Create a new alias set entry for VAR in AI->ADDRESSABLE_VARS.  */
+   This file contains functions for disambiguating memory references,
+   the so called alias-oracle and tools for walking of the gimple IL.
 
-static void
-create_alias_map_for (tree var, struct alias_info *ai)
-{
-  struct alias_map_d *alias_map;
-  alias_map = XCNEW (struct alias_map_d);
-  alias_map->var = var;
-  alias_map->set = get_alias_set (var);
-  ai->addressable_vars[ai->num_addressable_vars++] = alias_map;
-}
+   The main alias-oracle entry-points are
 
+   bool stmt_may_clobber_ref_p (gimple, tree)
 
-/* Create memory tags for all the dereferenced pointers and build the
-   ADDRESSABLE_VARS and POINTERS arrays used for building the may-alias
-   sets.  Based on the address escape and points-to information collected
-   earlier, this pass will also clear the TREE_ADDRESSABLE flag from those
-   variables whose address is not needed anymore.  */
+     This function queries if a statement may invalidate (parts of)
+     the memory designated by the reference tree argument.
 
-static void
-setup_pointers_and_addressables (struct alias_info *ai)
-{
-  size_t num_addressable_vars, num_pointers;
-  referenced_var_iterator rvi;
-  tree var;
-  VEC (tree, heap) *varvec = NULL;
-  safe_referenced_var_iterator srvi;
+   bool ref_maybe_used_by_stmt_p (gimple, tree)
 
-  /* Size up the arrays ADDRESSABLE_VARS and POINTERS.  */
-  num_addressable_vars = num_pointers = 0;
-  
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    {
-      if (may_be_aliased (var))
-       num_addressable_vars++;
+     This function queries if a statement may need (parts of) the
+     memory designated by the reference tree argument.
 
-      if (POINTER_TYPE_P (TREE_TYPE (var)))
-       {
-         /* Since we don't keep track of volatile variables, assume that
-            these pointers are used in indirect store operations.  */
-         if (TREE_THIS_VOLATILE (var))
-           pointer_set_insert (ai->dereferenced_ptrs_store, var);
+   There are variants of these functions that only handle the call
+   part of a statement, call_may_clobber_ref_p and ref_maybe_used_by_call_p.
+   Note that these do not disambiguate against a possible call lhs.
 
-         num_pointers++;
-       }
-    }
+   bool refs_may_alias_p (tree, tree)
 
-  /* Create ADDRESSABLE_VARS and POINTERS.  Note that these arrays are
-     always going to be slightly bigger than we actually need them
-     because some TREE_ADDRESSABLE variables will be marked
-     non-addressable below and only pointers with unique symbol tags are
-     going to be added to POINTERS.  */
-  ai->addressable_vars = XCNEWVEC (struct alias_map_d *, num_addressable_vars);
-  ai->pointers = XCNEWVEC (struct alias_map_d *, num_pointers);
-  ai->num_addressable_vars = 0;
-  ai->num_pointers = 0;
-
-  FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, srvi)
-    {
-      subvar_t svars;
-
-      /* Name memory tags already have flow-sensitive aliasing
-        information, so they need not be processed by
-        compute_flow_insensitive_aliasing.  Similarly, symbol memory
-        tags are already accounted for when we process their
-        associated pointer. 
-      
-         Structure fields, on the other hand, have to have some of this
-         information processed for them, but it's pointless to mark them
-         non-addressable (since they are fake variables anyway).  */
-      if (MTAG_P (var) && TREE_CODE (var) != STRUCT_FIELD_TAG)
-       continue;
+     This function tries to disambiguate two reference trees.
 
-      /* Remove the ADDRESSABLE flag from every addressable variable whose
-         address is not needed anymore.  This is caused by the propagation
-         of ADDR_EXPR constants into INDIRECT_REF expressions and the
-         removal of dead pointer assignments done by the early scalar
-         cleanup passes.  */
-      if (TREE_ADDRESSABLE (var))
-       {
-         if (!bitmap_bit_p (gimple_addressable_vars (cfun), DECL_UID (var))
-             && TREE_CODE (var) != RESULT_DECL
-             && !is_global_var (var))
-           {
-             bool okay_to_mark = true;
+   bool ptr_deref_may_alias_global_p (tree)
 
-             /* Since VAR is now a regular GIMPLE register, we will need
-                to rename VAR into SSA afterwards.  */
-             mark_sym_for_renaming (var);
+     This function queries if dereferencing a pointer variable may
+     alias global memory.
 
-             /* If VAR can have sub-variables, and any of its
-                sub-variables has its address taken, then we cannot
-                remove the addressable flag from VAR.  */
-             if (var_can_have_subvars (var)
-                 && (svars = get_subvars_for_var (var)))
-               {
-                 subvar_t sv;
-
-                 for (sv = svars; sv; sv = sv->next)
-                   {         
-                     if (bitmap_bit_p (gimple_addressable_vars (cfun),
-                                       DECL_UID (sv->var)))
-                       okay_to_mark = false;
-                     mark_sym_for_renaming (sv->var);
-                   }
-               }
+   More low-level disambiguators are available and documented in
+   this file.  Low-level disambiguators dealing with points-to
+   information are in tree-ssa-structalias.c.  */
 
-             /* The address of VAR is not needed, remove the
-                addressable bit, so that it can be optimized as a
-                regular variable.  */
-             if (okay_to_mark)
-               {
-                 /* The memory partition holding VAR will no longer
-                    contain VAR, and statements referencing it will need
-                    to be updated.  */
-                 if (memory_partition (var))
-                   mark_sym_for_renaming (memory_partition (var));
 
-                 mark_non_addressable (var);
-               }
-           }
-       }
+/* Query statistics for the different low-level disambiguators.
+   A high-level query may trigger multiple of them.  */
 
-      /* Global variables and addressable locals may be aliased.  Create an
-         entry in ADDRESSABLE_VARS for VAR.  */
-      if (may_be_aliased (var))
-       {
-         if (!var_can_have_subvars (var)
-             || get_subvars_for_var (var) == NULL)
-           create_alias_map_for (var, ai);
+static struct {
+  unsigned HOST_WIDE_INT refs_may_alias_p_may_alias;
+  unsigned HOST_WIDE_INT refs_may_alias_p_no_alias;
+  unsigned HOST_WIDE_INT ref_maybe_used_by_call_p_may_alias;
+  unsigned HOST_WIDE_INT ref_maybe_used_by_call_p_no_alias;
+  unsigned HOST_WIDE_INT call_may_clobber_ref_p_may_alias;
+  unsigned HOST_WIDE_INT call_may_clobber_ref_p_no_alias;
+} alias_stats;
 
-         mark_sym_for_renaming (var);
-       }
+void
+dump_alias_stats (FILE *s)
+{
+  fprintf (s, "\nAlias oracle query stats:\n");
+  fprintf (s, "  refs_may_alias_p: "
+          HOST_WIDE_INT_PRINT_DEC" disambiguations, "
+          HOST_WIDE_INT_PRINT_DEC" queries\n",
+          alias_stats.refs_may_alias_p_no_alias,
+          alias_stats.refs_may_alias_p_no_alias
+          + alias_stats.refs_may_alias_p_may_alias);
+  fprintf (s, "  ref_maybe_used_by_call_p: "
+          HOST_WIDE_INT_PRINT_DEC" disambiguations, "
+          HOST_WIDE_INT_PRINT_DEC" queries\n",
+          alias_stats.ref_maybe_used_by_call_p_no_alias,
+          alias_stats.refs_may_alias_p_no_alias
+          + alias_stats.ref_maybe_used_by_call_p_may_alias);
+  fprintf (s, "  call_may_clobber_ref_p: "
+          HOST_WIDE_INT_PRINT_DEC" disambiguations, "
+          HOST_WIDE_INT_PRINT_DEC" queries\n",
+          alias_stats.call_may_clobber_ref_p_no_alias,
+          alias_stats.call_may_clobber_ref_p_no_alias
+          + alias_stats.call_may_clobber_ref_p_may_alias);
+}
+
+
+/* Return true, if dereferencing PTR may alias with a global variable.  */
 
-      /* Add pointer variables that have been dereferenced to the POINTERS
-         array and create a symbol memory tag for them.  */
-      if (POINTER_TYPE_P (TREE_TYPE (var)))
-       {
-         if ((pointer_set_contains (ai->dereferenced_ptrs_store, var)
-              || pointer_set_contains (ai->dereferenced_ptrs_load, var)))
-           {
-             tree tag, old_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_smt_for (var, ai);
-             t_ann = var_ann (tag);
-
-             /* The symbol tag will need to be renamed into SSA
-                afterwards. Note that we cannot do this inside
-                get_smt_for because aliasing may run multiple times
-                and we only create symbol tags the first time.  */
-             mark_sym_for_renaming (tag);
-
-             /* Similarly, if pointer VAR used to have another type
-                tag, we will need to process it in the renamer to
-                remove the stale virtual operands.  */
-             old_tag = symbol_mem_tag (var);
-             if (old_tag)
-               mark_sym_for_renaming (old_tag);
-
-             /* Associate the tag with pointer VAR.  */
-             set_symbol_mem_tag (var, tag);
-
-             /* If pointer VAR has been used in a store operation,
-                then its memory tag must be marked as written-to.  */
-             if (pointer_set_contains (ai->dereferenced_ptrs_store, var))
-               pointer_set_insert (ai->written_vars, tag);
-           }
-         else
-           {
-             /* The pointer has not been dereferenced.  If it had a
-                symbol memory tag, remove it and mark the old tag for
-                renaming to remove it out of the IL.  */
-             tree tag = symbol_mem_tag (var);
-             if (tag)
-               {
-                 mark_sym_for_renaming (tag);
-                 set_symbol_mem_tag (var, NULL_TREE);
-               }
-           }
-       }
-    }
+bool
+ptr_deref_may_alias_global_p (tree ptr)
+{
+  struct ptr_info_def *pi;
 
-  VEC_free (tree, heap, varvec);
-}
+  /* If we end up with a pointer constant here that may point
+     to global memory.  */
+  if (TREE_CODE (ptr) != SSA_NAME)
+    return true;
 
+  pi = SSA_NAME_PTR_INFO (ptr);
 
-/* Determine whether to use .GLOBAL_VAR to model call clobbering
-   semantics.  If the function makes no references to global
-   variables and contains at least one call to a non-pure function,
-   then we need to mark the side-effects of the call using .GLOBAL_VAR
-   to represent all possible global memory referenced by the callee.  */
+  /* If we do not have points-to information for this variable,
+     we have to punt.  */
+  if (!pi)
+    return true;
 
-static void
-maybe_create_global_var (struct alias_info *ai)
-{
-  /* No need to create it, if we have one already.  */
-  if (gimple_global_var (cfun) == NULL_TREE)
-    {
-      /* Create .GLOBAL_VAR if there are no call-clobbered
-        variables and the program contains a mixture of pure/const
-        and regular function calls.  This is to avoid the problem
-        described in PR 20115:
-
-             int X;
-             int func_pure (void) { return X; }
-             int func_non_pure (int a) { X += a; }
-             int foo ()
-             {
-               int a = func_pure ();
-               func_non_pure (a);
-               a = func_pure ();
-               return a;
-             }
-
-        Since foo() has no call-clobbered variables, there is
-        no relationship between the calls to func_pure and
-        func_non_pure.  Since func_pure has no side-effects, value
-        numbering optimizations elide the second call to func_pure.
-        So, if we have some pure/const and some regular calls in the
-        program we create .GLOBAL_VAR to avoid missing these
-        relations.  */
-      if (bitmap_count_bits (gimple_call_clobbered_vars (cfun)) == 0
-         && ai->num_calls_found > 0
-         && ai->num_pure_const_calls_found > 0
-         && ai->num_calls_found > ai->num_pure_const_calls_found)
-       create_global_var ();
-    }
+  /* ???  This does not use TBAA to prune globals ptr may not access.  */
+  return pt_solution_includes_global (&pi->pt);
 }
 
-
-/* Return TRUE if pointer PTR may point to variable VAR.
-   
-   MEM_ALIAS_SET is the alias set for the memory location pointed-to by PTR
-       This is needed because when checking for type conflicts we are
-       interested in the alias set of the memory location pointed-to by
-       PTR.  The alias set of PTR itself is irrelevant.
-   
-   VAR_ALIAS_SET is the alias set for VAR.  */
+/* Return true if dereferencing PTR may alias DECL.
+   The caller is responsible for applying TBAA to see if PTR
+   may access DECL at all.  */
 
 static bool
-may_alias_p (tree ptr, HOST_WIDE_INT mem_alias_set,
-            tree var, HOST_WIDE_INT var_alias_set,
-            bool alias_set_only)
+ptr_deref_may_alias_decl_p (tree ptr, tree decl)
 {
-  tree mem;
-
-  alias_stats.alias_queries++;
-  alias_stats.simple_queries++;
-
-  /* By convention, a variable cannot alias itself.  */
-  mem = symbol_mem_tag (ptr);
-  if (mem == var)
-    {
-      alias_stats.alias_noalias++;
-      alias_stats.simple_resolved++;
-      return false;
-    }
-
-  /* If -fargument-noalias-global is > 2, pointer arguments may
-     not point to anything else.  */
-  if (flag_argument_noalias > 2 && TREE_CODE (ptr) == PARM_DECL)
-    {
-      alias_stats.alias_noalias++;
-      alias_stats.simple_resolved++;
-      return false;
-    }
-
-  /* If -fargument-noalias-global is > 1, pointer arguments may
-     not point to global variables.  */
-  if (flag_argument_noalias > 1 && is_global_var (var)
-      && TREE_CODE (ptr) == PARM_DECL)
-    {
-      alias_stats.alias_noalias++;
-      alias_stats.simple_resolved++;
-      return false;
-    }
-
-  /* If either MEM or VAR is a read-only global and the other one
-     isn't, then PTR cannot point to VAR.  */
-  if ((unmodifiable_var_p (mem) && !unmodifiable_var_p (var))
-      || (unmodifiable_var_p (var) && !unmodifiable_var_p (mem)))
-    {
-      alias_stats.alias_noalias++;
-      alias_stats.simple_resolved++;
-      return false;
-    }
-
-  gcc_assert (TREE_CODE (mem) == SYMBOL_MEMORY_TAG);
+  struct ptr_info_def *pi;
 
-  alias_stats.tbaa_queries++;
+  gcc_assert ((TREE_CODE (ptr) == SSA_NAME
+              || TREE_CODE (ptr) == ADDR_EXPR
+              || TREE_CODE (ptr) == INTEGER_CST)
+             && (TREE_CODE (decl) == VAR_DECL
+                 || TREE_CODE (decl) == PARM_DECL
+                 || TREE_CODE (decl) == RESULT_DECL));
 
-  /* If the alias sets don't conflict then MEM cannot alias VAR.  */
-  if (!alias_sets_conflict_p (mem_alias_set, var_alias_set))
-    {
-      alias_stats.alias_noalias++;
-      alias_stats.tbaa_resolved++;
-      return false;
-    }
+  /* Non-aliased variables can not be pointed to.  */
+  if (!may_be_aliased (decl))
+    return false;
 
-  /* If VAR is a record or union type, PTR cannot point into VAR
-     unless there is some explicit address operation in the
-     program that can reference a field of the type pointed-to by PTR.
-     This also assumes that the types of both VAR and PTR are
-     contained within the compilation unit, and that there is no fancy
-     addressing arithmetic associated with any of the types
-     involved.  */
-  if (mem_alias_set != 0 && var_alias_set != 0)
-    {
-      tree ptr_type = TREE_TYPE (ptr);
-      tree var_type = TREE_TYPE (var);
-      
-      /* The star count is -1 if the type at the end of the pointer_to 
-        chain is not a record or union type. */ 
-      if ((!alias_set_only) && 
-         ipa_type_escape_star_count_of_interesting_type (var_type) >= 0)
-       {
-         int ptr_star_count = 0;
-         
-         /* ipa_type_escape_star_count_of_interesting_type is a
-            little too restrictive for the pointer type, need to
-            allow pointers to primitive types as long as those types
-            cannot be pointers to everything.  */
-         while (POINTER_TYPE_P (ptr_type))
-           {
-             /* Strip the *s off.  */ 
-             ptr_type = TREE_TYPE (ptr_type);
-             ptr_star_count++;
-           }
-         
-         /* There does not appear to be a better test to see if the 
-            pointer type was one of the pointer to everything 
-            types.  */
-         if (ptr_star_count > 0)
-           {
-             alias_stats.structnoaddress_queries++;
-             if (ipa_type_escape_field_does_not_clobber_p (var_type, 
-                                                           TREE_TYPE (ptr))) 
-               {
-                 alias_stats.structnoaddress_resolved++;
-                 alias_stats.alias_noalias++;
-                 return false;
-               }
-           }
-         else if (ptr_star_count == 0)
-           {
-             /* If PTR_TYPE was not really a pointer to type, it cannot 
-                alias.  */ 
-             alias_stats.structnoaddress_queries++;
-             alias_stats.structnoaddress_resolved++;
-             alias_stats.alias_noalias++;
-             return false;
-           }
-       }
+  /* ADDR_EXPR pointers either just offset another pointer or directly
+     specify the pointed-to set.  */
+  if (TREE_CODE (ptr) == ADDR_EXPR)
+    {
+      tree base = get_base_address (TREE_OPERAND (ptr, 0));
+      if (base
+         && INDIRECT_REF_P (base))
+       ptr = TREE_OPERAND (base, 0);
+      else if (base
+              && SSA_VAR_P (base))
+       return operand_equal_p (base, decl, 0);
+      else if (base
+              && CONSTANT_CLASS_P (base))
+       return false;
+      else
+       return true;
     }
 
-  alias_stats.alias_mayalias++;
-  return true;
-}
-
-
-/* Add ALIAS to the set of variables that may alias VAR.  */
-
-static void
-add_may_alias (tree var, tree alias)
-{
-
-  /* Don't allow self-referential aliases.  */
-  gcc_assert (var != alias);
-
-  /* ALIAS must be addressable if it's being added to an alias set.  */
-#if 1
-  TREE_ADDRESSABLE (alias) = 1;
-#else
-  gcc_assert (may_be_aliased (alias));
-#endif
-
-  /* VAR must be a symbol or a name tag.  */
-  gcc_assert (TREE_CODE (var) == SYMBOL_MEMORY_TAG
-              || TREE_CODE (var) == NAME_MEMORY_TAG);
-
-  if (MTAG_ALIASES (var) == NULL)
-    MTAG_ALIASES (var) = BITMAP_ALLOC (&alias_bitmap_obstack);
-  
-  bitmap_set_bit (MTAG_ALIASES (var), DECL_UID (alias));
-}
-
-
-/* Mark pointer PTR as pointing to an arbitrary memory location.  */
+  /* We can end up with dereferencing constant pointers.
+     Just bail out in this case.  */
+  if (TREE_CODE (ptr) == INTEGER_CST)
+    return true;
 
-static void
-set_pt_anything (tree ptr)
-{
-  struct ptr_info_def *pi = get_ptr_info (ptr);
+  /* If we do not have useful points-to information for this pointer
+     we cannot disambiguate anything else.  */
+  pi = SSA_NAME_PTR_INFO (ptr);
+  if (!pi)
+    return true;
 
-  pi->pt_anything = 1;
-  pi->pt_vars = NULL;
+  /* If the decl can be used as a restrict tag and we have a restrict
+     pointer and that pointers points-to set doesn't contain this decl
+     then they can't alias.  */
+  if (DECL_RESTRICTED_P (decl)
+      && TYPE_RESTRICT (TREE_TYPE (ptr))
+      && pi->pt.vars_contains_restrict)
+    return bitmap_bit_p (pi->pt.vars, DECL_UID (decl));
 
-  /* 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)
-    {
-      mark_sym_for_renaming (pi->name_mem_tag);
-      pi->name_mem_tag = NULL_TREE;
-    }
+  return pt_solution_includes (&pi->pt, decl);
 }
 
+/* Return true if dereferenced PTR1 and PTR2 may alias.
+   The caller is responsible for applying TBAA to see if accesses
+   through PTR1 and PTR2 may conflict at all.  */
 
-/* Return true if STMT is an "escape" site from the current function.  Escape
-   sites those statements which might expose the address of a variable
-   outside the current function.  STMT is an escape site iff:
-
-       1- STMT is a function call, or
-       2- STMT is an __asm__ expression, or
-       3- STMT is an assignment to a non-local variable, or
-       4- STMT is a return statement.
-
-   Return the type of escape site found, if we found one, or NO_ESCAPE
-   if none.  */
-
-enum escape_type
-is_escape_site (tree stmt)
-{
-  tree call = get_call_expr_in (stmt);
-  if (call != NULL_TREE)
-    {
-      if (!TREE_SIDE_EFFECTS (call))
-       return ESCAPE_TO_PURE_CONST;
-
-      return ESCAPE_TO_CALL;
+static bool
+ptr_derefs_may_alias_p (tree ptr1, tree ptr2)
+{
+  struct ptr_info_def *pi1, *pi2;
+
+  gcc_assert ((TREE_CODE (ptr1) == SSA_NAME
+              || TREE_CODE (ptr1) == ADDR_EXPR
+              || TREE_CODE (ptr1) == INTEGER_CST)
+             && (TREE_CODE (ptr2) == SSA_NAME
+                 || TREE_CODE (ptr2) == ADDR_EXPR
+                 || TREE_CODE (ptr2) == INTEGER_CST));
+
+  /* ADDR_EXPR pointers either just offset another pointer or directly
+     specify the pointed-to set.  */
+  if (TREE_CODE (ptr1) == ADDR_EXPR)
+    {
+      tree base = get_base_address (TREE_OPERAND (ptr1, 0));
+      if (base
+         && INDIRECT_REF_P (base))
+       ptr1 = TREE_OPERAND (base, 0);
+      else if (base
+              && SSA_VAR_P (base))
+       return ptr_deref_may_alias_decl_p (ptr2, base);
+      else
+       return true;
     }
-  else if (TREE_CODE (stmt) == ASM_EXPR)
-    return ESCAPE_TO_ASM;
-  else if (TREE_CODE (stmt) == GIMPLE_MODIFY_STMT)
+  if (TREE_CODE (ptr2) == ADDR_EXPR)
     {
-      tree lhs = GIMPLE_STMT_OPERAND (stmt, 0);
-
-      /* Get to the base of _REF nodes.  */
-      if (TREE_CODE (lhs) != SSA_NAME)
-       lhs = get_base_address (lhs);
-
-      /* If we couldn't recognize the LHS of the assignment, assume that it
-        is a non-local store.  */
-      if (lhs == NULL_TREE)
-       return ESCAPE_UNKNOWN;
-
-      if (TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == NOP_EXPR
-         || TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == CONVERT_EXPR
-         || TREE_CODE (GIMPLE_STMT_OPERAND (stmt, 1)) == VIEW_CONVERT_EXPR)
-       {
-         tree from
-           = TREE_TYPE (TREE_OPERAND (GIMPLE_STMT_OPERAND (stmt, 1), 0));
-         tree to = TREE_TYPE (GIMPLE_STMT_OPERAND (stmt, 1));
-
-         /* If the RHS is a conversion between a pointer and an integer, the
-            pointer escapes since we can't track the integer.  */
-         if (POINTER_TYPE_P (from) && !POINTER_TYPE_P (to))
-           return ESCAPE_BAD_CAST;
-
-         /* Same if the RHS is a conversion between a regular pointer and a
-            ref-all pointer since we can't track the SMT of the former.  */
-         if (POINTER_TYPE_P (from) && !TYPE_REF_CAN_ALIAS_ALL (from)
-             && POINTER_TYPE_P (to) && TYPE_REF_CAN_ALIAS_ALL (to))
-           return ESCAPE_BAD_CAST;
-       }
-
-      /* If the LHS is an SSA name, it can't possibly represent a non-local
-        memory store.  */
-      if (TREE_CODE (lhs) == SSA_NAME)
-       return NO_ESCAPE;
-
-      /* FIXME: LHS is not an SSA_NAME.  Even if it's an assignment to a
-        local variables we cannot be sure if it will escape, because we
-        don't have information about objects not in SSA form.  Need to
-        implement something along the lines of
-
-        J.-D. Choi, M. Gupta, M. J. Serrano, V. C. Sreedhar, and S. P.
-        Midkiff, ``Escape analysis for java,'' in Proceedings of the
-        Conference on Object-Oriented Programming Systems, Languages, and
-        Applications (OOPSLA), pp. 1-19, 1999.  */
-      return ESCAPE_STORED_IN_GLOBAL;
+      tree base = get_base_address (TREE_OPERAND (ptr2, 0));
+      if (base
+         && INDIRECT_REF_P (base))
+       ptr2 = TREE_OPERAND (base, 0);
+      else if (base
+              && SSA_VAR_P (base))
+       return ptr_deref_may_alias_decl_p (ptr1, base);
+      else
+       return true;
     }
-  else if (TREE_CODE (stmt) == RETURN_EXPR)
-    return ESCAPE_TO_RETURN;
-
-  return NO_ESCAPE;
-}
-
-/* Create a new memory tag of type TYPE.
-   Does NOT push it into the current binding.  */
-
-tree
-create_tag_raw (enum tree_code code, tree type, const char *prefix)
-{
-  tree tmp_var;
-
-  tmp_var = build_decl (code, create_tmp_var_name (prefix), type);
-
-  /* Make the variable writable.  */
-  TREE_READONLY (tmp_var) = 0;
-
-  /* It doesn't start out global.  */
-  MTAG_GLOBAL (tmp_var) = 0;
-  TREE_STATIC (tmp_var) = 0;
-  TREE_USED (tmp_var) = 1;
-
-  return tmp_var;
-}
-
-/* Create a new memory tag of type TYPE.  If IS_TYPE_TAG is true, the tag
-   is considered to represent all the pointers whose pointed-to types are
-   in the same alias set class.  Otherwise, the tag represents a single
-   SSA_NAME pointer variable.  */
-
-static tree
-create_memory_tag (tree type, bool is_type_tag)
-{
-  tree tag = create_tag_raw (is_type_tag ? SYMBOL_MEMORY_TAG : NAME_MEMORY_TAG,
-                            type, (is_type_tag) ? "SMT" : "NMT");
-
-  /* By default, memory tags are local variables.  Alias analysis will
-     determine whether they should be considered globals.  */
-  DECL_CONTEXT (tag) = current_function_decl;
-
-  /* Memory tags are by definition addressable.  */
-  TREE_ADDRESSABLE (tag) = 1;
-
-  set_symbol_mem_tag (tag, NULL_TREE);
 
-  /* Add the tag to the symbol table.  */
-  add_referenced_var (tag);
-
-  return tag;
-}
+  /* We can end up with dereferencing constant pointers.
+     Just bail out in this case.  */
+  if (TREE_CODE (ptr1) == INTEGER_CST
+      || TREE_CODE (ptr2) == INTEGER_CST)
+    return true;
 
+  /* We may end up with two empty points-to solutions for two same pointers.
+     In this case we still want to say both pointers alias, so shortcut
+     that here.  */
+  if (ptr1 == ptr2)
+    return true;
 
-/* Create a name memory tag to represent a specific SSA_NAME pointer P_i.
-   This is used if P_i has been found to point to a specific set of
-   variables or to a non-aliased memory location like the address returned
-   by malloc functions.  */
+  /* If we do not have useful points-to information for either pointer
+     we cannot disambiguate anything else.  */
+  pi1 = SSA_NAME_PTR_INFO (ptr1);
+  pi2 = SSA_NAME_PTR_INFO (ptr2);
+  if (!pi1 || !pi2)
+    return true;
 
-static tree
-get_nmt_for (tree ptr)
-{
-  struct ptr_info_def *pi = get_ptr_info (ptr);
-  tree tag = pi->name_mem_tag;
+  /* If both pointers are restrict-qualified try to disambiguate
+     with restrict information.  */
+  if (TYPE_RESTRICT (TREE_TYPE (ptr1))
+      && TYPE_RESTRICT (TREE_TYPE (ptr2))
+      && !pt_solutions_same_restrict_base (&pi1->pt, &pi2->pt))
+    return false;
 
-  if (tag == NULL_TREE)
-    tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
-  return tag;
+  /* ???  This does not use TBAA to prune decls from the intersection
+     that not both pointers may access.  */
+  return pt_solutions_intersect (&pi1->pt, &pi2->pt);
 }
 
+/* Return true if dereferencing PTR may alias *REF.
+   The caller is responsible for applying TBAA to see if PTR
+   may access *REF at all.  */
 
-/* Return the symbol memory tag associated to pointer PTR.  A memory
-   tag is an artificial variable that represents the memory location
-   pointed-to by PTR.  It is used to model the effects of pointer
-   de-references on addressable variables.
-   
-   AI points to the data gathered during alias analysis.  This
-   function populates the array AI->POINTERS.  */
-
-static tree
-get_smt_for (tree ptr, struct alias_info *ai)
+static bool
+ptr_deref_may_alias_ref_p_1 (tree ptr, ao_ref *ref)
 {
-  size_t i;
-  tree tag;
-  tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
-  HOST_WIDE_INT tag_set = get_alias_set (tag_type);
-
-  /* We use a unique memory tag for all the ref-all pointers.  */
-  if (PTR_IS_REF_ALL (ptr))
-    {
-      if (!ai->ref_all_symbol_mem_tag)
-       ai->ref_all_symbol_mem_tag = create_memory_tag (void_type_node, true);
-      return ai->ref_all_symbol_mem_tag;
-    }
-
-  /* To avoid creating unnecessary memory tags, only create one memory tag
-     per alias set class.  Note that it may be tempting to group
-     memory tags based on conflicting alias sets instead of
-     equivalence.  That would be wrong because alias sets are not
-     necessarily transitive (as demonstrated by the libstdc++ test
-     23_containers/vector/cons/4.cc).  Given three alias sets A, B, C
-     such that conflicts (A, B) == true and conflicts (A, C) == true,
-     it does not necessarily follow that conflicts (B, C) == true.  */
-  for (i = 0, tag = NULL_TREE; i < ai->num_pointers; i++)
-    {
-      struct alias_map_d *curr = ai->pointers[i];
-      tree curr_tag = symbol_mem_tag (curr->var);
-      if (tag_set == curr->set)
-       {
-         tag = curr_tag;
-         break;
-       }
-    }
-
-  /* If VAR cannot alias with any of the existing memory tags, create a new
-     tag for PTR and add it to the POINTERS array.  */
-  if (tag == NULL_TREE)
-    {
-      struct alias_map_d *alias_map;
-
-      /* If PTR did not have a symbol tag already, create a new SMT.*
-        artificial variable representing the memory location
-        pointed-to by PTR.  */
-      tag = symbol_mem_tag (ptr);
-      if (tag == NULL_TREE)
-       tag = create_memory_tag (tag_type, true);
-
-      /* 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
-        PTR points to.  */
-      alias_map = XCNEW (struct alias_map_d);
-      alias_map->var = ptr;
-      alias_map->set = tag_set;
-      ai->pointers[ai->num_pointers++] = alias_map;
-    }
-
-  /* If the pointed-to type is volatile, so is the tag.  */
-  TREE_THIS_VOLATILE (tag) |= TREE_THIS_VOLATILE (tag_type);
-
-  /* Make sure that the symbol tag has the same alias set as the
-     pointed-to type.  */
-  gcc_assert (tag_set == get_alias_set (tag));
-
-  return tag;
-}
-
+  tree base = ao_ref_base (ref);
 
-/* Create GLOBAL_VAR, an artificial global variable to act as a
-   representative of all the variables that may be clobbered by function
-   calls.  */
+  if (INDIRECT_REF_P (base))
+    return ptr_derefs_may_alias_p (ptr, TREE_OPERAND (base, 0));
+  else if (SSA_VAR_P (base))
+    return ptr_deref_may_alias_decl_p (ptr, base);
 
-static void
-create_global_var (void)
-{
-  tree global_var = build_decl (VAR_DECL, get_identifier (".GLOBAL_VAR"),
-                                void_type_node);
-  DECL_ARTIFICIAL (global_var) = 1;
-  TREE_READONLY (global_var) = 0;
-  DECL_EXTERNAL (global_var) = 1;
-  TREE_STATIC (global_var) = 1;
-  TREE_USED (global_var) = 1;
-  DECL_CONTEXT (global_var) = NULL_TREE;
-  TREE_THIS_VOLATILE (global_var) = 0;
-  TREE_ADDRESSABLE (global_var) = 0;
-
-  create_var_ann (global_var);
-  mark_call_clobbered (global_var, ESCAPE_UNKNOWN);
-  add_referenced_var (global_var);
-  mark_sym_for_renaming (global_var);
-  cfun->gimple_df->global_var = global_var;
+  return true;
 }
 
 
-/* Dump alias statistics on FILE.  */
-
-static void 
-dump_alias_stats (FILE *file)
-{
-  const char *funcname
-    = lang_hooks.decl_printable_name (current_function_decl, 2);
-  fprintf (file, "\nAlias statistics for %s\n\n", funcname);
-  fprintf (file, "Total alias queries:\t%u\n", alias_stats.alias_queries);
-  fprintf (file, "Total alias mayalias results:\t%u\n", 
-          alias_stats.alias_mayalias);
-  fprintf (file, "Total alias noalias results:\t%u\n",
-          alias_stats.alias_noalias);
-  fprintf (file, "Total simple queries:\t%u\n",
-          alias_stats.simple_queries);
-  fprintf (file, "Total simple resolved:\t%u\n",
-          alias_stats.simple_resolved);
-  fprintf (file, "Total TBAA queries:\t%u\n",
-          alias_stats.tbaa_queries);
-  fprintf (file, "Total TBAA resolved:\t%u\n",
-          alias_stats.tbaa_resolved);
-  fprintf (file, "Total non-addressable structure type queries:\t%u\n",
-          alias_stats.structnoaddress_queries);
-  fprintf (file, "Total non-addressable structure type resolved:\t%u\n",
-          alias_stats.structnoaddress_resolved);
-}
-  
-
 /* Dump alias information on FILE.  */
 
 void
@@ -2329,58 +322,39 @@ dump_alias_info (FILE *file)
   referenced_var_iterator rvi;
   tree var;
 
-  fprintf (file, "\nFlow-insensitive alias information for %s\n\n", funcname);
+  fprintf (file, "\n\nAlias information for %s\n\n", funcname);
 
   fprintf (file, "Aliased symbols\n\n");
-  
+
   FOR_EACH_REFERENCED_VAR (var, rvi)
     {
       if (may_be_aliased (var))
        dump_variable (file, var);
     }
 
-  fprintf (file, "\nDereferenced pointers\n\n");
-
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    if (symbol_mem_tag (var))
-      dump_variable (file, var);
+  fprintf (file, "\nCall clobber information\n");
 
-  fprintf (file, "\nSymbol memory tags\n\n");
-  
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    {
-      if (TREE_CODE (var) == SYMBOL_MEMORY_TAG)
-       dump_variable (file, var);
-    }
+  fprintf (file, "\nESCAPED");
+  dump_points_to_solution (file, &cfun->gimple_df->escaped);
+  fprintf (file, "\nCALLUSED");
+  dump_points_to_solution (file, &cfun->gimple_df->callused);
 
-  fprintf (file, "\n\nFlow-sensitive alias information for %s\n\n", funcname);
+  fprintf (file, "\n\nFlow-insensitive points-to information\n\n");
 
-  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;
-      
-      if (ptr == NULL_TREE)
+
+      if (ptr == NULL_TREE
+         || SSA_NAME_IN_FREE_LIST (ptr))
        continue;
 
       pi = SSA_NAME_PTR_INFO (ptr);
-      if (!SSA_NAME_IN_FREE_LIST (ptr)
-         && pi
-         && pi->name_mem_tag)
+      if (pi)
        dump_points_to_info_for (file, ptr);
     }
 
-  fprintf (file, "\nName memory tags\n\n");
-  
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    {
-      if (TREE_CODE (var) == NAME_MEMORY_TAG)
-       dump_variable (file, var);
-    }
-
-  dump_memory_partitions (file);
-
   fprintf (file, "\n");
 }
 
@@ -2408,12 +382,38 @@ get_ptr_info (tree t)
   if (pi == NULL)
     {
       pi = GGC_CNEW (struct ptr_info_def);
+      pt_solution_reset (&pi->pt);
       SSA_NAME_PTR_INFO (t) = pi;
     }
 
   return pi;
 }
 
+/* Dump the points-to set *PT into FILE.  */
+
+void
+dump_points_to_solution (FILE *file, struct pt_solution *pt)
+{
+  if (pt->anything)
+    fprintf (file, ", points-to anything");
+
+  if (pt->nonlocal)
+    fprintf (file, ", points-to non-local");
+
+  if (pt->escaped)
+    fprintf (file, ", points-to escaped");
+
+  if (pt->null)
+    fprintf (file, ", points-to NULL");
+
+  if (pt->vars)
+    {
+      fprintf (file, ", points-to vars: ");
+      dump_decl_set (file, pt->vars);
+      if (pt->vars_contains_global)
+       fprintf (file, " (includes global vars)");
+    }
+}
 
 /* Dump points-to information for SSA_NAME PTR into FILE.  */
 
@@ -2425,31 +425,9 @@ dump_points_to_info_for (FILE *file, tree ptr)
   print_generic_expr (file, ptr, dump_flags);
 
   if (pi)
-    {
-      if (pi->name_mem_tag)
-       {
-         fprintf (file, ", name memory tag: ");
-         print_generic_expr (file, pi->name_mem_tag, dump_flags);
-       }
-
-      if (pi->is_dereferenced)
-       fprintf (file, ", is dereferenced");
-
-      if (pi->value_escapes_p)
-       fprintf (file, ", its value escapes");
-
-      if (pi->pt_anything)
-       fprintf (file, ", points-to anything");
-
-      if (pi->pt_null)
-       fprintf (file, ", points-to NULL");
-
-      if (pi->pt_vars)
-       {
-         fprintf (file, ", points-to vars: ");
-         dump_decl_set (file, pi->pt_vars);
-       }
-    }
+    dump_points_to_solution (file, &pi->pt);
+  else
+    fprintf (file, ", points-to anything");
 
   fprintf (file, "\n");
 }
@@ -2464,847 +442,1145 @@ debug_points_to_info_for (tree var)
 }
 
 
-/* Dump points-to information into FILE.  NOTE: This function is slow, as
-   it needs to traverse the whole CFG looking for pointer SSA_NAMEs.  */
+/* Initializes the alias-oracle reference representation *R from REF.  */
 
 void
-dump_points_to_info (FILE *file)
+ao_ref_init (ao_ref *r, tree ref)
 {
-  basic_block bb;
-  block_stmt_iterator si;
-  ssa_op_iter iter;
-  const char *fname =
-    lang_hooks.decl_printable_name (current_function_decl, 2);
-  referenced_var_iterator rvi;
-  tree var;
+  r->ref = ref;
+  r->base = NULL_TREE;
+  r->offset = 0;
+  r->size = -1;
+  r->max_size = -1;
+  r->ref_alias_set = -1;
+  r->base_alias_set = -1;
+}
 
-  fprintf (file, "\n\nPointed-to sets for pointers in %s\n\n", fname);
+/* Returns the base object of the memory reference *REF.  */
 
-  /* First dump points-to information for the default definitions of
-     pointer variables.  This is necessary because default definitions are
-     not part of the code.  */
-  FOR_EACH_REFERENCED_VAR (var, rvi)
+tree
+ao_ref_base (ao_ref *ref)
+{
+  if (ref->base)
+    return ref->base;
+  ref->base = get_ref_base_and_extent (ref->ref, &ref->offset, &ref->size,
+                                      &ref->max_size);
+  return ref->base;
+}
+
+/* Returns the base object alias set of the memory reference *REF.  */
+
+static alias_set_type ATTRIBUTE_UNUSED
+ao_ref_base_alias_set (ao_ref *ref)
+{
+  if (ref->base_alias_set != -1)
+    return ref->base_alias_set;
+  ref->base_alias_set = get_alias_set (ao_ref_base (ref));
+  return ref->base_alias_set;
+}
+
+/* Returns the reference alias set of the memory reference *REF.  */
+
+alias_set_type
+ao_ref_alias_set (ao_ref *ref)
+{
+  if (ref->ref_alias_set != -1)
+    return ref->ref_alias_set;
+  ref->ref_alias_set = get_alias_set (ref->ref);
+  return ref->ref_alias_set;
+}
+
+/* Init an alias-oracle reference representation from a gimple pointer
+   PTR and a gimple size SIZE in bytes.  If SIZE is NULL_TREE the the
+   size is assumed to be unknown.  The access is assumed to be only
+   to or after of the pointer target, not before it.  */
+
+void
+ao_ref_init_from_ptr_and_size (ao_ref *ref, tree ptr, tree size)
+{
+  HOST_WIDE_INT t1, t2;
+  ref->ref = NULL_TREE;
+  if (TREE_CODE (ptr) == ADDR_EXPR)
+    ref->base = get_ref_base_and_extent (TREE_OPERAND (ptr, 0),
+                                        &ref->offset, &t1, &t2);
+  else
     {
-      if (POINTER_TYPE_P (TREE_TYPE (var)))
-       {
-         tree def = gimple_default_def (cfun, var);
-         if (def)
-           dump_points_to_info_for (file, def);
-       }
+      ref->base = build1 (INDIRECT_REF, char_type_node, ptr);
+      ref->offset = 0;
     }
+  if (size
+      && host_integerp (size, 0)
+      && TREE_INT_CST_LOW (size) * 8 / 8 == TREE_INT_CST_LOW (size))
+    ref->max_size = ref->size = TREE_INT_CST_LOW (size) * 8;
+  else
+    ref->max_size = ref->size = -1;
+  ref->ref_alias_set = 0;
+  ref->base_alias_set = 0;
+}
 
-  /* Dump points-to information for every pointer defined in the program.  */
-  FOR_EACH_BB (bb)
-    {
-      tree phi;
+/* Return 1 if TYPE1 and TYPE2 are to be considered equivalent for the
+   purpose of TBAA.  Return 0 if they are distinct and -1 if we cannot
+   decide.  */
 
-      for (phi = phi_nodes (bb); phi; phi = PHI_CHAIN (phi))
-       {
-         tree ptr = PHI_RESULT (phi);
-         if (POINTER_TYPE_P (TREE_TYPE (ptr)))
-           dump_points_to_info_for (file, ptr);
-       }
+static inline int
+same_type_for_tbaa (tree type1, tree type2)
+{
+  type1 = TYPE_MAIN_VARIANT (type1);
+  type2 = TYPE_MAIN_VARIANT (type2);
 
-       for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
-         {
-           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);
-         }
-    }
+  /* If we would have to do structural comparison bail out.  */
+  if (TYPE_STRUCTURAL_EQUALITY_P (type1)
+      || TYPE_STRUCTURAL_EQUALITY_P (type2))
+    return -1;
 
-  fprintf (file, "\n");
+  /* Compare the canonical types.  */
+  if (TYPE_CANONICAL (type1) == TYPE_CANONICAL (type2))
+    return 1;
+
+  /* ???  Array types are not properly unified in all cases as we have
+     spurious changes in the index types for example.  Removing this
+     causes all sorts of problems with the Fortran frontend.  */
+  if (TREE_CODE (type1) == ARRAY_TYPE
+      && TREE_CODE (type2) == ARRAY_TYPE)
+    return -1;
+
+  /* The types are known to be not equal.  */
+  return 0;
 }
 
+/* Determine if the two component references REF1 and REF2 which are
+   based on access types TYPE1 and TYPE2 and of which at least one is based
+   on an indirect reference may alias.  */
 
-/* Dump points-to info pointed to by PTO into STDERR.  */
+static bool
+aliasing_component_refs_p (tree ref1, tree type1,
+                          HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+                          tree ref2, tree type2,
+                          HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2)
+{
+  /* If one reference is a component references through pointers try to find a
+     common base and apply offset based disambiguation.  This handles
+     for example
+       struct A { int i; int j; } *q;
+       struct B { struct A a; int k; } *p;
+     disambiguating q->i and p->a.j.  */
+  tree *refp;
+  int same_p;
+
+  /* Now search for the type1 in the access path of ref2.  This
+     would be a common base for doing offset based disambiguation on.  */
+  refp = &ref2;
+  while (handled_component_p (*refp)
+        && same_type_for_tbaa (TREE_TYPE (*refp), type1) == 0)
+    refp = &TREE_OPERAND (*refp, 0);
+  same_p = same_type_for_tbaa (TREE_TYPE (*refp), type1);
+  /* If we couldn't compare types we have to bail out.  */
+  if (same_p == -1)
+    return true;
+  else if (same_p == 1)
+    {
+      HOST_WIDE_INT offadj, sztmp, msztmp;
+      get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp);
+      offset2 -= offadj;
+      return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+    }
+  /* If we didn't find a common base, try the other way around.  */
+  refp = &ref1;
+  while (handled_component_p (*refp)
+        && same_type_for_tbaa (TREE_TYPE (*refp), type2) == 0)
+    refp = &TREE_OPERAND (*refp, 0);
+  same_p = same_type_for_tbaa (TREE_TYPE (*refp), type2);
+  /* If we couldn't compare types we have to bail out.  */
+  if (same_p == -1)
+    return true;
+  else if (same_p == 1)
+    {
+      HOST_WIDE_INT offadj, sztmp, msztmp;
+      get_ref_base_and_extent (*refp, &offadj, &sztmp, &msztmp);
+      offset1 -= offadj;
+      return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+    }
 
-void
-debug_points_to_info (void)
-{
-  dump_points_to_info (stderr);
+  /* We haven't found any common base to apply offset-based disambiguation.
+     There are two cases:
+       1. The base access types have the same alias set.  This can happen
+         in Ada when a function with an unconstrained parameter passed by
+         reference is called on a constrained object and inlined: the types
+         have the same alias set but aren't equivalent.  The references may
+         alias in this case.
+       2. The base access types don't have the same alias set, i.e. one set
+         is a subset of the other.  We have proved that B1 is not in the
+         access path B2.path and that B2 is not in the access path B1.path
+         so the references may not alias.  */
+  return get_alias_set (type1) == get_alias_set (type2);
 }
 
-/* Dump to FILE the list of variables that may be aliasing VAR.  */
+/* Return true if two memory references based on the variables BASE1
+   and BASE2 constrained to [OFFSET1, OFFSET1 + MAX_SIZE1) and
+   [OFFSET2, OFFSET2 + MAX_SIZE2) may alias.  */
 
-void
-dump_may_aliases_for (FILE *file, tree var)
+static bool
+decl_refs_may_alias_p (tree base1,
+                      HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+                      tree base2,
+                      HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2)
 {
-  bitmap aliases;
-  
-  aliases = MTAG_ALIASES (var);
-  if (aliases)
-    {
-      bitmap_iterator bi;
-      unsigned int i;
-      tree al;
+  gcc_assert (SSA_VAR_P (base1) && SSA_VAR_P (base2));
 
-      fprintf (file, "{ ");
-      EXECUTE_IF_SET_IN_BITMAP (aliases, 0, i, bi)
-       {
-         al = referenced_var (i);
-         print_generic_expr (file, al, dump_flags);
-         fprintf (file, " ");
-       }
-      fprintf (file, "}");
-    }
+  /* If both references are based on different variables, they cannot alias.  */
+  if (!operand_equal_p (base1, base2, 0))
+    return false;
+
+  /* If both references are based on the same variable, they cannot alias if
+     the accesses do not overlap.  */
+  return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
 }
 
+/* Return true if an indirect reference based on *PTR1 constrained
+   to [OFFSET1, OFFSET1 + MAX_SIZE1) may alias a variable based on BASE2
+   constrained to [OFFSET2, OFFSET2 + MAX_SIZE2).  *PTR1 and BASE2 have
+   the alias sets BASE1_ALIAS_SET and BASE2_ALIAS_SET which can be -1
+   in which case they are computed on-demand.  REF1 and REF2
+   if non-NULL are the complete memory reference trees.  */
+
+static bool
+indirect_ref_may_alias_decl_p (tree ref1, tree ptr1,
+                              HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+                              alias_set_type base1_alias_set,
+                              tree ref2, tree base2,
+                              HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
+                              alias_set_type base2_alias_set)
+{
+  /* If only one reference is based on a variable, they cannot alias if
+     the pointer access is beyond the extent of the variable access.
+     (the pointer base cannot validly point to an offset less than zero
+     of the variable).
+     They also cannot alias if the pointer may not point to the decl.  */
+  if (max_size2 != -1
+      && !ranges_overlap_p (offset1, max_size1, 0, offset2 + max_size2))
+    return false;
+  if (!ptr_deref_may_alias_decl_p (ptr1, base2))
+    return false;
 
-/* Dump to stderr the list of variables that may be aliasing VAR.  */
+  /* Disambiguations that rely on strict aliasing rules follow.  */
+  if (!flag_strict_aliasing)
+    return true;
 
-void
-debug_may_aliases_for (tree var)
-{
-  dump_may_aliases_for (stderr, var);
+  /* If the alias set for a pointer access is zero all bets are off.  */
+  if (base1_alias_set == -1)
+    base1_alias_set = get_deref_alias_set (ptr1);
+  if (base1_alias_set == 0)
+    return true;
+  if (base2_alias_set == -1)
+    base2_alias_set = get_alias_set (base2);
+
+  /* If both references are through the same type, they do not alias
+     if the accesses do not overlap.  This does extra disambiguation
+     for mixed/pointer accesses but requires strict aliasing.  */
+  if (same_type_for_tbaa (TREE_TYPE (TREE_TYPE (ptr1)),
+                         TREE_TYPE (base2)) == 1)
+    return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+
+  /* The only way to access a variable is through a pointer dereference
+     of the same alias set or a subset of it.  */
+  if (base1_alias_set != base2_alias_set
+      && !alias_set_subset_of (base1_alias_set, base2_alias_set))
+    return false;
+
+  /* Do access-path based disambiguation.  */
+  if (ref1 && ref2
+      && handled_component_p (ref1)
+      && handled_component_p (ref2))
+    return aliasing_component_refs_p (ref1, TREE_TYPE (TREE_TYPE (ptr1)),
+                                     offset1, max_size1,
+                                     ref2, TREE_TYPE (base2),
+                                     offset2, max_size2);
+
+  return true;
 }
 
+/* Return true if two indirect references based on *PTR1
+   and *PTR2 constrained to [OFFSET1, OFFSET1 + MAX_SIZE1) and
+   [OFFSET2, OFFSET2 + MAX_SIZE2) may alias.  *PTR1 and *PTR2 have
+   the alias sets BASE1_ALIAS_SET and BASE2_ALIAS_SET which can be -1
+   in which case they are computed on-demand.  REF1 and REF2
+   if non-NULL are the complete memory reference trees. */
 
-/* Return true if VAR may be aliased.  */
+static bool
+indirect_refs_may_alias_p (tree ref1, tree ptr1,
+                          HOST_WIDE_INT offset1, HOST_WIDE_INT max_size1,
+                          alias_set_type base1_alias_set,
+                          tree ref2, tree ptr2,
+                          HOST_WIDE_INT offset2, HOST_WIDE_INT max_size2,
+                          alias_set_type base2_alias_set)
+{
+  /* If both bases are based on pointers they cannot alias if they may not
+     point to the same memory object or if they point to the same object
+     and the accesses do not overlap.  */
+  if (operand_equal_p (ptr1, ptr2, 0))
+    return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
+  if (!ptr_derefs_may_alias_p (ptr1, ptr2))
+    return false;
 
-bool
-may_be_aliased (tree var)
-{
-  /* Obviously.  */
-  if (TREE_ADDRESSABLE (var))
+  /* Disambiguations that rely on strict aliasing rules follow.  */
+  if (!flag_strict_aliasing)
     return true;
 
-  /* Globally visible variables can have their addresses taken by other
-     translation units.  */
-  if (MTAG_P (var)
-      && (MTAG_GLOBAL (var) || TREE_PUBLIC (var)))
+  /* If the alias set for a pointer access is zero all bets are off.  */
+  if (base1_alias_set == -1)
+    base1_alias_set = get_deref_alias_set (ptr1);
+  if (base1_alias_set == 0)
     return true;
-  else if (!MTAG_P (var)
-           && (DECL_EXTERNAL (var) || TREE_PUBLIC (var)))
+  if (base2_alias_set == -1)
+    base2_alias_set = get_deref_alias_set (ptr2);
+  if (base2_alias_set == 0)
     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 both references are through the same type, they do not alias
+     if the accesses do not overlap.  This does extra disambiguation
+     for mixed/pointer accesses but requires strict aliasing.  */
+  if (same_type_for_tbaa (TREE_TYPE (TREE_TYPE (ptr1)),
+                         TREE_TYPE (TREE_TYPE (ptr2))) == 1)
+    return ranges_overlap_p (offset1, max_size1, offset2, max_size2);
 
-  /* 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)
+  /* Do type-based disambiguation.  */
+  if (base1_alias_set != base2_alias_set
+      && !alias_sets_conflict_p (base1_alias_set, base2_alias_set))
     return false;
 
-  if (decl_function_context (var) == current_function_decl)
-    return false;
+  /* Do access-path based disambiguation.  */
+  if (ref1 && ref2
+      && handled_component_p (ref1)
+      && handled_component_p (ref2))
+    return aliasing_component_refs_p (ref1, TREE_TYPE (TREE_TYPE (ptr1)),
+                                     offset1, max_size1,
+                                     ref2, TREE_TYPE (TREE_TYPE (ptr2)),
+                                     offset2, max_size2);
 
   return true;
 }
 
-
-/* Given two symbols return TRUE if one is in the alias set of the
-   other.  */
+/* Return true, if the two memory references REF1 and REF2 may alias.  */
 
 bool
-is_aliased_with (tree tag, tree sym)
-{
-  bitmap aliases;
+refs_may_alias_p_1 (ao_ref *ref1, ao_ref *ref2, bool tbaa_p)
+{
+  tree base1, base2;
+  HOST_WIDE_INT offset1 = 0, offset2 = 0;
+  HOST_WIDE_INT max_size1 = -1, max_size2 = -1;
+  bool var1_p, var2_p, ind1_p, ind2_p;
+  alias_set_type set;
+
+  gcc_assert ((!ref1->ref
+              || SSA_VAR_P (ref1->ref)
+              || handled_component_p (ref1->ref)
+              || INDIRECT_REF_P (ref1->ref)
+              || TREE_CODE (ref1->ref) == TARGET_MEM_REF
+              || TREE_CODE (ref1->ref) == CONST_DECL)
+             && (!ref2->ref
+                 || SSA_VAR_P (ref2->ref)
+                 || handled_component_p (ref2->ref)
+                 || INDIRECT_REF_P (ref2->ref)
+                 || TREE_CODE (ref2->ref) == TARGET_MEM_REF
+                 || TREE_CODE (ref2->ref) == CONST_DECL));
+
+  /* Decompose the references into their base objects and the access.  */
+  base1 = ao_ref_base (ref1);
+  offset1 = ref1->offset;
+  max_size1 = ref1->max_size;
+  base2 = ao_ref_base (ref2);
+  offset2 = ref2->offset;
+  max_size2 = ref2->max_size;
+
+  /* We can end up with registers or constants as bases for example from
+     *D.1663_44 = VIEW_CONVERT_EXPR<struct DB_LSN>(__tmp$B0F64_59);
+     which is seen as a struct copy.  */
+  if (TREE_CODE (base1) == SSA_NAME
+      || TREE_CODE (base2) == SSA_NAME
+      || TREE_CODE (base1) == CONST_DECL
+      || TREE_CODE (base2) == CONST_DECL
+      || is_gimple_min_invariant (base1)
+      || is_gimple_min_invariant (base2))
+    return false;
 
-  if (MTAG_P (tag))
-    {
-      aliases = MTAG_ALIASES (tag);
+  /* We can end up refering to code via function decls.  As we likely
+     do not properly track code aliases conservatively bail out.  */
+  if (TREE_CODE (base1) == FUNCTION_DECL
+      || TREE_CODE (base2) == FUNCTION_DECL)
+    return true;
 
-      if (aliases == NULL)
-       return false;
+  /* Defer to simple offset based disambiguation if we have
+     references based on two decls.  Do this before defering to
+     TBAA to handle must-alias cases in conformance with the
+     GCC extension of allowing type-punning through unions.  */
+  var1_p = SSA_VAR_P (base1);
+  var2_p = SSA_VAR_P (base2);
+  if (var1_p && var2_p)
+    return decl_refs_may_alias_p (base1, offset1, max_size1,
+                                 base2, offset2, max_size2);
+
+  /* First defer to TBAA if possible.  */
+  if (tbaa_p
+      && flag_strict_aliasing
+      && !alias_sets_conflict_p (ao_ref_alias_set (ref1),
+                                ao_ref_alias_set (ref2)))
+    return false;
 
-      return bitmap_bit_p (aliases, DECL_UID (sym));      
-    }
+  /* If one reference is a TARGET_MEM_REF weird things are allowed.  Still
+     TBAA disambiguation based on the access type is possible, so bail
+     out only after that check.  */
+  if ((ref1->ref && TREE_CODE (ref1->ref) == TARGET_MEM_REF)
+      || (ref2->ref && TREE_CODE (ref2->ref) == TARGET_MEM_REF))
+    return true;
+
+  /* Dispatch to the pointer-vs-decl or pointer-vs-pointer disambiguators.  */
+  ind1_p = INDIRECT_REF_P (base1);
+  ind2_p = INDIRECT_REF_P (base2);
+  set = tbaa_p ? -1 : 0;
+  if (var1_p && ind2_p)
+    return indirect_ref_may_alias_decl_p (ref2->ref, TREE_OPERAND (base2, 0),
+                                         offset2, max_size2, set,
+                                         ref1->ref, base1,
+                                         offset1, max_size1, set);
+  else if (ind1_p && var2_p)
+    return indirect_ref_may_alias_decl_p (ref1->ref, TREE_OPERAND (base1, 0),
+                                         offset1, max_size1, set,
+                                         ref2->ref, base2,
+                                         offset2, max_size2, set);
+  else if (ind1_p && ind2_p)
+    return indirect_refs_may_alias_p (ref1->ref, TREE_OPERAND (base1, 0),
+                                     offset1, max_size1, set,
+                                     ref2->ref, TREE_OPERAND (base2, 0),
+                                     offset2, max_size2, set);
+
+  gcc_unreachable ();
+}
+
+bool
+refs_may_alias_p (tree ref1, tree ref2)
+{
+  ao_ref r1, r2;
+  bool res;
+  ao_ref_init (&r1, ref1);
+  ao_ref_init (&r2, ref2);
+  res = refs_may_alias_p_1 (&r1, &r2, true);
+  if (res)
+    ++alias_stats.refs_may_alias_p_may_alias;
   else
-    {
-      gcc_assert (MTAG_P (sym));
-      aliases = MTAG_ALIASES (sym);
+    ++alias_stats.refs_may_alias_p_no_alias;
+  return res;
+}
 
-      if (aliases == NULL)
-       return false;
+/* Returns true if there is a anti-dependence for the STORE that
+   executes after the LOAD.  */
 
-      return bitmap_bit_p (aliases, DECL_UID (tag));
-    }
+bool
+refs_anti_dependent_p (tree load, tree store)
+{
+  ao_ref r1, r2;
+  ao_ref_init (&r1, load);
+  ao_ref_init (&r2, store);
+  return refs_may_alias_p_1 (&r1, &r2, false);
+}
 
-  return false;
+/* Returns true if there is a output dependence for the stores
+   STORE1 and STORE2.  */
+
+bool
+refs_output_dependent_p (tree store1, tree store2)
+{
+  ao_ref r1, r2;
+  ao_ref_init (&r1, store1);
+  ao_ref_init (&r2, store2);
+  return refs_may_alias_p_1 (&r1, &r2, false);
 }
 
-/* The following is based on code in add_stmt_operand to ensure that the
-   same defs/uses/vdefs/vuses will be found after replacing a reference
-   to var (or ARRAY_REF to var) with an INDIRECT_REF to ptr whose value
-   is the address of var.  Return a memtag for the ptr, after adding the 
-   proper may_aliases to it (which are the aliases of var, if it has any,
-   or var itself).  */
+/* If the call CALL may use the memory reference REF return true,
+   otherwise return false.  */
 
-static tree
-add_may_alias_for_new_tag (tree tag, tree var)
+static bool
+ref_maybe_used_by_call_p_1 (gimple call, ao_ref *ref)
 {
-  bitmap aliases = NULL;
-  
-  if (MTAG_P (var))
-    aliases = may_aliases (var);
+  tree base, callee;
+  unsigned i;
+  int flags = gimple_call_flags (call);
+
+  /* Const functions without a static chain do not implicitly use memory.  */
+  if (!gimple_call_chain (call)
+      && (flags & (ECF_CONST|ECF_NOVOPS)))
+    goto process_args;
+
+  base = ao_ref_base (ref);
+  if (!base)
+    return true;
+
+  /* If the reference is based on a decl that is not aliased the call
+     cannot possibly use it.  */
+  if (DECL_P (base)
+      && !may_be_aliased (base)
+      /* But local statics can be used through recursion.  */
+      && !is_global_var (base))
+    goto process_args;
+
+  callee = gimple_call_fndecl (call);
+
+  /* Handle those builtin functions explicitly that do not act as
+     escape points.  See tree-ssa-structalias.c:find_func_aliases
+     for the list of builtins we might need to handle here.  */
+  if (callee != NULL_TREE
+      && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (callee))
+      {
+       /* All the following functions clobber memory pointed to by
+          their first argument.  */
+       case BUILT_IN_STRCPY:
+       case BUILT_IN_STRNCPY:
+       case BUILT_IN_MEMCPY:
+       case BUILT_IN_MEMMOVE:
+       case BUILT_IN_MEMPCPY:
+       case BUILT_IN_STPCPY:
+       case BUILT_IN_STPNCPY:
+       case BUILT_IN_STRCAT:
+       case BUILT_IN_STRNCAT:
+         {
+           ao_ref dref;
+           tree size = NULL_TREE;
+           if (gimple_call_num_args (call) == 3)
+             size = gimple_call_arg (call, 2);
+           ao_ref_init_from_ptr_and_size (&dref,
+                                          gimple_call_arg (call, 1),
+                                          size);
+           return refs_may_alias_p_1 (&dref, ref, false);
+         }
+       case BUILT_IN_BCOPY:
+         {
+           ao_ref dref;
+           tree size = gimple_call_arg (call, 2);
+           ao_ref_init_from_ptr_and_size (&dref,
+                                          gimple_call_arg (call, 0),
+                                          size);
+           return refs_may_alias_p_1 (&dref, ref, false);
+         }
+       /* The following builtins do not read from memory.  */
+       case BUILT_IN_FREE:
+       case BUILT_IN_MALLOC:
+       case BUILT_IN_MEMSET:
+       case BUILT_IN_FREXP:
+       case BUILT_IN_FREXPF:
+       case BUILT_IN_FREXPL:
+       case BUILT_IN_GAMMA_R:
+       case BUILT_IN_GAMMAF_R:
+       case BUILT_IN_GAMMAL_R:
+       case BUILT_IN_LGAMMA_R:
+       case BUILT_IN_LGAMMAF_R:
+       case BUILT_IN_LGAMMAL_R:
+       case BUILT_IN_MODF:
+       case BUILT_IN_MODFF:
+       case BUILT_IN_MODFL:
+       case BUILT_IN_REMQUO:
+       case BUILT_IN_REMQUOF:
+       case BUILT_IN_REMQUOL:
+       case BUILT_IN_SINCOS:
+       case BUILT_IN_SINCOSF:
+       case BUILT_IN_SINCOSL:
+         return false;
+
+       default:
+         /* Fallthru to general call handling.  */;
+      }
 
-  /* Case 1: |aliases| == 1  */
-  if (aliases && bitmap_count_bits (aliases) == 1)
+  /* Check if base is a global static variable that is not read
+     by the function.  */
+  if (TREE_CODE (base) == VAR_DECL
+      && TREE_STATIC (base)
+      && !TREE_PUBLIC (base))
     {
-      tree ali = referenced_var (bitmap_first_set_bit (aliases));
-      if (TREE_CODE (ali) == SYMBOL_MEMORY_TAG)
-        return ali;
+      bitmap not_read;
+
+      if (callee != NULL_TREE
+         && (not_read
+               = ipa_reference_get_not_read_global (cgraph_node (callee)))
+         && bitmap_bit_p (not_read, DECL_UID (base)))
+       goto process_args;
     }
 
-  /* Case 2: |aliases| == 0  */
-  if (aliases == NULL)
-    add_may_alias (tag, var);
-  else
+  /* If the base variable is call-used or call-clobbered then
+     it may be used.  */
+  if (flags & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
     {
-      /* Case 3: |aliases| > 1  */
-      union_alias_set_into (tag, aliases);
+      if (DECL_P (base))
+       {
+         if (is_call_used (base))
+           return true;
+       }
+      else if (INDIRECT_REF_P (base)
+              && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
+       {
+         struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
+         if (!pi)
+           return true;
+
+         if (pt_solution_includes_global (&pi->pt)
+             || pt_solutions_intersect (&cfun->gimple_df->callused, &pi->pt)
+             || pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt))
+           return true;
+       }
+      else
+       return true;
     }
-  return tag;
-}
-
-/* Create a new symbol tag for PTR.  Construct the may-alias list of this type
-   tag so that it has the aliasing of VAR, or of the relevant subvars of VAR
-   according to the location accessed by EXPR.
-
-   Note, the set of aliases represented by the new symbol tag are not marked
-   for renaming.  */
-
-void
-new_type_alias (tree ptr, tree var, tree expr)
-{
-  tree tag_type = TREE_TYPE (TREE_TYPE (ptr));
-  tree tag;
-  subvar_t svars;
-  tree ali = NULL_TREE;
-  HOST_WIDE_INT offset, size, maxsize;
-  tree ref;
-  VEC (tree, heap) *overlaps = NULL;
-  subvar_t sv;
-  unsigned int len;
-
-  gcc_assert (symbol_mem_tag (ptr) == NULL_TREE);
-  gcc_assert (!MTAG_P (var));
-
-  ref = get_ref_base_and_extent (expr, &offset, &size, &maxsize);
-  gcc_assert (ref);
-
-  tag = create_memory_tag (tag_type, true);
-  set_symbol_mem_tag (ptr, tag);
-
-  /* Add VAR to the may-alias set of PTR's new symbol tag.  If VAR has
-     subvars, add the subvars to the tag instead of the actual var.  */
-  if (var_can_have_subvars (ref)
-      && (svars = get_subvars_for_var (ref)))
+  else
     {
-      for (sv = svars; sv; sv = sv->next)
+      if (DECL_P (base))
+       {
+         if (is_call_clobbered (base))
+           return true;
+       }
+      else if (INDIRECT_REF_P (base)
+              && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
        {
-          bool exact;
+         struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
+         if (!pi)
+           return true;
 
-          if (overlap_subvar (offset, maxsize, sv->var, &exact))
-            VEC_safe_push (tree, heap, overlaps, sv->var);
-        }
-      gcc_assert (overlaps != NULL);
+         if (pt_solution_includes_global (&pi->pt)
+             || pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt))
+           return true;
+       }
+      else
+       return true;
     }
-  else if (var_can_have_subvars (var)
-          && (svars = get_subvars_for_var (var)))
+
+  /* Inspect call arguments for passed-by-value aliases.  */
+process_args:
+  for (i = 0; i < gimple_call_num_args (call); ++i)
     {
-      /* If the REF is not a direct access to VAR (e.g., it is a dereference
-        of a pointer), we should scan the virtual operands of REF the same
-        way as tree-ssa-operands do.  At the moment, this is somewhat
-        difficult, so we just give up and add all the subvars of VAR.
-        On mem-ssa branch, the scanning for virtual operands have been
-        split from the rest of tree-ssa-operands, so it should be much
-        easier to fix this problem correctly once mem-ssa is merged.  */
-      for (sv = svars; sv; sv = sv->next)
-       VEC_safe_push (tree, heap, overlaps, sv->var);
-
-      gcc_assert (overlaps != NULL);
+      tree op = gimple_call_arg (call, i);
+
+      if (TREE_CODE (op) == WITH_SIZE_EXPR)
+       op = TREE_OPERAND (op, 0);
+
+      if (TREE_CODE (op) != SSA_NAME
+         && !is_gimple_min_invariant (op))
+       {
+         ao_ref r;
+         ao_ref_init (&r, op);
+         if (refs_may_alias_p_1 (&r, ref, true))
+           return true;
+       }
     }
+
+  return false;
+}
+
+static bool
+ref_maybe_used_by_call_p (gimple call, tree ref)
+{
+  ao_ref r;
+  bool res;
+  ao_ref_init (&r, ref);
+  res = ref_maybe_used_by_call_p_1 (call, &r);
+  if (res)
+    ++alias_stats.ref_maybe_used_by_call_p_may_alias;
   else
-    ali = add_may_alias_for_new_tag (tag, var);
+    ++alias_stats.ref_maybe_used_by_call_p_no_alias;
+  return res;
+}
+
+
+/* If the statement STMT may use the memory reference REF return
+   true, otherwise return false.  */
 
-  len = VEC_length (tree, overlaps);
-  if (len > 0)
+bool
+ref_maybe_used_by_stmt_p (gimple stmt, tree ref)
+{
+  if (is_gimple_assign (stmt))
     {
-      if (dump_file && (dump_flags & TDF_DETAILS))
-       fprintf (dump_file, "\nnumber of overlapping subvars = %u\n", len);
+      tree rhs;
 
-      if (len == 1)
-       ali = add_may_alias_for_new_tag (tag, VEC_index (tree, overlaps, 0));
-      else if (len > 1)
-       {
-         unsigned int k;
-         tree sv_var;
+      /* All memory assign statements are single.  */
+      if (!gimple_assign_single_p (stmt))
+       return false;
 
-         for (k = 0; VEC_iterate (tree, overlaps, k, sv_var); k++)
-           {
-             ali = add_may_alias_for_new_tag (tag, sv_var);
+      rhs = gimple_assign_rhs1 (stmt);
+      if (is_gimple_reg (rhs)
+         || is_gimple_min_invariant (rhs)
+         || gimple_assign_rhs_code (stmt) == CONSTRUCTOR)
+       return false;
 
-             if (ali != tag)
-               {
-                 /* Can happen only if 'Case 1' of add_may_alias_for_new_tag
-                    took place.  Since more than one svar was found, we add 
-                    'ali' as one of the may_aliases of the new tag.  */ 
-                 add_may_alias (tag, ali);
-                 ali = tag;
-               }
-           }
-       }
-      VEC_free (tree, heap, overlaps);
+      return refs_may_alias_p (rhs, ref);
     }
+  else if (is_gimple_call (stmt))
+    return ref_maybe_used_by_call_p (stmt, ref);
 
-  set_symbol_mem_tag (ptr, ali);
-  TREE_READONLY (tag) = TREE_READONLY (var);
-  MTAG_GLOBAL (tag) = is_global_var (var);
+  return true;
 }
 
-/* This represents the used range of a variable.  */
+/* If the call in statement CALL may clobber the memory reference REF
+   return true, otherwise return false.  */
 
-typedef struct used_part
-{
-  HOST_WIDE_INT minused;
-  HOST_WIDE_INT maxused;
-  /* True if we have an explicit use/def of some portion of this variable,
-     even if it is all of it. i.e. a.b = 5 or temp = a.b.  */
-  bool explicit_uses;
-  /* True if we have an implicit use/def of some portion of this
-     variable.  Implicit uses occur when we can't tell what part we
-     are referencing, and have to make conservative assumptions.  */
-  bool implicit_uses;
-  /* True if the structure is only written to or taken its address.  */
-  bool write_only;
-} *used_part_t;
-
-/* An array of used_part structures, indexed by variable uid.  */
-
-static htab_t used_portions;
-
-struct used_part_map
+static bool
+call_may_clobber_ref_p_1 (gimple call, ao_ref *ref)
 {
-  unsigned int uid;
-  used_part_t to;
-};
+  tree base;
+  tree callee;
 
-/* Return true if the uid in the two used part maps are equal.  */
+  /* If the call is pure or const it cannot clobber anything.  */
+  if (gimple_call_flags (call)
+      & (ECF_PURE|ECF_CONST|ECF_LOOPING_CONST_OR_PURE|ECF_NOVOPS))
+    return false;
 
-static int
-used_part_map_eq (const void *va, const void *vb)
-{
-  const struct used_part_map *a = (const struct used_part_map *) va;
-  const struct used_part_map *b = (const struct used_part_map *) vb;
-  return (a->uid == b->uid);
-}
+  base = ao_ref_base (ref);
+  if (!base)
+    return true;
 
-/* Hash a from uid in a used_part_map.  */
+  if (TREE_CODE (base) == SSA_NAME
+      || CONSTANT_CLASS_P (base))
+    return false;
 
-static unsigned int
-used_part_map_hash (const void *item)
-{
-  return ((const struct used_part_map *)item)->uid;
-}
+  /* If the reference is based on a decl that is not aliased the call
+     cannot possibly clobber it.  */
+  if (DECL_P (base)
+      && !may_be_aliased (base)
+      /* But local non-readonly statics can be modified through recursion
+         or the call may implement a threading barrier which we must
+        treat as may-def.  */
+      && (TREE_READONLY (base)
+         || !is_global_var (base)))
+    return false;
 
-/* Free a used part map element.  */
+  callee = gimple_call_fndecl (call);
 
-static void 
-free_used_part_map (void *item)
-{
-  free (((struct used_part_map *)item)->to);
-  free (item);
-}
+  /* Handle those builtin functions explicitly that do not act as
+     escape points.  See tree-ssa-structalias.c:find_func_aliases
+     for the list of builtins we might need to handle here.  */
+  if (callee != NULL_TREE
+      && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL)
+    switch (DECL_FUNCTION_CODE (callee))
+      {
+       /* All the following functions clobber memory pointed to by
+          their first argument.  */
+       case BUILT_IN_STRCPY:
+       case BUILT_IN_STRNCPY:
+       case BUILT_IN_MEMCPY:
+       case BUILT_IN_MEMMOVE:
+       case BUILT_IN_MEMPCPY:
+       case BUILT_IN_STPCPY:
+       case BUILT_IN_STPNCPY:
+       case BUILT_IN_STRCAT:
+       case BUILT_IN_STRNCAT:
+       case BUILT_IN_MEMSET:
+         {
+           ao_ref dref;
+           tree size = NULL_TREE;
+           if (gimple_call_num_args (call) == 3)
+             size = gimple_call_arg (call, 2);
+           ao_ref_init_from_ptr_and_size (&dref,
+                                          gimple_call_arg (call, 0),
+                                          size);
+           return refs_may_alias_p_1 (&dref, ref, false);
+         }
+       case BUILT_IN_BCOPY:
+         {
+           ao_ref dref;
+           tree size = gimple_call_arg (call, 2);
+           ao_ref_init_from_ptr_and_size (&dref,
+                                          gimple_call_arg (call, 1),
+                                          size);
+           return refs_may_alias_p_1 (&dref, ref, false);
+         }
+       /* Allocating memory does not have any side-effects apart from
+          being the definition point for the pointer.  */
+       case BUILT_IN_MALLOC:
+         return false;
+       /* Freeing memory kills the pointed-to memory.  More importantly
+          the call has to serve as a barrier for moving loads and stores
+          across it.  */
+       case BUILT_IN_FREE:
+         {
+           tree ptr = gimple_call_arg (call, 0);
+           return ptr_deref_may_alias_ref_p_1 (ptr, ref);
+         }
+       case BUILT_IN_GAMMA_R:
+       case BUILT_IN_GAMMAF_R:
+       case BUILT_IN_GAMMAL_R:
+       case BUILT_IN_LGAMMA_R:
+       case BUILT_IN_LGAMMAF_R:
+       case BUILT_IN_LGAMMAL_R:
+         {
+           tree out = gimple_call_arg (call, 1);
+           if (ptr_deref_may_alias_ref_p_1 (out, ref))
+             return true;
+           if (flag_errno_math)
+             break;
+           return false;
+         }
+       case BUILT_IN_FREXP:
+       case BUILT_IN_FREXPF:
+       case BUILT_IN_FREXPL:
+       case BUILT_IN_MODF:
+       case BUILT_IN_MODFF:
+       case BUILT_IN_MODFL:
+         {
+           tree out = gimple_call_arg (call, 1);
+           return ptr_deref_may_alias_ref_p_1 (out, ref);
+         }
+       case BUILT_IN_REMQUO:
+       case BUILT_IN_REMQUOF:
+       case BUILT_IN_REMQUOL:
+         {
+           tree out = gimple_call_arg (call, 2);
+           if (ptr_deref_may_alias_ref_p_1 (out, ref))
+             return true;
+           if (flag_errno_math)
+             break;
+           return false;
+         }
+       case BUILT_IN_SINCOS:
+       case BUILT_IN_SINCOSF:
+       case BUILT_IN_SINCOSL:
+         {
+           tree sin = gimple_call_arg (call, 1);
+           tree cos = gimple_call_arg (call, 2);
+           return (ptr_deref_may_alias_ref_p_1 (sin, ref)
+                   || ptr_deref_may_alias_ref_p_1 (cos, ref));
+         }
+       default:
+         /* Fallthru to general call handling.  */;
+      }
 
-/* Lookup a used_part structure for a UID.  */
+  /* Check if base is a global static variable that is not written
+     by the function.  */
+  if (callee != NULL_TREE
+      && TREE_CODE (base) == VAR_DECL
+      && TREE_STATIC (base)
+      && !TREE_PUBLIC (base))
+    {
+      bitmap not_written;
 
-static used_part_t
-up_lookup (unsigned int uid)
-{
-  struct used_part_map *h, in;
-  in.uid = uid;
-  h = (struct used_part_map *) htab_find_with_hash (used_portions, &in, uid);
-  if (!h)
-    return NULL;
-  return h->to;
+      if ((not_written
+            = ipa_reference_get_not_written_global (cgraph_node (callee)))
+         && bitmap_bit_p (not_written, DECL_UID (base)))
+       return false;
+    }
+
+  if (DECL_P (base))
+    return is_call_clobbered (base);
+  else if (INDIRECT_REF_P (base)
+          && TREE_CODE (TREE_OPERAND (base, 0)) == SSA_NAME)
+    {
+      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (TREE_OPERAND (base, 0));
+      if (!pi)
+       return true;
+
+      return (pt_solution_includes_global (&pi->pt)
+             || pt_solutions_intersect (&cfun->gimple_df->escaped, &pi->pt));
+    }
+
+  return true;
 }
 
-/* Insert the pair UID, TO into the used part hashtable.  */
-static void 
-up_insert (unsigned int uid, used_part_t to)
-{ 
-  struct used_part_map *h;
-  void **loc;
-
-  h = XNEW (struct used_part_map);
-  h->uid = uid;
-  h->to = to;
-  loc = htab_find_slot_with_hash (used_portions, h,
-                                 uid, INSERT);
-  if (*loc != NULL)
-    free (*loc);
-  *(struct used_part_map **)  loc = h;
+static bool ATTRIBUTE_UNUSED
+call_may_clobber_ref_p (gimple call, tree ref)
+{
+  bool res;
+  ao_ref r;
+  ao_ref_init (&r, ref);
+  res = call_may_clobber_ref_p_1 (call, &r);
+  if (res)
+    ++alias_stats.call_may_clobber_ref_p_may_alias;
+  else
+    ++alias_stats.call_may_clobber_ref_p_no_alias;
+  return res;
 }
 
 
-/* Given a variable uid, UID, get or create the entry in the used portions
-   table for the variable.  */
+/* If the statement STMT may clobber the memory reference REF return true,
+   otherwise return false.  */
 
-static used_part_t
-get_or_create_used_part_for (size_t uid)
+bool
+stmt_may_clobber_ref_p_1 (gimple stmt, ao_ref *ref)
 {
-  used_part_t up;
-  if ((up = up_lookup (uid)) == NULL)
+  if (is_gimple_call (stmt))
+    {
+      tree lhs = gimple_call_lhs (stmt);
+      if (lhs
+         && !is_gimple_reg (lhs))
+       {
+         ao_ref r;
+         ao_ref_init (&r, lhs);
+         if (refs_may_alias_p_1 (ref, &r, true))
+           return true;
+       }
+
+      return call_may_clobber_ref_p_1 (stmt, ref);
+    }
+  else if (is_gimple_assign (stmt))
     {
-      up = XCNEW (struct used_part);
-      up->minused = INT_MAX;
-      up->maxused = 0;
-      up->explicit_uses = false;
-      up->implicit_uses = false;
-      up->write_only = true;
+      ao_ref r;
+      ao_ref_init (&r, gimple_assign_lhs (stmt));
+      return refs_may_alias_p_1 (ref, &r, true);
     }
+  else if (gimple_code (stmt) == GIMPLE_ASM)
+    return true;
 
-  return up;
+  return false;
 }
 
-
-/* Create and return a structure sub-variable for field type FIELD at
-   offset OFFSET, with size SIZE, of variable VAR.  */
-
-static tree
-create_sft (tree var, tree field, unsigned HOST_WIDE_INT offset,
-           unsigned HOST_WIDE_INT size)
+bool
+stmt_may_clobber_ref_p (gimple stmt, tree ref)
 {
-  tree subvar = create_tag_raw (STRUCT_FIELD_TAG, field, "SFT");
-
-  /* We need to copy the various flags from VAR to SUBVAR, so that
-     they are is_global_var iff the original variable was.  */
-  DECL_CONTEXT (subvar) = DECL_CONTEXT (var);
-  MTAG_GLOBAL (subvar) = DECL_EXTERNAL (var);
-  TREE_PUBLIC  (subvar) = TREE_PUBLIC (var);
-  TREE_STATIC (subvar) = TREE_STATIC (var);
-  TREE_READONLY (subvar) = TREE_READONLY (var);
-  TREE_ADDRESSABLE (subvar) = TREE_ADDRESSABLE (var);
-
-  /* Add the new variable to REFERENCED_VARS.  */
-  set_symbol_mem_tag (subvar, NULL);
-  add_referenced_var (subvar);
-  SFT_PARENT_VAR (subvar) = var;
-  SFT_OFFSET (subvar) = offset;
-  SFT_SIZE (subvar) = size;
-  return subvar;
+  ao_ref r;
+  ao_ref_init (&r, ref);
+  return stmt_may_clobber_ref_p_1 (stmt, &r);
 }
 
 
-/* Given an aggregate VAR, create the subvariables that represent its
-   fields.  */
+/* Walk the virtual use-def chain of VUSE until hitting the virtual operand
+   TARGET or a statement clobbering the memory reference REF in which
+   case false is returned.  The walk starts with VUSE, one argument of PHI.  */
 
-static void
-create_overlap_variables_for (tree var)
+static bool
+maybe_skip_until (gimple phi, tree target, ao_ref *ref,
+                 tree vuse, bitmap *visited)
 {
-  VEC(fieldoff_s,heap) *fieldstack = NULL;
-  used_part_t up;
-  size_t uid = DECL_UID (var);
+  if (!*visited)
+    *visited = BITMAP_ALLOC (NULL);
 
-  up = up_lookup (uid);
-  if (!up
-      || up->write_only)
-    return;
+  bitmap_set_bit (*visited, SSA_NAME_VERSION (PHI_RESULT (phi)));
 
-  push_fields_onto_fieldstack (TREE_TYPE (var), &fieldstack, 0, NULL);
-  if (VEC_length (fieldoff_s, fieldstack) != 0)
+  /* Walk until we hit the target.  */
+  while (vuse != target)
     {
-      subvar_t *subvars;
-      fieldoff_s *fo;
-      bool notokay = false;
-      int fieldcount = 0;
-      int i;
-      HOST_WIDE_INT lastfooffset = -1;
-      HOST_WIDE_INT lastfosize = -1;
-      tree lastfotype = NULL_TREE;
-
-      /* Not all fields have DECL_SIZE set, and those that don't, we don't
-        know their size, and thus, can't handle.
-        The same is true of fields with DECL_SIZE that is not an integer
-        constant (such as variable sized fields).
-        Fields with offsets which are not constant will have an offset < 0 
-        We *could* handle fields that are constant sized arrays, but
-        currently don't.  Doing so would require some extra changes to
-        tree-ssa-operands.c.  */
-
-      for (i = 0; VEC_iterate (fieldoff_s, fieldstack, i, fo); i++)
+      gimple def_stmt = SSA_NAME_DEF_STMT (vuse);
+      /* Recurse for PHI nodes.  */
+      if (gimple_code (def_stmt) == GIMPLE_PHI)
        {
-         if (!fo->size
-             || TREE_CODE (fo->size) != INTEGER_CST
-             || fo->offset < 0)
-           {
-             notokay = true;
-             break;
-           }
-          fieldcount++;
+         /* An already visited PHI node ends the walk successfully.  */
+         if (bitmap_bit_p (*visited, SSA_NAME_VERSION (PHI_RESULT (def_stmt))))
+           return true;
+         vuse = get_continuation_for_phi (def_stmt, ref, visited);
+         if (!vuse)
+           return false;
+         continue;
        }
+      /* A clobbering statement or the end of the IL ends it failing.  */
+      else if (gimple_nop_p (def_stmt)
+              || stmt_may_clobber_ref_p_1 (def_stmt, ref))
+       return false;
+      vuse = gimple_vuse (def_stmt);
+    }
+  return true;
+}
 
-      /* The current heuristic we use is as follows:
-        If the variable has no used portions in this function, no
-        structure vars are created for it.
-        Otherwise,
-         If the variable has less than SALIAS_MAX_IMPLICIT_FIELDS,
-        we always create structure vars for them.
-        If the variable has more than SALIAS_MAX_IMPLICIT_FIELDS, and
-        some explicit uses, we create structure vars for them.
-        If the variable has more than SALIAS_MAX_IMPLICIT_FIELDS, and
-        no explicit uses, we do not create structure vars for them.
-      */
-      
-      if (fieldcount >= SALIAS_MAX_IMPLICIT_FIELDS
-         && !up->explicit_uses)
+/* Starting from a PHI node for the virtual operand of the memory reference
+   REF find a continuation virtual operand that allows to continue walking
+   statements dominating PHI skipping only statements that cannot possibly
+   clobber REF.  Returns NULL_TREE if no suitable virtual operand can
+   be found.  */
+
+tree
+get_continuation_for_phi (gimple phi, ao_ref *ref, bitmap *visited)
+{
+  unsigned nargs = gimple_phi_num_args (phi);
+
+  /* Through a single-argument PHI we can simply look through.  */
+  if (nargs == 1)
+    return PHI_ARG_DEF (phi, 0);
+
+  /* For two arguments try to skip non-aliasing code until we hit
+     the phi argument definition that dominates the other one.  */
+  if (nargs == 2)
+    {
+      tree arg0 = PHI_ARG_DEF (phi, 0);
+      tree arg1 = PHI_ARG_DEF (phi, 1);
+      gimple def0 = SSA_NAME_DEF_STMT (arg0);
+      gimple def1 = SSA_NAME_DEF_STMT (arg1);
+      tree common_vuse;
+
+      if (arg0 == arg1)
+       return arg0;
+      else if (gimple_nop_p (def0)
+              || (!gimple_nop_p (def1)
+                  && dominated_by_p (CDI_DOMINATORS,
+                                     gimple_bb (def1), gimple_bb (def0))))
        {
-         if (dump_file && (dump_flags & TDF_DETAILS))
-           {
-             fprintf (dump_file, "Variable ");
-             print_generic_expr (dump_file, var, 0);
-             fprintf (dump_file, " has no explicit uses in this function, and is > SALIAS_MAX_IMPLICIT_FIELDS, so skipping\n");
-           }
-         notokay = true;
+         if (maybe_skip_until (phi, arg0, ref, arg1, visited))
+           return arg0;
        }
-      
-      /* Bail out, if we can't create overlap variables.  */
-      if (notokay)
+      else if (gimple_nop_p (def1)
+              || dominated_by_p (CDI_DOMINATORS,
+                                 gimple_bb (def0), gimple_bb (def1)))
        {
-         VEC_free (fieldoff_s, heap, fieldstack);
-         return;
+         if (maybe_skip_until (phi, arg1, ref, arg0, visited))
+           return arg1;
        }
-      
-      /* Otherwise, create the variables.  */
-      subvars = lookup_subvars_for_var (var);
-      
-      sort_fieldstack (fieldstack);
-
-      for (i = VEC_length (fieldoff_s, fieldstack);
-          VEC_iterate (fieldoff_s, fieldstack, --i, fo);)
+      /* Special case of a diamond:
+          MEM_1 = ...
+          goto (cond) ? L1 : L2
+          L1: store1 = ...    #MEM_2 = vuse(MEM_1)
+              goto L3
+          L2: store2 = ...    #MEM_3 = vuse(MEM_1)
+          L3: MEM_4 = PHI<MEM_2, MEM_3>
+        We were called with the PHI at L3, MEM_2 and MEM_3 don't
+        dominate each other, but still we can easily skip this PHI node
+        if we recognize that the vuse MEM operand is the same for both,
+        and that we can skip both statements (they don't clobber us).
+        This is still linear.  Don't use maybe_skip_until, that might
+        potentially be slow.  */
+      else if ((common_vuse = gimple_vuse (def0))
+              && common_vuse == gimple_vuse (def1))
        {
-         subvar_t sv;
-         HOST_WIDE_INT fosize;
-         tree currfotype;
-
-         fosize = TREE_INT_CST_LOW (fo->size);
-         currfotype = fo->type;
-
-         /* If this field isn't in the used portion,
-            or it has the exact same offset and size as the last
-            field, skip it.  */
-
-         if (((fo->offset <= up->minused
-               && fo->offset + fosize <= up->minused)
-              || fo->offset >= up->maxused)
-             || (fo->offset == lastfooffset
-                 && fosize == lastfosize
-                 && currfotype == lastfotype))
-           continue;
-         sv = GGC_NEW (struct subvar);
-         sv->next = *subvars;
-         sv->var = create_sft (var, fo->type, fo->offset, fosize);
-
-         if (dump_file)
-           {
-             fprintf (dump_file, "structure field tag %s created for var %s",
-                      get_name (sv->var), get_name (var));
-             fprintf (dump_file, " offset " HOST_WIDE_INT_PRINT_DEC,
-                      SFT_OFFSET (sv->var));
-             fprintf (dump_file, " size " HOST_WIDE_INT_PRINT_DEC,
-                      SFT_SIZE (sv->var));
-             fprintf (dump_file, "\n");
-           }
-         
-         lastfotype = currfotype;
-         lastfooffset = fo->offset;
-         lastfosize = fosize;
-         *subvars = sv;
+         if (!stmt_may_clobber_ref_p_1 (def0, ref)
+             && !stmt_may_clobber_ref_p_1 (def1, ref))
+           return common_vuse;
        }
-
-      /* Once we have created subvars, the original is no longer call
-        clobbered on its own.  Its call clobbered status depends
-        completely on the call clobbered status of the subvars.
-
-        add_referenced_var in the above loop will take care of
-        marking subvars of global variables as call clobbered for us
-        to start, since they are global as well.  */
-      clear_call_clobbered (var);
     }
 
-  VEC_free (fieldoff_s, heap, fieldstack);
+  return NULL_TREE;
 }
 
+/* Based on the memory reference REF and its virtual use VUSE call
+   WALKER for each virtual use that is equivalent to VUSE, including VUSE
+   itself.  That is, for each virtual use for which its defining statement
+   does not clobber REF.
 
-/* Find the conservative answer to the question of what portions of what 
-   structures are used by this statement.  We assume that if we have a
-   component ref with a known size + offset, that we only need that part
-   of the structure.  For unknown cases, or cases where we do something
-   to the whole structure, we assume we need to create fields for the 
-   entire structure.  */
-
-static tree
-find_used_portions (tree *tp, int *walk_subtrees, void *lhs_p)
-{
-  switch (TREE_CODE (*tp))
-    {
-    case GIMPLE_MODIFY_STMT:
-      /* Recurse manually here to track whether the use is in the
-        LHS of an assignment.  */
-      find_used_portions (&GIMPLE_STMT_OPERAND (*tp, 0), walk_subtrees, tp);
-      return find_used_portions (&GIMPLE_STMT_OPERAND (*tp, 1),
-                                walk_subtrees, NULL);
-    case REALPART_EXPR:
-    case IMAGPART_EXPR:
-    case COMPONENT_REF:
-    case ARRAY_REF:
-      {
-       HOST_WIDE_INT bitsize;
-       HOST_WIDE_INT bitmaxsize;
-       HOST_WIDE_INT bitpos;
-       tree ref;
-       ref = get_ref_base_and_extent (*tp, &bitpos, &bitsize, &bitmaxsize);
-       if (DECL_P (ref)
-           && var_can_have_subvars (ref)
-           && bitmaxsize != -1)
-         {
-           size_t uid = DECL_UID (ref);
-           used_part_t up;
-
-           up = get_or_create_used_part_for (uid);         
-
-           if (bitpos <= up->minused)
-             up->minused = bitpos;
-           if ((bitpos + bitmaxsize >= up->maxused))
-             up->maxused = bitpos + bitmaxsize;
-
-           if (bitsize == bitmaxsize)
-             up->explicit_uses = true;
-           else
-             up->implicit_uses = true;
-           if (!lhs_p)
-             up->write_only = false;
-           up_insert (uid, up);
-
-           *walk_subtrees = 0;
-           return NULL_TREE;
-         }
-      }
-      break;
-      /* This is here to make sure we mark the entire base variable as used
-        when you take its address.  Because our used portion analysis is
-        simple, we aren't looking at casts or pointer arithmetic to see what
-        happens when you take the address.  */
-    case ADDR_EXPR:
-      {
-       tree var = get_base_address (TREE_OPERAND (*tp, 0));
+   WALKER is called with REF, the current virtual use and DATA.  If
+   WALKER returns non-NULL the walk stops and its result is returned.
+   At the end of a non-successful walk NULL is returned.
 
-       if (var 
-           && DECL_P (var)
-           && DECL_SIZE (var)
-           && var_can_have_subvars (var)
-           && TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
-         {
-           used_part_t up;
-           size_t uid = DECL_UID (var);
-           
-           up = get_or_create_used_part_for (uid);
-           up->minused = 0;
-           up->maxused = TREE_INT_CST_LOW (DECL_SIZE (var));
-           up->implicit_uses = true;
-           if (!lhs_p)
-             up->write_only = false;
-
-           up_insert (uid, up);
-           *walk_subtrees = 0;
-           return NULL_TREE;
-         }
-      }
-      break;
-    case CALL_EXPR:
-      {
-       tree *arg;
-       for (arg = &TREE_OPERAND (*tp, 1); *arg; arg = &TREE_CHAIN (*arg))
-         {
-           if (TREE_CODE (TREE_VALUE (*arg)) != ADDR_EXPR)
-              find_used_portions (&TREE_VALUE (*arg), walk_subtrees, NULL);
-         }
-       *walk_subtrees = 0;
-       return NULL_TREE;
-      }
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-      {
-       tree var = *tp;
-       if (DECL_SIZE (var)
-           && var_can_have_subvars (var)
-           && TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
-         {
-           used_part_t up;
-           size_t uid = DECL_UID (var);
-           
-           up = get_or_create_used_part_for (uid);
-           up->minused = 0;
-           up->maxused = TREE_INT_CST_LOW (DECL_SIZE (var));
-           up->implicit_uses = true;
-
-           up_insert (uid, up);
-           *walk_subtrees = 0;
-           return NULL_TREE;
-         }
-      }
-      break;
-      
-    default:
-      break;
-      
-    }
-  return NULL_TREE;
-}
+   TRANSLATE if non-NULL is called with a pointer to REF, the virtual
+   use which definition is a statement that may clobber REF and DATA.
+   If TRANSLATE returns (void *)-1 the walk stops and NULL is returned.
+   If TRANSLATE returns non-NULL the walk stops and its result is returned.
+   If TRANSLATE returns NULL the walk continues and TRANSLATE is supposed
+   to adjust REF and *DATA to make that valid.
 
-/* Create structure field variables for structures used in this function.  */
+   TODO: Cache the vector of equivalent vuses per ref, vuse pair.  */
 
-static unsigned int
-create_structure_vars (void)
+void *
+walk_non_aliased_vuses (ao_ref *ref, tree vuse,
+                       void *(*walker)(ao_ref *, tree, void *),
+                       void *(*translate)(ao_ref *, tree, void *), void *data)
 {
-  basic_block bb;
-  safe_referenced_var_iterator rvi;
-  VEC (tree, heap) *varvec = NULL;
-  tree var;
+  bitmap visited = NULL;
+  void *res;
 
-  used_portions = htab_create (10, used_part_map_hash, used_part_map_eq, 
-                               free_used_part_map);
-  
-  FOR_EACH_BB (bb)
-    {
-      block_stmt_iterator bsi;
-      for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-       {
-         walk_tree_without_duplicates (bsi_stmt_ptr (bsi), 
-                                       find_used_portions,
-                                       NULL);
-       }
-    }
-  FOR_EACH_REFERENCED_VAR_SAFE (var, varvec, rvi)
+  timevar_push (TV_ALIAS_STMT_WALK);
+
+  do
     {
-      /* The C++ FE creates vars without DECL_SIZE set, for some reason.  */
-      if (var    
-         && DECL_SIZE (var)
-         && var_can_have_subvars (var)
-         && !MTAG_P (var)
-         && TREE_CODE (DECL_SIZE (var)) == INTEGER_CST)
-       create_overlap_variables_for (var);
-    }
-  htab_delete (used_portions);
-  VEC_free (tree, heap, varvec);
+      gimple def_stmt;
 
-  /* Update SSA operands of statements mentioning variables we split.  */
-  if (gimple_in_ssa_p (cfun))
-    FOR_EACH_BB (bb)
-      {
-       block_stmt_iterator bsi;
-       for (bsi = bsi_start (bb); !bsi_end_p (bsi); bsi_next (&bsi))
-         {
-           tree stmt = bsi_stmt (bsi);
-           bool update = false;
-           unsigned int i;
-           bitmap_iterator bi;
+      /* ???  Do we want to account this to TV_ALIAS_STMT_WALK?  */
+      res = (*walker) (ref, vuse, data);
+      if (res)
+       break;
 
-           if (STORED_SYMS (stmt))
-              EXECUTE_IF_SET_IN_BITMAP (STORED_SYMS (stmt), 0, i, bi)
+      def_stmt = SSA_NAME_DEF_STMT (vuse);
+      if (gimple_nop_p (def_stmt))
+       break;
+      else if (gimple_code (def_stmt) == GIMPLE_PHI)
+       vuse = get_continuation_for_phi (def_stmt, ref, &visited);
+      else
+       {
+         if (stmt_may_clobber_ref_p_1 (def_stmt, ref))
+           {
+             if (!translate)
+               break;
+             res = (*translate) (ref, vuse, data);
+             /* Failed lookup and translation.  */
+             if (res == (void *)-1)
                {
-                 tree sym = referenced_var_lookup (i);
-                 if (get_subvars_for_var (sym))
-                   {
-                     update=true;
-                     break;
-                   }
+                 res = NULL;
+                 break;
                }
+             /* Lookup succeeded.  */
+             else if (res != NULL)
+               break;
+             /* Translation succeeded, continue walking.  */
+           }
+         vuse = gimple_vuse (def_stmt);
+       }
+    }
+  while (vuse);
 
-           if (LOADED_SYMS (stmt) && !update)
-              EXECUTE_IF_SET_IN_BITMAP (LOADED_SYMS (stmt), 0, i, bi)
-               {
-                 tree sym = referenced_var_lookup (i);
-                 if (get_subvars_for_var (sym))
-                   {
-                     update=true;
-                     break;
-                   }
-               }
+  if (visited)
+    BITMAP_FREE (visited);
 
-           if (stmt_ann (stmt)->addresses_taken && !update)
-              EXECUTE_IF_SET_IN_BITMAP (stmt_ann (stmt)->addresses_taken,
-                                        0, i, bi)
-               {
-                 tree sym = referenced_var_lookup (i);
-                 if (get_subvars_for_var (sym))
-                   {
-                     update=true;
-                     break;
-                   }
-               }
+  timevar_pop (TV_ALIAS_STMT_WALK);
 
-           if (update)
-             update_stmt (stmt);
-         }
-      }
-  
-  return 0;
+  return res;
 }
 
-static bool
-gate_structure_vars (void)
-{
-  return flag_tree_salias != 0;
-}
 
-struct tree_opt_pass pass_create_structure_vars = 
-{
-  "salias",             /* name */
-  gate_structure_vars,  /* gate */
-  create_structure_vars, /* execute */
-  NULL,                         /* sub */
-  NULL,                         /* next */
-  0,                    /* static_pass_number */
-  0,                    /* tv_id */
-  PROP_cfg,             /* properties_required */
-  0,                    /* properties_provided */
-  0,                    /* properties_destroyed */
-  0,                    /* todo_flags_start */
-  TODO_dump_func,       /* todo_flags_finish */
-  0                     /* letter */
-};
-
-/* Reset the call_clobbered flags on our referenced vars.  In
-   theory, this only needs to be done for globals.  */
+/* Based on the memory reference REF call WALKER for each vdef which
+   defining statement may clobber REF, starting with VDEF.  If REF
+   is NULL_TREE, each defining statement is visited.
+
+   WALKER is called with REF, the current vdef and DATA.  If WALKER
+   returns true the walk is stopped, otherwise it continues.
+
+   At PHI nodes walk_aliased_vdefs forks into one walk for reach
+   PHI argument (but only one walk continues on merge points), the
+   return value is true if any of the walks was successful.
+
+   The function returns the number of statements walked.  */
 
 static unsigned int
-reset_cc_flags (void)
+walk_aliased_vdefs_1 (ao_ref *ref, tree vdef,
+                     bool (*walker)(ao_ref *, tree, void *), void *data,
+                     bitmap *visited, unsigned int cnt)
 {
-  tree var;
-  referenced_var_iterator rvi;
+  do
+    {
+      gimple def_stmt = SSA_NAME_DEF_STMT (vdef);
 
-  FOR_EACH_REFERENCED_VAR (var, rvi)
-    var_ann (var)->call_clobbered = false;
-  return 0;
+      if (*visited
+         && !bitmap_set_bit (*visited, SSA_NAME_VERSION (vdef)))
+       return cnt;
+
+      if (gimple_nop_p (def_stmt))
+       return cnt;
+      else if (gimple_code (def_stmt) == GIMPLE_PHI)
+       {
+         unsigned i;
+         if (!*visited)
+           *visited = BITMAP_ALLOC (NULL);
+         for (i = 0; i < gimple_phi_num_args (def_stmt); ++i)
+           cnt += walk_aliased_vdefs_1 (ref, gimple_phi_arg_def (def_stmt, i),
+                                        walker, data, visited, 0);
+         return cnt;
+       }
+
+      /* ???  Do we want to account this to TV_ALIAS_STMT_WALK?  */
+      cnt++;
+      if ((!ref
+          || stmt_may_clobber_ref_p_1 (def_stmt, ref))
+         && (*walker) (ref, vdef, data))
+       return cnt;
+
+      vdef = gimple_vuse (def_stmt);
+    }
+  while (1);
 }
 
-struct tree_opt_pass pass_reset_cc_flags =
+unsigned int
+walk_aliased_vdefs (ao_ref *ref, tree vdef,
+                   bool (*walker)(ao_ref *, tree, void *), void *data,
+                   bitmap *visited)
 {
-  NULL,                 /* name */
-  NULL,         /* gate */
-  reset_cc_flags, /* execute */
-  NULL,                         /* sub */
-  NULL,                         /* next */
-  0,                    /* static_pass_number */
-  0,                    /* tv_id */
-  PROP_referenced_vars |PROP_cfg, /* properties_required */
-  0,                    /* properties_provided */
-  0,                    /* properties_destroyed */
-  0,                    /* todo_flags_start */
-  0,                    /* todo_flags_finish */
-  0                     /* letter */
-};
+  bitmap local_visited = NULL;
+  unsigned int ret;
+
+  timevar_push (TV_ALIAS_STMT_WALK);
+
+  ret = walk_aliased_vdefs_1 (ref, vdef, walker, data,
+                             visited ? visited : &local_visited, 0);
+  if (local_visited)
+    BITMAP_FREE (local_visited);
+
+  timevar_pop (TV_ALIAS_STMT_WALK);
+
+  return ret;
+}
+