Mercurial > hg > CbC > CbC_gcc
diff gcc/tree-ssa-dce.c @ 145:1830386684a0
gcc-9.2.0
author | anatofuz |
---|---|
date | Thu, 13 Feb 2020 11:34:05 +0900 |
parents | 84e7813d76e9 |
children |
line wrap: on
line diff
--- a/gcc/tree-ssa-dce.c Thu Oct 25 07:37:49 2018 +0900 +++ b/gcc/tree-ssa-dce.c Thu Feb 13 11:34:05 2020 +0900 @@ -1,5 +1,5 @@ /* Dead code elimination pass for the GNU compiler. - Copyright (C) 2002-2018 Free Software Foundation, Inc. + Copyright (C) 2002-2020 Free Software Foundation, Inc. Contributed by Ben Elliston <bje@redhat.com> and Andrew MacLeod <amacleod@redhat.com> Adapted to use control dependence by Steven Bosscher, SUSE Labs. @@ -115,6 +115,14 @@ static int *bb_postorder; +/* True if we should treat any stmt with a vdef as necessary. */ + +static inline bool +keep_all_vdefs_p () +{ + return optimize_debug; +} + /* If STMT is not already marked necessary, mark it, and add it to the worklist if ADD_TO_WORKLIST is true. */ @@ -237,6 +245,12 @@ default:; } + + if (callee != NULL_TREE + && flag_allocation_dce + && DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee)) + return; + /* 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. */ @@ -245,6 +259,17 @@ mark_stmt_necessary (stmt, true); return; } + /* IFN_GOACC_LOOP calls are necessary in that they are used to + represent parameter (i.e. step, bound) of a lowered OpenACC + partitioned loop. But this kind of partitioned loop might not + survive from aggressive loop removal for it has loop exit and + is assumed to be finite. Therefore, we need to explicitly mark + these calls. (An example is libgomp.oacc-c-c++-common/pr84955.c) */ + if (gimple_call_internal_p (stmt, IFN_GOACC_LOOP)) + { + mark_stmt_necessary (stmt, true); + return; + } if (!gimple_call_lhs (stmt)) return; break; @@ -300,6 +325,12 @@ return; } + if (gimple_vdef (stmt) && keep_all_vdefs_p ()) + { + mark_stmt_necessary (stmt, true); + return; + } + return; } @@ -400,7 +431,7 @@ /* Prevent the empty possibly infinite loops from being removed. */ if (aggressive) { - struct loop *loop; + class loop *loop; if (mark_irreducible_loops ()) FOR_EACH_BB_FN (bb, cfun) { @@ -420,7 +451,7 @@ if (!finite_loop_p (loop)) { if (dump_file) - fprintf (dump_file, "can not prove finiteness of loop %i\n", loop->num); + fprintf (dump_file, "cannot prove finiteness of loop %i\n", loop->num); mark_control_dependent_edges_necessary (loop->latch, false); } } @@ -515,6 +546,9 @@ static void mark_aliased_reaching_defs_necessary (gimple *stmt, tree ref) { + /* Should have been caught before calling this function. */ + gcc_checking_assert (!keep_all_vdefs_p ()); + unsigned int chain; ao_ref refd; gcc_assert (!chain_ovfl); @@ -577,6 +611,11 @@ default:; } + + if (callee != NULL_TREE + && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee) + || DECL_IS_OPERATOR_DELETE_P (callee))) + return false; } if (! gimple_clobber_p (def_stmt)) @@ -588,6 +627,8 @@ static void mark_all_reaching_defs_necessary (gimple *stmt) { + /* Should have been caught before calling this function. */ + gcc_checking_assert (!keep_all_vdefs_p ()); walk_aliased_vdefs (NULL, gimple_vuse (stmt), mark_all_reaching_defs_necessary_1, NULL, &visited); } @@ -763,7 +804,11 @@ /* 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)) + bool is_delete_operator + = (is_gimple_call (stmt) + && gimple_call_operator_delete_p (as_a <gcall *> (stmt))); + if (is_delete_operator + || gimple_call_builtin_p (stmt, BUILT_IN_FREE)) { tree ptr = gimple_call_arg (stmt, 0); gimple *def_stmt; @@ -773,11 +818,25 @@ 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_ALIGNED_ALLOC - || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC - || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC)) - continue; + && ((DECL_BUILT_IN_CLASS (def_callee) == BUILT_IN_NORMAL + && (DECL_FUNCTION_CODE (def_callee) == BUILT_IN_ALIGNED_ALLOC + || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_MALLOC + || DECL_FUNCTION_CODE (def_callee) == BUILT_IN_CALLOC)) + || DECL_IS_REPLACEABLE_OPERATOR_NEW_P (def_callee))) + { + /* Delete operators can have alignment and (or) size as next + arguments. When being a SSA_NAME, they must be marked + as necessary. */ + if (is_delete_operator && gimple_call_num_args (stmt) >= 2) + for (unsigned i = 1; i < gimple_call_num_args (stmt); i++) + { + tree arg = gimple_call_arg (stmt, i); + if (TREE_CODE (arg) == SSA_NAME) + mark_operand_necessary (arg); + } + + continue; + } } FOR_EACH_SSA_TREE_OPERAND (use, stmt, iter, SSA_OP_USE) @@ -787,6 +846,10 @@ if (!use) continue; + /* No need to search for vdefs if we intrinsicly keep them all. */ + if (keep_all_vdefs_p ()) + continue; + /* If we dropped to simple mode make all immediately reachable definitions necessary. */ if (chain_ovfl) @@ -831,6 +894,11 @@ || DECL_FUNCTION_CODE (callee) == BUILT_IN_ASSUME_ALIGNED)) continue; + if (callee != NULL_TREE + && (DECL_IS_REPLACEABLE_OPERATOR_NEW_P (callee) + || DECL_IS_OPERATOR_DELETE_P (callee))) + continue; + /* Calls implicitly load from memory, their arguments in addition may explicitly perform memory loads. */ mark_all_reaching_defs_necessary (stmt); @@ -985,7 +1053,8 @@ containing I so that we don't have to look it up. */ static void -remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb) +remove_dead_stmt (gimple_stmt_iterator *i, basic_block bb, + vec<edge> &to_remove_edges) { gimple *stmt = gsi_stmt (*i); @@ -1045,20 +1114,17 @@ e->flags |= EDGE_FALLTHRU; /* Remove the remaining outgoing edges. */ - for (ei = ei_start (bb->succs); (e2 = ei_safe_edge (ei)); ) + FOR_EACH_EDGE (e2, ei, bb->succs) if (e != e2) { - cfg_altered = true; /* If we made a BB unconditionally exit a loop or removed an entry into an irreducible region, then this transform alters the set of BBs in the loop. Schedule a fixup. */ if (loop_exit_edge_p (bb->loop_father, e) || (e2->dest->flags & BB_IRREDUCIBLE_LOOP)) loops_state_set (LOOPS_NEED_FIXUP); - remove_edge (e2); + to_remove_edges.safe_push (e2); } - else - ei_next (&ei); } /* If this is a store into a variable that is being optimized away, @@ -1201,6 +1267,7 @@ gimple *stmt; tree call; vec<basic_block> h; + auto_vec<edge> to_remove_edges; if (dump_file && (dump_flags & TDF_DETAILS)) fprintf (dump_file, "\nEliminating unnecessary statements:\n"); @@ -1238,6 +1305,7 @@ bb = h.pop (); /* Remove dead statements. */ + auto_bitmap debug_seen; for (gsi = gsi_last_bb (bb); !gsi_end_p (gsi); gsi = psi) { stmt = gsi_stmt (gsi); @@ -1251,7 +1319,9 @@ defining statement of its argument is not necessary (and thus is getting removed). */ if (gimple_plf (stmt, STMT_NECESSARY) - && gimple_call_builtin_p (stmt, BUILT_IN_FREE)) + && (gimple_call_builtin_p (stmt, BUILT_IN_FREE) + || (is_gimple_call (stmt) + && gimple_call_operator_delete_p (as_a <gcall *> (stmt))))) { tree ptr = gimple_call_arg (stmt, 0); if (TREE_CODE (ptr) == SSA_NAME) @@ -1283,11 +1353,15 @@ } } if (!dead) - continue; + { + bitmap_clear (debug_seen); + continue; + } } if (!is_gimple_debug (stmt)) something_changed = true; - remove_dead_stmt (&gsi, bb); + remove_dead_stmt (&gsi, bb, to_remove_edges); + continue; } else if (is_gimple_call (stmt)) { @@ -1304,12 +1378,13 @@ 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_ALIGNED_ALLOC - && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC - && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC - && !ALLOCA_FUNCTION_CODE_P - (DECL_FUNCTION_CODE (call))))) + || ((DECL_BUILT_IN_CLASS (call) != BUILT_IN_NORMAL + || (DECL_FUNCTION_CODE (call) != BUILT_IN_ALIGNED_ALLOC + && DECL_FUNCTION_CODE (call) != BUILT_IN_MALLOC + && DECL_FUNCTION_CODE (call) != BUILT_IN_CALLOC + && !ALLOCA_FUNCTION_CODE_P + (DECL_FUNCTION_CODE (call)))) + && !DECL_IS_REPLACEABLE_OPERATOR_NEW_P (call)))) { something_changed = true; if (dump_file && (dump_flags & TDF_DETAILS)) @@ -1324,14 +1399,18 @@ update_stmt (stmt); release_ssa_name (name); - /* GOMP_SIMD_LANE or ASAN_POISON without lhs is not - needed. */ + /* GOMP_SIMD_LANE (unless three argument) or ASAN_POISON + without lhs is not needed. */ if (gimple_call_internal_p (stmt)) switch (gimple_call_internal_fn (stmt)) { case IFN_GOMP_SIMD_LANE: + if (gimple_call_num_args (stmt) >= 3 + && !integer_nonzerop (gimple_call_arg (stmt, 2))) + break; + /* FALLTHRU */ case IFN_ASAN_POISON: - remove_dead_stmt (&gsi, bb); + remove_dead_stmt (&gsi, bb, to_remove_edges); break; default: break; @@ -1353,7 +1432,22 @@ break; } } + else if (gimple_debug_bind_p (stmt)) + { + /* We are only keeping the last debug-bind of a + non-DEBUG_EXPR_DECL variable in a series of + debug-bind stmts. */ + tree var = gimple_debug_bind_get_var (stmt); + if (TREE_CODE (var) != DEBUG_EXPR_DECL + && !bitmap_set_bit (debug_seen, DECL_UID (var))) + remove_dead_stmt (&gsi, bb, to_remove_edges); + continue; + } + bitmap_clear (debug_seen); } + + /* Remove dead PHI nodes. */ + something_changed |= remove_dead_phis (bb); } h.release (); @@ -1361,10 +1455,16 @@ /* Since we don't track liveness of virtual PHI nodes, it is possible that we rendered some PHI nodes unreachable while they are still in use. Mark them for renaming. */ - if (cfg_altered) + if (!to_remove_edges.is_empty ()) { basic_block prev_bb; + /* Remove edges. We've delayed this to not get bogus debug stmts + during PHI node removal. */ + for (unsigned i = 0; i < to_remove_edges.length (); ++i) + remove_edge (to_remove_edges[i]); + cfg_altered = true; + find_unreachable_blocks (); /* Delete all unreachable basic blocks in reverse dominator order. */ @@ -1430,11 +1530,6 @@ } } } - FOR_EACH_BB_FN (bb, cfun) - { - /* Remove dead PHI nodes. */ - something_changed |= remove_dead_phis (bb); - } if (bb_postorder) free (bb_postorder);