OSDN Git Service

* c-common.c (shorten_compare): Use force_fit_type directly.
[pf3gnuchains/gcc-fork.git] / gcc / tree-ssa-dce.c
index c94a2f6..111f540 100644 (file)
@@ -107,7 +107,6 @@ static inline basic_block find_pdom (basic_block);
 static inline void mark_stmt_necessary (tree, bool);
 static inline void mark_operand_necessary (tree);
 
-static bool need_to_preserve_store (tree);
 static void mark_stmt_if_obviously_necessary (tree, bool);
 static void find_obviously_necessary_stmts (struct edge_list *);
 
@@ -267,14 +266,6 @@ mark_operand_necessary (tree op)
   VARRAY_PUSH_TREE (worklist, stmt);
 }
 \f
-/* Return true if a store to a variable needs to be preserved.  */
-
-static inline bool
-need_to_preserve_store (tree ssa_name)
-{
-  return (needs_to_live_in_memory (SSA_NAME_VAR (ssa_name)));
-}
-\f
 
 /* Mark STMT as necessary if it is obviously is.  Add it to the worklist if
    it can make other statements necessary.
@@ -367,10 +358,11 @@ mark_stmt_if_obviously_necessary (tree stmt, bool aggressive)
     }
 
   ann = stmt_ann (stmt);
-  /* If the statement has volatile operands, it needs to be preserved.  Same
-     for statements that can alter control flow in unpredictable ways.  */
-  if (ann->has_volatile_ops
-      || is_ctrl_altering_stmt (stmt))
+
+  /* If the statement has volatile operands, it needs to be preserved.
+     Same for statements that can alter control flow in unpredictable
+     ways.  */
+  if (ann->has_volatile_ops || is_ctrl_altering_stmt (stmt))
     {
       mark_stmt_necessary (stmt, true);
       return;
@@ -382,33 +374,87 @@ mark_stmt_if_obviously_necessary (tree stmt, bool aggressive)
   for (i = 0; i < NUM_DEFS (defs); i++)
     {
       tree def = DEF_OP (defs, i);
-      if (need_to_preserve_store (def))
+      if (is_global_var (SSA_NAME_VAR (def)))
        {
          mark_stmt_necessary (stmt, true);
          return;
         }
     }
 
+  /* Check virtual definitions.  If we get here, the only virtual
+     definitions we should see are those generated by assignment
+     statements.  */
   v_may_defs = V_MAY_DEF_OPS (ann);
-  for (i = 0; i < NUM_V_MAY_DEFS (v_may_defs); i++)
-    {
-      tree v_may_def = V_MAY_DEF_RESULT (v_may_defs, i);
-      if (need_to_preserve_store (v_may_def))
-       {
-         mark_stmt_necessary (stmt, true);
-         return;
-        }
-    }
-    
   v_must_defs = V_MUST_DEF_OPS (ann);
-  for (i = 0; i < NUM_V_MUST_DEFS (v_must_defs); i++)
+  if (NUM_V_MAY_DEFS (v_may_defs) > 0 || NUM_V_MUST_DEFS (v_must_defs) > 0)
     {
-      tree v_must_def = V_MUST_DEF_OP (v_must_defs, i);
-      if (need_to_preserve_store (v_must_def))
+      tree lhs;
+
+#if defined ENABLE_CHECKING
+      if (TREE_CODE (stmt) != MODIFY_EXPR)
+       abort ();
+#endif
+
+      /* Note that we must not check the individual virtual operands
+        here.  In particular, if this is an aliased store, we could
+        end up with something like the following (SSA notation
+        redacted for brevity):
+
+               foo (int *p, int i)
+               {
+                 int x;
+                 p_1 = (i_2 > 3) ? &x : p_1;
+
+                 # x_4 = V_MAY_DEF <x_3>
+                 *p_1 = 5;
+
+                 return 2;
+               }
+
+        Notice that the store to '*p_1' should be preserved, if we
+        were to check the virtual definitions in that store, we would
+        not mark it needed.  This is because 'x' is not a global
+        variable.
+
+        Therefore, we check the base address of the LHS.  If the
+        address is a pointer, we check if its name tag or type tag is
+        a global variable.  Otherwise, we check if the base variable
+        is a global.  */
+      lhs = TREE_OPERAND (stmt, 0);
+      if (TREE_CODE_CLASS (TREE_CODE (lhs)) == 'r')
+       lhs = get_base_address (lhs);
+
+      if (lhs == NULL_TREE)
        {
+         /* If LHS is NULL, it means that we couldn't get the base
+            address of the reference.  In which case, we should not
+            remove this store. */
          mark_stmt_necessary (stmt, true);
-         return;
-        }
+       }
+      else if (DECL_P (lhs))
+       {
+         /* If the store is to a global symbol, we need to keep it.  */
+         if (is_global_var (lhs))
+           mark_stmt_necessary (stmt, true);
+       }
+      else if (TREE_CODE (lhs) == INDIRECT_REF)
+       {
+         tree ptr = TREE_OPERAND (lhs, 0);
+         struct ptr_info_def *pi = SSA_NAME_PTR_INFO (ptr);
+         tree nmt = (pi) ? pi->name_mem_tag : NULL_TREE;
+         tree tmt = var_ann (SSA_NAME_VAR (ptr))->type_mem_tag;
+
+         /* If either the name tag or the type tag for PTR is a
+            global variable, then the store is necessary.  */
+         if ((nmt && is_global_var (nmt))
+             || (tmt && is_global_var (tmt)))
+           {
+             mark_stmt_necessary (stmt, true);
+             return;
+           }
+       }
+      else
+       abort ();
     }
 
   return;
@@ -444,7 +490,7 @@ find_obviously_necessary_stmts (struct edge_list *el)
             Thus, we only need to mark PHIs for real variables which
             need their result preserved as being inherently necessary.  */
          if (is_gimple_reg (PHI_RESULT (phi))
-             && need_to_preserve_store (PHI_RESULT (phi)))
+             && is_global_var (SSA_NAME_VAR (PHI_RESULT (phi))))
            mark_stmt_necessary (phi, true);
         }