OSDN Git Service

Daily bump.
[pf3gnuchains/gcc-fork.git] / gcc / reg-stack.c
index 38803b2..b79c874 100644 (file)
@@ -2,22 +2,22 @@
    Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
    1999, 2000, 2001 Free Software Foundation, Inc.
 
-   This file is part of GNU CC.
+   This file is part of GCC.
 
-   GNU CC is free software; you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2, or (at your option)
    any later version.
 
-   GNU CC is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
-   GNU General Public License for more details.
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GNU CC; see the file COPYING.  If not, write to
-   the Free Software Foundation, 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with GCC; see the file COPYING.  If not, write to the Free
+   Software Foundation, 59 Temple Place - Suite 330, Boston, MA
+   02111-1307, USA.  */
 
 /* This pass converts stack-like registers from the "flat register
    file" model that gcc uses, to a stack convention that the 387 uses.
@@ -194,8 +194,11 @@ typedef struct stack_def
 typedef struct block_info_def
 {
   struct stack_def stack_in;   /* Input stack configuration.  */
+  struct stack_def stack_out;  /* Output stack configuration.  */
   HARD_REG_SET out_reg_set;    /* Stack regs live on output.  */
   int done;                    /* True if block already converted.  */
+  int predecesors;             /* Number of predecesors that needs
+                                  to be visited.  */
 } *block_info;
 
 #define BLOCK_INFO(B)  ((block_info) (B)->aux)
@@ -242,7 +245,6 @@ static void replace_reg                     PARAMS ((rtx *, int));
 static void remove_regno_note          PARAMS ((rtx, enum reg_note,
                                                 unsigned int));
 static int get_hard_regnum             PARAMS ((stack, rtx));
-static void delete_insn_for_stacker    PARAMS ((rtx));
 static rtx emit_pop_insn               PARAMS ((rtx, stack, rtx,
                                               enum emit_where));
 static void emit_swap_insn             PARAMS ((rtx, stack, rtx));
@@ -263,6 +265,7 @@ static int convert_regs                     PARAMS ((FILE *));
 static void print_stack                PARAMS ((FILE *, stack));
 static rtx next_flags_user             PARAMS ((rtx));
 static void record_label_references    PARAMS ((rtx, rtx));
+static bool compensate_edge            PARAMS ((edge, FILE *));
 \f
 /* Return non-zero if any stack register is mentioned somewhere within PAT.  */
 
@@ -270,8 +273,8 @@ static int
 stack_regs_mentioned_p (pat)
      rtx pat;
 {
-  register const char *fmt;
-  register int i;
+  const char *fmt;
+  int i;
 
   if (STACK_REG_P (pat))
     return 1;
@@ -281,7 +284,7 @@ stack_regs_mentioned_p (pat)
     {
       if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
 
          for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
            if (stack_regs_mentioned_p (XVECEXP (pat, i, j)))
@@ -417,7 +420,6 @@ reg_to_stack (first, file)
 {
   int i;
   int max_uid;
-  block_info bi;
 
   /* Clean up previous run.  */
   if (stack_regs_mentioned_data)
@@ -443,12 +445,19 @@ reg_to_stack (first, file)
     find_basic_blocks (first, max_reg_num (), file);
   count_or_remove_death_notes (NULL, 1);
   life_analysis (first, file, PROP_DEATH_NOTES);
+  mark_dfs_back_edges ();
 
   /* Set up block info for each basic block.  */
-  bi = (block_info) xcalloc ((n_basic_blocks + 1), sizeof (*bi));
+  alloc_aux_for_blocks (sizeof (struct block_info_def));
   for (i = n_basic_blocks - 1; i >= 0; --i)
-    BASIC_BLOCK (i)->aux = bi + i;
-  EXIT_BLOCK_PTR->aux = bi + n_basic_blocks;
+    {
+      edge e;
+      basic_block bb = BASIC_BLOCK (i);
+      for (e = bb->pred; e; e=e->pred_next)
+       if (!(e->flags & EDGE_DFS_BACK)
+           && e->src != ENTRY_BLOCK_PTR)
+         BLOCK_INFO (bb)->predecesors++;
+    }
 
   /* Create the replacement registers up front.  */
   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
@@ -488,7 +497,7 @@ reg_to_stack (first, file)
 
   convert_regs (file);
 
-  free (bi);
+  free_aux_for_blocks ();
 }
 \f
 /* Check PAT, which is in INSN, for LABEL_REFs.  Add INSN to the
@@ -499,14 +508,14 @@ static void
 record_label_references (insn, pat)
      rtx insn, pat;
 {
-  register enum rtx_code code = GET_CODE (pat);
-  register int i;
-  register const char *fmt;
+  enum rtx_code code = GET_CODE (pat);
+  int i;
+  const char *fmt;
 
   if (code == LABEL_REF)
     {
-      register rtx label = XEXP (pat, 0);
-      register rtx ref;
+      rtx label = XEXP (pat, 0);
+      rtx ref;
 
       if (GET_CODE (label) != CODE_LABEL)
        abort ();
@@ -538,7 +547,7 @@ record_label_references (insn, pat)
        record_label_references (insn, XEXP (pat, i));
       if (fmt[i] == 'E')
        {
-         register int j;
+         int j;
          for (j = 0; j < XVECLEN (pat, i); j++)
            record_label_references (insn, XVECEXP (pat, i, j));
        }
@@ -858,7 +867,7 @@ remove_regno_note (insn, note, regno)
      enum reg_note note;
      unsigned int regno;
 {
-  register rtx *note_link, this;
+  rtx *note_link, this;
 
   note_link = &REG_NOTES(insn);
   for (this = *note_link; this; this = XEXP (this, 1))
@@ -894,19 +903,6 @@ get_hard_regnum (regstack, reg)
 
   return i >= 0 ? (FIRST_STACK_REG + regstack->top - i) : -1;
 }
-
-/* Delete INSN from the RTL.  Mark the insn, but don't remove it from
-   the chain of insns.  Doing so could confuse block_begin and block_end
-   if this were the only insn in the block.  */
-
-static void
-delete_insn_for_stacker (insn)
-     rtx insn;
-{
-  PUT_CODE (insn, NOTE);
-  NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
-  NOTE_SOURCE_FILE (insn) = 0;
-}
 \f
 /* Emit an insn to pop virtual register REG before or after INSN.
    REGSTACK is the stack state after INSN and is updated to reflect this
@@ -951,9 +947,9 @@ emit_pop_insn (insn, regstack, reg, where)
                         FP_MODE_REG (FIRST_STACK_REG, DFmode));
 
   if (where == EMIT_AFTER)
-    pop_insn = emit_block_insn_after (pop_rtx, insn, current_block);
+    pop_insn = emit_insn_after (pop_rtx, insn);
   else
-    pop_insn = emit_block_insn_before (pop_rtx, insn, current_block);
+    pop_insn = emit_insn_before (pop_rtx, insn);
 
   REG_NOTES (pop_insn)
     = gen_rtx_EXPR_LIST (REG_DEAD, FP_MODE_REG (FIRST_STACK_REG, DFmode),
@@ -1049,9 +1045,9 @@ emit_swap_insn (insn, regstack, reg)
                         FP_MODE_REG (FIRST_STACK_REG, XFmode));
 
   if (i1)
-    emit_block_insn_after (swap_rtx, i1, current_block);
+    emit_insn_after (swap_rtx, i1);
   else if (current_block)
-    emit_block_insn_before (swap_rtx, current_block->head, current_block);
+    emit_insn_before (swap_rtx, current_block->head);
   else
     emit_insn_before (swap_rtx, insn);
 }
@@ -1101,7 +1097,7 @@ move_for_stack_reg (insn, regstack, pat)
            {
              emit_pop_insn (insn, regstack, src, EMIT_AFTER);
 
-             delete_insn_for_stacker (insn);
+             delete_insn (insn);
              return;
            }
 
@@ -1110,7 +1106,7 @@ move_for_stack_reg (insn, regstack, pat)
          SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
          CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
 
-         delete_insn_for_stacker (insn);
+         delete_insn (insn);
 
          return;
        }
@@ -1127,7 +1123,7 @@ move_for_stack_reg (insn, regstack, pat)
          if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
            emit_pop_insn (insn, regstack, dest, EMIT_AFTER);
 
-         delete_insn_for_stacker (insn);
+         delete_insn (insn);
          return;
        }
 
@@ -1204,14 +1200,14 @@ move_for_stack_reg (insn, regstack, pat)
 \f
 /* Swap the condition on a branch, if there is one.  Return true if we
    found a condition to swap.  False if the condition was not used as
-   such. */
+   such.  */
 
 static int
 swap_rtx_condition_1 (pat)
      rtx pat;
 {
-  register const char *fmt;
-  register int i, r = 0;
+  const char *fmt;
+  int i, r = 0;
 
   if (GET_RTX_CLASS (GET_CODE (pat)) == '<')
     {
@@ -1225,7 +1221,7 @@ swap_rtx_condition_1 (pat)
        {
          if (fmt[i] == 'E')
            {
-             register int j;
+             int j;
 
              for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
                r |= swap_rtx_condition_1 (XVECEXP (pat, i, j));
@@ -1760,22 +1756,48 @@ subst_stack_regs_pat (insn, regstack, pat)
            break;
 
          case IF_THEN_ELSE:
-           /* This insn requires the top of stack to be the destination. */
+           /* This insn requires the top of stack to be the destination.  */
+
+           src1 = get_true_reg (&XEXP (pat_src, 1));
+           src2 = get_true_reg (&XEXP (pat_src, 2));
+
+           src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+           src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
 
            /* If the comparison operator is an FP comparison operator,
               it is handled correctly by compare_for_stack_reg () who
               will move the destination to the top of stack. But if the
               comparison operator is not an FP comparison operator, we
-              have to handle it here. */
+              have to handle it here.  */
            if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
                && REGNO (*dest) != regstack->reg[regstack->top])
-             emit_swap_insn (insn, regstack, *dest);   
-
-           src1 = get_true_reg (&XEXP (pat_src, 1));
-           src2 = get_true_reg (&XEXP (pat_src, 2));
-
-           src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
-           src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+             {
+               /* In case one of operands is the top of stack and the operands
+                  dies, it is safe to make it the destination operand by reversing
+                  the direction of cmove and avoid fxch.  */
+               if ((REGNO (*src1) == regstack->reg[regstack->top]
+                    && src1_note)
+                   || (REGNO (*src2) == regstack->reg[regstack->top]
+                       && src2_note))
+                 {
+                   int idx1 = (get_hard_regnum (regstack, *src1)
+                               - FIRST_STACK_REG);
+                   int idx2 = (get_hard_regnum (regstack, *src2)
+                               - FIRST_STACK_REG);
+
+                   /* Make reg-stack believe that the operands are already
+                      swapped on the stack */
+                   regstack->reg[regstack->top - idx1] = REGNO (*src2);
+                   regstack->reg[regstack->top - idx2] = REGNO (*src1);
+
+                   /* Reverse condition to compensate the operand swap.
+                      i386 do have comparison always reversible.  */
+                   PUT_CODE (XEXP (pat_src, 0),
+                             reversed_comparison_code (XEXP (pat_src, 0), insn));
+                 }
+               else
+                 emit_swap_insn (insn, regstack, *dest);       
+             }
 
            {
              rtx src_note [3];
@@ -1804,16 +1826,14 @@ subst_stack_regs_pat (insn, regstack, pat)
                                       EMIT_AFTER);
                      }
                    else
-                     {
-                       CLEAR_HARD_REG_BIT (regstack->reg_set, regno);
-                       replace_reg (&XEXP (src_note[i], 0), FIRST_STACK_REG);
-                       regstack->top--;
-                     }
+                     /* Top of stack never dies, as it is the
+                        destination.  */
+                     abort ();
                  }
            }
 
            /* Make dest the top of stack.  Add dest to regstack if
-              not present. */
+              not present.  */
            if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
              regstack->reg[++regstack->top] = REGNO (*dest);   
            SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
@@ -2135,8 +2155,8 @@ subst_stack_regs (insn, regstack)
      rtx insn;
      stack regstack;
 {
-  register rtx *note_link, note;
-  register int i;
+  rtx *note_link, note;
+  int i;
 
   if (GET_CODE (insn) == CALL_INSN)
     {
@@ -2452,6 +2472,143 @@ convert_regs_exit ()
     }
 }
 
+/* Adjust the stack of this block on exit to match the stack of the
+   target block, or copy stack info into the stack of the successor
+   of the successor hasn't been processed yet.  */
+static bool
+compensate_edge (e, file)
+    edge e;
+    FILE *file;
+{
+  basic_block block = e->src, target = e->dest;
+  block_info bi = BLOCK_INFO (block);
+  struct stack_def regstack, tmpstack;
+  stack target_stack = &BLOCK_INFO (target)->stack_in;
+  int reg;
+
+  current_block = block;
+  regstack = bi->stack_out;
+  if (file)
+    fprintf (file, "Edge %d->%d: ", block->index, target->index);
+
+  if (target_stack->top == -2)
+    {
+      /* The target block hasn't had a stack order selected.
+         We need merely ensure that no pops are needed.  */
+      for (reg = regstack.top; reg >= 0; --reg)
+       if (!TEST_HARD_REG_BIT (target_stack->reg_set, regstack.reg[reg]))
+         break;
+
+      if (reg == -1)
+       {
+         if (file)
+           fprintf (file, "new block; copying stack position\n");
+
+         /* change_stack kills values in regstack.  */
+         tmpstack = regstack;
+
+         change_stack (block->end, &tmpstack, target_stack, EMIT_AFTER);
+          return false;
+       }
+
+      if (file)
+       fprintf (file, "new block; pops needed\n");
+    }
+  else
+    {
+      if (target_stack->top == regstack.top)
+       {
+         for (reg = target_stack->top; reg >= 0; --reg)
+           if (target_stack->reg[reg] != regstack.reg[reg])
+             break;
+
+         if (reg == -1)
+           {
+             if (file)
+               fprintf (file, "no changes needed\n");
+             return false;
+           }
+       }
+
+      if (file)
+       {
+         fprintf (file, "correcting stack to ");
+         print_stack (file, target_stack);
+       }
+    }
+
+  /* Care for non-call EH edges specially.  The normal return path have
+     values in registers.  These will be popped en masse by the unwind
+     library.  */
+  if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
+    target_stack->top = -1;
+
+  /* Other calls may appear to have values live in st(0), but the
+     abnormal return path will not have actually loaded the values.  */
+  else if (e->flags & EDGE_ABNORMAL_CALL)
+    {
+      /* Assert that the lifetimes are as we expect -- one value
+         live at st(0) on the end of the source block, and no
+         values live at the beginning of the destination block.  */
+      HARD_REG_SET tmp;
+
+      CLEAR_HARD_REG_SET (tmp);
+      GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
+      abort ();
+    eh1:
+
+      SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
+      GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
+      abort ();
+    eh2:
+
+      target_stack->top = -1;
+    }
+
+  /* It is better to output directly to the end of the block
+     instead of to the edge, because emit_swap can do minimal
+     insn scheduling.  We can do this when there is only one
+     edge out, and it is not abnormal.  */
+  else if (block->succ->succ_next == NULL && !(e->flags & EDGE_ABNORMAL))
+    {
+      /* change_stack kills values in regstack.  */
+      tmpstack = regstack;
+
+      change_stack (block->end, &tmpstack, target_stack,
+                   (GET_CODE (block->end) == JUMP_INSN
+                    ? EMIT_BEFORE : EMIT_AFTER));
+    }
+  else
+    {
+      rtx seq, after;
+
+      /* We don't support abnormal edges.  Global takes care to
+         avoid any live register across them, so we should never
+         have to insert instructions on such edges.  */
+      if (e->flags & EDGE_ABNORMAL)
+       abort ();
+
+      current_block = NULL;
+      start_sequence ();
+
+      /* ??? change_stack needs some point to emit insns after. 
+         Also needed to keep gen_sequence from returning a 
+         pattern as opposed to a sequence, which would lose
+         REG_DEAD notes.  */
+      after = emit_note (NULL, NOTE_INSN_DELETED);
+
+      tmpstack = regstack;
+      change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
+
+      seq = gen_sequence ();
+      end_sequence ();
+
+      insert_insn_on_edge (seq, e);
+      return true;
+    }
+  return false;
+}
+
 /* Convert stack register references in one block.  */
 
 static int
@@ -2459,14 +2616,51 @@ convert_regs_1 (file, block)
      FILE *file;
      basic_block block;
 {
-  struct stack_def regstack, tmpstack;
+  struct stack_def regstack;
   block_info bi = BLOCK_INFO (block);
   int inserted, reg;
   rtx insn, next;
-  edge e;
+  edge e, beste = NULL;
 
-  current_block = block;
+  inserted = 0;
+
+  /* Find the edge we will copy stack from.  It should be the most frequent
+     one as it will get cheapest after compensation code is generated,
+     if multiple such exists, take one with largest count, preffer critical
+     one (as splitting critical edges is more expensive), or one with lowest
+     index, to avoid random changes with different orders of the edges.  */
+  for (e = block->pred; e ; e = e->pred_next)
+    {
+      if (e->flags & EDGE_DFS_BACK)
+       ;
+      else if (! beste)
+       beste = e;
+      else if (EDGE_FREQUENCY (beste) < EDGE_FREQUENCY (e))
+       beste = e;
+      else if (EDGE_FREQUENCY (beste) > EDGE_FREQUENCY (e))
+       ;
+      else if (beste->count < e->count)
+       beste = e;
+      else if (beste->count > e->count)
+       ;
+      else if ((EDGE_CRITICAL_P (e) != 0)
+              != (EDGE_CRITICAL_P (beste) != 0))
+       {
+         if (EDGE_CRITICAL_P (e))
+           beste = e;
+       }
+      else if (e->src->index < beste->src->index)
+       beste = e;
+    }
+
+  /* Entry block does have stack already initialized.  */
+  if (bi->stack_in.top == -2)
+    inserted |= compensate_edge (beste, file);
+  else
+    beste = NULL;
   
+  current_block = block;
+
   if (file)
     {
       fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
@@ -2537,7 +2731,7 @@ convert_regs_1 (file, block)
 
          set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode),
                             nan);
-         insn = emit_block_insn_after (set, insn, block);
+         insn = emit_insn_after (set, insn);
          subst_stack_regs (insn, &regstack);
        }
     }
@@ -2546,137 +2740,28 @@ convert_regs_1 (file, block)
   GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
   abort ();
  win:
+  bi->stack_out = regstack;
 
-  /* Adjust the stack of this block on exit to match the stack of the
-     target block, or copy stack info into the stack of the successor
-     of the successor hasn't been processed yet.  */
-  inserted = 0;
+  /* Compensate the back edges, as those wasn't visited yet.  */
   for (e = block->succ; e ; e = e->succ_next)
     {
-      basic_block target = e->dest;
-      stack target_stack = &BLOCK_INFO (target)->stack_in;
-
-      if (file)
-       fprintf (file, "Edge to block %d: ", target->index);
-
-      if (target_stack->top == -2)
-       {
-         /* The target block hasn't had a stack order selected.
-            We need merely ensure that no pops are needed.  */
-         for (reg = regstack.top; reg >= 0; --reg)
-           if (! TEST_HARD_REG_BIT (target_stack->reg_set,
-                                    regstack.reg[reg]))
-             break;
-
-         if (reg == -1)
-           {
-             if (file)
-               fprintf (file, "new block; copying stack position\n");
-
-             /* change_stack kills values in regstack.  */
-             tmpstack = regstack;
-
-             change_stack (block->end, &tmpstack,
-                           target_stack, EMIT_AFTER);
-             continue;
-           }
-
-         if (file)
-           fprintf (file, "new block; pops needed\n");
-       }
-      else
-       {
-         if (target_stack->top == regstack.top)
-           {
-             for (reg = target_stack->top; reg >= 0; --reg)
-               if (target_stack->reg[reg] != regstack.reg[reg])
-                 break;
-
-             if (reg == -1)
-               {
-                 if (file)
-                   fprintf (file, "no changes needed\n");
-                 continue;
-               }
-           }
-
-         if (file)
-           {
-             fprintf (file, "correcting stack to ");
-             print_stack (file, target_stack);
-           }
-       }
-
-      /* Care for non-call EH edges specially.  The normal return path have
-        values in registers.  These will be popped en masse by the unwind
-        library.  */
-      if ((e->flags & (EDGE_EH | EDGE_ABNORMAL_CALL)) == EDGE_EH)
-       target_stack->top = -1;
-
-      /* Other calls may appear to have values live in st(0), but the
-        abnormal return path will not have actually loaded the values.  */
-      else if (e->flags & EDGE_ABNORMAL_CALL)
-       {
-         /* Assert that the lifetimes are as we expect -- one value
-            live at st(0) on the end of the source block, and no
-            values live at the beginning of the destination block.  */
-         HARD_REG_SET tmp;
-
-         CLEAR_HARD_REG_SET (tmp);
-         GO_IF_HARD_REG_EQUAL (target_stack->reg_set, tmp, eh1);
-         abort();
-       eh1:
-
-         SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
-         GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
-         abort();
-       eh2:
-
-         target_stack->top = -1;
-       }
-
-      /* It is better to output directly to the end of the block
-        instead of to the edge, because emit_swap can do minimal
-        insn scheduling.  We can do this when there is only one
-        edge out, and it is not abnormal.  */
-      else if (block->succ->succ_next == NULL
-              && ! (e->flags & EDGE_ABNORMAL))
+      if (e->flags & EDGE_DFS_BACK
+         || (e->dest == EXIT_BLOCK_PTR))
        {
-         /* change_stack kills values in regstack.  */
-         tmpstack = regstack;
-
-         change_stack (block->end, &tmpstack, target_stack,
-                       (GET_CODE (block->end) == JUMP_INSN
-                        ? EMIT_BEFORE : EMIT_AFTER));
+         if (!BLOCK_INFO (e->dest)->done
+             && e->dest != block)
+           abort ();
+          inserted |= compensate_edge (e, file);
        }
-      else
+    }
+  for (e = block->pred; e ; e = e->pred_next)
+    {
+      if (e != beste && !(e->flags & EDGE_DFS_BACK)
+         && e->src != ENTRY_BLOCK_PTR)
        {
-         rtx seq, after;
-
-         /* We don't support abnormal edges.  Global takes care to
-            avoid any live register across them, so we should never
-            have to insert instructions on such edges.  */
-         if (e->flags & EDGE_ABNORMAL)
+         if (!BLOCK_INFO (e->src)->done)
            abort ();
-
-         current_block = NULL;
-         start_sequence ();
-                 
-         /* ??? change_stack needs some point to emit insns after. 
-            Also needed to keep gen_sequence from returning a 
-            pattern as opposed to a sequence, which would lose
-            REG_DEAD notes.  */
-         after = emit_note (NULL, NOTE_INSN_DELETED);
-
-         tmpstack = regstack;
-         change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
-
-         seq = gen_sequence ();
-         end_sequence ();
-
-         insert_insn_on_edge (seq, e);
-         inserted = 1;
-         current_block = block;
+          inserted |= compensate_edge (e, file);
        }
     }
 
@@ -2697,7 +2782,6 @@ convert_regs_2 (file, block)
   sp = stack;
 
   *sp++ = block;
-  BLOCK_INFO (block)->done = 1;
 
   inserted = 0;
   do
@@ -2706,12 +2790,14 @@ convert_regs_2 (file, block)
 
       block = *--sp;
       inserted |= convert_regs_1 (file, block);
+      BLOCK_INFO (block)->done = 1;
 
       for (e = block->succ; e ; e = e->succ_next)
-       if (! BLOCK_INFO (e->dest)->done)
+       if (! (e->flags & EDGE_DFS_BACK))
          {
-           *sp++ = e->dest;
-           BLOCK_INFO (e->dest)->done = 1;
+           BLOCK_INFO (e->dest)->predecesors--;
+           if (!BLOCK_INFO (e->dest)->predecesors)
+              *sp++ = e->dest;
          }
     }
   while (sp != stack);