OSDN Git Service

* cppinit.c (cpp_start_read): Free the imacros list as we
[pf3gnuchains/gcc-fork.git] / gcc / reg-stack.c
index ab27407..558735f 100644 (file)
@@ -1,22 +1,23 @@
 /* Register to Stack convert for GNU compiler.
-   Copyright (C) 1992, 93-99, 2000 Free Software Foundation, Inc.
+   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.
 #include "regs.h"
 #include "hard-reg-set.h"
 #include "flags.h"
-#include "insn-flags.h"
 #include "toplev.h"
 #include "recog.h"
 #include "output.h"
 #include "basic-block.h"
 #include "varray.h"
+#include "reload.h"
 
 #ifdef STACK_REGS
 
@@ -184,7 +185,7 @@ typedef struct stack_def
 {
   int top;                     /* index to top stack element */
   HARD_REG_SET reg_set;                /* set of live registers */
-  char reg[REG_STACK_SIZE];    /* register - stack mapping */
+  unsigned char reg[REG_STACK_SIZE];/* register - stack mapping */
 } *stack;
 
 /* This is used to carry information about basic blocks.  It is 
@@ -193,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)
@@ -238,7 +242,8 @@ static int check_asm_stack_operands PARAMS ((rtx));
 static int get_asm_operand_n_inputs    PARAMS ((rtx));
 static rtx stack_result                        PARAMS ((tree));
 static void replace_reg                        PARAMS ((rtx *, int));
-static void remove_regno_note          PARAMS ((rtx, enum reg_note, 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,
@@ -259,6 +264,9 @@ static int convert_regs_1           PARAMS ((FILE *, basic_block));
 static int convert_regs_2              PARAMS ((FILE *, basic_block));
 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.  */
 
@@ -299,7 +307,7 @@ stack_regs_mentioned (insn)
   unsigned int uid, max;
   int test;
 
-  if (GET_RTX_CLASS (GET_CODE (insn)) != 'i')
+  if (! INSN_P (insn) || !stack_regs_mentioned_data)
     return 0;
 
   uid = INSN_UID (insn);
@@ -331,23 +339,18 @@ next_flags_user (insn)
 {
   /* Search forward looking for the first use of this value. 
      Stop at block boundaries.  */
-  /* ??? This really cries for BLOCK_END!  */
 
-  while (1)
+  while (insn != current_block->end)
     {
       insn = NEXT_INSN (insn);
-      if (!insn)
-       return NULL_RTX;
 
-      if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-          && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
+      if (INSN_P (insn) && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
         return insn;
 
-      if (GET_CODE (insn) == JUMP_INSN
-         || GET_CODE (insn) == CODE_LABEL
-         || GET_CODE (insn) == CALL_INSN)
+      if (GET_CODE (insn) == CALL_INSN)
        return NULL_RTX;
     }
+  return NULL_RTX;
 }
 \f
 /* Reorganise the stack into ascending numbers,
@@ -407,7 +410,7 @@ pop_stack (regstack, regno)
    dump file, if used.
 
    Construct a CFG and run life analysis.  Then convert each insn one
-   by one.  Run a last jump_optimize pass, if optimizing, to eliminate
+   by one.  Run a last cleanup_cfg pass, if optimizing, to eliminate
    code duplication created when the converter inserts pop insns on
    the edges.  */
 
@@ -420,6 +423,16 @@ reg_to_stack (first, file)
   int max_uid;
   block_info bi;
 
+  /* Clean up previous run.  */
+  if (stack_regs_mentioned_data)
+    {
+      VARRAY_FREE (stack_regs_mentioned_data);
+      stack_regs_mentioned_data = 0;
+    }
+
+  if (!optimize)
+    split_all_insns (0);
+
   /* See if there is something to do.  Flow analysis is quite
      expensive so we might save some compilation time.  */
   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
@@ -430,14 +443,24 @@ reg_to_stack (first, file)
 
   /* Ok, floating point instructions exist.  If not optimizing, 
      build the CFG and run life analysis.  */
-  find_basic_blocks (first, max_reg_num (), file);
+  if (!optimize)
+    find_basic_blocks (first, max_reg_num (), file);
   count_or_remove_death_notes (NULL, 1);
-  life_analysis (first, max_reg_num (), file, 0);
+  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));
   for (i = n_basic_blocks - 1; i >= 0; --i)
-    BASIC_BLOCK (i)->aux = bi + i;
+    {
+      edge e;
+      basic_block bb = BASIC_BLOCK (i);
+      bb->aux = bi + 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++;
+    }
   EXIT_BLOCK_PTR->aux = bi + n_basic_blocks;
 
   /* Create the replacement registers up front.  */
@@ -476,14 +499,8 @@ reg_to_stack (first, file)
   VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1,
                    "stack_regs_mentioned cache");
 
-  if (convert_regs (file) && optimize)
-    {
-      jump_optimize (first, JUMP_CROSS_JUMP_DEATH_MATTERS,
-                    !JUMP_NOOP_MOVES, !JUMP_AFTER_REGSCAN);
-    }
+  convert_regs (file);
 
-  /* Clean up.  */
-  VARRAY_FREE (stack_regs_mentioned_data);
   free (bi);
 }
 \f
@@ -559,7 +576,11 @@ get_true_reg (pat)
          rtx subreg;
          if (FP_REG_P (subreg = SUBREG_REG (*pat)))
            {
-             *pat = FP_MODE_REG (REGNO (subreg) + SUBREG_WORD (*pat),
+             int regno_off = subreg_regno_offset (REGNO (subreg),
+                                                  GET_MODE (subreg),
+                                                  SUBREG_BYTE (*pat),
+                                                  GET_MODE (*pat));
+             *pat = FP_MODE_REG (REGNO (subreg) + regno_off,
                                  GET_MODE (subreg));
            default:
              return pat;
@@ -659,7 +680,20 @@ check_asm_stack_operands (insn)
            malformed_asm = 1;
          }
         else
-         reg_used_as_output[REGNO (recog_data.operand[i])] = 1;
+         {
+           int j;
+
+           for (j = 0; j < n_clobbers; j++)
+             if (REGNO (recog_data.operand[i]) == REGNO (clobber_reg[j]))
+               {
+                 error_for_asm (insn, "Output constraint %d cannot be specified together with \"%s\" clobber",
+                                i, reg_names [REGNO (clobber_reg[j])]);
+                 malformed_asm = 1;
+                 break;
+               }
+           if (j == n_clobbers)
+             reg_used_as_output[REGNO (recog_data.operand[i])] = 1;
+         }
       }
 
 
@@ -786,12 +820,8 @@ stack_result (decl)
   if (aggregate_value_p (DECL_RESULT (decl)))
     return 0;
 
-  result = DECL_RTL (DECL_RESULT (decl));
-  /* ?!?  What is this code supposed to do?  Can this code actually
-     trigger if we kick out aggregates above?  */
-  if (result != 0
-      && ! (GET_CODE (result) == REG
-           && REGNO (result) < FIRST_PSEUDO_REGISTER))
+  result = DECL_RTL_IF_SET (DECL_RESULT (decl));
+  if (result != 0)
     {
 #ifdef FUNCTION_OUTGOING_VALUE
       result
@@ -839,7 +869,7 @@ static void
 remove_regno_note (insn, note, regno)
      rtx insn;
      enum reg_note note;
-     int regno;
+     unsigned int regno;
 {
   register rtx *note_link, this;
 
@@ -908,6 +938,23 @@ emit_pop_insn (insn, regstack, reg, where)
   rtx pop_insn, pop_rtx;
   int hard_regno;
 
+  /* For complex types take care to pop both halves.  These may survive in
+     CLOBBER and USE expressions.  */
+  if (COMPLEX_MODE_P (GET_MODE (reg)))
+    {
+      rtx reg1 = FP_MODE_REG (REGNO (reg), DFmode);
+      rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, DFmode);
+
+      pop_insn = NULL_RTX;
+      if (get_hard_regnum (regstack, reg1) >= 0)
+         pop_insn = emit_pop_insn (insn, regstack, reg1, where);
+      if (get_hard_regnum (regstack, reg2) >= 0)
+         pop_insn = emit_pop_insn (insn, regstack, reg2, where);
+      if (!pop_insn)
+       abort ();
+      return pop_insn;
+    }
+
   hard_regno = get_hard_regnum (regstack, reg);
 
   if (hard_regno < FIRST_STACK_REG)
@@ -971,11 +1018,12 @@ emit_swap_insn (insn, regstack, reg)
   if (current_block && insn != current_block->head)
     {
       rtx tmp = PREV_INSN (insn);
-      while (tmp != current_block->head)
+      rtx limit = PREV_INSN (current_block->head);
+      while (tmp != limit)
        {
          if (GET_CODE (tmp) == CODE_LABEL
-             || (GET_CODE (tmp) == NOTE
-                 && NOTE_LINE_NUMBER (tmp) == NOTE_INSN_BASIC_BLOCK)
+             || GET_CODE (tmp) == CALL_INSN
+             || NOTE_INSN_BASIC_BLOCK_P (tmp)
              || (GET_CODE (tmp) == INSN
                  && stack_regs_mentioned (tmp)))
            {
@@ -996,14 +1044,15 @@ emit_swap_insn (insn, regstack, reg)
         swap with, omit the swap.  */
 
       if (GET_CODE (i1dest) == REG && REGNO (i1dest) == FIRST_STACK_REG
-         && GET_CODE (i1src) == REG && REGNO (i1src) == hard_regno - 1
+         && GET_CODE (i1src) == REG
+         && REGNO (i1src) == (unsigned) hard_regno - 1
          && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX)
        return;
 
       /* If the previous insn wrote to the reg we are to swap with,
         omit the swap.  */
 
-      if (GET_CODE (i1dest) == REG && REGNO (i1dest) == hard_regno
+      if (GET_CODE (i1dest) == REG && REGNO (i1dest) == (unsigned) hard_regno
          && GET_CODE (i1src) == REG && REGNO (i1src) == FIRST_STACK_REG
          && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX)
        return;
@@ -1015,10 +1064,7 @@ emit_swap_insn (insn, regstack, reg)
   if (i1)
     emit_block_insn_after (swap_rtx, i1, current_block);
   else if (current_block)
-    {
-      i1 = emit_insn_before (swap_rtx, current_block->head);
-      current_block->head = i1;
-    }
+    emit_block_insn_before (swap_rtx, current_block->head, current_block);
   else
     emit_insn_before (swap_rtx, insn);
 }
@@ -1123,7 +1169,8 @@ move_for_stack_reg (insn, regstack, pat)
          regstack->top--;
          CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
        }
-      else if (GET_MODE (src) == XFmode && regstack->top < REG_STACK_SIZE - 1)
+      else if ((GET_MODE (src) == XFmode || GET_MODE (src) == TFmode)
+              && regstack->top < REG_STACK_SIZE - 1)
        {
          /* A 387 cannot write an XFmode value to a MEM without
             clobbering the source reg.  The output code can handle
@@ -1133,9 +1180,12 @@ move_for_stack_reg (insn, regstack, pat)
             stack is not full, and then write the value to memory via
             a pop.  */
          rtx push_rtx, push_insn;
-         rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, XFmode);
+         rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, GET_MODE (src));
 
-         push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
+         if (GET_MODE (src) == TFmode)
+           push_rtx = gen_movtf (top_stack_reg, top_stack_reg);
+         else
+           push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
          push_insn = emit_insn_before (push_rtx, insn);
          REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, top_stack_reg,
                                                REG_NOTES (insn));
@@ -1167,7 +1217,7 @@ 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)
@@ -1231,18 +1281,12 @@ swap_rtx_condition (insn)
 
       /* Search forward looking for the first use of this value. 
         Stop at block boundaries.  */
-      /* ??? This really cries for BLOCK_END!  */
-      while (1)
+      while (insn != current_block->end)
        {
          insn = NEXT_INSN (insn);
-         if (insn == NULL_RTX)
-           return 0;
-         if (GET_RTX_CLASS (GET_CODE (insn)) == 'i'
-             && reg_mentioned_p (dest, insn))
+         if (INSN_P (insn) && reg_mentioned_p (dest, insn))
            break;
-         if (GET_CODE (insn) == JUMP_INSN)
-           return 0;
-         if (GET_CODE (insn) == CODE_LABEL)
+         if (GET_CODE (insn) == CALL_INSN)
            return 0;
        }
 
@@ -1263,7 +1307,28 @@ swap_rtx_condition (insn)
       pat = PATTERN (insn);
     }
 
-  return swap_rtx_condition_1 (pat);
+  if (swap_rtx_condition_1 (pat))
+    {
+      int fail = 0;
+      INSN_CODE (insn) = -1;
+      if (recog_memoized (insn) == -1)
+       fail = 1;
+      /* In case the flags don't die here, recurse to try fix
+         following user too.  */
+      else if (! dead_or_set_p (insn, ix86_flags_rtx))
+       {
+         insn = next_flags_user (insn);
+         if (!insn || !swap_rtx_condition (insn))
+           fail = 1;
+       }
+      if (fail)
+       {
+         swap_rtx_condition_1 (pat);
+         return 0;
+       }
+      return 1;
+    }
+  return 0;
 }
 
 /* Handle a comparison.  Special care needs to be taken to avoid
@@ -1436,6 +1501,15 @@ subst_stack_regs_pat (insn, regstack, pat)
                    PATTERN (insn) = pat;
                    move_for_stack_reg (insn, regstack, pat);
                  }
+               if (! note && COMPLEX_MODE_P (GET_MODE (*dest))
+                   && get_hard_regnum (regstack, FP_MODE_REG (REGNO (*dest), DFmode)) == -1)
+                 {
+                   pat = gen_rtx_SET (VOIDmode,
+                                      FP_MODE_REG (REGNO (*dest) + 1, SFmode),
+                                      nan);
+                   PATTERN (insn) = pat;
+                   move_for_stack_reg (insn, regstack, pat);
+                 }
              }
          }
        break;
@@ -1443,7 +1517,7 @@ subst_stack_regs_pat (insn, regstack, pat)
 
     case SET:
       {
-       rtx *src1 = (rtx *) NULL_PTR, *src2;
+       rtx *src1 = (rtx *) 0, *src2;
        rtx src1_note, src2_note;
        rtx pat_src;
 
@@ -1637,9 +1711,9 @@ subst_stack_regs_pat (insn, regstack, pat)
                && REG_P (*src1) && REG_P (*src2)
                && REGNO (*src1) != REGNO (*dest))
             {
-               rtx tmp = *src1;
-               *src1 = *src2;
-               *src2 = tmp;
+               int tmp = REGNO (*src1);
+               replace_reg (src1, REGNO (*src2));
+               replace_reg (src2, tmp);
             }
            break;
 
@@ -1699,13 +1773,13 @@ 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.  */
 
            /* 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);   
@@ -1752,7 +1826,7 @@ subst_stack_regs_pat (insn, regstack, pat)
            }
 
            /* 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));
@@ -1914,7 +1988,7 @@ subst_asm_stack_regs (insn, regstack)
        if (regno < 0)
          abort ();
 
-       if (regno != REGNO (recog_data.operand[i]))
+       if ((unsigned int) regno != REGNO (recog_data.operand[i]))
          {
            /* recog_data.operand[i] is not in the right place.  Find
               it and swap it with whatever is already in I's place.
@@ -2016,7 +2090,7 @@ subst_asm_stack_regs (insn, regstack)
 
       for (j = 0; j < n_outputs; j++)
        if (STACK_REG_P (recog_data.operand[j])
-           && REGNO (recog_data.operand[j]) == i)
+           && REGNO (recog_data.operand[j]) == (unsigned) i)
          {
            regstack->reg[++regstack->top] = i;
            SET_HARD_REG_BIT (regstack->reg_set, i);
@@ -2391,6 +2465,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
@@ -2398,14 +2609,50 @@ 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 ((e->flags & EDGE_CRITICAL) != (beste->flags & EDGE_CRITICAL))
+       {
+         if (e->flags & EDGE_CRITICAL)
+           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);
@@ -2485,132 +2732,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 EH edges specially.  The normal return path may return
-        a value in st(0), but the EH path will not, and there's no need
-        to add popping code to the edge.  */
-      if (e->flags & EDGE_EH)
-       {
-         /* 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);
        }
     }
 
@@ -2631,7 +2774,6 @@ convert_regs_2 (file, block)
   sp = stack;
 
   *sp++ = block;
-  BLOCK_INFO (block)->done = 1;
 
   inserted = 0;
   do
@@ -2640,12 +2782,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);