X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Ftree-ssa-dce.c;h=ace9ef9972d40151cac637c937805017a6dba454;hb=02be8f84f05bae942940b9eae1ae1f74d7a6610c;hp=6900ee77e869570aba49b40299a8a82fcf614e31;hpb=841424ccaf396ea0dfbfc1e27eeabe3ef5889cd0;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/tree-ssa-dce.c b/gcc/tree-ssa-dce.c index 6900ee77e86..ace9ef9972d 100644 --- a/gcc/tree-ssa-dce.c +++ b/gcc/tree-ssa-dce.c @@ -299,17 +299,32 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive) return; case GIMPLE_CALL: - /* Most, but not all function calls are required. Function calls that - produce no result and have no side effects (i.e. const pure - functions) are unnecessary. */ - if (gimple_has_side_effects (stmt)) - { - mark_stmt_necessary (stmt, true); + { + tree callee = gimple_call_fndecl (stmt); + if (callee != NULL_TREE + && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_MALLOC: + case BUILT_IN_CALLOC: + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + return; + + default:; + } + /* Most, but not all function calls are required. Function calls that + produce no result and have no side effects (i.e. const pure + functions) are unnecessary. */ + if (gimple_has_side_effects (stmt)) + { + mark_stmt_necessary (stmt, true); + return; + } + if (!gimple_call_lhs (stmt)) return; - } - if (!gimple_call_lhs (stmt)) - return; - break; + break; + } case GIMPLE_DEBUG: /* Debug temps without a value are not useful. ??? If we could @@ -336,6 +351,12 @@ mark_stmt_if_obviously_necessary (gimple stmt, bool aggressive) mark_stmt_necessary (stmt, true); break; + case GIMPLE_ASSIGN: + if (TREE_CODE (gimple_assign_lhs (stmt)) == SSA_NAME + && TREE_CLOBBER_P (gimple_assign_rhs1 (stmt))) + return; + break; + default: break; } @@ -490,6 +511,7 @@ find_obviously_necessary_stmts (struct edge_list *el) static bool ref_may_be_aliased (tree ref) { + gcc_assert (TREE_CODE (ref) != WITH_SIZE_EXPR); while (handled_component_p (ref)) ref = TREE_OPERAND (ref, 0); if (TREE_CODE (ref) == MEM_REF @@ -612,6 +634,26 @@ mark_all_reaching_defs_necessary_1 (ao_ref *ref ATTRIBUTE_UNUSED, return false; } + /* We want to skip statments that do not constitute stores but have + a virtual definition. */ + if (is_gimple_call (def_stmt)) + { + tree callee = gimple_call_fndecl (def_stmt); + if (callee != NULL_TREE + && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL) + switch (DECL_FUNCTION_CODE (callee)) + { + case BUILT_IN_MALLOC: + case BUILT_IN_CALLOC: + case BUILT_IN_ALLOCA: + case BUILT_IN_ALLOCA_WITH_ALIGN: + case BUILT_IN_FREE: + return false; + + default:; + } + } + mark_operand_necessary (vdef); return false; @@ -792,6 +834,25 @@ propagate_necessity (struct edge_list *el) ssa_op_iter iter; tree use; + /* If this is a call to free which is directly fed by an + allocation function do not mark that necessary through + processing the argument. */ + if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)) + { + tree ptr = gimple_call_arg (stmt, 0); + gimple def_stmt; + tree def_callee; + /* If the pointer we free is defined by an allocation + function do not add the call to the worklist. */ + if (TREE_CODE (ptr) == SSA_NAME + && is_gimple_call (def_stmt = SSA_NAME_DEF_STMT (ptr)) + && (def_callee = gimple_call_fndecl (def_stmt)) + && DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL + && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC + || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC)) + continue; + } + FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) mark_operand_necessary (use); @@ -831,11 +892,17 @@ propagate_necessity (struct edge_list *el) if (callee != NULL_TREE && DECL_BUILT_IN_CLASS (callee) == BUILT_IN_NORMAL && (DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET + || DECL_FUNCTION_CODE (callee) == BUILT_IN_MEMSET_CHK || DECL_FUNCTION_CODE (callee) == BUILT_IN_MALLOC + || DECL_FUNCTION_CODE (callee) == BUILT_IN_CALLOC || DECL_FUNCTION_CODE (callee) == BUILT_IN_FREE + || DECL_FUNCTION_CODE (callee) == BUILT_IN_VA_END || DECL_FUNCTION_CODE (callee) == BUILT_IN_ALLOCA + || (DECL_FUNCTION_CODE (callee) + == BUILT_IN_ALLOCA_WITH_ALIGN) || DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_SAVE - || DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE)) + || DECL_FUNCTION_CODE (callee) == BUILT_IN_STACK_RESTORE + || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED)) continue; /* Calls implicitly load from memory, their arguments @@ -847,6 +914,8 @@ propagate_necessity (struct edge_list *el) if (TREE_CODE (arg) == SSA_NAME || is_gimple_min_invariant (arg)) continue; + if (TREE_CODE (arg) == WITH_SIZE_EXPR) + arg = TREE_OPERAND (arg, 0); if (!ref_may_be_aliased (arg)) mark_aliased_reaching_defs_necessary (stmt, arg); } @@ -854,19 +923,17 @@ propagate_necessity (struct edge_list *el) else if (gimple_assign_single_p (stmt)) { tree rhs; - bool rhs_aliased = false; /* If this is a load mark things necessary. */ rhs = gimple_assign_rhs1 (stmt); if (TREE_CODE (rhs) != SSA_NAME - && !is_gimple_min_invariant (rhs)) + && !is_gimple_min_invariant (rhs) + && TREE_CODE (rhs) != CONSTRUCTOR) { if (!ref_may_be_aliased (rhs)) mark_aliased_reaching_defs_necessary (stmt, rhs); else - rhs_aliased = true; + mark_all_reaching_defs_necessary (stmt); } - if (rhs_aliased) - mark_all_reaching_defs_necessary (stmt); } else if (gimple_code (stmt) == GIMPLE_RETURN) { @@ -874,7 +941,8 @@ propagate_necessity (struct edge_list *el) /* A return statement may perform a load. */ if (rhs && TREE_CODE (rhs) != SSA_NAME - && !is_gimple_min_invariant (rhs)) + && !is_gimple_min_invariant (rhs) + && TREE_CODE (rhs) != CONSTRUCTOR) { if (!ref_may_be_aliased (rhs)) mark_aliased_reaching_defs_necessary (stmt, rhs); @@ -892,10 +960,18 @@ propagate_necessity (struct edge_list *el) tree op = TREE_VALUE (gimple_asm_input_op (stmt, i)); if (TREE_CODE (op) != SSA_NAME && !is_gimple_min_invariant (op) + && TREE_CODE (op) != CONSTRUCTOR && !ref_may_be_aliased (op)) mark_aliased_reaching_defs_necessary (stmt, op); } } + else if (gimple_code (stmt) == GIMPLE_TRANSACTION) + { + /* The beginning of a transaction is a memory barrier. */ + /* ??? If we were really cool, we'd only be a barrier + for the memories touched within the transaction. */ + mark_all_reaching_defs_necessary (stmt); + } else gcc_unreachable (); @@ -919,18 +995,36 @@ propagate_necessity (struct edge_list *el) } } -/* Replace all uses of result of PHI by underlying variable and mark it +/* Replace all uses of NAME by underlying variable and mark it for renaming. */ void -mark_virtual_phi_result_for_renaming (gimple phi) +mark_virtual_operand_for_renaming (tree name) { bool used = false; imm_use_iterator iter; use_operand_p use_p; gimple stmt; - tree result_ssa, result_var; + tree name_var; + + name_var = SSA_NAME_VAR (name); + FOR_EACH_IMM_USE_STMT (stmt, iter, name) + { + FOR_EACH_IMM_USE_ON_STMT (use_p, iter) + SET_USE (use_p, name_var); + update_stmt (stmt); + used = true; + } + if (used) + mark_sym_for_renaming (name_var); +} + +/* Replace all uses of result of PHI by underlying variable and mark it + for renaming. */ +void +mark_virtual_phi_result_for_renaming (gimple phi) +{ if (dump_file && (dump_flags & TDF_DETAILS)) { fprintf (dump_file, "Marking result for renaming : "); @@ -938,19 +1032,10 @@ mark_virtual_phi_result_for_renaming (gimple phi) fprintf (dump_file, "\n"); } - result_ssa = gimple_phi_result (phi); - result_var = SSA_NAME_VAR (result_ssa); - FOR_EACH_IMM_USE_STMT (stmt, iter, result_ssa) - { - FOR_EACH_IMM_USE_ON_STMT (use_p, iter) - SET_USE (use_p, result_var); - update_stmt (stmt); - used = true; - } - if (used) - mark_sym_for_renaming (result_var); + mark_virtual_operand_for_renaming (gimple_phi_result (phi)); } + /* Remove dead PHI nodes from block BB. */ static bool @@ -1137,6 +1222,26 @@ remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb) ei_next (&ei); } + /* If this is a store into a variable that is being optimized away, + add a debug bind stmt if possible. */ + if (MAY_HAVE_DEBUG_STMTS + && gimple_assign_single_p (stmt) + && is_gimple_val (gimple_assign_rhs1 (stmt))) + { + tree lhs = gimple_assign_lhs (stmt); + if ((TREE_CODE (lhs) == VAR_DECL || TREE_CODE (lhs) == PARM_DECL) + && !DECL_IGNORED_P (lhs) + && is_gimple_reg_type (TREE_TYPE (lhs)) + && !is_global_var (lhs) + && !DECL_HAS_VALUE_EXPR_P (lhs)) + { + tree rhs = gimple_assign_rhs1 (stmt); + gimple note + = gimple_build_debug_bind (lhs, unshare_expr (rhs), stmt); + gsi_insert_after (i, note, GSI_SAME_STMT); + } + } + unlink_stmt_vdef (stmt); gsi_remove (i, true); release_defs (stmt); @@ -1199,6 +1304,29 @@ eliminate_unnecessary_stmts (void) stats.total++; + /* We can mark a call to free as not necessary if the + defining statement of its argument is an allocation + function and that is not necessary itself. */ + if (gimple_call_builtin_p (stmt, BUILT_IN_FREE)) + { + tree ptr = gimple_call_arg (stmt, 0); + tree callee2; + gimple def_stmt; + if (TREE_CODE (ptr) != SSA_NAME) + continue; + def_stmt = SSA_NAME_DEF_STMT (ptr); + if (!is_gimple_call (def_stmt) + || gimple_plf (def_stmt, STMT_NECESSARY)) + continue; + callee2 = gimple_call_fndecl (def_stmt); + if (callee2 == NULL_TREE + || DECL_BUILT_IN_CLASS (callee2) != BUILT_IN_NORMAL + || (DECL_FUNCTION_CODE (callee2) != BUILT_IN_MALLOC + && DECL_FUNCTION_CODE (callee2) != BUILT_IN_CALLOC)) + continue; + gimple_set_plf (stmt, STMT_NECESSARY, false); + } + /* If GSI is not necessary then remove it. */ if (!gimple_plf (stmt, STMT_NECESSARY)) { @@ -1208,31 +1336,38 @@ eliminate_unnecessary_stmts (void) } else if (is_gimple_call (stmt)) { - call = gimple_call_fndecl (stmt); - if (call) + tree name = gimple_call_lhs (stmt); + + notice_special_calls (stmt); + + /* When LHS of var = call (); is dead, simplify it into + call (); saving one operand. */ + if (name + && TREE_CODE (name) == SSA_NAME + && !TEST_BIT (processed, SSA_NAME_VERSION (name)) + /* Avoid doing so for allocation calls which we + did not mark as necessary, it will confuse the + special logic we apply to malloc/free pair removal. */ + && (!(call = gimple_call_fndecl (stmt)) + || DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL + || (DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC + && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC + && DECL_FUNCTION_CODE (call) != BUILT_IN_ALLOCA + && (DECL_FUNCTION_CODE (call) + != BUILT_IN_ALLOCA_WITH_ALIGN)))) { - tree name; - - /* When LHS of var = call (); is dead, simplify it into - call (); saving one operand. */ - name = gimple_call_lhs (stmt); - if (name && TREE_CODE (name) == SSA_NAME - && !TEST_BIT (processed, SSA_NAME_VERSION (name))) + something_changed = true; + if (dump_file && (dump_flags & TDF_DETAILS)) { - something_changed = true; - if (dump_file && (dump_flags & TDF_DETAILS)) - { - fprintf (dump_file, "Deleting LHS of call: "); - print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); - fprintf (dump_file, "\n"); - } - - gimple_call_set_lhs (stmt, NULL_TREE); - maybe_clean_or_replace_eh_stmt (stmt, stmt); - update_stmt (stmt); - release_ssa_name (name); + fprintf (dump_file, "Deleting LHS of call: "); + print_gimple_stmt (dump_file, stmt, 0, TDF_SLIM); + fprintf (dump_file, "\n"); } - notice_special_calls (stmt); + + gimple_call_set_lhs (stmt, NULL_TREE); + maybe_clean_or_replace_eh_stmt (stmt, stmt); + update_stmt (stmt); + release_ssa_name (name); } } }