OSDN Git Service

2003-07-30 Chris Demetriou <cgd@broadcom.com>
[pf3gnuchains/gcc-fork.git] / gcc / reg-stack.c
index 942f257..016c5c7 100644 (file)
@@ -1,6 +1,6 @@
 /* Register to Stack convert for GNU compiler.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998,
-   1999, 2000, 2001, 2002 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
+   2000, 2001, 2002, 2003 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
 \f
 #include "config.h"
 #include "system.h"
+#include "coretypes.h"
+#include "tm.h"
 #include "tree.h"
 #include "rtl.h"
 #include "tm_p.h"
 #include "basic-block.h"
 #include "varray.h"
 #include "reload.h"
+#include "ggc.h"
+
+/* We use this array to cache info about insns, because otherwise we
+   spend too much time in stack_regs_mentioned_p.
+
+   Indexed by insn UIDs.  A value of zero is uninitialized, one indicates
+   the insn uses stack registers, two indicates the insn does not use
+   stack registers.  */
+static GTY(()) varray_type stack_regs_mentioned_data;
 
 #ifdef STACK_REGS
 
@@ -210,18 +221,10 @@ enum emit_where
   EMIT_BEFORE
 };
 
-/* We use this array to cache info about insns, because otherwise we
-   spend too much time in stack_regs_mentioned_p.
-
-   Indexed by insn UIDs.  A value of zero is uninitialized, one indicates
-   the insn uses stack registers, two indicates the insn does not use
-   stack registers.  */
-static varray_type stack_regs_mentioned_data;
-
 /* The block we're currently working on.  */
 static basic_block current_block;
 
-/* This is the register file for all register after conversion */
+/* This is the register file for all register after conversion */
 static rtx
   FP_mode_reg[LAST_STACK_REG+1-FIRST_STACK_REG][(int) MAX_MACHINE_MODE];
 
@@ -233,45 +236,41 @@ static rtx nan;
 
 /* Forward declarations */
 
-static int stack_regs_mentioned_p      PARAMS ((rtx pat));
-static void straighten_stack           PARAMS ((rtx, stack));
-static void pop_stack                  PARAMS ((stack, int));
-static rtx *get_true_reg               PARAMS ((rtx *));
-
-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,
-                                                unsigned int));
-static int get_hard_regnum             PARAMS ((stack, rtx));
-static rtx emit_pop_insn               PARAMS ((rtx, stack, rtx,
-                                              enum emit_where));
-static void emit_swap_insn             PARAMS ((rtx, stack, rtx));
-static void move_for_stack_reg         PARAMS ((rtx, stack, rtx));
-static int swap_rtx_condition_1                PARAMS ((rtx));
-static int swap_rtx_condition          PARAMS ((rtx));
-static void compare_for_stack_reg      PARAMS ((rtx, stack, rtx));
-static void subst_stack_regs_pat       PARAMS ((rtx, stack, rtx));
-static void subst_asm_stack_regs       PARAMS ((rtx, stack));
-static void subst_stack_regs           PARAMS ((rtx, stack));
-static void change_stack               PARAMS ((rtx, stack, stack,
-                                              enum emit_where));
-static int convert_regs_entry          PARAMS ((void));
-static void convert_regs_exit          PARAMS ((void));
-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 *));
+static int stack_regs_mentioned_p (rtx pat);
+static void straighten_stack (rtx, stack);
+static void pop_stack (stack, int);
+static rtx *get_true_reg (rtx *);
+
+static int check_asm_stack_operands (rtx);
+static int get_asm_operand_n_inputs (rtx);
+static rtx stack_result (tree);
+static void replace_reg (rtx *, int);
+static void remove_regno_note (rtx, enum reg_note, unsigned int);
+static int get_hard_regnum (stack, rtx);
+static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where);
+static void emit_swap_insn (rtx, stack, rtx);
+static void move_for_stack_reg (rtx, stack, rtx);
+static int swap_rtx_condition_1 (rtx);
+static int swap_rtx_condition (rtx);
+static void compare_for_stack_reg (rtx, stack, rtx);
+static void subst_stack_regs_pat (rtx, stack, rtx);
+static void subst_asm_stack_regs (rtx, stack);
+static void subst_stack_regs (rtx, stack);
+static void change_stack (rtx, stack, stack, enum emit_where);
+static int convert_regs_entry (void);
+static void convert_regs_exit (void);
+static int convert_regs_1 (FILE *, basic_block);
+static int convert_regs_2 (FILE *, basic_block);
+static int convert_regs (FILE *);
+static void print_stack (FILE *, stack);
+static rtx next_flags_user (rtx);
+static void record_label_references (rtx, rtx);
+static bool compensate_edge (edge, FILE *);
 \f
-/* Return non-zero if any stack register is mentioned somewhere within PAT.  */
+/* Return nonzero if any stack register is mentioned somewhere within PAT.  */
 
 static int
-stack_regs_mentioned_p (pat)
-     rtx pat;
+stack_regs_mentioned_p (rtx pat)
 {
   const char *fmt;
   int i;
@@ -300,8 +299,7 @@ stack_regs_mentioned_p (pat)
 /* Return nonzero if INSN mentions stacked registers, else return zero.  */
 
 int
-stack_regs_mentioned (insn)
-     rtx insn;
+stack_regs_mentioned (rtx insn)
 {
   unsigned int uid, max;
   int test;
@@ -333,8 +331,7 @@ stack_regs_mentioned (insn)
 static rtx ix86_flags_rtx;
 
 static rtx
-next_flags_user (insn)
-     rtx insn;
+next_flags_user (rtx insn)
 {
   /* Search forward looking for the first use of this value.
      Stop at block boundaries.  */
@@ -352,13 +349,11 @@ next_flags_user (insn)
   return NULL_RTX;
 }
 \f
-/* Reorganise the stack into ascending numbers,
+/* Reorganize the stack into ascending numbers,
    after this insn.  */
 
 static void
-straighten_stack (insn, regstack)
-     rtx insn;
-     stack regstack;
+straighten_stack (rtx insn, stack regstack)
 {
   struct stack_def temp_stack;
   int top;
@@ -378,18 +373,16 @@ straighten_stack (insn, regstack)
   change_stack (insn, regstack, &temp_stack, EMIT_AFTER);
 }
 
-/* Pop a register from the stack */
+/* Pop a register from the stack */
 
 static void
-pop_stack (regstack, regno)
-     stack regstack;
-     int   regno;
+pop_stack (stack regstack, int regno)
 {
   int top = regstack->top;
 
   CLEAR_HARD_REG_BIT (regstack->reg_set, regno);
   regstack->top--;
-  /* If regno was not at the top of stack then adjust stack */
+  /* If regno was not at the top of stack then adjust stack */
   if (regstack->reg [top] != regno)
     {
       int i;
@@ -413,23 +406,15 @@ pop_stack (regstack, regno)
    code duplication created when the converter inserts pop insns on
    the edges.  */
 
-void
-reg_to_stack (first, file)
-     rtx first;
-     FILE *file;
+bool
+reg_to_stack (rtx first, FILE *file)
 {
+  basic_block bb;
   int i;
   int max_uid;
 
   /* 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);
+  stack_regs_mentioned_data = 0;
 
   /* See if there is something to do.  Flow analysis is quite
      expensive so we might save some compilation time.  */
@@ -437,13 +422,16 @@ reg_to_stack (first, file)
     if (regs_ever_live[i])
       break;
   if (i > LAST_STACK_REG)
-    return;
+    return false;
 
   /* Ok, floating point instructions exist.  If not optimizing,
-     build the CFG and run life analysis.  */
-  if (!optimize)
+     build the CFG and run life analysis.
+     Also need to rebuild life when superblock scheduling is done
+     as it don't update liveness yet.  */
+  if (!optimize
+      || (flag_sched2_use_superblocks
+         && flag_schedule_insns_after_reload))
     {
-      find_basic_blocks (first, max_reg_num (), file);
       count_or_remove_death_notes (NULL, 1);
       life_analysis (first, file, PROP_DEATH_NOTES);
     }
@@ -451,11 +439,10 @@ reg_to_stack (first, file)
 
   /* Set up block info for each basic block.  */
   alloc_aux_for_blocks (sizeof (struct block_info_def));
-  for (i = n_basic_blocks - 1; i >= 0; --i)
+  FOR_EACH_BB_REVERSE (bb)
     {
       edge e;
-      basic_block bb = BASIC_BLOCK (i);
-      for (e = bb->pred; e; e=e->pred_next)
+      for (e = bb->pred; e; e = e->pred_next)
        if (!(e->flags & EDGE_DFS_BACK)
            && e->src != ENTRY_BLOCK_PTR)
          BLOCK_INFO (bb)->predecessors++;
@@ -480,7 +467,7 @@ reg_to_stack (first, file)
   /* A QNaN for initializing uninitialized variables.
 
      ??? We can't load from constant memory in PIC mode, because
-     we're insertting these instructions before the prologue and
+     we're inserting these instructions before the prologue and
      the PIC register hasn't been set up.  In that case, fall back
      on zero, which we can get from `ldz'.  */
 
@@ -500,6 +487,7 @@ reg_to_stack (first, file)
   convert_regs (file);
 
   free_aux_for_blocks ();
+  return true;
 }
 \f
 /* Check PAT, which is in INSN, for LABEL_REFs.  Add INSN to the
@@ -507,8 +495,7 @@ reg_to_stack (first, file)
    reference.  */
 
 static void
-record_label_references (insn, pat)
-     rtx insn, pat;
+record_label_references (rtx insn, rtx pat)
 {
   enum rtx_code code = GET_CODE (pat);
   int i;
@@ -561,14 +548,13 @@ record_label_references (insn, pat)
    PAT that stopped the search.  */
 
 static rtx *
-get_true_reg (pat)
-     rtx *pat;
+get_true_reg (rtx *pat)
 {
   for (;;)
     switch (GET_CODE (*pat))
       {
       case SUBREG:
-       /* Eliminate FP subregister accesses in favour of the
+       /* Eliminate FP subregister accesses in favor of the
           actual FP register in use.  */
        {
          rtx subreg;
@@ -591,13 +577,15 @@ get_true_reg (pat)
       }
 }
 \f
+/* Set if we find any malformed asms in a block.  */
+static bool any_malformed_asm;
+
 /* There are many rules that an asm statement for stack-like regs must
    follow.  Those rules are explained at the top of this file: the rule
    numbers below refer to that explanation.  */
 
 static int
-check_asm_stack_operands (insn)
-     rtx insn;
+check_asm_stack_operands (rtx insn)
 {
   int i;
   int n_clobbers;
@@ -642,7 +630,7 @@ check_asm_stack_operands (insn)
 
   if (GET_CODE (body) == PARALLEL)
     {
-      clobber_reg = (rtx *) alloca (XVECLEN (body, 0) * sizeof (rtx));
+      clobber_reg = alloca (XVECLEN (body, 0) * sizeof (rtx));
 
       for (i = 0; i < XVECLEN (body, 0); i++)
        if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
@@ -748,7 +736,7 @@ check_asm_stack_operands (insn)
       malformed_asm = 1;
     }
 
-  /* Enfore rule #3: If any input operand uses the "f" constraint, all
+  /* Enforce rule #3: If any input operand uses the "f" constraint, all
      output constraints must use the "&" earlyclobber.
 
      ??? Detect this more deterministically by having constrain_asm_operands
@@ -772,6 +760,7 @@ check_asm_stack_operands (insn)
     {
       /* Avoid further trouble with this insn.  */
       PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
+      any_malformed_asm = true;
       return 0;
     }
 
@@ -784,8 +773,7 @@ check_asm_stack_operands (insn)
    placed.  */
 
 static int
-get_asm_operand_n_inputs (body)
-     rtx body;
+get_asm_operand_n_inputs (rtx body)
 {
   if (GET_CODE (body) == SET && GET_CODE (SET_SRC (body)) == ASM_OPERANDS)
     return ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body));
@@ -808,8 +796,7 @@ get_asm_operand_n_inputs (body)
    return the REG.  Otherwise, return 0.  */
 
 static rtx
-stack_result (decl)
-     tree decl;
+stack_result (tree decl)
 {
   rtx result;
 
@@ -842,9 +829,7 @@ stack_result (decl)
    the desired hard REGNO.  */
 
 static void
-replace_reg (reg, regno)
-     rtx *reg;
-     int regno;
+replace_reg (rtx *reg, int regno)
 {
   if (regno < FIRST_STACK_REG || regno > LAST_STACK_REG
       || ! STACK_REG_P (*reg))
@@ -864,10 +849,7 @@ replace_reg (reg, regno)
    number REGNO from INSN.  Remove only one such note.  */
 
 static void
-remove_regno_note (insn, note, regno)
-     rtx insn;
-     enum reg_note note;
-     unsigned int regno;
+remove_regno_note (rtx insn, enum reg_note note, unsigned int regno)
 {
   rtx *note_link, this;
 
@@ -890,9 +872,7 @@ remove_regno_note (insn, note, regno)
    returned if the register is not found.  */
 
 static int
-get_hard_regnum (regstack, reg)
-     stack regstack;
-     rtx reg;
+get_hard_regnum (stack regstack, rtx reg)
 {
   int i;
 
@@ -914,11 +894,7 @@ get_hard_regnum (regstack, reg)
    cases the movdf pattern to pop.  */
 
 static rtx
-emit_pop_insn (insn, regstack, reg, where)
-     rtx insn;
-     stack regstack;
-     rtx reg;
-     enum emit_where where;
+emit_pop_insn (rtx insn, stack regstack, rtx reg, enum emit_where where)
 {
   rtx pop_insn, pop_rtx;
   int hard_regno;
@@ -973,10 +949,7 @@ emit_pop_insn (insn, regstack, reg, where)
    If REG is already at the top of the stack, no insn is emitted.  */
 
 static void
-emit_swap_insn (insn, regstack, reg)
-     rtx insn;
-     stack regstack;
-     rtx reg;
+emit_swap_insn (rtx insn, stack regstack, rtx reg)
 {
   int hard_regno;
   rtx swap_rtx;
@@ -1058,10 +1031,7 @@ emit_swap_insn (insn, regstack, reg)
    REGSTACK is the current stack.  */
 
 static void
-move_for_stack_reg (insn, regstack, pat)
-     rtx insn;
-     stack regstack;
-     rtx pat;
+move_for_stack_reg (rtx insn, stack regstack, rtx pat)
 {
   rtx *psrc =  get_true_reg (&SET_SRC (pat));
   rtx *pdest = get_true_reg (&SET_DEST (pat));
@@ -1129,7 +1099,7 @@ move_for_stack_reg (insn, regstack, pat)
          return;
        }
 
-      /* The destination ought to be dead */
+      /* The destination ought to be dead */
       if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
        abort ();
 
@@ -1185,7 +1155,7 @@ move_for_stack_reg (insn, regstack, pat)
         stack. The stack mapping is changed to reflect that DEST is
         now at top of stack.  */
 
-      /* The destination ought to be dead */
+      /* The destination ought to be dead */
       if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
        abort ();
 
@@ -1205,8 +1175,7 @@ move_for_stack_reg (insn, regstack, pat)
    such.  */
 
 static int
-swap_rtx_condition_1 (pat)
-     rtx pat;
+swap_rtx_condition_1 (rtx pat)
 {
   const char *fmt;
   int i, r = 0;
@@ -1237,8 +1206,7 @@ swap_rtx_condition_1 (pat)
 }
 
 static int
-swap_rtx_condition (insn)
-     rtx insn;
+swap_rtx_condition (rtx insn)
 {
   rtx pat = PATTERN (insn);
 
@@ -1325,10 +1293,7 @@ swap_rtx_condition (insn)
    set up.  */
 
 static void
-compare_for_stack_reg (insn, regstack, pat_src)
-     rtx insn;
-     stack regstack;
-     rtx pat_src;
+compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
 {
   rtx *src1, *src2;
   rtx src1_note, src2_note;
@@ -1417,10 +1382,7 @@ compare_for_stack_reg (insn, regstack, pat_src)
    is the current register layout.  */
 
 static void
-subst_stack_regs_pat (insn, regstack, pat)
-     rtx insn;
-     stack regstack;
-     rtx pat;
+subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
 {
   rtx *dest, *src;
 
@@ -1691,7 +1653,7 @@ subst_stack_regs_pat (insn, regstack, pat)
                replace_reg (dest, get_hard_regnum (regstack, *dest));
              }
 
-           /* Keep operand 1 maching with destination.  */
+           /* Keep operand 1 matching with destination.  */
            if (GET_RTX_CLASS (GET_CODE (pat_src)) == 'c'
                && REG_P (*src1) && REG_P (*src2)
                && REGNO (*src1) != REGNO (*dest))
@@ -1707,6 +1669,8 @@ subst_stack_regs_pat (insn, regstack, pat)
              {
              case UNSPEC_SIN:
              case UNSPEC_COS:
+             case UNSPEC_FRNDINT:
+             case UNSPEC_F2XM1:
                /* These insns only operate on the top of the stack.  */
 
                src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
@@ -1728,6 +1692,75 @@ subst_stack_regs_pat (insn, regstack, pat)
                replace_reg (src1, FIRST_STACK_REG);
                break;
 
+             case UNSPEC_FPATAN:
+             case UNSPEC_FYL2X:
+             case UNSPEC_FSCALE:
+               /* These insns operate on the top two stack slots.  */
+
+               src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+               src2 = get_true_reg (&XVECEXP (pat_src, 0, 1));
+
+               src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+               src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+
+               {
+                 struct stack_def temp_stack;
+                 int regno, j, k, temp;
+
+                 temp_stack = *regstack;
+
+                 /* Place operand 1 at the top of stack.  */
+                 regno = get_hard_regnum (&temp_stack, *src1);
+                 if (regno < 0)
+                   abort ();
+                 if (regno != FIRST_STACK_REG)
+                   {
+                     k = temp_stack.top - (regno - FIRST_STACK_REG);
+                     j = temp_stack.top;
+
+                     temp = temp_stack.reg[k];
+                     temp_stack.reg[k] = temp_stack.reg[j];
+                     temp_stack.reg[j] = temp;
+                   }
+
+                 /* Place operand 2 next on the stack.  */
+                 regno = get_hard_regnum (&temp_stack, *src2);
+                 if (regno < 0)
+                   abort ();
+                 if (regno != FIRST_STACK_REG + 1)
+                   {
+                     k = temp_stack.top - (regno - FIRST_STACK_REG);
+                     j = temp_stack.top - 1;
+
+                     temp = temp_stack.reg[k];
+                     temp_stack.reg[k] = temp_stack.reg[j];
+                     temp_stack.reg[j] = temp;
+                   }
+
+                 change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
+               }
+
+               replace_reg (src1, FIRST_STACK_REG);
+               replace_reg (src2, FIRST_STACK_REG + 1);
+
+               if (src1_note)
+                 replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+               if (src2_note)
+                 replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
+
+               /* Pop both input operands from the stack.  */
+               CLEAR_HARD_REG_BIT (regstack->reg_set,
+                                   regstack->reg[regstack->top]);
+               CLEAR_HARD_REG_BIT (regstack->reg_set,
+                                   regstack->reg[regstack->top - 1]);
+               regstack->top -= 2;
+
+               /* Push the result back onto the stack.  */
+               regstack->reg[++regstack->top] = REGNO (*dest);
+               SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+               replace_reg (dest, FIRST_STACK_REG);
+               break;
+
              case UNSPEC_SAHF:
                /* (unspec [(unspec [(compare)] UNSPEC_FNSTSW)] UNSPEC_SAHF)
                   The combination matches the PPRO fcomi instruction.  */
@@ -1862,9 +1895,7 @@ subst_stack_regs_pat (insn, regstack, pat)
    requirements, since record_asm_stack_regs removes any problem asm.  */
 
 static void
-subst_asm_stack_regs (insn, regstack)
-     rtx insn;
-     stack regstack;
+subst_asm_stack_regs (rtx insn, stack regstack)
 {
   rtx body = PATTERN (insn);
   int alt;
@@ -1915,9 +1946,9 @@ subst_asm_stack_regs (insn, regstack)
   for (i = 0, note = REG_NOTES (insn); note; note = XEXP (note, 1))
     i++;
 
-  note_reg = (rtx *) alloca (i * sizeof (rtx));
-  note_loc = (rtx **) alloca (i * sizeof (rtx *));
-  note_kind = (enum reg_note *) alloca (i * sizeof (enum reg_note));
+  note_reg = alloca (i * sizeof (rtx));
+  note_loc = alloca (i * sizeof (rtx *));
+  note_kind = alloca (i * sizeof (enum reg_note));
 
   n_notes = 0;
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
@@ -1948,8 +1979,8 @@ subst_asm_stack_regs (insn, regstack)
 
   if (GET_CODE (body) == PARALLEL)
     {
-      clobber_reg = (rtx *) alloca (XVECLEN (body, 0) * sizeof (rtx));
-      clobber_loc = (rtx **) alloca (XVECLEN (body, 0) * sizeof (rtx *));
+      clobber_reg = alloca (XVECLEN (body, 0) * sizeof (rtx));
+      clobber_loc = alloca (XVECLEN (body, 0) * sizeof (rtx *));
 
       for (i = 0; i < XVECLEN (body, 0); i++)
        if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
@@ -2151,9 +2182,7 @@ subst_asm_stack_regs (insn, regstack)
    stack for the 387 based on the contents of the insn.  */
 
 static void
-subst_stack_regs (insn, regstack)
-     rtx insn;
-     stack regstack;
+subst_stack_regs (rtx insn, stack regstack)
 {
   rtx *note_link, note;
   int i;
@@ -2245,11 +2274,7 @@ subst_stack_regs (insn, regstack)
    is no longer needed once this has executed.  */
 
 static void
-change_stack (insn, old, new, where)
-     rtx insn;
-     stack old;
-     stack new;
-     enum emit_where where;
+change_stack (rtx insn, stack old, stack new, enum emit_where where)
 {
   int reg;
   int update_end = 0;
@@ -2348,9 +2373,7 @@ change_stack (insn, old, new, where)
 /* Print stack configuration.  */
 
 static void
-print_stack (file, s)
-     FILE *file;
-     stack s;
+print_stack (FILE *file, stack s)
 {
   if (! file)
     return;
@@ -2378,14 +2401,14 @@ print_stack (file, s)
    commit_edge_insertions needs to be called.  */
 
 static int
-convert_regs_entry ()
+convert_regs_entry (void)
 {
-  int inserted = 0, i;
+  int inserted = 0;
   edge e;
+  basic_block block;
 
-  for (i = n_basic_blocks - 1; i >= 0; --i)
+  FOR_EACH_BB_REVERSE (block)
     {
-      basic_block block = BASIC_BLOCK (i);
       block_info bi = BLOCK_INFO (block);
       int reg;
 
@@ -2408,7 +2431,7 @@ convert_regs_entry ()
      the push/pop code happy, and to not scrog the register stack, we
      must put something in these registers.  Use a QNaN.
 
-     Note that we are insertting converted code here.  This code is
+     Note that we are inserting converted code here.  This code is
      never seen by the convert_regs pass.  */
 
   for (e = ENTRY_BLOCK_PTR->succ; e ; e = e->succ_next)
@@ -2441,7 +2464,7 @@ convert_regs_entry ()
    be `empty', or the function return value at top-of-stack.  */
 
 static void
-convert_regs_exit ()
+convert_regs_exit (void)
 {
   int value_reg_low, value_reg_high;
   stack output_stack;
@@ -2466,7 +2489,7 @@ convert_regs_exit ()
       output_stack->top = value_reg_high - value_reg_low;
       for (reg = value_reg_low; reg <= value_reg_high; ++reg)
        {
-         output_stack->reg[reg - value_reg_low] = reg;
+         output_stack->reg[value_reg_high - reg] = reg;
          SET_HARD_REG_BIT (output_stack->reg_set, reg);
        }
     }
@@ -2476,9 +2499,7 @@ convert_regs_exit ()
    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;
+compensate_edge (edge e, FILE *file)
 {
   basic_block block = e->src, target = e->dest;
   block_info bi = BLOCK_INFO (block);
@@ -2557,7 +2578,11 @@ compensate_edge (e, file)
       abort ();
     eh1:
 
+      /* We are sure that there is st(0) live, otherwise we won't compensate.
+        For complex return values, we may have st(1) live as well.  */
       SET_HARD_REG_BIT (tmp, FIRST_STACK_REG);
+      if (TEST_HARD_REG_BIT (regstack.reg_set, FIRST_STACK_REG + 1))
+        SET_HARD_REG_BIT (tmp, FIRST_STACK_REG + 1);
       GO_IF_HARD_REG_EQUAL (regstack.reg_set, tmp, eh2);
       abort ();
     eh2:
@@ -2591,16 +2616,13 @@ compensate_edge (e, file)
       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);
+      /* ??? change_stack needs some point to emit insns after.  */
+      after = emit_note (NOTE_INSN_DELETED);
 
       tmpstack = regstack;
       change_stack (after, &tmpstack, target_stack, EMIT_BEFORE);
 
-      seq = gen_sequence ();
+      seq = get_insns ();
       end_sequence ();
 
       insert_insn_on_edge (seq, e);
@@ -2612,9 +2634,7 @@ compensate_edge (e, file)
 /* Convert stack register references in one block.  */
 
 static int
-convert_regs_1 (file, block)
-     FILE *file;
-     basic_block block;
+convert_regs_1 (FILE *file, basic_block block)
 {
   struct stack_def regstack;
   block_info bi = BLOCK_INFO (block);
@@ -2623,6 +2643,7 @@ convert_regs_1 (file, block)
   edge e, beste = NULL;
 
   inserted = 0;
+  any_malformed_asm = false;
 
   /* 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,
@@ -2736,9 +2757,12 @@ convert_regs_1 (file, block)
        }
     }
 
-  /* Something failed if the stack lives don't match.  */
+  /* Something failed if the stack lives don't match.  If we had malformed
+     asms, we zapped the instruction itself, but that didn't produce the
+     same pattern of register kills as before.  */
   GO_IF_HARD_REG_EQUAL (regstack.reg_set, bi->out_reg_set, win);
-  abort ();
+  if (!any_malformed_asm)
+    abort ();
  win:
   bi->stack_out = regstack;
 
@@ -2771,14 +2795,12 @@ convert_regs_1 (file, block)
 /* Convert registers in all blocks reachable from BLOCK.  */
 
 static int
-convert_regs_2 (file, block)
-     FILE *file;
-     basic_block block;
+convert_regs_2 (FILE *file, basic_block block)
 {
   basic_block *stack, *sp;
   int inserted;
 
-  stack = (basic_block *) xmalloc (sizeof (*stack) * n_basic_blocks);
+  stack = xmalloc (sizeof (*stack) * n_basic_blocks);
   sp = stack;
 
   *sp++ = block;
@@ -2810,10 +2832,10 @@ convert_regs_2 (file, block)
    to the stack-like registers the 387 uses.  */
 
 static int
-convert_regs (file)
-     FILE *file;
+convert_regs (FILE *file)
 {
-  int inserted, i;
+  int inserted;
+  basic_block b;
   edge e;
 
   /* Initialize uninitialized registers on function entry.  */
@@ -2833,9 +2855,8 @@ convert_regs (file)
 
   /* ??? Process all unreachable blocks.  Though there's no excuse
      for keeping these even when not optimizing.  */
-  for (i = 0; i < n_basic_blocks; ++i)
+  FOR_EACH_BB (b)
     {
-      basic_block b = BASIC_BLOCK (i);
       block_info bi = BLOCK_INFO (b);
 
       if (! bi->done)
@@ -2851,6 +2872,7 @@ convert_regs (file)
          inserted |= convert_regs_2 (file, b);
        }
     }
+  clear_aux_for_blocks ();
 
   fixup_abnormal_edges ();
   if (inserted)
@@ -2862,3 +2884,5 @@ convert_regs (file)
   return inserted;
 }
 #endif /* STACK_REGS */
+
+#include "gt-reg-stack.h"