OSDN Git Service

2004-12-05 Daniel Berlin <dberlin@dberlin.org>
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-alias.c
index ae06ea0..b321d26 100644 (file)
@@ -73,7 +73,7 @@ struct alias_info
   /* SSA names visited while collecting points-to information.  If bit I
      is set, it means that SSA variable with version I has already been
      visited.  */
-  bitmap ssa_names_visited;
+  sbitmap ssa_names_visited;
 
   /* Array of SSA_NAME pointers processed by the points-to collector.  */
   varray_type processed_ptrs;
@@ -147,13 +147,11 @@ static void setup_pointers_and_addressables (struct alias_info *);
 static bool collect_points_to_info_r (tree, tree, void *);
 static bool is_escape_site (tree, size_t *);
 static void add_pointed_to_var (struct alias_info *, tree, tree);
-static void add_pointed_to_expr (tree, tree);
 static void create_global_var (void);
 static void collect_points_to_info_for (struct alias_info *, tree);
 static bool ptr_is_dereferenced_by (tree, tree, bool *);
 static void maybe_create_global_var (struct alias_info *ai);
 static void group_aliases (struct alias_info *);
-static struct ptr_info_def *get_ptr_info (tree t);
 static void set_pt_anything (tree ptr);
 static void set_pt_malloc (tree ptr);
 
@@ -197,7 +195,8 @@ tree global_var;
    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.
+   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
@@ -238,15 +237,14 @@ tree global_var;
 
            foo (int i)
            {
-             int *p, *q, a, b;
+             int *p, a, b;
            
              if (i > 10)
                p = &a;
              else
-               q = &b;
+               p = &b;
            
              *p = 3;
-             *q = 5;
              a = b + 2;
              return *p;
            }
@@ -360,6 +358,62 @@ struct tree_opt_pass pass_may_alias =
   0                                    /* letter */
 };
 
+/* Count the number of calls in the function and conditionally
+   create GLOBAL_VAR.   This is performed before translation
+   into SSA (and thus before alias analysis) to avoid compile time
+   and memory utilization explosions in functions with many
+   of calls and call clobbered variables.  */
+
+static void
+count_calls_and_maybe_create_global_var (void)
+{
+  struct alias_info ai;
+  basic_block bb;
+  bool temp;
+
+  memset (&ai, 0, sizeof (struct alias_info));
+
+  /* First count the number of calls in the IL.  */
+  FOR_EACH_BB (bb)
+    {
+      block_stmt_iterator si;
+
+      for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+        {
+          tree stmt = bsi_stmt (si);
+
+         if (get_call_expr_in (stmt) != NULL_TREE)
+           ai.num_calls_found++;
+       }
+    }
+
+  /* If there are no call clobbered variables, then maybe_create_global_var
+     will always create a GLOBAL_VAR.  At this point we do not want that
+     behavior.  So we turn on one bit in CALL_CLOBBERED_VARs, call
+     maybe_create_global_var, then reset the bit to its original state.  */
+  temp = bitmap_bit_p (call_clobbered_vars, 0);
+  bitmap_set_bit (call_clobbered_vars, 0);
+  maybe_create_global_var (&ai);
+  if (!temp)
+    bitmap_clear_bit (call_clobbered_vars, 0);
+}
+
+struct tree_opt_pass pass_maybe_create_global_var = 
+{
+  "maybe_create_global_var",           /* name */
+  NULL,                                        /* gate */
+  count_calls_and_maybe_create_global_var, /* execute */
+  NULL,                                        /* sub */
+  NULL,                                        /* next */
+  0,                                   /* static_pass_number */
+  TV_TREE_MAY_ALIAS,                   /* tv_id */
+  PROP_cfg,                            /* properties_required */
+  0,                                   /* properties_provided */
+  0,                                   /* properties_destroyed */
+  0,                                   /* todo_flags_start */
+  0,                                   /* todo_flags_finish */
+  0                                    /* letter */
+};
 
 /* Initialize the data structures used for alias analysis.  */
 
@@ -370,7 +424,8 @@ init_alias_info (void)
   static bool aliases_computed_p = false;
 
   ai = xcalloc (1, sizeof (struct alias_info));
-  ai->ssa_names_visited = BITMAP_XMALLOC ();
+  ai->ssa_names_visited = sbitmap_alloc (num_ssa_names);
+  sbitmap_zero (ai->ssa_names_visited);
   VARRAY_TREE_INIT (ai->processed_ptrs, 50, "processed_ptrs");
   ai->addresses_needed = BITMAP_XMALLOC ();
   VARRAY_UINT_INIT (ai->num_references, num_referenced_vars, "num_references");
@@ -381,11 +436,26 @@ init_alias_info (void)
   /* If aliases have been computed before, clear existing information.  */
   if (aliases_computed_p)
     {
-      size_t i;
+      unsigned i;
+      bitmap_iterator bi;
+      basic_block bb;
+  
+     /* Make sure that every statement has a valid set of operands.
+       If a statement needs to be scanned for operands while we
+       compute aliases, it may get erroneous operands because all
+       the alias relations are not built at that point.
+       FIXME: This code will become obsolete when operands are not
+       lazily updated.  */
+      FOR_EACH_BB (bb)
+       {
+         block_stmt_iterator si;
+         for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
+           get_stmt_operands (bsi_stmt (si));
+       }
 
       /* Clear the call-clobbered set.  We are going to re-discover
          call-clobbered variables.  */
-      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
+      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
        {
          tree var = referenced_var (i);
 
@@ -394,7 +464,7 @@ init_alias_info (void)
             code, so we can't remove them from CALL_CLOBBERED_VARS.  */
          if (!is_call_clobbered (var))
            bitmap_clear_bit (call_clobbered_vars, var_ann (var)->uid);
-       });
+       }
 
       /* Similarly, clear the set of addressable variables.  In this
         case, we can just clear the set because addressability is
@@ -414,7 +484,7 @@ init_alias_info (void)
        {
          tree name = ssa_name (i);
 
-         if (!POINTER_TYPE_P (TREE_TYPE (name)))
+         if (!name || !POINTER_TYPE_P (TREE_TYPE (name)))
            continue;
 
          if (SSA_NAME_PTR_INFO (name))
@@ -450,7 +520,7 @@ delete_alias_info (struct alias_info *ai)
 {
   size_t i;
 
-  BITMAP_XFREE (ai->ssa_names_visited);
+  sbitmap_free (ai->ssa_names_visited);
   ai->processed_ptrs = NULL;
   BITMAP_XFREE (ai->addresses_needed);
 
@@ -485,9 +555,9 @@ collect_points_to_info_for (struct alias_info *ai, tree ptr)
 {
   gcc_assert (POINTER_TYPE_P (TREE_TYPE (ptr)));
 
-  if (!bitmap_bit_p (ai->ssa_names_visited, SSA_NAME_VERSION (ptr)))
+  if (!TEST_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (ptr)))
     {
-      bitmap_set_bit (ai->ssa_names_visited, SSA_NAME_VERSION (ptr));
+      SET_BIT (ai->ssa_names_visited, SSA_NAME_VERSION (ptr));
       walk_use_def_chains (ptr, collect_points_to_info_r, ai, true);
       VARRAY_PUSH_TREE (ai->processed_ptrs, ptr);
     }
@@ -495,14 +565,14 @@ collect_points_to_info_for (struct alias_info *ai, tree ptr)
 
 
 /* Helper for ptr_is_dereferenced_by.  Called by walk_tree to look for
-   INDIRECT_REF nodes for the pointer passed in DATA.  */
+   (ALIGN/MISALIGNED_)INDIRECT_REF nodes for the pointer passed in DATA.  */
 
 static tree
 find_ptr_dereference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
 {
   tree ptr = (tree) data;
 
-  if (TREE_CODE (*tp) == INDIRECT_REF
+  if (INDIRECT_REF_P (*tp)
       && TREE_OPERAND (*tp, 0) == ptr)
     return *tp;
 
@@ -510,8 +580,9 @@ find_ptr_dereference (tree *tp, int *walk_subtrees ATTRIBUTE_UNUSED, void *data)
 }
 
 
-/* Return true if STMT contains INDIRECT_REF <PTR>.  *IS_STORE is set
-   to 'true' if the dereference is on the LHS of an assignment.  */
+/* Return true if STMT contains (ALIGN/MISALIGNED_)INDIRECT_REF <PTR>.  
+   *IS_STORE is set to 'true' if the dereference is on the LHS of an 
+   assignment.  */
 
 static bool
 ptr_is_dereferenced_by (tree ptr, tree stmt, bool *is_store)
@@ -570,7 +641,7 @@ static void
 compute_points_to_and_addr_escape (struct alias_info *ai)
 {
   basic_block bb;
-  size_t i;
+  unsigned i;
   tree op;
   ssa_op_iter iter;
 
@@ -586,6 +657,7 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
          bitmap addr_taken;
          tree stmt = bsi_stmt (si);
          bool stmt_escapes_p = is_escape_site (stmt, &ai->num_calls_found);
+         bitmap_iterator bi;
 
          /* Mark all the variables whose address are taken by the
             statement.  Note that this will miss all the addresses taken
@@ -594,33 +666,17 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
          get_stmt_operands (stmt);
          addr_taken = addresses_taken (stmt);
          if (addr_taken)
-           EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i,
-               {
-                 tree var = referenced_var (i);
-                 bitmap_set_bit (ai->addresses_needed, var_ann (var)->uid);
-                 if (stmt_escapes_p)
-                   mark_call_clobbered (var);
-               });
+           EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i, bi)
+             {
+               tree var = referenced_var (i);
+               bitmap_set_bit (ai->addresses_needed, var_ann (var)->uid);
+               if (stmt_escapes_p)
+                 mark_call_clobbered (var);
+             }
 
          if (stmt_escapes_p)
            block_ann->has_escape_site = 1;
 
-         /* Special case for silly ADDR_EXPR tricks
-            (gcc.c-torture/unsorted/pass.c).  If this statement is an
-            assignment to a non-pointer variable and the RHS takes the
-            address of a variable, assume that the variable on the RHS is
-            call-clobbered.  We could add the LHS to the list of
-            "pointers" and follow it to see if it really escapes, but it's
-            not worth the pain.  */
-         if (addr_taken
-             && TREE_CODE (stmt) == MODIFY_EXPR
-             && !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 0))))
-           EXECUTE_IF_SET_IN_BITMAP (addr_taken, 0, i,
-               {
-                 tree var = referenced_var (i);
-                 mark_call_clobbered (var);
-               });
-
          FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
            {
              var_ann_t v_ann = var_ann (SSA_NAME_VAR (op));
@@ -746,8 +802,7 @@ create_name_tags (struct alias_info *ai)
          continue;
        }
 
-      if (pi->pt_vars
-         && bitmap_first_set_bit (pi->pt_vars) >= 0)
+      if (pi->pt_vars && !bitmap_empty_p (pi->pt_vars))
        {
          size_t j;
          tree old_name_tag = pi->name_mem_tag;
@@ -804,6 +859,9 @@ create_name_tags (struct alias_info *ai)
          continue;
        }
 
+      TREE_THIS_VOLATILE (pi->name_mem_tag)
+         |= TREE_THIS_VOLATILE (TREE_TYPE (TREE_TYPE (ptr)));
+
       /* Mark the new name tag for renaming.  */
       bitmap_set_bit (vars_to_rename, var_ann (pi->name_mem_tag)->uid);
     }
@@ -828,10 +886,11 @@ compute_flow_sensitive_aliasing (struct alias_info *ai)
 
   for (i = 0; i < VARRAY_ACTIVE_SIZE (ai->processed_ptrs); i++)
     {
-      size_t j;
+      unsigned j;
       tree ptr = VARRAY_TREE (ai->processed_ptrs, i);
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
       var_ann_t v_ann = var_ann (SSA_NAME_VAR (ptr));
+      bitmap_iterator bi;
 
       if (pi->value_escapes_p || pi->pt_anything)
        {
@@ -844,16 +903,20 @@ compute_flow_sensitive_aliasing (struct alias_info *ai)
            mark_call_clobbered (v_ann->type_mem_tag);
 
          if (pi->pt_vars)
-           EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j,
-               mark_call_clobbered (referenced_var (j)));
+           EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j, bi)
+             {
+               mark_call_clobbered (referenced_var (j));
+             }
        }
 
       /* Set up aliasing information for PTR's name memory tag (if it has
         one).  Note that only pointers that have been dereferenced will
         have a name memory tag.  */
       if (pi->name_mem_tag && pi->pt_vars)
-       EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j,
-           add_may_alias (pi->name_mem_tag, referenced_var (j)));
+       EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j, bi)
+         {
+           add_may_alias (pi->name_mem_tag, referenced_var (j));
+         }
 
       /* If the name tag is call clobbered, so is the type tag
         associated with the base VAR_DECL.  */
@@ -878,7 +941,6 @@ static void
 compute_flow_insensitive_aliasing (struct alias_info *ai)
 {
   size_t i;
-  sbitmap res;
 
   /* Initialize counter for the total number of virtual operands that
      aliasing will introduce.  When AI->TOTAL_ALIAS_VOPS goes beyond the
@@ -913,11 +975,16 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
          /* 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 = bitmap_bit_p (ai->written_vars, tag_ann->uid)
-                        || is_call_clobbered (tag);
-         var_stored_p = bitmap_bit_p (ai->written_vars, v_ann->uid)
-                        || is_call_clobbered (var);
+            function calls.
+
+            Note this is effectively random accessing elements in
+            the sparse bitset, which can be highly inefficient.
+            So we first check the call_clobbered status of the
+            tag and variable before querying the bitmap.  */
+         tag_stored_p = is_call_clobbered (tag)
+                        || bitmap_bit_p (ai->written_vars, tag_ann->uid);
+         var_stored_p = is_call_clobbered (var)
+                        || bitmap_bit_p (ai->written_vars, v_ann->uid);
          if (!tag_stored_p && !var_stored_p)
            continue;
             
@@ -967,8 +1034,6 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
      To avoid this problem, we do a final traversal of AI->POINTERS
      looking for pairs of pointers that have no aliased symbols in
      common and yet have conflicting alias set numbers.  */
-  res = sbitmap_alloc (num_referenced_vars);
-
   for (i = 0; i < ai->num_pointers; i++)
     {
       size_t j;
@@ -988,8 +1053,7 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
 
          /* The two pointers may alias each other.  If they already have
             symbols in common, do nothing.  */
-         sbitmap_a_and_b (res, may_aliases1, may_aliases2);
-         if (sbitmap_first_set_bit (res) >= 0)
+         if (sbitmap_any_common_bits (may_aliases1, may_aliases2))
            continue;
 
          if (sbitmap_first_set_bit (may_aliases2) >= 0)
@@ -1011,8 +1075,6 @@ compute_flow_insensitive_aliasing (struct alias_info *ai)
        }
     }
 
-  sbitmap_free (res);
-
   if (dump_file)
     fprintf (dump_file, "%s: Total number of aliased vops: %ld\n",
             get_name (current_function_decl),
@@ -1155,15 +1217,12 @@ static void
 group_aliases (struct alias_info *ai)
 {
   size_t i;
-  sbitmap res;
 
   /* Sort the POINTERS array in descending order of contributed
      virtual operands.  */
   qsort (ai->pointers, ai->num_pointers, sizeof (struct alias_map_d *),
          total_alias_vops_cmp);
 
-  res = sbitmap_alloc (num_referenced_vars);
-
   /* For every pointer in AI->POINTERS, reverse the roles of its tag
      and the tag's may-aliases set.  */
   for (i = 0; i < ai->num_pointers; i++)
@@ -1183,8 +1242,7 @@ group_aliases (struct alias_info *ai)
        {
          sbitmap tag2_aliases = ai->pointers[j]->may_aliases;
 
-         sbitmap_a_and_b (res, tag1_aliases, tag2_aliases);
-         if (sbitmap_first_set_bit (res) >= 0)
+          if (sbitmap_any_common_bits (tag1_aliases, tag2_aliases))
            {
              tree tag2 = var_ann (ai->pointers[j]->var)->type_mem_tag;
 
@@ -1254,8 +1312,6 @@ group_aliases (struct alias_info *ai)
        }
     }
 
-  sbitmap_free (res);
-
   if (dump_file)
     fprintf (dump_file,
             "%s: Total number of aliased vops after grouping: %ld%s\n",
@@ -1347,6 +1403,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
        {
          if (!bitmap_bit_p (ai->addresses_needed, v_ann->uid)
              && v_ann->mem_tag_kind == NOT_A_TAG
+             && TREE_CODE (var) != RESULT_DECL
              && !is_global_var (var))
            {
              /* The address of VAR is not needed, remove the
@@ -1471,14 +1528,18 @@ setup_pointers_and_addressables (struct alias_info *ai)
 static void
 maybe_create_global_var (struct alias_info *ai)
 {
-  size_t i, n_clobbered;
+  unsigned i, n_clobbered;
+  bitmap_iterator bi;
   
   /* No need to create it, if we have one already.  */
   if (global_var == NULL_TREE)
     {
       /* Count all the call-clobbered variables.  */
       n_clobbered = 0;
-      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, n_clobbered++);
+      EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
+       {
+         n_clobbered++;
+       }
 
       /* Create .GLOBAL_VAR if we have too many call-clobbered
         variables.  We also create .GLOBAL_VAR when there no
@@ -1506,7 +1567,7 @@ maybe_create_global_var (struct alias_info *ai)
   /* If the function has calls to clobbering functions and .GLOBAL_VAR has
      been created, make it an alias for all call-clobbered variables.  */
   if (global_var)
-    EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
+    EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i, bi)
       {
        tree var = referenced_var (i);
        if (var != global_var)
@@ -1514,7 +1575,7 @@ maybe_create_global_var (struct alias_info *ai)
             add_may_alias (var, global_var);
             bitmap_set_bit (vars_to_rename, var_ann (var)->uid);
          }
-      });
+      }
 }
 
 
@@ -1674,14 +1735,17 @@ set_pt_malloc (tree ptr)
 }
 
 
-/* Given two pointers DEST and ORIG.  Merge the points-to information in
-   ORIG into DEST.  AI is as in collect_points_to_info.  */
+/* Given two different pointers DEST and ORIG.  Merge the points-to
+   information in ORIG into DEST.  AI is as in
+   collect_points_to_info.  */
 
 static void
 merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
 {
   struct ptr_info_def *dest_pi, *orig_pi;
 
+  gcc_assert (dest != orig);
+
   /* Make sure we have points-to information for ORIG.  */
   collect_points_to_info_for (ai, orig);
 
@@ -1698,20 +1762,19 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
         ...
         P_j = P_i + X;
 
-        P_j would be marked as PT_MALLOC, which is wrong because
-        PT_MALLOC implies that the pointer may not point to another
-        variable.
-
-        FIXME 1: Subsequent analysis may determine that P_j
-        cannot alias anything else, but we are being conservative
-        here.
-
-        FIXME 2: If the merging comes from a copy assignment, we
-        ought to merge PT_MALLOC, but then both pointers would end up
-        getting different name tags because create_name_tags is not
-        smart enough to determine that the two come from the same
-        malloc call.  Copy propagation before aliasing should cure
-        this.  */
+        P_j would be marked as PT_MALLOC, however we currently do not
+        handle cases of more than one pointer pointing to the same
+        malloc'd area.
+
+        FIXME: If the merging comes from an expression that preserves
+        the PT_MALLOC attribute (copy assignment, address
+        arithmetic), we ought to merge PT_MALLOC, but then both
+        pointers would end up getting different name tags because
+        create_name_tags is not smart enough to determine that the
+        two come from the same malloc call.  Copy propagation before
+        aliasing should cure this.  */
+      gcc_assert (orig_pi != dest_pi);
+      
       dest_pi->pt_malloc = 0;
 
       if (orig_pi->pt_malloc || orig_pi->pt_anything)
@@ -1719,7 +1782,7 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
 
       if (!dest_pi->pt_anything
          && orig_pi->pt_vars
-         && bitmap_first_set_bit (orig_pi->pt_vars) >= 0)
+         && !bitmap_empty_p (orig_pi->pt_vars))
        {
          if (dest_pi->pt_vars == NULL)
            {
@@ -1727,9 +1790,7 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
              bitmap_copy (dest_pi->pt_vars, orig_pi->pt_vars);
            }
          else
-           bitmap_a_or_b (dest_pi->pt_vars,
-                          dest_pi->pt_vars,
-                          orig_pi->pt_vars);
+           bitmap_ior_into (dest_pi->pt_vars, orig_pi->pt_vars);
        }
     }
   else
@@ -1737,41 +1798,78 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
 }
 
 
-/* Add VALUE to the list of expressions pointed-to by PTR.  */
+/* Add EXPR to the list of expressions pointed-to by PTR.  */
 
 static void
-add_pointed_to_expr (tree ptr, tree value)
+add_pointed_to_expr (struct alias_info *ai, tree ptr, tree expr)
 {
-  if (TREE_CODE (value) == WITH_SIZE_EXPR)
-    value = TREE_OPERAND (value, 0);
-
-  /* Pointer variables should have been handled by merge_pointed_to_info.  */
-  gcc_assert (TREE_CODE (value) != SSA_NAME
-             || !POINTER_TYPE_P (TREE_TYPE (value)));
+  if (TREE_CODE (expr) == WITH_SIZE_EXPR)
+    expr = TREE_OPERAND (expr, 0);
 
   get_ptr_info (ptr);
 
-  /* If VALUE is the result of a malloc-like call, then the area pointed to
-     PTR is guaranteed to not alias with anything else.  */
-  if (TREE_CODE (value) == CALL_EXPR
-      && (call_expr_flags (value) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
-    set_pt_malloc (ptr);
-  else
-    set_pt_anything (ptr);
-
-  if (dump_file)
+  if (TREE_CODE (expr) == CALL_EXPR
+      && (call_expr_flags (expr) & (ECF_MALLOC | ECF_MAY_BE_ALLOCA)))
     {
-      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+      /* If EXPR is a malloc-like call, then the area pointed to PTR
+        is guaranteed to not alias with anything else.  */
+      set_pt_malloc (ptr);
+    }
+  else if (TREE_CODE (expr) == ADDR_EXPR)
+    {
+      /* Found P_i = ADDR_EXPR  */
+      add_pointed_to_var (ai, ptr, expr);
+    }
+  else if (TREE_CODE (expr) == SSA_NAME && POINTER_TYPE_P (TREE_TYPE (expr)))
+    {
+      /* Found P_i = Q_j.  */
+      merge_pointed_to_info (ai, ptr, expr);
+    }
+  else if (TREE_CODE (expr) == PLUS_EXPR || TREE_CODE (expr) == MINUS_EXPR)
+    {
+      /* Found P_i = PLUS_EXPR or P_i = MINUS_EXPR  */
+      tree op0 = TREE_OPERAND (expr, 0);
+      tree op1 = TREE_OPERAND (expr, 1);
+
+      /* Both operands may be of pointer type.  FIXME: Shouldn't
+        we just expect PTR + OFFSET always?  */
+      if (POINTER_TYPE_P (TREE_TYPE (op0))
+         && TREE_CODE (op0) != INTEGER_CST)
+       {
+         if (TREE_CODE (op0) == SSA_NAME)
+           merge_pointed_to_info (ai, ptr, op0);
+         else if (TREE_CODE (op0) == ADDR_EXPR)
+           add_pointed_to_var (ai, ptr, op0);
+         else
+           set_pt_anything (ptr);
+       }
 
-      fprintf (dump_file, "Pointer ");
-      print_generic_expr (dump_file, ptr, dump_flags);
-      fprintf (dump_file, " points to ");
-      if (pi->pt_malloc)
-       fprintf (dump_file, "malloc space: ");
-      else
-       fprintf (dump_file, "an arbitrary address: ");
-      print_generic_expr (dump_file, value, dump_flags);
-      fprintf (dump_file, "\n");
+      if (POINTER_TYPE_P (TREE_TYPE (op1))
+         && TREE_CODE (op1) != INTEGER_CST)
+       {
+         if (TREE_CODE (op1) == SSA_NAME)
+           merge_pointed_to_info (ai, ptr, op1);
+         else if (TREE_CODE (op1) == ADDR_EXPR)
+           add_pointed_to_var (ai, ptr, op1);
+         else
+           set_pt_anything (ptr);
+       }
+
+      /* Neither operand is a pointer?  VAR can be pointing anywhere.
+        FIXME: Shouldn't we abort here?  If we get here, we found
+        PTR = INT_CST + INT_CST, which should not be a valid pointer
+        expression.  */
+      if (!(POINTER_TYPE_P (TREE_TYPE (op0))
+           && TREE_CODE (op0) != INTEGER_CST)
+         && !(POINTER_TYPE_P (TREE_TYPE (op1))
+              && TREE_CODE (op1) != INTEGER_CST))
+       set_pt_anything (ptr);
+    }
+  else
+    {
+      /* If we can't recognize the expression, assume that PTR may
+        point anywhere.  */
+      set_pt_anything (ptr);
     }
 }
 
@@ -1844,62 +1942,10 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
       {
        tree rhs = TREE_OPERAND (stmt, 1);
        STRIP_NOPS (rhs);
-
-       /* Found P_i = ADDR_EXPR  */
-       if (TREE_CODE (rhs) == ADDR_EXPR)
-         add_pointed_to_var (ai, var, rhs);
-
-       /* Found P_i = Q_j.  */
-       else if (TREE_CODE (rhs) == SSA_NAME
-                && POINTER_TYPE_P (TREE_TYPE (rhs)))
-         merge_pointed_to_info (ai, var, rhs);
-
-       /* Found P_i = PLUS_EXPR or P_i = MINUS_EXPR  */
-       else if (TREE_CODE (rhs) == PLUS_EXPR
-                || TREE_CODE (rhs) == MINUS_EXPR)
-         {
-           tree op0 = TREE_OPERAND (rhs, 0);
-           tree op1 = TREE_OPERAND (rhs, 1);
-           
-           /* Both operands may be of pointer type.  FIXME: Shouldn't
-              we just expect PTR + OFFSET always?  */
-           if (POINTER_TYPE_P (TREE_TYPE (op0))
-               && TREE_CODE (op0) != INTEGER_CST)
-             {
-               if (TREE_CODE (op0) == SSA_NAME)
-                 merge_pointed_to_info (ai, var, op0);
-               else if (TREE_CODE (op0) == ADDR_EXPR)
-                 add_pointed_to_var (ai, var, op0);
-               else
-                 add_pointed_to_expr (var, op0);
-             }
-
-           if (POINTER_TYPE_P (TREE_TYPE (op1))
-               && TREE_CODE (op1) != INTEGER_CST)
-             {
-               if (TREE_CODE (op1) == SSA_NAME)
-                 merge_pointed_to_info (ai, var, op1);
-               else if (TREE_CODE (op1) == ADDR_EXPR)
-                 add_pointed_to_var (ai, var, op1);
-               else
-                 add_pointed_to_expr (var, op1);
-             }
-
-           /* Neither operand is a pointer?  VAR can be pointing
-              anywhere.  FIXME: Is this right?  If we get here, we
-              found PTR = INT_CST + INT_CST.  */
-           if (!(POINTER_TYPE_P (TREE_TYPE (op0))
-                 && TREE_CODE (op0) != INTEGER_CST)
-               && !(POINTER_TYPE_P (TREE_TYPE (op1))
-                    && TREE_CODE (op1) != INTEGER_CST))
-             add_pointed_to_expr (var, rhs);
-         }
-
-       /* Something else.  */
-       else
-         add_pointed_to_expr (var, rhs);
+       add_pointed_to_expr (ai, var, rhs);
        break;
       }
+
     case ASM_EXPR:
       /* Pointers defined by __asm__ statements can point anywhere.  */
       set_pt_anything (var);
@@ -1911,13 +1957,14 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
          tree decl = SSA_NAME_VAR (var);
          
          if (TREE_CODE (decl) == PARM_DECL)
-           add_pointed_to_expr (var, decl);
+           add_pointed_to_expr (ai, var, decl);
          else if (DECL_INITIAL (decl))
-           add_pointed_to_var (ai, var, DECL_INITIAL (decl));
+           add_pointed_to_expr (ai, var, DECL_INITIAL (decl));
          else
-           add_pointed_to_expr (var, decl);
+           add_pointed_to_expr (ai, var, decl);
        }
       break;
+
     case PHI_NODE:
       {
         /* It STMT is a PHI node, then VAR is one of its arguments.  The
@@ -1931,16 +1978,19 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
            break;
            
          case SSA_NAME:
-           merge_pointed_to_info (ai, lhs, var);
+           /* Avoid unnecessary merges.  */
+           if (lhs != var)
+             merge_pointed_to_info (ai, lhs, var);
            break;
            
          default:
            gcc_assert (is_gimple_min_invariant (var));
-           add_pointed_to_expr (lhs, var);
+           add_pointed_to_expr (ai, lhs, var);
            break;
          }
        break;
       }
+
     default:
       gcc_unreachable ();
     }
@@ -1986,6 +2036,16 @@ is_escape_site (tree stmt, size_t *num_calls_p)
       if (lhs == NULL_TREE)
        return true;
 
+      /* If the RHS is a conversion between a pointer and an integer, the
+        pointer escapes since we can't track the integer.  */
+      if ((TREE_CODE (TREE_OPERAND (stmt, 1)) == NOP_EXPR
+          || TREE_CODE (TREE_OPERAND (stmt, 1)) == CONVERT_EXPR
+          || TREE_CODE (TREE_OPERAND (stmt, 1)) == VIEW_CONVERT_EXPR)
+         && POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND
+                                       (TREE_OPERAND (stmt, 1), 0)))
+         && !POINTER_TYPE_P (TREE_TYPE (TREE_OPERAND (stmt, 1))))
+       return true;
+
       /* If the LHS is an SSA name, it can't possibly represent a non-local
         memory store.  */
       if (TREE_CODE (lhs) == SSA_NAME)
@@ -2024,9 +2084,6 @@ create_memory_tag (tree type, bool is_type_tag)
      determine whether they should be considered globals.  */
   DECL_CONTEXT (tag) = current_function_decl;
 
-  /* If the pointed-to type is volatile, so is the tag.  */
-  TREE_THIS_VOLATILE (tag) = TREE_THIS_VOLATILE (type);
-
   /* Memory tags are by definition addressable.  This also prevents
      is_gimple_ref frome confusing memory tags with optimizable
      variables.  */
@@ -2125,6 +2182,9 @@ get_tmt_for (tree ptr, struct alias_info *ai)
       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 type tag has the same alias set as the
      pointed-to type.  */
   gcc_assert (tag_set == get_alias_set (tag));
@@ -2141,7 +2201,7 @@ static void
 create_global_var (void)
 {
   global_var = build_decl (VAR_DECL, get_identifier (".GLOBAL_VAR"),
-                           size_type_node);
+                           void_type_node);
   DECL_ARTIFICIAL (global_var) = 1;
   TREE_READONLY (global_var) = 0;
   DECL_EXTERNAL (global_var) = 1;
@@ -2223,7 +2283,12 @@ dump_alias_info (FILE *file)
   for (i = 1; i < num_ssa_names; i++)
     {
       tree ptr = ssa_name (i);
-      struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+      struct ptr_info_def *pi;
+      
+      if (ptr == NULL_TREE)
+       continue;
+
+      pi = SSA_NAME_PTR_INFO (ptr);
       if (!SSA_NAME_IN_FREE_LIST (ptr)
          && pi
          && pi->name_mem_tag)
@@ -2255,7 +2320,7 @@ debug_alias_info (void)
 /* Return the alias information associated with pointer T.  It creates a
    new instance if none existed.  */
 
-static struct ptr_info_def *
+struct ptr_info_def *
 get_ptr_info (tree t)
 {
   struct ptr_info_def *pi;
@@ -2306,13 +2371,14 @@ dump_points_to_info_for (FILE *file, tree ptr)
       if (pi->pt_vars)
        {
          unsigned ix;
+         bitmap_iterator bi;
 
          fprintf (file, ", points-to vars: { ");
-         EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix,
-             {
-               print_generic_expr (file, referenced_var (ix), dump_flags);
-               fprintf (file, " ");
-             });
+         EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, ix, bi)
+           {
+             print_generic_expr (file, referenced_var (ix), dump_flags);
+             fprintf (file, " ");
+           }
          fprintf (file, "}");
        }
     }