cfgexpand.c (expand_gimple_tailcall): Fix case where we need to create a new basic...
authorRichard Henderson <rth@redhat.com>
Thu, 22 Jul 2004 00:45:54 +0000 (17:45 -0700)
committerRichard Henderson <rth@gcc.gnu.org>
Thu, 22 Jul 2004 00:45:54 +0000 (17:45 -0700)
        * cfgexpand.c (expand_gimple_tailcall): Fix case where we need
        to create a new basic block.

From-SVN: r85029

gcc/ChangeLog
gcc/cfgexpand.c

index 41622fb420b3dfe65eac0fe57cf1521b3f8b7a89..4065d959f61161416a2a775abb5cc35082573bc4 100644 (file)
@@ -1,3 +1,8 @@
+2004-07-21  Richard Henderson  <rth@redhat.com>
+
+       * cfgexpand.c (expand_gimple_tailcall): Fix case where we need
+       to create a new basic block.
+
 2004-07-22  Joseph S. Myers  <jsm@polyomino.org.uk>
 
        PR c/15052
index 5bcb59cde1ac9b3473523afa2177787e70d0b4c5..f4fe86075b288d4f37e8bed8ee4082f7d26f6083 100644 (file)
@@ -111,77 +111,95 @@ expand_gimple_cond_expr (basic_block bb, tree stmt)
 }
 
 /* A subroutine of expand_gimple_basic_block.  Expand one CALL_EXPR
-   that has CALL_EXPR_TAILCALL set.  Returns a new basic block if we've
-   terminated the current basic block and created a new one.  */
+   that has CALL_EXPR_TAILCALL set.  Returns non-null if we actually
+   generated a tail call (something that might be denied by the ABI
+   rules governing the call; see calls.c).  */
 
 static basic_block
 expand_gimple_tailcall (basic_block bb, tree stmt)
 {
   rtx last = get_last_insn ();
+  edge e;
+  int probability;
+  gcov_type count;
 
   expand_expr_stmt (stmt);
 
   for (last = NEXT_INSN (last); last; last = NEXT_INSN (last))
-    {
-      if (CALL_P (last) && SIBLING_CALL_P (last))
-       {
-         edge e;
-         int probability = 0;
-         gcov_type count = 0;
+    if (CALL_P (last) && SIBLING_CALL_P (last))
+      goto found;
 
-         do_pending_stack_adjust ();
-         e = bb->succ;
-         while (e)
-           {
-             edge next = e->succ_next;
-
-             if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH)))
-               {
-                 if (e->dest != EXIT_BLOCK_PTR)
-                   {
-                     e->dest->count -= e->count;
-                     e->dest->frequency -= EDGE_FREQUENCY (e);
-                     if (e->dest->count < 0)
-                       e->dest->count = 0;
-                     if (e->dest->frequency < 0)
-                       e->dest->frequency = 0;
-                   }
-                 count += e->count;
-                 probability += e->probability;
-                 remove_edge (e);
-               }
-
-             e = next;
-           }
+  return NULL;
+
+ found:
+  /* ??? Wouldn't it be better to just reset any pending stack adjust?
+     Any instructions emitted here are about to be deleted.  */
+  do_pending_stack_adjust ();
 
-         /* This is somewhat ugly: the call_expr expander often emits
-            instructions after the sibcall (to perform the function
-            return).  These confuse the find_sub_basic_blocks code,
-            so we need to get rid of these.  */
-         last = NEXT_INSN (last);
-         if (!BARRIER_P (last))
-           abort ();
-         while (NEXT_INSN (last))
+  /* Remove any non-eh, non-abnormal edges that don't go to exit.  */
+  /* ??? I.e. the fallthrough edge.  HOWEVER!  If there were to be
+     EH or abnormal edges, we shouldn't have created a tail call in
+     the first place.  So it seems to me we should just be removing
+     all edges here, or redirecting the existing fallthru edge to
+     the exit block.  */
+
+  e = bb->succ;
+  probability = 0;
+  count = 0;
+  while (e)
+    {
+      edge next = e->succ_next;
+
+      if (!(e->flags & (EDGE_ABNORMAL | EDGE_EH)))
+       {
+         if (e->dest != EXIT_BLOCK_PTR)
            {
-             /* For instance an sqrt builtin expander expands if with
-                sibcall in the then and label for `else`.  */
-             if (LABEL_P (NEXT_INSN (last)))
-               break;
-             delete_insn (NEXT_INSN (last));
+             e->dest->count -= e->count;
+             e->dest->frequency -= EDGE_FREQUENCY (e);
+             if (e->dest->count < 0)
+               e->dest->count = 0;
+             if (e->dest->frequency < 0)
+               e->dest->frequency = 0;
            }
-         e = make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL | EDGE_SIBCALL);
-         e->probability += probability;
-         e->count += count;
-         BB_END (bb) = last;
-         update_bb_for_insn (bb);
-         if (NEXT_INSN (last))
-           bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb);
-         else
-           return bb;
+         count += e->count;
+         probability += e->probability;
+         remove_edge (e);
        }
+
+      e = next;
     }
 
-  return NULL;
+  /* This is somewhat ugly: the call_expr expander often emits instructions
+     after the sibcall (to perform the function return).  These confuse the
+     find_sub_basic_blocks code, so we need to get rid of these.  */
+  last = NEXT_INSN (last);
+  if (!BARRIER_P (last))
+    abort ();
+  while (NEXT_INSN (last))
+    {
+      /* For instance an sqrt builtin expander expands if with
+        sibcall in the then and label for `else`.  */
+      if (LABEL_P (NEXT_INSN (last)))
+       break;
+      delete_insn (NEXT_INSN (last));
+    }
+
+  e = make_edge (bb, EXIT_BLOCK_PTR, EDGE_ABNORMAL | EDGE_SIBCALL);
+  e->probability += probability;
+  e->count += count;
+  BB_END (bb) = last;
+  update_bb_for_insn (bb);
+
+  if (NEXT_INSN (last))
+    {
+      bb = create_basic_block (NEXT_INSN (last), get_last_insn (), bb);
+
+      last = BB_END (bb);
+      if (BARRIER_P (last))
+       BB_END (bb) = PREV_INSN (last);
+    }
+
+  return bb;
 }
 
 /* Expand basic block BB from GIMPLE trees to RTL.  */