aboutsummaryrefslogtreecommitdiff
path: root/gcc/tree-ssa-dce.c
diff options
context:
space:
mode:
authorDiego Novillo <dnovillo@redhat.com>2004-08-12 14:34:11 +0000
committerDiego Novillo <dnovillo@gcc.gnu.org>2004-08-12 10:34:11 -0400
commitc597ef4eab9a2de9ad0b2187547ac9bac0b53132 (patch)
treea0fa15664fe5d4dfd7f6bced8b73b4839f33dfcb /gcc/tree-ssa-dce.c
parentab5c8549a48977b865f8ed8dd4bd4e745b1cec75 (diff)
re PR tree-optimization/16867 (Inline array initializer miscompilation at -O)
PR tree-optimization/16867 * tree.c (is_global_var): New function. (needs_to_live_in_memory): Check for TREE_ADDRESSABLE. Call is_global_var. * tree.h (DECL_NEEDS_TO_LIVE_IN_MEMORY_INTERNAL): Remove. Update all users. (is_global_var): Declare. * tree-dfa.c (dump_variable): Display global and addressable attributes. (add_referenced_var): Clarify documentation when marking variables call-clobbered. * tree-flow-inline.h (is_call_clobbered): Call is_global_var instead of needs_to_live_in_memory. (mark_call_clobbered): If the variable is a tag, mark it DECL_EXTERNAL. * tree-gimple.c (is_gimple_reg): Don't check for TREE_ADDRESSABLE. (is_gimple_non_addressable): Likewise. * tree-ssa-alias.c (get_nmt_for): Always check whether the tag needs to be marked call-clobbered. (setup_pointers_and_addressables): Call is_global_var instead of needs_to_live_in_memory. * tree-ssa-dce.c (need_to_preserve_store): Remove. Update all users with is_global_var. (mark_stmt_if_obviously_necessary): Fix processing of aliased stores. Don't check the virtual definitions. Rather, check whether the store is going into global memory. (find_obviously_necessary_stmts): Get the symbol from the PHI result. * tree-ssa-operands.c (get_call_expr_operands): Do not add clobbering may-defs if the call does not have side effects. libjava/ChangeLog PR tree-optimization/16867 * testsuite/libjava.lang/PR16867.java: New test. From-SVN: r85874
Diffstat (limited to 'gcc/tree-ssa-dce.c')
-rw-r--r--gcc/tree-ssa-dce.c106
1 files changed, 76 insertions, 30 deletions
diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c
index c94a2f6c6d6..111f5400b9f 100644
--- a/gcc/tree-ssa-dce.c
+++ b/gcc/tree-ssa-dce.c
@@ -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);
}
-/* 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)));
-}
-
/* 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);
}