diff options
-rw-r--r-- | gcc/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gcc/testsuite/gcc.c-torture/compile/20050202-1.c | 10 | ||||
-rw-r--r-- | gcc/tree-cfg.c | 24 | ||||
-rw-r--r-- | gcc/tree-flow-inline.h | 10 | ||||
-rw-r--r-- | gcc/tree-flow.h | 3 | ||||
-rw-r--r-- | gcc/tree-ssa.c | 1 |
7 files changed, 60 insertions, 5 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 708d7f8513c..70fe886844e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,15 @@ +2005-02-02 Richard Sandiford <rsandifo@redhat.com> + + PR tree-optimization/19578 + * tree-flow.h (modified_noreturn_calls): Declare. + (noreturn_call_p): Declare. + * tree-flow-inline.h (noreturn_call_p): New function. + (modify_stmt): Add modified noreturn calls to modified_noreturn_calls. + * tree-cfg.c (modified_noreturn_calls): New variable. + (cleanup_control_flow): Use noreturn_call_p. Split basic blocks + that contain a mid-block noreturn call. + * tree-ssa.c (delete_tree_ssa): Clear modified_noreturn_calls. + 2005-02-02 Kazu Hirata <kazu@cs.umass.edu> * df.c (df_def_record_1, df_uses_record): Don't use diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ea9c8904b0c..a1dbc3fb03f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2005-02-02 Richard Sandiford <rsandifo@redhat.com> + + PR tree-optimization/19578 + * gcc.c-torture/compile/20050202-1.c: New test. + 2005-02-02 Joseph S. Myers <joseph@codesourcery.com> PR c/19435 diff --git a/gcc/testsuite/gcc.c-torture/compile/20050202-1.c b/gcc/testsuite/gcc.c-torture/compile/20050202-1.c new file mode 100644 index 00000000000..b3f81764538 --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/20050202-1.c @@ -0,0 +1,10 @@ +/* From PR 19578. */ +extern void foo (void) __attribute__((noreturn)); + +void +g (void) +{ + void (*f) (void) = foo; + f (); + f (); +} diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c index ba4fbdc0ac7..cade864f191 100644 --- a/gcc/tree-cfg.c +++ b/gcc/tree-cfg.c @@ -2052,6 +2052,14 @@ remove_bb (basic_block bb) remove_phi_nodes_and_edges_for_unreachable_block (bb); } +/* A list of all the noreturn calls passed to modify_stmt. + cleanup_control_flow uses it to detect cases where a mid-block + indirect call has been turned into a noreturn call. When this + happens, all the instructions after the call are no longer + reachable and must be deleted as dead. */ + +VEC(tree) *modified_noreturn_calls; + /* Try to remove superfluous control structures. */ static bool @@ -2060,7 +2068,16 @@ cleanup_control_flow (void) basic_block bb; block_stmt_iterator bsi; bool retval = false; - tree stmt, call; + tree stmt; + + /* Detect cases where a mid-block call is now known not to return. */ + while (VEC_length (tree, modified_noreturn_calls)) + { + stmt = VEC_pop (tree, modified_noreturn_calls); + bb = bb_for_stmt (stmt); + if (bb != NULL && last_stmt (bb) != stmt && noreturn_call_p (stmt)) + split_block (bb, stmt); + } FOR_EACH_BB (bb) { @@ -2076,10 +2093,7 @@ cleanup_control_flow (void) /* Check for indirect calls that have been turned into noreturn calls. */ - call = get_call_expr_in (stmt); - if (call != 0 - && (call_expr_flags (call) & ECF_NORETURN) != 0 - && remove_fallthru_edge (bb->succs)) + if (noreturn_call_p (stmt) && remove_fallthru_edge (bb->succs)) { free_dominance_info (CDI_DOMINATORS); retval = true; diff --git a/gcc/tree-flow-inline.h b/gcc/tree-flow-inline.h index ef6888882d1..70450537698 100644 --- a/gcc/tree-flow-inline.h +++ b/gcc/tree-flow-inline.h @@ -131,6 +131,14 @@ get_filename (tree expr) return "???"; } +/* Return true if T is a noreturn call. */ +static inline bool +noreturn_call_p (tree t) +{ + tree call = get_call_expr_in (t); + return call != 0 && (call_expr_flags (call) & ECF_NORETURN) != 0; +} + /* Mark statement T as modified. */ static inline void modify_stmt (tree t) @@ -138,6 +146,8 @@ modify_stmt (tree t) stmt_ann_t ann = stmt_ann (t); if (ann == NULL) ann = create_stmt_ann (t); + else if (noreturn_call_p (t)) + VEC_safe_push (tree, modified_noreturn_calls, t); ann->modified = 1; } diff --git a/gcc/tree-flow.h b/gcc/tree-flow.h index d8d64fba1f1..b0d0c0fd5ba 100644 --- a/gcc/tree-flow.h +++ b/gcc/tree-flow.h @@ -297,6 +297,8 @@ union tree_ann_d GTY((desc ("ann_type ((tree_ann_t)&%h)"))) struct stmt_ann_d GTY((tag ("STMT_ANN"))) stmt; }; +extern GTY(()) VEC(tree) *modified_noreturn_calls; + typedef union tree_ann_d *tree_ann_t; typedef struct var_ann_d *var_ann_t; typedef struct stmt_ann_d *stmt_ann_t; @@ -310,6 +312,7 @@ static inline stmt_ann_t get_stmt_ann (tree); static inline enum tree_ann_type ann_type (tree_ann_t); static inline basic_block bb_for_stmt (tree); extern void set_bb_for_stmt (tree, basic_block); +static inline bool noreturn_call_p (tree); static inline void modify_stmt (tree); static inline void unmodify_stmt (tree); static inline bool stmt_modified_p (tree); diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c index 88493b72644..c34ddd86264 100644 --- a/gcc/tree-ssa.c +++ b/gcc/tree-ssa.c @@ -766,6 +766,7 @@ delete_tree_ssa (void) call_clobbered_vars = NULL; BITMAP_XFREE (addressable_vars); addressable_vars = NULL; + modified_noreturn_calls = NULL; } |