re PR tree-optimization/19578 (function pointer propagation fails for noreturn functi...
authorRichard Sandiford <rsandifo@redhat.com>
Wed, 2 Feb 2005 20:58:39 +0000 (20:58 +0000)
committerRichard Sandiford <rsandifo@gcc.gnu.org>
Wed, 2 Feb 2005 20:58:39 +0000 (20:58 +0000)
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.

From-SVN: r94610

gcc/ChangeLog
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.c-torture/compile/20050202-1.c [new file with mode: 0644]
gcc/tree-cfg.c
gcc/tree-flow-inline.h
gcc/tree-flow.h
gcc/tree-ssa.c

index 708d7f8513c90621f1594db1ac938240c7788e75..70fe886844e4eec2fe6c2456af343642c9c35891 100644 (file)
@@ -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
index ea9c8904b0c94e62ed919ac4e27e48ca8220e3b7..a1dbc3fb03fdf1bbc41ae4cf54c160d4cf5efbbb 100644 (file)
@@ -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 (file)
index 0000000..b3f8176
--- /dev/null
@@ -0,0 +1,10 @@
+/* From PR 19578.  */
+extern void foo (void) __attribute__((noreturn));
+
+void
+g (void)
+{
+  void (*f) (void) = foo;
+  f ();
+  f ();
+}
index ba4fbdc0ac789a5a79e63089941334bf3b759f94..cade864f191de427eec8de3f84a060596abe4938 100644 (file)
@@ -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;
index ef6888882d1e0ff161930ac4f43fb4c3fe2aae5b..70450537698cb921e225521a1288e4501891ab88 100644 (file)
@@ -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;
 }
 
index d8d64fba1f1c1ff4912f00dd2a99f49ca93542c9..b0d0c0fd5bacd2d4195df4b14737ecfa4718eb4b 100644 (file)
@@ -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);
index 88493b72644f022b6a45a564358436e9dca22270..c34ddd8626448cff997c725d2a6f548924eb9af7 100644 (file)
@@ -766,6 +766,7 @@ delete_tree_ssa (void)
   call_clobbered_vars = NULL;
   BITMAP_XFREE (addressable_vars);
   addressable_vars = NULL;
+  modified_noreturn_calls = NULL;
 }