summaryrefslogtreecommitdiff
path: root/gcc/tree-cfg.c
diff options
context:
space:
mode:
authormatz <matz@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-08 16:03:11 +0000
committermatz <matz@138bc75d-0d04-0410-961f-82ee72b054a4>2009-10-08 16:03:11 +0000
commitc90b5d400f562a31cf58dc58a8f330252133ac15 (patch)
treedfbfdde0ac425b160f559d82eab975a3ba3e115a /gcc/tree-cfg.c
parent7366cbe7c235ed9ed2f93486b64e262eb5c60509 (diff)
downloadgcc-c90b5d400f562a31cf58dc58a8f330252133ac15.tar.gz
PR middle-end/41573
* builtins.c (fold_builtin_isascii): Use fold_build2. (fold_builtin_isdigit): Ditto. * except.c (duplicate_eh_regions_1): Tolerate NULL labels. * tree-cfg.c (struct rus_data, remove_useless_stmts_warn_notreached, remove_useless_stmts_cond, remove_useless_stmts_tf, remove_useless_stmts_tc, remove_useless_stmts_bind, remove_useless_stmts_goto, remove_useless_stmts_label, remove_useless_stmts_1, remove_useless_stmts, pass_remove_useless_stmts): Remove. * tree-pass.h (pass_remove_useless_stmts): Don't declare. * passes.c (init_optimization_passes): Don't add pass_remove_useless_stmts. * tree-eh.c (lower_eh_constructs_2): Handle empty cleanups. * tree.c (free_lang_data_in_decl): Don't clear DECL_INITIAL of static constants. * lto-symtab.c (lto_symtab_register_decl): Accepts DECL_INITIAL for static constants. * lto-streamer-out.c (output_gimple_stmt): Handle GIMPLE_NOP. * lto-streamer-in.c (input_gimple_stmt): Handle GIMPLE_NOP. testsuite/ * gcc.dg/tree-ssa/foldstring-1.c: Use fre dump. * gcc.dg/tree-ssa/useless-1.c: Use gimple dump. * gcc.dg/pr41573.c: New test. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@152563 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/tree-cfg.c')
-rw-r--r--gcc/tree-cfg.c599
1 files changed, 0 insertions, 599 deletions
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index e392f48af3e..1c820a3e3c5 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -1715,423 +1715,6 @@ single_noncomplex_succ (basic_block bb)
return bb;
}
-
-/* Walk the function tree removing unnecessary statements.
-
- * Empty statement nodes are removed
-
- * Unnecessary TRY_FINALLY and TRY_CATCH blocks are removed
-
- * Unnecessary COND_EXPRs are removed
-
- * Some unnecessary BIND_EXPRs are removed
-
- * GOTO_EXPRs immediately preceding destination are removed.
-
- Clearly more work could be done. The trick is doing the analysis
- and removal fast enough to be a net improvement in compile times.
-
- Note that when we remove a control structure such as a COND_EXPR
- BIND_EXPR, or TRY block, we will need to repeat this optimization pass
- to ensure we eliminate all the useless code. */
-
-struct rus_data
-{
- bool repeat;
- bool may_throw;
- bool may_branch;
- bool has_label;
- bool last_was_goto;
- gimple_stmt_iterator last_goto_gsi;
-};
-
-
-static void remove_useless_stmts_1 (gimple_stmt_iterator *gsi, struct rus_data *);
-
-/* Given a statement sequence, find the first executable statement with
- location information, and warn that it is unreachable. When searching,
- descend into containers in execution order. */
-
-static bool
-remove_useless_stmts_warn_notreached (gimple_seq stmts)
-{
- gimple_stmt_iterator gsi;
-
- for (gsi = gsi_start (stmts); !gsi_end_p (gsi); gsi_next (&gsi))
- {
- gimple stmt = gsi_stmt (gsi);
-
- if (gimple_no_warning_p (stmt)) return false;
-
- if (gimple_has_location (stmt))
- {
- location_t loc = gimple_location (stmt);
- if (LOCATION_LINE (loc) > 0)
- {
- warning_at (loc, OPT_Wunreachable_code, "will never be executed");
- return true;
- }
- }
-
- switch (gimple_code (stmt))
- {
- /* Unfortunately, we need the CFG now to detect unreachable
- branches in a conditional, so conditionals are not handled here. */
-
- case GIMPLE_TRY:
- if (remove_useless_stmts_warn_notreached (gimple_try_eval (stmt)))
- return true;
- if (remove_useless_stmts_warn_notreached (gimple_try_cleanup (stmt)))
- return true;
- break;
-
- case GIMPLE_CATCH:
- return remove_useless_stmts_warn_notreached (gimple_catch_handler (stmt));
-
- case GIMPLE_EH_FILTER:
- return remove_useless_stmts_warn_notreached (gimple_eh_filter_failure (stmt));
-
- case GIMPLE_BIND:
- return remove_useless_stmts_warn_notreached (gimple_bind_body (stmt));
-
- default:
- break;
- }
- }
-
- return false;
-}
-
-/* Helper for remove_useless_stmts_1. Handle GIMPLE_COND statements. */
-
-static void
-remove_useless_stmts_cond (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
- gimple stmt = gsi_stmt (*gsi);
-
- /* The folded result must still be a conditional statement. */
- fold_stmt (gsi);
- gcc_assert (gsi_stmt (*gsi) == stmt);
-
- data->may_branch = true;
-
- /* Replace trivial conditionals with gotos. */
- if (gimple_cond_true_p (stmt))
- {
- /* Goto THEN label. */
- tree then_label = gimple_cond_true_label (stmt);
-
- gsi_replace (gsi, gimple_build_goto (then_label), false);
- data->last_goto_gsi = *gsi;
- data->last_was_goto = true;
- data->repeat = true;
- }
- else if (gimple_cond_false_p (stmt))
- {
- /* Goto ELSE label. */
- tree else_label = gimple_cond_false_label (stmt);
-
- gsi_replace (gsi, gimple_build_goto (else_label), false);
- data->last_goto_gsi = *gsi;
- data->last_was_goto = true;
- data->repeat = true;
- }
- else
- {
- tree then_label = gimple_cond_true_label (stmt);
- tree else_label = gimple_cond_false_label (stmt);
-
- if (then_label == else_label)
- {
- /* Goto common destination. */
- gsi_replace (gsi, gimple_build_goto (then_label), false);
- data->last_goto_gsi = *gsi;
- data->last_was_goto = true;
- data->repeat = true;
- }
- }
-
- gsi_next (gsi);
-
- data->last_was_goto = false;
-}
-
-/* Helper for remove_useless_stmts_1.
- Handle the try-finally case for GIMPLE_TRY statements. */
-
-static void
-remove_useless_stmts_tf (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
- bool save_may_branch, save_may_throw;
- bool this_may_branch, this_may_throw;
-
- gimple_seq eval_seq, cleanup_seq;
- gimple_stmt_iterator eval_gsi, cleanup_gsi;
-
- gimple stmt = gsi_stmt (*gsi);
-
- /* Collect may_branch and may_throw information for the body only. */
- save_may_branch = data->may_branch;
- save_may_throw = data->may_throw;
- data->may_branch = false;
- data->may_throw = false;
- data->last_was_goto = false;
-
- eval_seq = gimple_try_eval (stmt);
- eval_gsi = gsi_start (eval_seq);
- remove_useless_stmts_1 (&eval_gsi, data);
-
- this_may_branch = data->may_branch;
- this_may_throw = data->may_throw;
- data->may_branch |= save_may_branch;
- data->may_throw |= save_may_throw;
- data->last_was_goto = false;
-
- cleanup_seq = gimple_try_cleanup (stmt);
- cleanup_gsi = gsi_start (cleanup_seq);
- remove_useless_stmts_1 (&cleanup_gsi, data);
-
- /* If the body is empty, then we can emit the FINALLY block without
- the enclosing TRY_FINALLY_EXPR. */
- if (gimple_seq_empty_p (eval_seq))
- {
- gsi_insert_seq_before (gsi, cleanup_seq, GSI_SAME_STMT);
- gsi_remove (gsi, false);
- data->repeat = true;
- }
-
- /* If the handler is empty, then we can emit the TRY block without
- the enclosing TRY_FINALLY_EXPR. */
- else if (gimple_seq_empty_p (cleanup_seq))
- {
- gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
- gsi_remove (gsi, false);
- data->repeat = true;
- }
-
- /* If the body neither throws, nor branches, then we can safely
- string the TRY and FINALLY blocks together. */
- else if (!this_may_branch && !this_may_throw)
- {
- gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
- gsi_insert_seq_before (gsi, cleanup_seq, GSI_SAME_STMT);
- gsi_remove (gsi, false);
- data->repeat = true;
- }
- else
- gsi_next (gsi);
-}
-
-/* Helper for remove_useless_stmts_1.
- Handle the try-catch case for GIMPLE_TRY statements. */
-
-static void
-remove_useless_stmts_tc (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
- bool save_may_throw, this_may_throw;
-
- gimple_seq eval_seq, cleanup_seq, handler_seq, failure_seq;
- gimple_stmt_iterator eval_gsi, cleanup_gsi, handler_gsi, failure_gsi;
-
- gimple stmt = gsi_stmt (*gsi);
-
- /* Collect may_throw information for the body only. */
- save_may_throw = data->may_throw;
- data->may_throw = false;
- data->last_was_goto = false;
-
- eval_seq = gimple_try_eval (stmt);
- eval_gsi = gsi_start (eval_seq);
- remove_useless_stmts_1 (&eval_gsi, data);
-
- this_may_throw = data->may_throw;
- data->may_throw = save_may_throw;
-
- cleanup_seq = gimple_try_cleanup (stmt);
-
- /* If the body cannot throw, then we can drop the entire TRY_CATCH_EXPR. */
- if (!this_may_throw)
- {
- if (warn_notreached)
- {
- remove_useless_stmts_warn_notreached (cleanup_seq);
- }
- gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
- gsi_remove (gsi, false);
- data->repeat = true;
- return;
- }
-
- /* Process the catch clause specially. We may be able to tell that
- no exceptions propagate past this point. */
-
- this_may_throw = true;
- cleanup_gsi = gsi_start (cleanup_seq);
- stmt = gsi_stmt (cleanup_gsi);
- data->last_was_goto = false;
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_CATCH:
- /* If the first element is a catch, they all must be. */
- while (!gsi_end_p (cleanup_gsi))
- {
- stmt = gsi_stmt (cleanup_gsi);
- /* If we catch all exceptions, then the body does not
- propagate exceptions past this point. */
- if (gimple_catch_types (stmt) == NULL)
- this_may_throw = false;
- data->last_was_goto = false;
- handler_seq = gimple_catch_handler (stmt);
- handler_gsi = gsi_start (handler_seq);
- remove_useless_stmts_1 (&handler_gsi, data);
- gsi_next (&cleanup_gsi);
- }
- gsi_next (gsi);
- break;
-
- case GIMPLE_EH_FILTER:
- if (gimple_eh_filter_types (stmt) == NULL)
- this_may_throw = false;
- failure_seq = gimple_eh_filter_failure (stmt);
- failure_gsi = gsi_start (failure_seq);
- remove_useless_stmts_1 (&failure_gsi, data);
- gsi_next (gsi);
- break;
-
- case GIMPLE_EH_MUST_NOT_THROW:
- this_may_throw = false;
- gsi_next (gsi);
- break;
-
- default:
- /* Otherwise this is a list of cleanup statements. */
- remove_useless_stmts_1 (&cleanup_gsi, data);
-
- /* If the cleanup is empty, then we can emit the TRY block without
- the enclosing TRY_CATCH_EXPR. */
- if (gimple_seq_empty_p (cleanup_seq))
- {
- gsi_insert_seq_before (gsi, eval_seq, GSI_SAME_STMT);
- gsi_remove(gsi, false);
- data->repeat = true;
- }
- else
- gsi_next (gsi);
- break;
- }
-
- data->may_throw |= this_may_throw;
-}
-
-/* Helper for remove_useless_stmts_1. Handle GIMPLE_BIND statements. */
-
-static void
-remove_useless_stmts_bind (gimple_stmt_iterator *gsi, struct rus_data *data ATTRIBUTE_UNUSED)
-{
- tree block;
- gimple_seq body_seq, fn_body_seq;
- gimple_stmt_iterator body_gsi;
-
- gimple stmt = gsi_stmt (*gsi);
-
- /* First remove anything underneath the BIND_EXPR. */
-
- body_seq = gimple_bind_body (stmt);
- body_gsi = gsi_start (body_seq);
- remove_useless_stmts_1 (&body_gsi, data);
-
- /* If the GIMPLE_BIND has no variables, then we can pull everything
- up one level and remove the GIMPLE_BIND, unless this is the toplevel
- GIMPLE_BIND for the current function or an inlined function.
-
- When this situation occurs we will want to apply this
- optimization again. */
- block = gimple_bind_block (stmt);
- fn_body_seq = gimple_body (current_function_decl);
- if (gimple_bind_vars (stmt) == NULL_TREE
- && (gimple_seq_empty_p (fn_body_seq)
- || stmt != gimple_seq_first_stmt (fn_body_seq))
- && (! block
- || ! BLOCK_ABSTRACT_ORIGIN (block)
- || (TREE_CODE (BLOCK_ABSTRACT_ORIGIN (block))
- != FUNCTION_DECL)))
- {
- tree var = NULL_TREE;
- /* Even if there are no gimple_bind_vars, there might be other
- decls in BLOCK_VARS rendering the GIMPLE_BIND not useless. */
- if (block && !BLOCK_NUM_NONLOCALIZED_VARS (block))
- for (var = BLOCK_VARS (block); var; var = TREE_CHAIN (var))
- if (TREE_CODE (var) == IMPORTED_DECL)
- break;
- if (var || (block && BLOCK_NUM_NONLOCALIZED_VARS (block)))
- gsi_next (gsi);
- else
- {
- gsi_insert_seq_before (gsi, body_seq, GSI_SAME_STMT);
- gsi_remove (gsi, false);
- data->repeat = true;
- }
- }
- else
- gsi_next (gsi);
-}
-
-/* Helper for remove_useless_stmts_1. Handle GIMPLE_GOTO statements. */
-
-static void
-remove_useless_stmts_goto (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
- gimple stmt = gsi_stmt (*gsi);
-
- tree dest = gimple_goto_dest (stmt);
-
- data->may_branch = true;
- data->last_was_goto = false;
-
- /* Record iterator for last goto expr, so that we can delete it if unnecessary. */
- if (TREE_CODE (dest) == LABEL_DECL)
- {
- data->last_goto_gsi = *gsi;
- data->last_was_goto = true;
- }
-
- gsi_next(gsi);
-}
-
-/* Helper for remove_useless_stmts_1. Handle GIMPLE_LABEL statements. */
-
-static void
-remove_useless_stmts_label (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
- gimple stmt = gsi_stmt (*gsi);
-
- tree label = gimple_label_label (stmt);
-
- data->has_label = true;
-
- /* We do want to jump across non-local label receiver code. */
- if (DECL_NONLOCAL (label))
- data->last_was_goto = false;
-
- else if (data->last_was_goto
- && gimple_goto_dest (gsi_stmt (data->last_goto_gsi)) == label)
- {
- /* Replace the preceding GIMPLE_GOTO statement with
- a GIMPLE_NOP, which will be subsequently removed.
- In this way, we avoid invalidating other iterators
- active on the statement sequence. */
- gsi_replace(&data->last_goto_gsi, gimple_build_nop(), false);
- data->last_was_goto = false;
- data->repeat = true;
- }
-
- /* ??? Add something here to delete unused labels. */
-
- gsi_next (gsi);
-}
-
-
/* T is CALL_EXPR. Set current_function_calls_* flags. */
void
@@ -2156,188 +1739,6 @@ clear_special_calls (void)
cfun->calls_setjmp = false;
}
-/* Remove useless statements from a statement sequence, and perform
- some preliminary simplifications. */
-
-static void
-remove_useless_stmts_1 (gimple_stmt_iterator *gsi, struct rus_data *data)
-{
- while (!gsi_end_p (*gsi))
- {
- gimple stmt = gsi_stmt (*gsi);
-
- switch (gimple_code (stmt))
- {
- case GIMPLE_COND:
- remove_useless_stmts_cond (gsi, data);
- break;
-
- case GIMPLE_GOTO:
- remove_useless_stmts_goto (gsi, data);
- break;
-
- case GIMPLE_LABEL:
- remove_useless_stmts_label (gsi, data);
- break;
-
- case GIMPLE_ASSIGN:
- fold_stmt (gsi);
- stmt = gsi_stmt (*gsi);
- data->last_was_goto = false;
- if (stmt_could_throw_p (stmt))
- data->may_throw = true;
- gsi_next (gsi);
- break;
-
- case GIMPLE_ASM:
- fold_stmt (gsi);
- data->last_was_goto = false;
- gsi_next (gsi);
- break;
-
- case GIMPLE_CALL:
- fold_stmt (gsi);
- stmt = gsi_stmt (*gsi);
- data->last_was_goto = false;
- if (is_gimple_call (stmt))
- notice_special_calls (stmt);
-
- /* We used to call update_gimple_call_flags here,
- which copied side-effects and nothrows status
- from the function decl to the call. In the new
- tuplified GIMPLE, the accessors for this information
- always consult the function decl, so this copying
- is no longer necessary. */
- if (stmt_could_throw_p (stmt))
- data->may_throw = true;
- gsi_next (gsi);
- break;
-
- case GIMPLE_RETURN:
- fold_stmt (gsi);
- data->last_was_goto = false;
- data->may_branch = true;
- gsi_next (gsi);
- break;
-
- case GIMPLE_BIND:
- remove_useless_stmts_bind (gsi, data);
- break;
-
- case GIMPLE_TRY:
- if (gimple_try_kind (stmt) == GIMPLE_TRY_CATCH)
- remove_useless_stmts_tc (gsi, data);
- else if (gimple_try_kind (stmt) == GIMPLE_TRY_FINALLY)
- remove_useless_stmts_tf (gsi, data);
- else
- gcc_unreachable ();
- break;
-
- case GIMPLE_CATCH:
- gcc_unreachable ();
- break;
-
- case GIMPLE_NOP:
- gsi_remove (gsi, false);
- break;
-
- case GIMPLE_OMP_FOR:
- {
- gimple_seq pre_body_seq = gimple_omp_for_pre_body (stmt);
- gimple_stmt_iterator pre_body_gsi = gsi_start (pre_body_seq);
-
- remove_useless_stmts_1 (&pre_body_gsi, data);
- data->last_was_goto = false;
- }
- /* FALLTHROUGH */
- case GIMPLE_OMP_CRITICAL:
- case GIMPLE_OMP_CONTINUE:
- case GIMPLE_OMP_MASTER:
- case GIMPLE_OMP_ORDERED:
- case GIMPLE_OMP_SECTION:
- case GIMPLE_OMP_SECTIONS:
- case GIMPLE_OMP_SINGLE:
- {
- gimple_seq body_seq = gimple_omp_body (stmt);
- gimple_stmt_iterator body_gsi = gsi_start (body_seq);
-
- remove_useless_stmts_1 (&body_gsi, data);
- data->last_was_goto = false;
- gsi_next (gsi);
- }
- break;
-
- case GIMPLE_OMP_PARALLEL:
- case GIMPLE_OMP_TASK:
- {
- /* Make sure the outermost GIMPLE_BIND isn't removed
- as useless. */
- gimple_seq body_seq = gimple_omp_body (stmt);
- gimple bind = gimple_seq_first_stmt (body_seq);
- gimple_seq bind_seq = gimple_bind_body (bind);
- gimple_stmt_iterator bind_gsi = gsi_start (bind_seq);
-
- remove_useless_stmts_1 (&bind_gsi, data);
- data->last_was_goto = false;
- gsi_next (gsi);
- }
- break;
-
- default:
- data->last_was_goto = false;
- gsi_next (gsi);
- break;
- }
- }
-}
-
-/* Walk the function tree, removing useless statements and performing
- some preliminary simplifications. */
-
-static unsigned int
-remove_useless_stmts (void)
-{
- struct rus_data data;
-
- clear_special_calls ();
-
- do
- {
- gimple_stmt_iterator gsi;
-
- gsi = gsi_start (gimple_body (current_function_decl));
- memset (&data, 0, sizeof (data));
- remove_useless_stmts_1 (&gsi, &data);
- }
- while (data.repeat);
-
-#ifdef ENABLE_TYPES_CHECKING
- verify_types_in_gimple_seq (gimple_body (current_function_decl));
-#endif
-
- return 0;
-}
-
-
-struct gimple_opt_pass pass_remove_useless_stmts =
-{
- {
- GIMPLE_PASS,
- "useless", /* name */
- NULL, /* gate */
- remove_useless_stmts, /* execute */
- NULL, /* sub */
- NULL, /* next */
- 0, /* static_pass_number */
- TV_NONE, /* tv_id */
- PROP_gimple_any, /* properties_required */
- 0, /* properties_provided */
- 0, /* properties_destroyed */
- 0, /* todo_flags_start */
- TODO_dump_func /* todo_flags_finish */
- }
-};
-
/* Remove PHI nodes associated with basic block BB and all edges out of BB. */
static void