diff options
author | Diego Novillo <dnovillo@redhat.com> | 2004-08-12 14:34:11 +0000 |
---|---|---|
committer | Diego Novillo <dnovillo@gcc.gnu.org> | 2004-08-12 10:34:11 -0400 |
commit | c597ef4eab9a2de9ad0b2187547ac9bac0b53132 (patch) | |
tree | a0fa15664fe5d4dfd7f6bced8b73b4839f33dfcb /gcc/tree-ssa-dce.c | |
parent | ab5c8549a48977b865f8ed8dd4bd4e745b1cec75 (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.c | 106 |
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); } |