OSDN Git Service

Fix aliasing bug that also caused memory usage problems.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-alias.c
index 1ec2464..4027ec9 100644 (file)
@@ -390,7 +390,6 @@ init_alias_info (void)
       EXECUTE_IF_SET_IN_BITMAP (call_clobbered_vars, 0, i,
        {
          tree var = referenced_var (i);
-         DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL (var) = 0;
 
          /* Variables that are intrinsically call-clobbered (globals,
             local statics, etc) will not be marked by the aliasing
@@ -577,6 +576,8 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
 {
   basic_block bb;
   size_t i;
+  tree op;
+  ssa_op_iter iter;
 
   timevar_push (TV_TREE_PTA);
 
@@ -587,11 +588,6 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
 
       for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
        {
-         use_optype uses;
-         def_optype defs;
-         v_may_def_optype v_may_defs;
-         v_must_def_optype v_must_defs;
-         stmt_ann_t ann;
          bitmap addr_taken;
          tree stmt = bsi_stmt (si);
          bool stmt_escapes_p = is_escape_site (stmt, &ai->num_calls_found);
@@ -630,11 +626,8 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
                  mark_call_clobbered (var);
                });
 
-         ann = stmt_ann (stmt);
-         uses = USE_OPS (ann);
-         for (i = 0; i < NUM_USES (uses); i++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_USE)
            {
-             tree op = USE_OP (uses, i);
              var_ann_t v_ann = var_ann (SSA_NAME_VAR (op));
              struct ptr_info_def *pi;
              bool is_store;
@@ -654,16 +647,14 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
 
              collect_points_to_info_for (ai, op);
 
-             pi =  SSA_NAME_PTR_INFO (op);
+             pi = SSA_NAME_PTR_INFO (op);
              if (ptr_is_dereferenced_by (op, stmt, &is_store))
                {
-                 /* If we found OP to point to a set of variables or
-                    malloc, then mark it as being dereferenced.  In a
-                    subsequent pass, dereferenced pointers that point
-                    to a set of variables will be assigned a name tag
-                    to alias all the variables OP points to.  */
-                 if (pi->pt_malloc || pi->pt_vars)
-                   pi->is_dereferenced = 1;
+                 /* Mark OP as dereferenced.  In a subsequent pass,
+                    dereferenced pointers that point to a set of
+                    variables will be assigned a name tag to alias
+                    all the variables OP points to.  */
+                 pi->is_dereferenced = 1;
 
                  /* Keep track of how many time we've dereferenced each
                     pointer.  Again, we don't need to grow
@@ -701,10 +692,8 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
          /* Update reference counter for definitions to any
             potentially aliased variable.  This is used in the alias
             grouping heuristics.  */
-         defs = DEF_OPS (ann);
-         for (i = 0; i < NUM_DEFS (defs); i++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_DEF)
            {
-             tree op = DEF_OP (defs, i);
              tree var = SSA_NAME_VAR (op);
              var_ann_t ann = var_ann (var);
              bitmap_set_bit (ai->written_vars, ann->uid);
@@ -713,25 +702,13 @@ compute_points_to_and_addr_escape (struct alias_info *ai)
            }
 
          /* Mark variables in V_MAY_DEF operands as being written to.  */
-         v_may_defs = V_MAY_DEF_OPS (ann);
-         for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
+         FOR_EACH_SSA_TREE_OPERAND (op, stmt, iter, SSA_OP_VIRTUAL_DEFS)
            {
-             tree op = V_MAY_DEF_OP (v_may_defs, i);
              tree var = SSA_NAME_VAR (op);
              var_ann_t ann = var_ann (var);
              bitmap_set_bit (ai->written_vars, ann->uid);
            }
            
-         /* Mark variables in V_MUST_DEF operands as being written to.  */
-         v_must_defs = V_MUST_DEF_OPS (ann);
-         for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
-           {
-             tree op = V_MUST_DEF_OP (v_must_defs, i);
-             tree var = SSA_NAME_VAR (op);
-             var_ann_t ann = var_ann (var);
-             bitmap_set_bit (ai->written_vars, ann->uid);
-           }
-
          /* After promoting variables and computing aliasing we will
             need to re-scan most statements.  FIXME: Try to minimize the
             number of statements re-scanned.  It's not really necessary to
@@ -763,15 +740,16 @@ create_name_tags (struct alias_info *ai)
       tree ptr = VARRAY_TREE (ai->processed_ptrs, i);
       struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
 
-      if (!pi->is_dereferenced)
+      if (pi->pt_anything || !pi->is_dereferenced)
        {
          /* No name tags for pointers that have not been
-            dereferenced.  */
+            dereferenced or point to an arbitrary location.  */
          pi->name_mem_tag = NULL_TREE;
          continue;
        }
 
-      if (pi->pt_vars)
+      if (pi->pt_vars
+         && bitmap_first_set_bit (pi->pt_vars) >= 0)
        {
          size_t j;
          tree old_name_tag = pi->name_mem_tag;
@@ -860,38 +838,14 @@ compute_flow_sensitive_aliasing (struct alias_info *ai)
       if (pi->value_escapes_p || pi->pt_anything)
        {
          /* If PTR escapes or may point to anything, then its associated
-            memory tags are call-clobbered.  */
+            memory tags and pointed-to variables are call-clobbered.  */
          if (pi->name_mem_tag)
            mark_call_clobbered (pi->name_mem_tag);
 
          if (v_ann->type_mem_tag)
            mark_call_clobbered (v_ann->type_mem_tag);
 
-         /* If PTR may point to anything, mark call-clobbered all the
-            addressables with the same alias set as the type pointed-to by
-            PTR.  */
-         if (pi->pt_anything)
-           {
-             HOST_WIDE_INT ptr_set;
-             ptr_set = get_alias_set (TREE_TYPE (TREE_TYPE (ptr)));
-             for (j = 0; j < ai->num_addressable_vars; j++)
-               {
-                 struct alias_map_d *alias_map = ai->addressable_vars[j];
-                 if (alias_map->set == ptr_set)
-                   mark_call_clobbered (alias_map->var);
-               }
-           }
-
-         /* If PTR's value may escape and PTR is never dereferenced, we
-            need to mark all the variables PTR points-to as
-            call-clobbered.  Note that we only need do this it PTR is
-            never dereferenced.  If PTR is dereferenced, it will have a
-            name memory tag, which will have been marked call-clobbered.
-            This will in turn mark the pointed-to variables as
-            call-clobbered when we call add_may_alias below.  */
-         if (pi->value_escapes_p
-             && pi->name_mem_tag == NULL_TREE
-             && pi->pt_vars)
+         if (pi->pt_vars)
            EXECUTE_IF_SET_IN_BITMAP (pi->pt_vars, 0, j,
                mark_call_clobbered (referenced_var (j)));
        }
@@ -1329,7 +1283,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
-             && !needs_to_live_in_memory (var))
+             && !is_global_var (var))
            {
              /* The address of VAR is not needed, remove the
                 addressable bit, so that it can be optimized as a
@@ -1391,7 +1345,7 @@ setup_pointers_and_addressables (struct alias_info *ai)
              /* If pointer VAR is a global variable or a PARM_DECL,
                 then its memory tag should be considered a global
                 variable.  */
-             if (TREE_CODE (var) == PARM_DECL || needs_to_live_in_memory (var))
+             if (TREE_CODE (var) == PARM_DECL || is_global_var (var))
                mark_call_clobbered (tag);
 
              /* All the dereferences of pointer VAR count as
@@ -1685,7 +1639,9 @@ add_may_alias (tree var, tree alias)
     if (alias == VARRAY_TREE (v_ann->may_aliases, i))
       return;
 
-  /* If VAR is a call-clobbered variable, so is its new ALIAS.  */
+  /* If VAR is a call-clobbered variable, so is its new ALIAS.
+     FIXME, call-clobbering should only depend on whether an address
+     escapes.  It should be independent of aliasing.  */
   if (is_call_clobbered (var))
     mark_call_clobbered (alias);
 
@@ -1706,7 +1662,9 @@ replace_may_alias (tree var, size_t i, tree new_alias)
   var_ann_t v_ann = var_ann (var);
   VARRAY_TREE (v_ann->may_aliases, i) = new_alias;
 
-  /* If VAR is a call-clobbered variable, so is NEW_ALIAS.  */
+  /* If VAR is a call-clobbered variable, so is NEW_ALIAS.
+     FIXME, call-clobbering should only depend on whether an address
+     escapes.  It should be independent of aliasing.  */
   if (is_call_clobbered (var))
     mark_call_clobbered (new_alias);
 
@@ -1725,8 +1683,6 @@ set_pt_anything (tree ptr)
 
   pi->pt_anything = 1;
   pi->pt_malloc = 0;
-  pi->pt_vars = NULL;
-  pi->is_dereferenced = 0;
 
   /* The pointer used to have a name tag, but we now found it pointing
      to an arbitrary location.  The name tag needs to be renamed and
@@ -1813,6 +1769,8 @@ merge_pointed_to_info (struct alias_info *ai, tree dest, tree orig)
                           orig_pi->pt_vars);
        }
     }
+  else
+    set_pt_anything (dest);
 }
 
 
@@ -1883,14 +1841,14 @@ add_pointed_to_var (struct alias_info *ai, tree ptr, tree value)
       uid = var_ann (pt_var)->uid;
       bitmap_set_bit (ai->addresses_needed, uid);
 
-      /* If PTR has already been found to point anywhere, don't
-        add the variable to PTR's points-to set.  */
-      if (!pi->pt_anything)
-       {
-         if (pi->pt_vars == NULL)
-           pi->pt_vars = BITMAP_GGC_ALLOC ();
-         bitmap_set_bit (pi->pt_vars, uid);
-       }
+      if (pi->pt_vars == NULL)
+       pi->pt_vars = BITMAP_GGC_ALLOC ();
+      bitmap_set_bit (pi->pt_vars, uid);
+
+      /* If the variable is a global, mark the pointer as pointing to
+        global memory (which will make its tag a global variable).  */
+      if (is_global_var (pt_var))
+       pi->pt_global_mem = 1;
     }
 }
 
@@ -1938,17 +1896,33 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
          tree op0 = TREE_OPERAND (rhs, 0);
          tree op1 = TREE_OPERAND (rhs, 1);
 
-         if (TREE_CODE (op0) == SSA_NAME
-             && POINTER_TYPE_P (TREE_TYPE (op0)))
-           merge_pointed_to_info (ai, var, op0);
-         else if (TREE_CODE (op1) == SSA_NAME
-                  && POINTER_TYPE_P (TREE_TYPE (op1)))
-           merge_pointed_to_info (ai, var, op1);
-         else if (TREE_CODE (op0) == ADDR_EXPR)
-           add_pointed_to_var (ai, var, op0);
-         else if (TREE_CODE (op1) == ADDR_EXPR)
-           add_pointed_to_var (ai, var, op1);
-         else
+         /* Both operands may be of pointer type.  FIXME: Shouldn't
+            we just expect PTR + OFFSET always?  */
+         if (POINTER_TYPE_P (TREE_TYPE (op0)))
+           {
+             if (TREE_CODE (op0) == SSA_NAME)
+               merge_pointed_to_info (ai, var, op0);
+             else if (TREE_CODE (op0) == ADDR_EXPR)
+               add_pointed_to_var (ai, var, op0);
+             else
+               add_pointed_to_expr (var, op0);
+           }
+
+         if (POINTER_TYPE_P (TREE_TYPE (op1)))
+           {
+             if (TREE_CODE (op1) == SSA_NAME)
+               merge_pointed_to_info (ai, var, op1);
+             else if (TREE_CODE (op1) == ADDR_EXPR)
+               add_pointed_to_var (ai, var, op1);
+             else
+               add_pointed_to_expr (var, op1);
+           }
+
+         /* Neither operand is a pointer?  VAR can be pointing
+            anywhere.   FIXME: Is this right?  If we get here, we
+            found PTR = INT_CST + INT_CST.  */
+         if (!POINTER_TYPE_P (TREE_TYPE (op0))
+             && !POINTER_TYPE_P (TREE_TYPE (op1)))
            add_pointed_to_expr (var, rhs);
        }
 
@@ -1981,12 +1955,7 @@ collect_points_to_info_r (tree var, tree stmt, void *data)
       if (TREE_CODE (var) == ADDR_EXPR)
        add_pointed_to_var (ai, lhs, var);
       else if (TREE_CODE (var) == SSA_NAME)
-       {
-         if (bitmap_bit_p (ai->ssa_names_visited, SSA_NAME_VERSION (var)))
-           merge_pointed_to_info (ai, lhs, var);
-         else
-           set_pt_anything (lhs);
-       }
+       merge_pointed_to_info (ai, lhs, var);
       else if (is_gimple_min_invariant (var))
        add_pointed_to_expr (lhs, var);
       else
@@ -2105,18 +2074,14 @@ get_nmt_for (tree ptr)
   tree tag = pi->name_mem_tag;
 
   if (tag == NULL_TREE)
-    {
-      tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
+    tag = create_memory_tag (TREE_TYPE (TREE_TYPE (ptr)), false);
 
-      /* If PTR is a PARM_DECL, its memory tag should be considered a
-        global variable.  */
-      if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL)
-       mark_call_clobbered (tag);
-
-      /* Similarly, if PTR points to malloc, then TAG is a global.  */
-      if (pi->pt_malloc)
-       mark_call_clobbered (tag);
-    }
+  /* If PTR is a PARM_DECL, it points to a global variable or malloc,
+     then its name tag should be considered a global variable.  */
+  if (TREE_CODE (SSA_NAME_VAR (ptr)) == PARM_DECL
+      || pi->pt_malloc
+      || pi->pt_global_mem)
+    mark_call_clobbered (tag);
 
   return tag;
 }
@@ -2406,6 +2371,7 @@ dump_points_to_info (FILE *file)
   basic_block bb;
   block_stmt_iterator si;
   size_t i;
+  ssa_op_iter iter;
   const char *fname =
     lang_hooks.decl_printable_name (current_function_decl, 2);
 
@@ -2439,12 +2405,11 @@ dump_points_to_info (FILE *file)
 
        for (si = bsi_start (bb); !bsi_end_p (si); bsi_next (&si))
          {
-           stmt_ann_t ann = stmt_ann (bsi_stmt (si));
-           def_optype defs = DEF_OPS (ann);
-           if (defs)
-             for (i = 0; i < NUM_DEFS (defs); i++)
-               if (POINTER_TYPE_P (TREE_TYPE (DEF_OP (defs, i))))
-                 dump_points_to_info_for (file, DEF_OP (defs, i));
+           tree stmt = bsi_stmt (si);
+           tree def;
+           FOR_EACH_SSA_TREE_OPERAND (def, stmt, iter, SSA_OP_DEF)
+             if (POINTER_TYPE_P (TREE_TYPE (def)))
+               dump_points_to_info_for (file, def);
          }
     }
 
@@ -2502,15 +2467,17 @@ may_be_aliased (tree var)
   if (TREE_ADDRESSABLE (var))
     return true;
 
-  /* Automatic variables can't have their addresses escape any other way.  */
-  if (!TREE_STATIC (var))
-    return false;
-
   /* Globally visible variables can have their addresses taken by other
      translation units.  */
   if (DECL_EXTERNAL (var) || TREE_PUBLIC (var))
     return true;
 
+  /* Automatic variables can't have their addresses escape any other way.
+     This must be after the check for global variables, as extern declarations
+     do not have TREE_STATIC set.  */
+  if (!TREE_STATIC (var))
+    return false;
+
   /* If we're in unit-at-a-time mode, then we must have seen all occurrences
      of address-of operators, and so we can trust TREE_ADDRESSABLE.  Otherwise
      we can only be sure the variable isn't addressable if it's local to the