OSDN Git Service

2009-04-08 Thomas Quinot <quinot@adacore.com>
[pf3gnuchains/gcc-fork.git] / gcc / reg-stack.c
index fc59118..c1fc820 100644 (file)
@@ -1,12 +1,13 @@
 /* Register to Stack convert for GNU compiler.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
-   2000, 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
+   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
+   Free Software Foundation, Inc.
 
    This file is part of GCC.
 
    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)
+   the Free Software Foundation; either version 3, or (at your option)
    any later version.
 
    GCC is distributed in the hope that it will be useful, but WITHOUT
@@ -15,9 +16,8 @@
    License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with GCC; see the file COPYING.  If not, write to the Free
-   Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.  */
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
 
 /* This pass converts stack-like registers from the "flat register
    file" model that gcc uses, to a stack convention that the 387 uses.
 #include "recog.h"
 #include "output.h"
 #include "basic-block.h"
+#include "cfglayout.h"
 #include "varray.h"
 #include "reload.h"
 #include "ggc.h"
 #include "timevar.h"
 #include "tree-pass.h"
 #include "target.h"
+#include "df.h"
+#include "vecprim.h"
+
+#ifdef STACK_REGS
 
 /* 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
+static VEC(char,heap) *stack_regs_mentioned_data;
 
 #define REG_STACK_SIZE (LAST_STACK_REG - FIRST_STACK_REG + 1)
 
+int regstack_completed = 0;
+
 /* This is the basic stack record.  TOP is an index into REG[] such
    that REG[TOP] is the top of stack.  If TOP is -1 the stack is empty.
 
@@ -244,7 +249,7 @@ static rtx not_a_num;
 
 /* Forward declarations */
 
-static int stack_regs_mentioned_p (rtx pat);
+static int stack_regs_mentioned_p (const_rtx pat);
 static void pop_stack (stack, int);
 static rtx *get_true_reg (rtx *);
 
@@ -271,7 +276,7 @@ static rtx next_flags_user (rtx);
 /* Return nonzero if any stack register is mentioned somewhere within PAT.  */
 
 static int
-stack_regs_mentioned_p (rtx pat)
+stack_regs_mentioned_p (const_rtx pat)
 {
   const char *fmt;
   int i;
@@ -300,7 +305,7 @@ stack_regs_mentioned_p (rtx pat)
 /* Return nonzero if INSN mentions stacked registers, else return zero.  */
 
 int
-stack_regs_mentioned (rtx insn)
+stack_regs_mentioned (const_rtx insn)
 {
   unsigned int uid, max;
   int test;
@@ -309,21 +314,21 @@ stack_regs_mentioned (rtx insn)
     return 0;
 
   uid = INSN_UID (insn);
-  max = VARRAY_SIZE (stack_regs_mentioned_data);
+  max = VEC_length (char, stack_regs_mentioned_data);
   if (uid >= max)
     {
       /* Allocate some extra size to avoid too many reallocs, but
         do not grow too quickly.  */
-      max = uid + uid / 20;
-      VARRAY_GROW (stack_regs_mentioned_data, max);
+      max = uid + uid / 20 + 1;
+      VEC_safe_grow_cleared (char, heap, stack_regs_mentioned_data, max);
     }
 
-  test = VARRAY_CHAR (stack_regs_mentioned_data, uid);
+  test = VEC_index (char, stack_regs_mentioned_data, uid);
   if (test == 0)
     {
       /* This insn has yet to be examined.  Do so now.  */
       test = stack_regs_mentioned_p (PATTERN (insn)) ? 1 : 2;
-      VARRAY_CHAR (stack_regs_mentioned_data, uid) = test;
+      VEC_replace (char, stack_regs_mentioned_data, uid, test);
     }
 
   return test == 1;
@@ -420,7 +425,6 @@ get_true_reg (rtx *pat)
                                                   GET_MODE (*pat));
              *pat = FP_MODE_REG (REGNO (subreg) + regno_off,
                                  GET_MODE (subreg));
-           default:
              return pat;
            }
        }
@@ -430,11 +434,19 @@ get_true_reg (rtx *pat)
        pat = & XEXP (*pat, 0);
        break;
 
+      case UNSPEC:
+       if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP)
+         pat = & XVECEXP (*pat, 0, 0);
+       return pat;
+
       case FLOAT_TRUNCATE:
        if (!flag_unsafe_math_optimizations)
          return pat;
        pat = & XEXP (*pat, 0);
        break;
+
+      default:
+       return pat;
       }
 }
 \f
@@ -491,7 +503,7 @@ check_asm_stack_operands (rtx insn)
 
   if (GET_CODE (body) == PARALLEL)
     {
-      clobber_reg = alloca (XVECLEN (body, 0) * sizeof (rtx));
+      clobber_reg = XALLOCAVEC (rtx, XVECLEN (body, 0));
 
       for (i = 0; i < XVECLEN (body, 0); i++)
        if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
@@ -686,8 +698,7 @@ stack_result (tree decl)
 static void
 replace_reg (rtx *reg, int regno)
 {
-  gcc_assert (regno >= FIRST_STACK_REG);
-  gcc_assert (regno <= LAST_STACK_REG);
+  gcc_assert (IN_RANGE (regno, FIRST_STACK_REG, LAST_STACK_REG));
   gcc_assert (STACK_REG_P (*reg));
 
   gcc_assert (SCALAR_FLOAT_MODE_P (GET_MODE (*reg))
@@ -702,18 +713,18 @@ replace_reg (rtx *reg, int regno)
 static void
 remove_regno_note (rtx insn, enum reg_note note, unsigned int regno)
 {
-  rtx *note_link, this;
+  rtx *note_link, this_rtx;
 
   note_link = &REG_NOTES (insn);
-  for (this = *note_link; this; this = XEXP (this, 1))
-    if (REG_NOTE_KIND (this) == note
-       && REG_P (XEXP (this, 0)) && REGNO (XEXP (this, 0)) == regno)
+  for (this_rtx = *note_link; this_rtx; this_rtx = XEXP (this_rtx, 1))
+    if (REG_NOTE_KIND (this_rtx) == note
+       && REG_P (XEXP (this_rtx, 0)) && REGNO (XEXP (this_rtx, 0)) == regno)
       {
-       *note_link = XEXP (this, 1);
+       *note_link = XEXP (this_rtx, 1);
        return;
       }
     else
-      note_link = &XEXP (this, 1);
+      note_link = &XEXP (this_rtx, 1);
 
   gcc_unreachable ();
 }
@@ -777,9 +788,7 @@ emit_pop_insn (rtx insn, stack regstack, rtx reg, enum emit_where where)
   else
     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),
-                        REG_NOTES (pop_insn));
+  add_reg_note (pop_insn, REG_DEAD, FP_MODE_REG (FIRST_STACK_REG, DFmode));
 
   regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
     = regstack->reg[regstack->top];
@@ -807,9 +816,19 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg)
 
   hard_regno = get_hard_regnum (regstack, reg);
 
-  gcc_assert (hard_regno >= FIRST_STACK_REG);
   if (hard_regno == FIRST_STACK_REG)
     return;
+  if (hard_regno == -1)
+    {
+      /* Something failed if the register wasn't on the stack.  If we had
+        malformed asms, we zapped the instruction itself, but that didn't
+        produce the same pattern of register sets as before.  To prevent
+        further failure, adjust REGSTACK to include REG at TOP.  */
+      gcc_assert (any_malformed_asm);
+      regstack->reg[++regstack->top] = REGNO (reg);
+      return;
+    }
+  gcc_assert (hard_regno >= FIRST_STACK_REG);
 
   other_reg = regstack->top - (hard_regno - FIRST_STACK_REG);
 
@@ -1043,14 +1062,15 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
 
          push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
          emit_insn_before (push_rtx, insn);
-         REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_DEAD, top_stack_reg,
-                                               REG_NOTES (insn));
+         add_reg_note (insn, REG_DEAD, top_stack_reg);
        }
 
       replace_reg (psrc, FIRST_STACK_REG);
     }
   else
     {
+      rtx pat = PATTERN (insn);
+
       gcc_assert (STACK_REG_P (dest));
 
       /* Load from MEM, or possibly integer REG or constant, into the
@@ -1058,8 +1078,18 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
         stack. The stack mapping is changed to reflect that DEST is
         now at top of stack.  */
 
-      /* The destination ought to be dead.  */
-      gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
+      /* The destination ought to be dead.  However, there is a
+        special case with i387 UNSPEC_TAN, where destination is live
+        (an argument to fptan) but inherent load of 1.0 is modelled
+        as a load from a constant.  */
+      if (GET_CODE (pat) == PARALLEL
+         && XVECLEN (pat, 0) == 2
+         && GET_CODE (XVECEXP (pat, 0, 1)) == SET
+         && GET_CODE (SET_SRC (XVECEXP (pat, 0, 1))) == UNSPEC
+         && XINT (SET_SRC (XVECEXP (pat, 0, 1)), 1) == UNSPEC_TAN)
+       emit_swap_insn (insn, regstack, dest);
+      else
+       gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
 
       gcc_assert (regstack->top < REG_STACK_SIZE);
 
@@ -1316,12 +1346,18 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
       if (STACK_REG_P (*src)
          && find_regno_note (insn, REG_DEAD, REGNO (*src)))
        {
-         emit_pop_insn (insn, regstack, *src, EMIT_AFTER);
+         /* USEs are ignored for liveness information so USEs of dead
+            register might happen.  */
+          if (TEST_HARD_REG_BIT (regstack->reg_set, REGNO (*src)))
+           emit_pop_insn (insn, regstack, *src, EMIT_AFTER);
          return control_flow_insn_deleted;
        }
-      /* ??? Uninitialized USE should not happen.  */
-      else
-       gcc_assert (get_hard_regnum (regstack, *src) != -1);
+      /* Uninitialized USE might happen for functions returning uninitialized
+         value.  We will properly initialize the USE on the edge to EXIT_BLOCK,
+        so it is safe to ignore the use here. This is consistent with behavior
+        of dataflow analyzer that ignores USE too.  (This also imply that 
+        forcibly initializing the register to NaN here would lead to ICE later,
+        since the REG_DEAD notes are not issued.)  */
       break;
 
     case CLOBBER:
@@ -1362,16 +1398,20 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                if (!note)
                  {
                    rtx t = *dest;
-                   if (get_hard_regnum (regstack, t) == -1)
-                     control_flow_insn_deleted
-                       |= move_nan_for_stack_reg (insn, regstack, t);
                    if (COMPLEX_MODE_P (GET_MODE (t)))
                      {
-                       t = FP_MODE_REG (REGNO (t) + 1, DFmode);
-                       if (get_hard_regnum (regstack, t) == -1)
-                         control_flow_insn_deleted
-                           |= move_nan_for_stack_reg (insn, regstack, t);
+                       rtx u = FP_MODE_REG (REGNO (t) + 1, SFmode);
+                       if (get_hard_regnum (regstack, u) == -1)
+                         {
+                           rtx pat2 = gen_rtx_CLOBBER (VOIDmode, u);
+                           rtx insn2 = emit_insn_before (pat2, insn);
+                           control_flow_insn_deleted
+                             |= move_nan_for_stack_reg (insn2, regstack, u);
+                         }
                      }
+                   if (get_hard_regnum (regstack, t) == -1)
+                     control_flow_insn_deleted
+                       |= move_nan_for_stack_reg (insn, regstack, t);
                  }
              }
          }
@@ -1487,15 +1527,30 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
            else
              {
                /* Both operands are REG.  If neither operand is already
-                  at the top of stack, choose to make the one that is the dest
-                  the new top of stack.  */
+                  at the top of stack, choose to make the one that is the
+                  dest the new top of stack.  */
 
                int src1_hard_regnum, src2_hard_regnum;
 
                src1_hard_regnum = get_hard_regnum (regstack, *src1);
                src2_hard_regnum = get_hard_regnum (regstack, *src2);
-               gcc_assert (src1_hard_regnum != -1);
-               gcc_assert (src2_hard_regnum != -1);
+
+               /* If the source is not live, this is yet another case of
+                  uninitialized variables.  Load up a NaN instead.  */
+               if (src1_hard_regnum == -1)
+                 {
+                   rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src1);
+                   rtx insn2 = emit_insn_before (pat2, insn);
+                   control_flow_insn_deleted
+                     |= move_nan_for_stack_reg (insn2, regstack, *src1);
+                 }
+               if (src2_hard_regnum == -1)
+                 {
+                   rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src2);
+                   rtx insn2 = emit_insn_before (pat2, insn);
+                   control_flow_insn_deleted
+                     |= move_nan_for_stack_reg (insn2, regstack, *src2);
+                 }
 
                if (src1_hard_regnum != FIRST_STACK_REG
                    && src2_hard_regnum != FIRST_STACK_REG)
@@ -1607,6 +1662,27 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                replace_reg (src1, FIRST_STACK_REG);
                break;
 
+             case UNSPEC_FXAM:
+
+               /* This insn only operate on the top of the stack.  */
+
+               src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+               emit_swap_insn (insn, regstack, *src1);
+
+               src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+               replace_reg (src1, FIRST_STACK_REG);
+
+               if (src1_note)
+                 {
+                   remove_regno_note (insn, REG_DEAD,
+                                      REGNO (XEXP (src1_note, 0)));
+                   emit_pop_insn (insn, regstack, XEXP (src1_note, 0),
+                                  EMIT_AFTER);
+                 }
+
+               break;
+
              case UNSPEC_SIN:
              case UNSPEC_COS:
              case UNSPEC_FRNDINT:
@@ -1617,14 +1693,19 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
              case UNSPEC_FRNDINT_TRUNC:
              case UNSPEC_FRNDINT_MASK_PM:
 
-               /* These insns only operate on the top of the stack.  */
+               /* Above insns operate on the top of the stack.  */
+
+             case UNSPEC_SINCOS_COS:
+             case UNSPEC_XTRACT_FRACT:
+
+               /* Above insns operate on the top two stack slots,
+                  first part of one input, double output insn.  */
 
                src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
 
                emit_swap_insn (insn, regstack, *src1);
 
-               /* Input should never die, it is
-                  replaced with output.  */
+               /* Input should never die, it is replaced with output.  */
                src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
                gcc_assert (!src1_note);
 
@@ -1634,6 +1715,36 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                replace_reg (src1, FIRST_STACK_REG);
                break;
 
+             case UNSPEC_SINCOS_SIN:
+             case UNSPEC_XTRACT_EXP:
+
+               /* These insns operate on the top two stack slots,
+                  second part of one input, double output insn.  */
+
+               regstack->top++;
+               /* FALLTHRU */
+
+             case UNSPEC_TAN:
+
+               /* For UNSPEC_TAN, regstack->top is already increased
+                  by inherent load of constant 1.0.  */
+
+               /* Output value is generated in the second stack slot.
+                  Move current value from second slot to the top.  */
+               regstack->reg[regstack->top]
+                 = regstack->reg[regstack->top - 1];
+
+               gcc_assert (STACK_REG_P (*dest));
+
+               regstack->reg[regstack->top - 1] = REGNO (*dest);
+               SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+               replace_reg (dest, FIRST_STACK_REG + 1);
+
+               src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+
+               replace_reg (src1, FIRST_STACK_REG);
+               break;
+
              case UNSPEC_FPATAN:
              case UNSPEC_FYL2X:
              case UNSPEC_FYL2XP1:
@@ -1671,7 +1782,7 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
              case UNSPEC_FSCALE_FRACT:
              case UNSPEC_FPREM_F:
              case UNSPEC_FPREM1_F:
-               /* These insns operate on the top two stack slots.
+               /* These insns operate on the top two stack slots,
                   first part of double input, double output insn.  */
 
                src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
@@ -1689,11 +1800,12 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
 
                /* Push the result back onto stack. Empty stack slot
                   will be filled in second part of insn.  */
-               if (STACK_REG_P (*dest)) {
-                 regstack->reg[regstack->top] = REGNO (*dest);
-                 SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
-                 replace_reg (dest, FIRST_STACK_REG);
-               }
+               if (STACK_REG_P (*dest))
+                 {
+                   regstack->reg[regstack->top] = REGNO (*dest);
+                   SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+                   replace_reg (dest, FIRST_STACK_REG);
+                 }
 
                replace_reg (src1, FIRST_STACK_REG);
                replace_reg (src2, FIRST_STACK_REG + 1);
@@ -1702,86 +1814,34 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
              case UNSPEC_FSCALE_EXP:
              case UNSPEC_FPREM_U:
              case UNSPEC_FPREM1_U:
-               /* These insns operate on the top two stack slots./
+               /* These insns operate on the top two stack slots,
                   second part of double input, double output insn.  */
 
                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));
-
-               /* Inputs should never die, they are
-                  replaced with outputs.  */
-               gcc_assert (!src1_note);
-               gcc_assert (!src2_note);
-
-               swap_to_top (insn, regstack, *src1, *src2);
-
                /* Push the result back onto stack. Fill empty slot from
                   first part of insn and fix top of stack pointer.  */
-               if (STACK_REG_P (*dest)) {
-                 regstack->reg[regstack->top - 1] = REGNO (*dest);
-                 SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
-                 replace_reg (dest, FIRST_STACK_REG + 1);
-               }
+               if (STACK_REG_P (*dest))
+                 {
+                   regstack->reg[regstack->top - 1] = REGNO (*dest);
+                   SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+                   replace_reg (dest, FIRST_STACK_REG + 1);
+                 }
 
                replace_reg (src1, FIRST_STACK_REG);
                replace_reg (src2, FIRST_STACK_REG + 1);
                break;
 
-             case UNSPEC_SINCOS_COS:
-             case UNSPEC_TAN_ONE:
-             case UNSPEC_XTRACT_FRACT:
-               /* These insns operate on the top two stack slots,
-                  first part of one input, double output insn.  */
-
-               src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
-
-               emit_swap_insn (insn, regstack, *src1);
-
-               /* Input should never die, it is
-                  replaced with output.  */
-               src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
-               gcc_assert (!src1_note);
-
-               /* Push the result back onto stack. Empty stack slot
-                  will be filled in second part of insn.  */
-               if (STACK_REG_P (*dest)) {
-                 regstack->reg[regstack->top + 1] = REGNO (*dest);
-                 SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
-                 replace_reg (dest, FIRST_STACK_REG);
-               }
-
-               replace_reg (src1, FIRST_STACK_REG);
-               break;
-
-             case UNSPEC_SINCOS_SIN:
-             case UNSPEC_TAN_TAN:
-             case UNSPEC_XTRACT_EXP:
-               /* These insns operate on the top two stack slots,
-                  second part of one input, double output insn.  */
+             case UNSPEC_C2_FLAG:
+               /* This insn operates on the top two stack slots,
+                  third part of C2 setting double input insn.  */
 
                src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
-
-               emit_swap_insn (insn, regstack, *src1);
-
-               /* Input should never die, it is
-                  replaced with output.  */
-               src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
-               gcc_assert (!src1_note);
-
-               /* Push the result back onto stack. Fill empty slot from
-                  first part of insn and fix top of stack pointer.  */
-               if (STACK_REG_P (*dest)) {
-                 regstack->reg[regstack->top] = REGNO (*dest);
-                 SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
-                 replace_reg (dest, FIRST_STACK_REG + 1);
-
-                 regstack->top++;
-               }
+               src2 = get_true_reg (&XVECEXP (pat_src, 0, 1));
 
                replace_reg (src1, FIRST_STACK_REG);
+               replace_reg (src2, FIRST_STACK_REG + 1);
                break;
 
              case UNSPEC_SAHF:
@@ -1964,9 +2024,9 @@ subst_asm_stack_regs (rtx insn, stack regstack)
   for (i = 0, note = REG_NOTES (insn); note; note = XEXP (note, 1))
     i++;
 
-  note_reg = alloca (i * sizeof (rtx));
-  note_loc = alloca (i * sizeof (rtx *));
-  note_kind = alloca (i * sizeof (enum reg_note));
+  note_reg = XALLOCAVEC (rtx, i);
+  note_loc = XALLOCAVEC (rtx *, i);
+  note_kind = XALLOCAVEC (enum reg_note, i);
 
   n_notes = 0;
   for (note = REG_NOTES (insn); note; note = XEXP (note, 1))
@@ -1997,8 +2057,8 @@ subst_asm_stack_regs (rtx insn, stack regstack)
 
   if (GET_CODE (body) == PARALLEL)
     {
-      clobber_reg = alloca (XVECLEN (body, 0) * sizeof (rtx));
-      clobber_loc = alloca (XVECLEN (body, 0) * sizeof (rtx *));
+      clobber_reg = XALLOCAVEC (rtx, XVECLEN (body, 0));
+      clobber_loc = XALLOCAVEC (rtx *, XVECLEN (body, 0));
 
       for (i = 0; i < XVECLEN (body, 0); i++)
        if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
@@ -2269,6 +2329,16 @@ subst_stack_regs (rtx insn, stack regstack)
   if (NOTE_P (insn) || INSN_DELETED_P (insn))
     return control_flow_insn_deleted;
 
+  /* If this a noreturn call, we can't insert pop insns after it.
+     Instead, reset the stack state to empty.  */
+  if (CALL_P (insn)
+      && find_reg_note (insn, REG_NORETURN, NULL))
+    {
+      regstack->top = -1;
+      CLEAR_HARD_REG_SET (regstack->reg_set);
+      return control_flow_insn_deleted;
+    }
+
   /* If there is a REG_UNUSED note on a stack register on this insn,
      the indicated reg must be popped.  The REG_UNUSED note is removed,
      since the form of the newly emitted pop insn references the reg,
@@ -2300,10 +2370,11 @@ subst_stack_regs (rtx insn, stack regstack)
    is no longer needed once this has executed.  */
 
 static void
-change_stack (rtx insn, stack old, stack new, enum emit_where where)
+change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
 {
   int reg;
   int update_end = 0;
+  int i;
 
   /* Stack adjustments for the first insn in a block update the
      current_block's stack_in instead of inserting insns directly.
@@ -2312,9 +2383,9 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
       && starting_stack_p
       && where == EMIT_BEFORE)
     {
-      BLOCK_INFO (current_block)->stack_in = *new;
+      BLOCK_INFO (current_block)->stack_in = *new_stack;
       starting_stack_p = false;
-      *old = *new;
+      *old = *new_stack;
       return;
     }
 
@@ -2328,33 +2399,44 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
       insn = NEXT_INSN (insn);
     }
 
+  /* Initialize partially dead variables.  */
+  for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++)
+    if (TEST_HARD_REG_BIT (new_stack->reg_set, i)
+       && !TEST_HARD_REG_BIT (old->reg_set, i))
+      {
+       old->reg[++old->top] = i;
+        SET_HARD_REG_BIT (old->reg_set, i);
+       emit_insn_before (gen_rtx_SET (VOIDmode,
+                                      FP_MODE_REG (i, SFmode), not_a_num), insn);
+      }
+
   /* Pop any registers that are not needed in the new block.  */
 
   /* If the destination block's stack already has a specified layout
      and contains two or more registers, use a more intelligent algorithm
      to pop registers that minimizes the number number of fxchs below.  */
-  if (new->top > 0)
+  if (new_stack->top > 0)
     {
       bool slots[REG_STACK_SIZE];
       int pops[REG_STACK_SIZE];
       int next, dest, topsrc;
 
       /* First pass to determine the free slots.  */
-      for (reg = 0; reg <= new->top; reg++)
-       slots[reg] = TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]);
+      for (reg = 0; reg <= new_stack->top; reg++)
+       slots[reg] = TEST_HARD_REG_BIT (new_stack->reg_set, old->reg[reg]);
 
       /* Second pass to allocate preferred slots.  */
       topsrc = -1;
-      for (reg = old->top; reg > new->top; reg--)
-       if (TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
+      for (reg = old->top; reg > new_stack->top; reg--)
+       if (TEST_HARD_REG_BIT (new_stack->reg_set, old->reg[reg]))
          {
            dest = -1;
-           for (next = 0; next <= new->top; next++)
-             if (!slots[next] && new->reg[next] == old->reg[reg])
+           for (next = 0; next <= new_stack->top; next++)
+             if (!slots[next] && new_stack->reg[next] == old->reg[reg])
                {
                  /* If this is a preference for the new top of stack, record
                     the fact by remembering it's old->reg in topsrc.  */
-                  if (next == new->top)
+                  if (next == new_stack->top)
                    topsrc = reg;
                  slots[next] = true;
                  dest = next;
@@ -2371,18 +2453,18 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
         slot is still unallocated, in which case we should place the
         top of stack there.  */
       if (topsrc != -1)
-       for (reg = 0; reg < new->top; reg++)
+       for (reg = 0; reg < new_stack->top; reg++)
          if (!slots[reg])
            {
              pops[topsrc] = reg;
-             slots[new->top] = false;
+             slots[new_stack->top] = false;
              slots[reg] = true;
              break;
            }
 
       /* Third pass allocates remaining slots and emits pop insns.  */
-      next = new->top;
-      for (reg = old->top; reg > new->top; reg--)
+      next = new_stack->top;
+      for (reg = old->top; reg > new_stack->top; reg--)
        {
          dest = pops[reg];
          if (dest == -1)
@@ -2405,14 +2487,14 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
 
       live = 0;
       for (reg = 0; reg <= old->top; reg++)
-        if (TEST_HARD_REG_BIT (new->reg_set, old->reg[reg]))
+        if (TEST_HARD_REG_BIT (new_stack->reg_set, old->reg[reg]))
           live++;
 
       next = live;
       while (old->top >= live)
-        if (TEST_HARD_REG_BIT (new->reg_set, old->reg[old->top]))
+        if (TEST_HARD_REG_BIT (new_stack->reg_set, old->reg[old->top]))
          {
-           while (TEST_HARD_REG_BIT (new->reg_set, old->reg[next]))
+           while (TEST_HARD_REG_BIT (new_stack->reg_set, old->reg[next]))
              next--;
            emit_pop_insn (insn, old, FP_MODE_REG (old->reg[next], DFmode),
                           EMIT_BEFORE);
@@ -2422,13 +2504,13 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
                         EMIT_BEFORE);
     }
 
-  if (new->top == -2)
+  if (new_stack->top == -2)
     {
       /* If the new block has never been processed, then it can inherit
         the old stack order.  */
 
-      new->top = old->top;
-      memcpy (new->reg, old->reg, sizeof (new->reg));
+      new_stack->top = old->top;
+      memcpy (new_stack->reg, old->reg, sizeof (new_stack->reg));
     }
   else
     {
@@ -2438,12 +2520,10 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
       /* By now, the only difference should be the order of the stack,
         not their depth or liveliness.  */
 
-      GO_IF_HARD_REG_EQUAL (old->reg_set, new->reg_set, win);
-      gcc_unreachable ();
-    win:
-      gcc_assert (old->top == new->top);
+      gcc_assert (hard_reg_set_equal_p (old->reg_set, new_stack->reg_set));
+      gcc_assert (old->top == new_stack->top);
 
-      /* If the stack is not empty (new->top != -1), loop here emitting
+      /* If the stack is not empty (new_stack->top != -1), loop here emitting
         swaps until the stack is correct.
 
         The worst case number of swaps emitted is N + 2, where N is the
@@ -2452,16 +2532,16 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
         other regs.  But since we never swap any other reg away from
         its correct slot, this algorithm will converge.  */
 
-      if (new->top != -1)
+      if (new_stack->top != -1)
        do
          {
            /* Swap the reg at top of stack into the position it is
               supposed to be in, until the correct top of stack appears.  */
 
-           while (old->reg[old->top] != new->reg[new->top])
+           while (old->reg[old->top] != new_stack->reg[new_stack->top])
              {
-               for (reg = new->top; reg >= 0; reg--)
-                 if (new->reg[reg] == old->reg[old->top])
+               for (reg = new_stack->top; reg >= 0; reg--)
+                 if (new_stack->reg[reg] == old->reg[old->top])
                    break;
 
                gcc_assert (reg != -1);
@@ -2474,8 +2554,8 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
             incorrect reg to the top of stack, and let the while loop
             above fix it.  */
 
-           for (reg = new->top; reg >= 0; reg--)
-             if (new->reg[reg] != old->reg[reg])
+           for (reg = new_stack->top; reg >= 0; reg--)
+             if (new_stack->reg[reg] != old->reg[reg])
                {
                  emit_swap_insn (insn, old,
                                  FP_MODE_REG (old->reg[reg], DFmode));
@@ -2486,7 +2566,7 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
       /* At this point there must be no differences.  */
 
       for (reg = old->top; reg >= 0; reg--)
-       gcc_assert (old->reg[reg] == new->reg[reg]);
+       gcc_assert (old->reg[reg] == new_stack->reg[reg]);
     }
 
   if (update_end)
@@ -2580,8 +2660,7 @@ convert_regs_exit (void)
   if (retvalue)
     {
       value_reg_low = REGNO (retvalue);
-      value_reg_high = value_reg_low
-       + hard_regno_nregs[value_reg_low][GET_MODE (retvalue)] - 1;
+      value_reg_high = END_HARD_REGNO (retvalue) - 1;
     }
 
   output_stack = &BLOCK_INFO (EXIT_BLOCK_PTR)->stack_in;
@@ -2616,6 +2695,12 @@ propagate_stack (edge e)
   for (reg = 0; reg <= src_stack->top; ++reg)
     if (TEST_HARD_REG_BIT (dest_stack->reg_set, src_stack->reg[reg]))
       dest_stack->reg[++dest_stack->top] = src_stack->reg[reg];
+
+  /* Push in any partially dead values.  */
+  for (reg = FIRST_STACK_REG; reg < LAST_STACK_REG + 1; reg++)
+    if (TEST_HARD_REG_BIT (dest_stack->reg_set, reg)
+        && !TEST_HARD_REG_BIT (src_stack->reg_set, reg))
+      dest_stack->reg[++dest_stack->top] = reg;
 }
 
 
@@ -2624,7 +2709,7 @@ propagate_stack (edge e)
    should have been defined by now.  */
 
 static bool
-compensate_edge (edge e, FILE *file)
+compensate_edge (edge e)
 {
   basic_block source = e->src, target = e->dest;
   stack target_stack = &BLOCK_INFO (target)->stack_in;
@@ -2632,8 +2717,8 @@ compensate_edge (edge e, FILE *file)
   struct stack_def regstack;
   int reg;
 
-  if (file)
-    fprintf (file, "Edge %d->%d: ", source->index, target->index);
+  if (dump_file)
+    fprintf (dump_file, "Edge %d->%d: ", source->index, target->index);
 
   gcc_assert (target_stack->top != -2);
 
@@ -2646,16 +2731,16 @@ compensate_edge (edge e, FILE *file)
 
       if (reg == -1)
        {
-         if (file)
-           fprintf (file, "no changes needed\n");
+         if (dump_file)
+           fprintf (dump_file, "no changes needed\n");
          return false;
        }
     }
 
-  if (file)
+  if (dump_file)
     {
-      fprintf (file, "correcting stack to ");
-      print_stack (file, target_stack);
+      fprintf (dump_file, "correcting stack to ");
+      print_stack (dump_file, target_stack);
     }
 
   /* Abnormal calls may appear to have values live in st(0), but the
@@ -2724,7 +2809,7 @@ compensate_edge (edge e, FILE *file)
    source block to the stack_in of the destination block.  */
 
 static bool
-compensate_edges (FILE *file)
+compensate_edges (void)
 {
   bool inserted = false;
   basic_block bb;
@@ -2738,7 +2823,7 @@ compensate_edges (FILE *file)
         edge_iterator ei;
 
         FOR_EACH_EDGE (e, ei, bb->succs)
-         inserted |= compensate_edge (e, file);
+         inserted |= compensate_edge (e);
       }
   return inserted;
 }
@@ -2777,7 +2862,7 @@ better_edge (edge e1, edge e2)
 /* Convert stack register references in one block.  */
 
 static void
-convert_regs_1 (FILE *file, basic_block block)
+convert_regs_1 (basic_block block)
 {
   struct stack_def regstack;
   block_info bi = BLOCK_INFO (block);
@@ -2811,10 +2896,10 @@ convert_regs_1 (FILE *file, basic_block block)
        }
     }
 
-  if (file)
+  if (dump_file)
     {
-      fprintf (file, "\nBasic block %d\nInput stack: ", block->index);
-      print_stack (file, &bi->stack_in);
+      fprintf (dump_file, "\nBasic block %d\nInput stack: ", block->index);
+      print_stack (dump_file, &bi->stack_in);
     }
 
   /* Process all insns in this block.  Keep track of NEXT so that we
@@ -2839,11 +2924,11 @@ convert_regs_1 (FILE *file, basic_block block)
       if (stack_regs_mentioned (insn)
          || CALL_P (insn))
        {
-         if (file)
+         if (dump_file)
            {
-             fprintf (file, "  insn %d input stack: ",
+             fprintf (dump_file, "  insn %d input stack: ",
                       INSN_UID (insn));
-             print_stack (file, &regstack);
+             print_stack (dump_file, &regstack);
            }
          control_flow_insn_deleted |= subst_stack_regs (insn, &regstack);
          starting_stack_p = false;
@@ -2851,14 +2936,14 @@ convert_regs_1 (FILE *file, basic_block block)
     }
   while (next);
 
-  if (file)
+  if (dump_file)
     {
-      fprintf (file, "Expected live registers [");
+      fprintf (dump_file, "Expected live registers [");
       for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
        if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
-         fprintf (file, " %d", reg);
-      fprintf (file, " ]\nOutput stack: ");
-      print_stack (file, &regstack);
+         fprintf (dump_file, " %d", reg);
+      fprintf (dump_file, " ]\nOutput stack: ");
+      print_stack (dump_file, &regstack);
     }
 
   insn = BB_END (block);
@@ -2876,8 +2961,8 @@ convert_regs_1 (FILE *file, basic_block block)
        {
          rtx set;
 
-         if (file)
-           fprintf (file, "Emitting insn initializing reg %d\n", reg);
+         if (dump_file)
+           fprintf (dump_file, "Emitting insn initializing reg %d\n", reg);
 
          set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode), not_a_num);
          insn = emit_insn_after (set, insn);
@@ -2908,9 +2993,9 @@ convert_regs_1 (FILE *file, basic_block block)
   /* 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);
-  gcc_assert (any_malformed_asm);
- win:
+     
+  gcc_assert (hard_reg_set_equal_p (regstack.reg_set, bi->out_reg_set)
+             || any_malformed_asm);
   bi->stack_out = regstack;
   bi->done = true;
 }
@@ -2918,7 +3003,7 @@ convert_regs_1 (FILE *file, basic_block block)
 /* Convert registers in all blocks reachable from BLOCK.  */
 
 static void
-convert_regs_2 (FILE *file, basic_block block)
+convert_regs_2 (basic_block block)
 {
   basic_block *stack, *sp;
 
@@ -2926,7 +3011,7 @@ convert_regs_2 (FILE *file, basic_block block)
      is only processed after all its predecessors.  The number of predecessors
      of every block has already been computed.  */ 
 
-  stack = xmalloc (sizeof (*stack) * n_basic_blocks);
+  stack = XNEWVEC (basic_block, n_basic_blocks);
   sp = stack;
 
   *sp++ = block;
@@ -2959,7 +3044,7 @@ convert_regs_2 (FILE *file, basic_block block)
              *sp++ = e->dest;
          }
 
-      convert_regs_1 (file, block);
+      convert_regs_1 (block);
     }
   while (sp != stack);
 
@@ -2971,7 +3056,7 @@ convert_regs_2 (FILE *file, basic_block block)
    to the stack-like registers the 387 uses.  */
 
 static void
-convert_regs (FILE *file)
+convert_regs (void)
 {
   int inserted;
   basic_block b;
@@ -2991,7 +3076,7 @@ convert_regs (FILE *file)
 
   /* Process all blocks reachable from all entry points.  */
   FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
-    convert_regs_2 (file, e->dest);
+    convert_regs_2 (e->dest);
 
   /* ??? Process all unreachable blocks.  Though there's no excuse
      for keeping these even when not optimizing.  */
@@ -3000,10 +3085,10 @@ convert_regs (FILE *file)
       block_info bi = BLOCK_INFO (b);
 
       if (! bi->done)
-       convert_regs_2 (file, b);
+       convert_regs_2 (b);
     }
 
-  inserted |= compensate_edges (file);
+  inserted |= compensate_edges ();
 
   clear_aux_for_blocks ();
 
@@ -3011,8 +3096,8 @@ convert_regs (FILE *file)
   if (inserted)
     commit_edge_insertions ();
 
-  if (file)
-    fputc ('\n', file);
+  if (dump_file)
+    fputc ('\n', dump_file);
 }
 \f
 /* Convert register usage from "flat" register file usage to a "stack
@@ -3024,34 +3109,27 @@ convert_regs (FILE *file)
    the edges.  */
 
 static bool
-reg_to_stack (FILE *file)
+reg_to_stack (void)
 {
   basic_block bb;
   int i;
   int max_uid;
 
   /* Clean up previous run.  */
-  stack_regs_mentioned_data = 0;
+  if (stack_regs_mentioned_data != NULL)
+    VEC_free (char, heap, stack_regs_mentioned_data);
 
   /* 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++)
-    if (regs_ever_live[i])
+    if (df_regs_ever_live_p (i))
       break;
   if (i > LAST_STACK_REG)
     return false;
 
-  /* Ok, floating point instructions exist.  If not optimizing,
-     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_sched2_use_traces)
-         && flag_schedule_insns_after_reload))
-    {
-      count_or_remove_death_notes (NULL, 1);
-      life_analysis (file, PROP_DEATH_NOTES);
-    }
+  df_note_add_problem ();
+  df_analyze ();
+
   mark_dfs_back_edges ();
 
   /* Set up block info for each basic block.  */
@@ -3074,9 +3152,9 @@ reg_to_stack (FILE *file)
       /* Copy live_at_end and live_at_start into temporaries.  */
       for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; reg++)
        {
-         if (REGNO_REG_SET_P (bb->il.rtl->global_live_at_end, reg))
+         if (REGNO_REG_SET_P (DF_LR_OUT (bb), reg))
            SET_HARD_REG_BIT (bi->out_reg_set, reg);
-         if (REGNO_REG_SET_P (bb->il.rtl->global_live_at_start, reg))
+         if (REGNO_REG_SET_P (DF_LR_IN (bb), reg))
            SET_HARD_REG_BIT (bi->stack_in.reg_set, reg);
        }
     }
@@ -3102,22 +3180,27 @@ reg_to_stack (FILE *file)
      ??? We can't load from constant memory in PIC mode, because
      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'.  */
+     on zero, which we can get from `fldz'.  */
 
-  if (flag_pic)
+  if ((flag_pic && !TARGET_64BIT)
+      || ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
     not_a_num = CONST0_RTX (SFmode);
   else
     {
-      not_a_num = gen_lowpart (SFmode, GEN_INT (0x7fc00000));
+      REAL_VALUE_TYPE r;
+
+      real_nan (&r, "", 1, SFmode);
+      not_a_num = CONST_DOUBLE_FROM_REAL_VALUE (r, SFmode);
       not_a_num = force_const_mem (SFmode, not_a_num);
     }
 
   /* Allocate a cache for stack_regs_mentioned.  */
   max_uid = get_max_uid ();
-  VARRAY_CHAR_INIT (stack_regs_mentioned_data, max_uid + 1,
-                   "stack_regs_mentioned cache");
+  stack_regs_mentioned_data = VEC_alloc (char, heap, max_uid + 1);
+  memset (VEC_address (char, stack_regs_mentioned_data),
+         0, sizeof (char) * (max_uid + 1));
 
-  convert_regs (file);
+  convert_regs ();
 
   free_aux_for_blocks ();
   return true;
@@ -3134,29 +3217,43 @@ gate_handle_stack_regs (void)
 #endif
 }
 
+struct rtl_opt_pass pass_stack_regs =
+{
+ {
+  RTL_PASS,
+  NULL,                                 /* name */
+  gate_handle_stack_regs,               /* gate */
+  NULL,                                        /* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_REG_STACK,                         /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0                                     /* todo_flags_finish */
+ }
+};
+
 /* Convert register usage from flat register file usage to a stack
    register file.  */
-static void
+static unsigned int
 rest_of_handle_stack_regs (void)
 {
 #ifdef STACK_REGS
-  if (reg_to_stack (dump_file) && optimize)
-    {
-      if (cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK
-                       | (flag_crossjumping ? CLEANUP_CROSSJUMP : 0))
-          && (flag_reorder_blocks || flag_reorder_blocks_and_partition))
-        {
-          reorder_basic_blocks (0);
-          cleanup_cfg (CLEANUP_EXPENSIVE | CLEANUP_POST_REGSTACK);
-        }
-    }
+  reg_to_stack ();
+  regstack_completed = 1;
 #endif
+  return 0;
 }
 
-struct tree_opt_pass pass_stack_regs =
+struct rtl_opt_pass pass_stack_regs_run =
 {
+ {
+  RTL_PASS,
   "stack",                              /* name */
-  gate_handle_stack_regs,               /* gate */
+  NULL,                                 /* gate */
   rest_of_handle_stack_regs,            /* execute */
   NULL,                                 /* sub */
   NULL,                                 /* next */
@@ -3166,9 +3263,8 @@ struct tree_opt_pass pass_stack_regs =
   0,                                    /* properties_provided */
   0,                                    /* properties_destroyed */
   0,                                    /* todo_flags_start */
+  TODO_df_finish | TODO_verify_rtl_sharing |
   TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'k'                                   /* letter */
+  TODO_ggc_collect                      /* todo_flags_finish */
+ }
 };
-
-#include "gt-reg-stack.h"