aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog12
-rw-r--r--gcc/testsuite/ChangeLog5
-rw-r--r--gcc/testsuite/gcc.c-torture/compile/20050202-1.c10
-rw-r--r--gcc/tree-cfg.c24
-rw-r--r--gcc/tree-flow-inline.h10
-rw-r--r--gcc/tree-flow.h3
-rw-r--r--gcc/tree-ssa.c1
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;
}