diff options
author | matz <matz@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-10-08 16:03:11 +0000 |
---|---|---|
committer | matz <matz@138bc75d-0d04-0410-961f-82ee72b054a4> | 2009-10-08 16:03:11 +0000 |
commit | c90b5d400f562a31cf58dc58a8f330252133ac15 (patch) | |
tree | dfbfdde0ac425b160f559d82eab975a3ba3e115a /gcc/tree-cfg.c | |
parent | 7366cbe7c235ed9ed2f93486b64e262eb5c60509 (diff) | |
download | gcc-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.c | 599 |
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 |