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 | |
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')
-rw-r--r-- | gcc/ChangeLog | 23 | ||||
-rw-r--r-- | gcc/builtins.c | 10 | ||||
-rw-r--r-- | gcc/except.c | 7 | ||||
-rw-r--r-- | gcc/lto-streamer-in.c | 1 | ||||
-rw-r--r-- | gcc/lto-streamer-out.c | 1 | ||||
-rw-r--r-- | gcc/lto-symtab.c | 6 | ||||
-rw-r--r-- | gcc/passes.c | 1 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/pr41573.c | 15 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/foldstring-1.c | 6 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/tree-ssa/useless-1.c | 6 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 599 | ||||
-rw-r--r-- | gcc/tree-eh.c | 32 | ||||
-rw-r--r-- | gcc/tree-pass.h | 1 | ||||
-rw-r--r-- | gcc/tree.c | 3 |
15 files changed, 88 insertions, 630 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 11eb0f80ba1..b21fbc2b4be 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,26 @@ +2009-10-08 Michael Matz <matz@suse.de> + + 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. + 2009-10-08 Richard Guenther <rguenther@suse.de> * gimple.c (free_gimple_type_tables): New function. diff --git a/gcc/builtins.c b/gcc/builtins.c index c9bc23010a1..55228d22c40 100644 --- a/gcc/builtins.c +++ b/gcc/builtins.c @@ -9238,9 +9238,9 @@ fold_builtin_isascii (location_t loc, tree arg) else { /* Transform isascii(c) -> ((c & ~0x7f) == 0). */ - arg = build2 (BIT_AND_EXPR, integer_type_node, arg, - build_int_cst (NULL_TREE, - ~ (unsigned HOST_WIDE_INT) 0x7f)); + arg = fold_build2 (BIT_AND_EXPR, integer_type_node, arg, + build_int_cst (NULL_TREE, + ~ (unsigned HOST_WIDE_INT) 0x7f)); return fold_build2_loc (loc, EQ_EXPR, integer_type_node, arg, integer_zero_node); } @@ -9278,8 +9278,8 @@ fold_builtin_isdigit (location_t loc, tree arg) return NULL_TREE; arg = fold_convert_loc (loc, unsigned_type_node, arg); - arg = build2 (MINUS_EXPR, unsigned_type_node, arg, - build_int_cst (unsigned_type_node, target_digit0)); + arg = fold_build2 (MINUS_EXPR, unsigned_type_node, arg, + build_int_cst (unsigned_type_node, target_digit0)); return fold_build2_loc (loc, LE_EXPR, integer_type_node, arg, build_int_cst (unsigned_type_node, 9)); } diff --git a/gcc/except.c b/gcc/except.c index c00bcd397bd..b25e48b6c9b 100644 --- a/gcc/except.c +++ b/gcc/except.c @@ -552,8 +552,11 @@ duplicate_eh_regions_1 (struct duplicate_eh_regions_data *data, case ERT_ALLOWED_EXCEPTIONS: new_r->u.allowed.type_list = old_r->u.allowed.type_list; - new_r->u.allowed.label - = data->label_map (old_r->u.allowed.label, data->label_map_data); + if (old_r->u.allowed.label) + new_r->u.allowed.label + = data->label_map (old_r->u.allowed.label, data->label_map_data); + else + new_r->u.allowed.label = NULL_TREE; break; case ERT_MUST_NOT_THROW: diff --git a/gcc/lto-streamer-in.c b/gcc/lto-streamer-in.c index 175a1e771e7..f41aa75b823 100644 --- a/gcc/lto-streamer-in.c +++ b/gcc/lto-streamer-in.c @@ -942,6 +942,7 @@ input_gimple_stmt (struct lto_input_block *ib, struct data_in *data_in, } break; + case GIMPLE_NOP: case GIMPLE_PREDICT: break; diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c index 616486762c4..499734f4988 100644 --- a/gcc/lto-streamer-out.c +++ b/gcc/lto-streamer-out.c @@ -1692,6 +1692,7 @@ output_gimple_stmt (struct output_block *ob, gimple stmt) } break; + case GIMPLE_NOP: case GIMPLE_PREDICT: break; diff --git a/gcc/lto-symtab.c b/gcc/lto-symtab.c index 7d30448447a..2a0783a12be 100644 --- a/gcc/lto-symtab.c +++ b/gcc/lto-symtab.c @@ -323,8 +323,10 @@ lto_symtab_register_decl (tree decl, && (TREE_CODE (decl) == VAR_DECL || TREE_CODE (decl) == FUNCTION_DECL) && DECL_ASSEMBLER_NAME_SET_P (decl)); - if (TREE_CODE (decl) == VAR_DECL) - gcc_assert (!(DECL_EXTERNAL (decl) && DECL_INITIAL (decl))); + if (TREE_CODE (decl) == VAR_DECL + && DECL_INITIAL (decl)) + gcc_assert (!DECL_EXTERNAL (decl) + || (TREE_STATIC (decl) && TREE_READONLY (decl))); if (TREE_CODE (decl) == FUNCTION_DECL) gcc_assert (!DECL_ABSTRACT (decl)); diff --git a/gcc/passes.c b/gcc/passes.c index 60a850969c2..5ed12060739 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -683,7 +683,6 @@ init_optimization_passes (void) p = &all_lowering_passes; NEXT_PASS (pass_warn_unused_result); NEXT_PASS (pass_diagnose_omp_blocks); - NEXT_PASS (pass_remove_useless_stmts); NEXT_PASS (pass_mudflap_1); NEXT_PASS (pass_lower_omp); NEXT_PASS (pass_lower_cf); diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 9b9b141b9f3..bf7e5ba08f4 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,10 @@ +2009-10-08 Michael Matz <matz@suse.de> + + PR middle-end/41573 + * 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. + 2009-10-07 Joseph Myers <joseph@codesourcery.com> PR c/41182 diff --git a/gcc/testsuite/gcc.dg/pr41573.c b/gcc/testsuite/gcc.dg/pr41573.c new file mode 100644 index 00000000000..52961db8f22 --- /dev/null +++ b/gcc/testsuite/gcc.dg/pr41573.c @@ -0,0 +1,15 @@ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ +__inline __attribute__ ((__always_inline__)) char * +strcpy (char *__dest, __const char *__src) +{ + return __builtin___strcpy_chk (__dest, __src, __builtin_object_size (__dest, 2 > 1)); +} + +const char* get_attr(unsigned attr) +{ + static char tmp[256]; + + strcpy(tmp, ""); + return tmp; +} diff --git a/gcc/testsuite/gcc.dg/tree-ssa/foldstring-1.c b/gcc/testsuite/gcc.dg/tree-ssa/foldstring-1.c index 25a7ef49f8a..fa64ae14cc4 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/foldstring-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/foldstring-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O1 -fdump-tree-useless" } */ +/* { dg-options "-O1 -fdump-tree-fre" } */ void arf () @@ -7,5 +7,5 @@ arf () if (""[0] == 0) blah (); } -/* { dg-final { scan-tree-dump-times "= 0;" 1 "useless"} } */ -/* { dg-final { cleanup-tree-dump "useless" } } */ +/* { dg-final { scan-tree-dump-times "= 0;" 1 "fre"} } */ +/* { dg-final { cleanup-tree-dump "fre" } } */ diff --git a/gcc/testsuite/gcc.dg/tree-ssa/useless-1.c b/gcc/testsuite/gcc.dg/tree-ssa/useless-1.c index 9170b7ca4de..68eab70046c 100644 --- a/gcc/testsuite/gcc.dg/tree-ssa/useless-1.c +++ b/gcc/testsuite/gcc.dg/tree-ssa/useless-1.c @@ -1,5 +1,5 @@ /* { dg-do compile } */ -/* { dg-options "-O1 -fdump-tree-useless" } */ +/* { dg-options "-O1 -fdump-tree-gimple" } */ void foo (void) @@ -13,5 +13,5 @@ foo (void) in the loop exit condition, it would be re-introduced during GIMPLE lowering, at the cost of an extra statement, label, and basic block. */ -/* { dg-final { scan-tree-dump-times "goto" 3 "useless"} } */ -/* { dg-final { cleanup-tree-dump "useless" } } */ +/* { dg-final { scan-tree-dump-times "goto" 3 "gimple"} } */ +/* { dg-final { cleanup-tree-dump "gimple" } } */ 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 diff --git a/gcc/tree-eh.c b/gcc/tree-eh.c index 3ed92a59bc7..e782738b6d2 100644 --- a/gcc/tree-eh.c +++ b/gcc/tree-eh.c @@ -1919,21 +1919,27 @@ lower_eh_constructs_2 (struct leh_state *state, gimple_stmt_iterator *gsi) else { x = gimple_seq_first_stmt (gimple_try_cleanup (stmt)); - switch (gimple_code (x)) + if (!x) { - case GIMPLE_CATCH: - replace = lower_catch (state, stmt); - break; - case GIMPLE_EH_FILTER: - replace = lower_eh_filter (state, stmt); - break; - case GIMPLE_EH_MUST_NOT_THROW: - replace = lower_eh_must_not_throw (state, stmt); - break; - default: - replace = lower_cleanup (state, stmt); - break; + replace = gimple_try_eval (stmt); + lower_eh_constructs_1 (state, replace); } + else + switch (gimple_code (x)) + { + case GIMPLE_CATCH: + replace = lower_catch (state, stmt); + break; + case GIMPLE_EH_FILTER: + replace = lower_eh_filter (state, stmt); + break; + case GIMPLE_EH_MUST_NOT_THROW: + replace = lower_eh_must_not_throw (state, stmt); + break; + default: + replace = lower_cleanup (state, stmt); + break; + } } /* Remove the old stmt and insert the transformed sequence diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h index 2cbe3e4b448..b829cee08b3 100644 --- a/gcc/tree-pass.h +++ b/gcc/tree-pass.h @@ -333,7 +333,6 @@ extern void tree_lowering_passes (tree decl); extern struct gimple_opt_pass pass_mudflap_1; extern struct gimple_opt_pass pass_mudflap_2; -extern struct gimple_opt_pass pass_remove_useless_stmts; extern struct gimple_opt_pass pass_lower_cf; extern struct gimple_opt_pass pass_refactor_eh; extern struct gimple_opt_pass pass_lower_eh; diff --git a/gcc/tree.c b/gcc/tree.c index 77ba3f8498c..4c3f52bd7b7 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -4438,7 +4438,8 @@ free_lang_data_in_decl (tree decl) && !TREE_STATIC (expr) && !DECL_EXTERNAL (expr)) SET_DECL_DEBUG_EXPR (decl, NULL_TREE); - if (DECL_EXTERNAL (decl)) + if (DECL_EXTERNAL (decl) + && (!TREE_STATIC (decl) || !TREE_READONLY (decl))) DECL_INITIAL (decl) = NULL_TREE; } else if (TREE_CODE (decl) == TYPE_DECL) |