Backport from GCC mainline.
[platform/upstream/linaro-gcc.git] / gcc / reg-stack.c
index f21d833..89a7a11 100644 (file)
@@ -1,12 +1,11 @@
 /* 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-2016 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 +14,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 "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
-#include "tree.h"
+#include "backend.h"
+#include "target.h"
 #include "rtl.h"
-#include "tm_p.h"
-#include "function.h"
+#include "tree.h"
+#include "df.h"
 #include "insn-config.h"
-#include "regs.h"
-#include "hard-reg-set.h"
-#include "flags.h"
-#include "toplev.h"
+#include "emit-rtl.h"  /* FIXME: Can go away once crtl is moved to rtl.h.  */
 #include "recog.h"
-#include "output.h"
-#include "basic-block.h"
-#include "varray.h"
+#include "varasm.h"
+#include "rtl-error.h"
+#include "cfgrtl.h"
+#include "cfganal.h"
+#include "cfgbuild.h"
+#include "cfgcleanup.h"
 #include "reload.h"
-#include "ggc.h"
-#include "timevar.h"
 #include "tree-pass.h"
-#include "target.h"
-#include "vecprim.h"
+#include "rtl-iter.h"
 
 #ifdef STACK_REGS
 
    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 VEC(char,heap) *stack_regs_mentioned_data;
+static vec<char> stack_regs_mentioned_data;
 
 #define REG_STACK_SIZE (LAST_STACK_REG - FIRST_STACK_REG + 1)
 
@@ -203,7 +198,7 @@ typedef struct stack_def
   int top;                     /* index to top stack element */
   HARD_REG_SET reg_set;                /* set of live registers */
   unsigned char reg[REG_STACK_SIZE];/* register - stack mapping */
-} *stack;
+} *stack_ptr;
 
 /* This is used to carry information about basic blocks.  It is
    attached to the AUX field of the standard CFG block.  */
@@ -247,34 +242,34 @@ static rtx not_a_num;
 
 /* Forward declarations */
 
-static int stack_regs_mentioned_p (rtx pat);
-static void pop_stack (stack, int);
+static int stack_regs_mentioned_p (const_rtx pat);
+static void pop_stack (stack_ptr, int);
 static rtx *get_true_reg (rtx *);
 
-static int check_asm_stack_operands (rtx);
-static int get_asm_operand_n_inputs (rtx);
+static int check_asm_stack_operands (rtx_insn *);
+static void get_asm_operands_in_out (rtx, int *, int *);
 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 swap_to_top(rtx, stack, rtx, rtx);
-static bool move_for_stack_reg (rtx, stack, rtx);
-static bool move_nan_for_stack_reg (rtx, stack, rtx);
+static void remove_regno_note (rtx_insn *, enum reg_note, unsigned int);
+static int get_hard_regnum (stack_ptr, rtx);
+static rtx_insn *emit_pop_insn (rtx_insn *, stack_ptr, rtx, enum emit_where);
+static void swap_to_top (rtx_insn *, stack_ptr, rtx, rtx);
+static bool move_for_stack_reg (rtx_insn *, stack_ptr, rtx);
+static bool move_nan_for_stack_reg (rtx_insn *, stack_ptr, rtx);
 static int swap_rtx_condition_1 (rtx);
-static int swap_rtx_condition (rtx);
-static void compare_for_stack_reg (rtx, stack, rtx);
-static bool subst_stack_regs_pat (rtx, stack, rtx);
-static void subst_asm_stack_regs (rtx, stack);
-static bool subst_stack_regs (rtx, stack);
-static void change_stack (rtx, stack, stack, enum emit_where);
-static void print_stack (FILE *, stack);
-static rtx next_flags_user (rtx);
+static int swap_rtx_condition (rtx_insn *);
+static void compare_for_stack_reg (rtx_insn *, stack_ptr, rtx);
+static bool subst_stack_regs_pat (rtx_insn *, stack_ptr, rtx);
+static void subst_asm_stack_regs (rtx_insn *, stack_ptr);
+static bool subst_stack_regs (rtx_insn *, stack_ptr);
+static void change_stack (rtx_insn *, stack_ptr, stack_ptr, enum emit_where);
+static void print_stack (FILE *, stack_ptr);
+static rtx_insn *next_flags_user (rtx_insn *);
 \f
 /* 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;
@@ -303,30 +298,30 @@ 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;
 
-  if (! INSN_P (insn) || !stack_regs_mentioned_data)
+  if (! INSN_P (insn) || !stack_regs_mentioned_data.exists ())
     return 0;
 
   uid = INSN_UID (insn);
-  max = VEC_length (char, stack_regs_mentioned_data);
+  max = stack_regs_mentioned_data.length ();
   if (uid >= max)
     {
       /* Allocate some extra size to avoid too many reallocs, but
         do not grow too quickly.  */
       max = uid + uid / 20 + 1;
-      VEC_safe_grow_cleared (char, heap, stack_regs_mentioned_data, max);
+      stack_regs_mentioned_data.safe_grow_cleared (max);
     }
 
-  test = VEC_index (char, stack_regs_mentioned_data, uid);
+  test = 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;
-      VEC_replace (char, stack_regs_mentioned_data, uid, test);
+      stack_regs_mentioned_data[uid] = test;
     }
 
   return test == 1;
@@ -334,8 +329,8 @@ stack_regs_mentioned (rtx insn)
 \f
 static rtx ix86_flags_rtx;
 
-static rtx
-next_flags_user (rtx insn)
+static rtx_insn *
+next_flags_user (rtx_insn *insn)
 {
   /* Search forward looking for the first use of this value.
      Stop at block boundaries.  */
@@ -348,15 +343,15 @@ next_flags_user (rtx insn)
        return insn;
 
       if (CALL_P (insn))
-       return NULL_RTX;
+       return NULL;
     }
-  return NULL_RTX;
+  return NULL;
 }
 \f
 /* Reorganize the stack into ascending numbers, before this insn.  */
 
 static void
-straighten_stack (rtx insn, stack regstack)
+straighten_stack (rtx_insn *insn, stack_ptr regstack)
 {
   struct stack_def temp_stack;
   int top;
@@ -379,7 +374,7 @@ straighten_stack (rtx insn, stack regstack)
 /* Pop a register from the stack.  */
 
 static void
-pop_stack (stack regstack, int regno)
+pop_stack (stack_ptr regstack, int regno)
 {
   int top = regstack->top;
 
@@ -415,7 +410,7 @@ get_true_reg (rtx *pat)
           actual FP register in use.  */
        {
          rtx subreg;
-         if (FP_REG_P (subreg = SUBREG_REG (*pat)))
+         if (STACK_REG_P (subreg = SUBREG_REG (*pat)))
            {
              int regno_off = subreg_regno_offset (REGNO (subreg),
                                                   GET_MODE (subreg),
@@ -423,7 +418,6 @@ get_true_reg (rtx *pat)
                                                   GET_MODE (*pat));
              *pat = FP_MODE_REG (REGNO (subreg) + regno_off,
                                  GET_MODE (subreg));
-           default:
              return pat;
            }
        }
@@ -434,7 +428,8 @@ get_true_reg (rtx *pat)
        break;
 
       case UNSPEC:
-       if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP)
+       if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP
+           || XINT (*pat, 1) == UNSPEC_FILD_ATOMIC)
          pat = & XVECEXP (*pat, 0, 0);
        return pat;
 
@@ -443,6 +438,9 @@ get_true_reg (rtx *pat)
          return pat;
        pat = & XEXP (*pat, 0);
        break;
+
+      default:
+       return pat;
       }
 }
 \f
@@ -454,7 +452,7 @@ static bool any_malformed_asm;
    numbers below refer to that explanation.  */
 
 static int
-check_asm_stack_operands (rtx insn)
+check_asm_stack_operands (rtx_insn *insn)
 {
   int i;
   int n_clobbers;
@@ -463,29 +461,26 @@ check_asm_stack_operands (rtx insn)
 
   char reg_used_as_output[FIRST_PSEUDO_REGISTER];
   char implicitly_dies[FIRST_PSEUDO_REGISTER];
-  int alt;
 
   rtx *clobber_reg = 0;
   int n_inputs, n_outputs;
 
   /* Find out what the constraints require.  If no constraint
      alternative matches, this asm is malformed.  */
-  extract_insn (insn);
-  constrain_operands (1);
-  alt = which_alternative;
+  extract_constrain_insn (insn);
 
-  preprocess_constraints ();
+  preprocess_constraints (insn);
 
-  n_inputs = get_asm_operand_n_inputs (body);
-  n_outputs = recog_data.n_operands - n_inputs;
+  get_asm_operands_in_out (body, &n_outputs, &n_inputs);
 
-  if (alt < 0)
+  if (which_alternative < 0)
     {
       malformed_asm = 1;
       /* Avoid further trouble with this insn.  */
       PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
       return 0;
     }
+  const operand_alternative *op_alt = which_op_alt ();
 
   /* Strip SUBREGs here to make the following code simpler.  */
   for (i = 0; i < recog_data.n_operands; i++)
@@ -499,7 +494,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)
@@ -529,7 +524,7 @@ check_asm_stack_operands (rtx insn)
   for (i = 0; i < n_outputs; i++)
     if (STACK_REG_P (recog_data.operand[i]))
       {
-       if (reg_class_size[(int) recog_op_alt[i][alt].cl] != 1)
+       if (reg_class_size[(int) op_alt[i].cl] != 1)
          {
            error_for_asm (insn, "output constraint %d must specify a single register", i);
            malformed_asm = 1;
@@ -584,7 +579,7 @@ check_asm_stack_operands (rtx insn)
          if (operands_match_p (clobber_reg[j], recog_data.operand[i]))
            break;
 
-       if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
+       if (j < n_clobbers || op_alt[i].matches >= 0)
          implicitly_dies[REGNO (recog_data.operand[i])] = 1;
       }
 
@@ -612,7 +607,7 @@ check_asm_stack_operands (rtx insn)
      record any earlyclobber.  */
 
   for (i = n_outputs; i < n_outputs + n_inputs; i++)
-    if (recog_op_alt[i][alt].matches == -1)
+    if (op_alt[i].matches == -1)
       {
        int j;
 
@@ -641,24 +636,15 @@ check_asm_stack_operands (rtx insn)
    N_INPUTS and N_OUTPUTS are pointers to ints into which the results are
    placed.  */
 
-static int
-get_asm_operand_n_inputs (rtx body)
+static void
+get_asm_operands_in_out (rtx body, int *pout, int *pin)
 {
-  switch (GET_CODE (body))
-    {
-    case SET:
-      gcc_assert (GET_CODE (SET_SRC (body)) == ASM_OPERANDS);
-      return ASM_OPERANDS_INPUT_LENGTH (SET_SRC (body));
-      
-    case ASM_OPERANDS:
-      return ASM_OPERANDS_INPUT_LENGTH (body);
-      
-    case PARALLEL:
-      return get_asm_operand_n_inputs (XVECEXP (body, 0, 0));
-      
-    default:
-      gcc_unreachable ();
-    }
+  rtx asmop = extract_asm_operands (body);
+
+  *pin = ASM_OPERANDS_INPUT_LENGTH (asmop);
+  *pout = (recog_data.n_operands
+          - ASM_OPERANDS_INPUT_LENGTH (asmop)
+          - ASM_OPERANDS_LABEL_LENGTH (asmop));
 }
 
 /* If current function returns its result in an fp stack register,
@@ -694,8 +680,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))
@@ -708,20 +693,20 @@ replace_reg (rtx *reg, int regno)
    number REGNO from INSN.  Remove only one such note.  */
 
 static void
-remove_regno_note (rtx insn, enum reg_note note, unsigned int regno)
+remove_regno_note (rtx_insn *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 ();
 }
@@ -731,7 +716,7 @@ remove_regno_note (rtx insn, enum reg_note note, unsigned int regno)
    returned if the register is not found.  */
 
 static int
-get_hard_regnum (stack regstack, rtx reg)
+get_hard_regnum (stack_ptr regstack, rtx reg)
 {
   int i;
 
@@ -751,10 +736,11 @@ get_hard_regnum (stack regstack, rtx reg)
    and source is the top of stack.  A death note for the top of stack
    cases the movdf pattern to pop.  */
 
-static rtx
-emit_pop_insn (rtx insn, stack regstack, rtx reg, enum emit_where where)
+static rtx_insn *
+emit_pop_insn (rtx_insn *insn, stack_ptr regstack, rtx reg, enum emit_where where)
 {
-  rtx pop_insn, pop_rtx;
+  rtx_insn *pop_insn;
+  rtx pop_rtx;
   int hard_regno;
 
   /* For complex types take care to pop both halves.  These may survive in
@@ -764,7 +750,7 @@ emit_pop_insn (rtx insn, stack regstack, rtx reg, enum emit_where where)
       rtx reg1 = FP_MODE_REG (REGNO (reg), DFmode);
       rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, DFmode);
 
-      pop_insn = NULL_RTX;
+      pop_insn = NULL;
       if (get_hard_regnum (regstack, reg1) >= 0)
        pop_insn = emit_pop_insn (insn, regstack, reg1, where);
       if (get_hard_regnum (regstack, reg2) >= 0)
@@ -777,7 +763,7 @@ emit_pop_insn (rtx insn, stack regstack, rtx reg, enum emit_where where)
 
   gcc_assert (hard_regno >= FIRST_STACK_REG);
 
-  pop_rtx = gen_rtx_SET (VOIDmode, FP_MODE_REG (hard_regno, DFmode),
+  pop_rtx = gen_rtx_SET (FP_MODE_REG (hard_regno, DFmode),
                         FP_MODE_REG (FIRST_STACK_REG, DFmode));
 
   if (where == EMIT_AFTER)
@@ -785,9 +771,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];
@@ -805,33 +789,40 @@ emit_pop_insn (rtx insn, stack regstack, rtx reg, enum emit_where where)
    If REG is already at the top of the stack, no insn is emitted.  */
 
 static void
-emit_swap_insn (rtx insn, stack regstack, rtx reg)
+emit_swap_insn (rtx_insn *insn, stack_ptr regstack, rtx reg)
 {
   int hard_regno;
   rtx swap_rtx;
-  int tmp, other_reg;          /* swap regno temps */
-  rtx i1;                      /* the stack-reg insn prior to INSN */
+  int other_reg;               /* swap regno temps */
+  rtx_insn *i1;                        /* the stack-reg insn prior to INSN */
   rtx i1set = NULL_RTX;                /* the SET rtx within I1 */
 
   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);
-
-  tmp = regstack->reg[other_reg];
-  regstack->reg[other_reg] = regstack->reg[regstack->top];
-  regstack->reg[regstack->top] = tmp;
+  std::swap (regstack->reg[regstack->top], regstack->reg[other_reg]);
 
   /* Find the previous insn involving stack regs, but don't pass a
      block boundary.  */
   i1 = NULL;
   if (current_block && insn != BB_HEAD (current_block))
     {
-      rtx tmp = PREV_INSN (insn);
-      rtx limit = PREV_INSN (BB_HEAD (current_block));
+      rtx_insn *tmp = PREV_INSN (insn);
+      rtx_insn *limit = PREV_INSN (BB_HEAD (current_block));
       while (tmp != limit)
        {
          if (LABEL_P (tmp)
@@ -902,10 +893,10 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg)
    is emitted.  */
 
 static void
-swap_to_top (rtx insn, stack regstack, rtx src1, rtx src2)
+swap_to_top (rtx_insn *insn, stack_ptr regstack, rtx src1, rtx src2)
 {
   struct stack_def temp_stack;
-  int regno, j, k, temp;
+  int regno, j, k;
 
   temp_stack = *regstack;
 
@@ -917,9 +908,7 @@ swap_to_top (rtx insn, stack regstack, rtx src1, rtx src2)
       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;
+      std::swap (temp_stack.reg[j], temp_stack.reg[k]);
     }
 
   /* Place operand 2 next on the stack.  */
@@ -930,9 +919,7 @@ swap_to_top (rtx insn, stack regstack, rtx src1, rtx src2)
       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;
+      std::swap (temp_stack.reg[j], temp_stack.reg[k]);
     }
 
   change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
@@ -943,7 +930,7 @@ swap_to_top (rtx insn, stack regstack, rtx src1, rtx src2)
    was deleted in the process.  */
 
 static bool
-move_for_stack_reg (rtx insn, stack regstack, rtx pat)
+move_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat)
 {
   rtx *psrc =  get_true_reg (&SET_SRC (pat));
   rtx *pdest = get_true_reg (&SET_DEST (pat));
@@ -1051,8 +1038,7 @@ 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);
@@ -1072,11 +1058,13 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
         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))
+      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);
@@ -1093,12 +1081,12 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
    a NaN into DEST, then invokes move_for_stack_reg.  */
 
 static bool
-move_nan_for_stack_reg (rtx insn, stack regstack, rtx dest)
+move_nan_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx dest)
 {
   rtx pat;
 
   dest = FP_MODE_REG (REGNO (dest), SFmode);
-  pat = gen_rtx_SET (VOIDmode, dest, not_a_num);
+  pat = gen_rtx_SET (dest, not_a_num);
   PATTERN (insn) = pat;
   INSN_CODE (insn) = -1;
 
@@ -1141,7 +1129,7 @@ swap_rtx_condition_1 (rtx pat)
 }
 
 static int
-swap_rtx_condition (rtx insn)
+swap_rtx_condition (rtx_insn *insn)
 {
   rtx pat = PATTERN (insn);
 
@@ -1232,7 +1220,7 @@ swap_rtx_condition (rtx insn)
    set up.  */
 
 static void
-compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
+compare_for_stack_reg (rtx_insn *insn, stack_ptr regstack, rtx pat_src)
 {
   rtx *src1, *src2;
   rtx src1_note, src2_note;
@@ -1247,10 +1235,7 @@ compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
           && get_hard_regnum (regstack, *src2) == FIRST_STACK_REG))
       && swap_rtx_condition (insn))
     {
-      rtx temp;
-      temp = XEXP (pat_src, 0);
-      XEXP (pat_src, 0) = XEXP (pat_src, 1);
-      XEXP (pat_src, 1) = temp;
+      std::swap (XEXP (pat_src, 0), XEXP (pat_src, 1));
 
       src1 = get_true_reg (&XEXP (pat_src, 0));
       src2 = get_true_reg (&XEXP (pat_src, 1));
@@ -1304,23 +1289,49 @@ compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
          /* The 386 can only represent death of the first operand in
             the case handled above.  In all other cases, emit a separate
             pop and remove the death note from here.  */
-
-         /* link_cc0_insns (insn); */
-
          remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src2_note, 0)));
-
          emit_pop_insn (insn, regstack, XEXP (src2_note, 0),
                         EMIT_AFTER);
        }
     }
 }
 \f
+/* Substitute hardware stack regs in debug insn INSN, using stack
+   layout REGSTACK.  If we can't find a hardware stack reg for any of
+   the REGs in it, reset the debug insn.  */
+
+static void
+subst_all_stack_regs_in_debug_insn (rtx_insn *insn, struct stack_def *regstack)
+{
+  subrtx_ptr_iterator::array_type array;
+  FOR_EACH_SUBRTX_PTR (iter, array, &INSN_VAR_LOCATION_LOC (insn), NONCONST)
+    {
+      rtx *loc = *iter;
+      rtx x = *loc;
+      if (STACK_REG_P (x))
+       {
+         int hard_regno = get_hard_regnum (regstack, x);
+
+         /* If we can't find an active register, reset this debug insn.  */
+         if (hard_regno == -1)
+           {
+             INSN_VAR_LOCATION_LOC (insn) = gen_rtx_UNKNOWN_VAR_LOC ();
+             return;
+           }
+
+         gcc_assert (hard_regno >= FIRST_STACK_REG);
+         replace_reg (loc, hard_regno);
+         iter.skip_subrtxes ();
+       }
+    }
+}
+
 /* Substitute new registers in PAT, which is part of INSN.  REGSTACK
    is the current register layout.  Return whether a control flow insn
    was deleted in the process.  */
 
 static bool
-subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
+subst_stack_regs_pat (rtx_insn *insn, stack_ptr regstack, rtx pat)
 {
   rtx *dest, *src;
   bool control_flow_insn_deleted = false;
@@ -1334,14 +1345,23 @@ 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 VAR_LOCATION:
+      gcc_unreachable ();
+
     case CLOBBER:
       {
        rtx note;
@@ -1353,21 +1373,23 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
 
            if (pat != PATTERN (insn))
              {
-               /* The fix_truncdi_1 pattern wants to be able to allocate
-                  its own scratch register.  It does this by clobbering
-                  an fp reg so that it is assured of an empty reg-stack
-                  register.  If the register is live, kill it now.
-                  Remove the DEAD/UNUSED note so we don't try to kill it
-                  later too.  */
+               /* The fix_truncdi_1 pattern wants to be able to
+                  allocate its own scratch register.  It does this by
+                  clobbering an fp reg so that it is assured of an
+                  empty reg-stack register.  If the register is live,
+                  kill it now.  Remove the DEAD/UNUSED note so we
+                  don't try to kill it later too.
+
+                  In reality the UNUSED note can be absent in some
+                  complicated cases when the register is reused for
+                  partially set variable.  */
 
                if (note)
                  emit_pop_insn (insn, regstack, *dest, EMIT_BEFORE);
                else
-                 {
-                   note = find_reg_note (insn, REG_UNUSED, *dest);
-                   gcc_assert (note);
-                 }
-               remove_note (insn, note);
+                 note = find_reg_note (insn, REG_UNUSED, *dest);
+               if (note)
+                 remove_note (insn, note);
                replace_reg (dest, FIRST_STACK_REG + 1);
              }
            else
@@ -1386,7 +1408,7 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                        if (get_hard_regnum (regstack, u) == -1)
                          {
                            rtx pat2 = gen_rtx_CLOBBER (VOIDmode, u);
-                           rtx insn2 = emit_insn_before (pat2, insn);
+                           rtx_insn *insn2 = emit_insn_before (pat2, insn);
                            control_flow_insn_deleted
                              |= move_nan_for_stack_reg (insn2, regstack, u);
                          }
@@ -1414,7 +1436,7 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
        if (STACK_REG_P (*src)
            || (STACK_REG_P (*dest)
                && (REG_P (*src) || MEM_P (*src)
-                   || GET_CODE (*src) == CONST_DOUBLE)))
+                   || CONST_DOUBLE_P (*src))))
          {
            control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
            break;
@@ -1429,8 +1451,7 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
          case CALL:
            {
              int count;
-             for (count = hard_regno_nregs[REGNO (*dest)][GET_MODE (*dest)];
-                  --count >= 0;)
+             for (count = REG_NREGS (*dest); --count >= 0;)
                {
                  regstack->reg[++regstack->top] = REGNO (*dest) + count;
                  SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count);
@@ -1509,15 +1530,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_insn *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_insn *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)
@@ -1605,6 +1641,7 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
            switch (XINT (pat_src, 1))
              {
              case UNSPEC_FIST:
+             case UNSPEC_FIST_ATOMIC:
 
              case UNSPEC_FIST_FLOOR:
              case UNSPEC_FIST_CEIL:
@@ -1749,7 +1786,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));
@@ -1781,22 +1818,12 @@ 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))
@@ -1810,6 +1837,17 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                replace_reg (src2, FIRST_STACK_REG + 1);
                break;
 
+             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));
+               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:
                /* (unspec [(unspec [(compare)] UNSPEC_FNSTSW)] UNSPEC_SAHF)
                   The combination matches the PPRO fcomi instruction.  */
@@ -1940,10 +1978,9 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
    requirements, since record_asm_stack_regs removes any problem asm.  */
 
 static void
-subst_asm_stack_regs (rtx insn, stack regstack)
+subst_asm_stack_regs (rtx_insn *insn, stack_ptr regstack)
 {
   rtx body = PATTERN (insn);
-  int alt;
 
   rtx *note_reg;               /* Array of note contents */
   rtx **note_loc;              /* Address of REG field of each note */
@@ -1965,16 +2002,12 @@ subst_asm_stack_regs (rtx insn, stack regstack)
   /* Find out what the constraints required.  If no constraint
      alternative matches, that is a compiler bug: we should have caught
      such an insn in check_asm_stack_operands.  */
-  extract_insn (insn);
-  constrain_operands (1);
-  alt = which_alternative;
+  extract_constrain_insn (insn);
 
-  preprocess_constraints ();
+  preprocess_constraints (insn);
+  const operand_alternative *op_alt = which_op_alt ();
 
-  n_inputs = get_asm_operand_n_inputs (body);
-  n_outputs = recog_data.n_operands - n_inputs;
-
-  gcc_assert (alt >= 0);
+  get_asm_operands_in_out (body, &n_outputs, &n_inputs);
 
   /* Strip SUBREGs here to make the following code simpler.  */
   for (i = 0; i < recog_data.n_operands; i++)
@@ -1990,13 +2023,15 @@ 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))
     {
+      if (GET_CODE (note) != EXPR_LIST)
+       continue;
       rtx reg = XEXP (note, 0);
       rtx *loc = & XEXP (note, 0);
 
@@ -2023,8 +2058,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)
@@ -2054,9 +2089,8 @@ subst_asm_stack_regs (rtx insn, stack regstack)
 
   for (i = n_outputs; i < n_outputs + n_inputs; i++)
     if (STACK_REG_P (recog_data.operand[i])
-       && reg_class_subset_p (recog_op_alt[i][alt].cl,
-                              FLOAT_REGS)
-       && recog_op_alt[i][alt].cl != FLOAT_REGS)
+       && reg_class_subset_p (op_alt[i].cl, FLOAT_REGS)
+       && op_alt[i].cl != FLOAT_REGS)
       {
        /* If an operand needs to be in a particular reg in
           FLOAT_REGS, the constraint was either 't' or 'u'.  Since
@@ -2075,15 +2109,13 @@ subst_asm_stack_regs (rtx insn, stack regstack)
               it and swap it with whatever is already in I's place.
               K is where recog_data.operand[i] is now.  J is where it
               should be.  */
-           int j, k, temp;
+           int j, k;
 
            k = temp_stack.top - (regno - FIRST_STACK_REG);
            j = (temp_stack.top
                 - (REGNO (recog_data.operand[i]) - FIRST_STACK_REG));
 
-           temp = temp_stack.reg[k];
-           temp_stack.reg[k] = temp_stack.reg[j];
-           temp_stack.reg[j] = temp;
+           std::swap (temp_stack.reg[j], temp_stack.reg[k]);
          }
       }
 
@@ -2144,7 +2176,7 @@ subst_asm_stack_regs (rtx insn, stack regstack)
          if (operands_match_p (clobber_reg[j], recog_data.operand[i]))
            break;
 
-       if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
+       if (j < n_clobbers || op_alt[i].matches >= 0)
          {
            /* recog_data.operand[i] might not be at the top of stack.
               But that's OK, because all we need to do is pop the
@@ -2224,7 +2256,7 @@ subst_asm_stack_regs (rtx insn, stack regstack)
    a control flow insn was deleted in the process.  */
 
 static bool
-subst_stack_regs (rtx insn, stack regstack)
+subst_stack_regs (rtx_insn *insn, stack_ptr regstack)
 {
   rtx *note_link, note;
   bool control_flow_insn_deleted = false;
@@ -2292,7 +2324,7 @@ subst_stack_regs (rtx insn, stack regstack)
   /* subst_stack_regs_pat may have deleted a no-op insn.  If so, any
      REG_UNUSED will already have been dealt with, so just return.  */
 
-  if (NOTE_P (insn) || INSN_DELETED_P (insn))
+  if (NOTE_P (insn) || insn->deleted ())
     return control_flow_insn_deleted;
 
   /* If this a noreturn call, we can't insert pop insns after it.
@@ -2336,10 +2368,12 @@ 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 *insn, stack_ptr old, stack_ptr 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.
@@ -2348,9 +2382,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;
     }
 
@@ -2364,33 +2398,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 (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)
+     to pop registers that minimizes the number of fxchs below.  */
+  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;
@@ -2407,18 +2452,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)
@@ -2441,14 +2486,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);
@@ -2458,13 +2503,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
     {
@@ -2474,12 +2519,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
@@ -2488,16 +2531,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);
@@ -2510,8 +2553,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));
@@ -2522,7 +2565,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)
@@ -2532,7 +2575,7 @@ change_stack (rtx insn, stack old, stack new, enum emit_where where)
 /* Print stack configuration.  */
 
 static void
-print_stack (FILE *file, stack s)
+print_stack (FILE *file, stack_ptr s)
 {
   if (! file)
     return;
@@ -2575,7 +2618,7 @@ convert_regs_entry (void)
      Note that we are inserting converted code here.  This code is
      never seen by the convert_regs pass.  */
 
-  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
     {
       basic_block block = e->dest;
       block_info bi = BLOCK_INFO (block);
@@ -2588,8 +2631,7 @@ convert_regs_entry (void)
 
            bi->stack_in.reg[++top] = reg;
 
-           init = gen_rtx_SET (VOIDmode,
-                               FP_MODE_REG (FIRST_STACK_REG, SFmode),
+           init = gen_rtx_SET (FP_MODE_REG (FIRST_STACK_REG, SFmode),
                                not_a_num);
            insert_insn_on_edge (init, e);
            inserted = 1;
@@ -2608,7 +2650,7 @@ static void
 convert_regs_exit (void)
 {
   int value_reg_low, value_reg_high;
-  stack output_stack;
+  stack_ptr output_stack;
   rtx retvalue;
 
   retvalue = stack_result (current_function_decl);
@@ -2616,11 +2658,10 @@ 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_REGNO (retvalue) - 1;
     }
 
-  output_stack = &BLOCK_INFO (EXIT_BLOCK_PTR)->stack_in;
+  output_stack = &BLOCK_INFO (EXIT_BLOCK_PTR_FOR_FN (cfun))->stack_in;
   if (value_reg_low == -1)
     output_stack->top = -1;
   else
@@ -2642,8 +2683,8 @@ convert_regs_exit (void)
 static void
 propagate_stack (edge e)
 {
-  stack src_stack = &BLOCK_INFO (e->src)->stack_out;
-  stack dest_stack = &BLOCK_INFO (e->dest)->stack_in;
+  stack_ptr src_stack = &BLOCK_INFO (e->src)->stack_out;
+  stack_ptr dest_stack = &BLOCK_INFO (e->dest)->stack_in;
   int reg;
 
   /* Preserve the order of the original stack, but check whether
@@ -2652,6 +2693,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;
 }
 
 
@@ -2663,8 +2710,8 @@ static bool
 compensate_edge (edge e)
 {
   basic_block source = e->src, target = e->dest;
-  stack target_stack = &BLOCK_INFO (target)->stack_in;
-  stack source_stack = &BLOCK_INFO (source)->stack_out;
+  stack_ptr target_stack = &BLOCK_INFO (target)->stack_in;
+  stack_ptr source_stack = &BLOCK_INFO (source)->stack_out;
   struct stack_def regstack;
   int reg;
 
@@ -2736,7 +2783,8 @@ compensate_edge (edge e)
     }
   else
     {
-      rtx seq, after;
+      rtx_insn *seq;
+      rtx_note *after;
 
       current_block = NULL;
       start_sequence ();
@@ -2767,8 +2815,8 @@ compensate_edges (void)
 
   starting_stack_p = false;
 
-  FOR_EACH_BB (bb)
-    if (bb != ENTRY_BLOCK_PTR)
+  FOR_EACH_BB_FN (bb, cfun)
+    if (bb != ENTRY_BLOCK_PTR_FOR_FN (cfun))
       {
         edge e;
         edge_iterator ei;
@@ -2810,16 +2858,19 @@ better_edge (edge e1, edge e2)
   return (e1->src->index < e2->src->index) ? e1 : e2;
 }
 
-/* Convert stack register references in one block.  */
+/* Convert stack register references in one block.  Return true if the CFG
+   has been modified in the process.  */
 
-static void
+static bool
 convert_regs_1 (basic_block block)
 {
   struct stack_def regstack;
   block_info bi = BLOCK_INFO (block);
   int reg;
-  rtx insn, next;
+  rtx_insn *insn, *next;
   bool control_flow_insn_deleted = false;
+  bool cfg_altered = false;
+  int debug_insns_with_starting_stack = 0;
 
   any_malformed_asm = false;
 
@@ -2872,8 +2923,24 @@ convert_regs_1 (basic_block block)
 
       /* Don't bother processing unless there is a stack reg
         mentioned or if it's a CALL_INSN.  */
-      if (stack_regs_mentioned (insn)
-         || CALL_P (insn))
+      if (DEBUG_INSN_P (insn))
+       {
+         if (starting_stack_p)
+           debug_insns_with_starting_stack++;
+         else
+           {
+             subst_all_stack_regs_in_debug_insn (insn, &regstack);
+
+             /* Nothing must ever die at a debug insn.  If something
+                is referenced in it that becomes dead, it should have
+                died before and the reference in the debug insn
+                should have been removed so as to avoid changing code
+                generation.  */
+             gcc_assert (!find_reg_note (insn, REG_DEAD, NULL));
+           }
+       }
+      else if (stack_regs_mentioned (insn)
+              || CALL_P (insn))
        {
          if (dump_file)
            {
@@ -2887,6 +2954,23 @@ convert_regs_1 (basic_block block)
     }
   while (next);
 
+  if (debug_insns_with_starting_stack)
+    {
+      /* Since it's the first non-debug instruction that determines
+        the stack requirements of the current basic block, we refrain
+        from updating debug insns before it in the loop above, and
+        fix them up here.  */
+      for (insn = BB_HEAD (block); debug_insns_with_starting_stack;
+          insn = NEXT_INSN (insn))
+       {
+         if (!DEBUG_INSN_P (insn))
+           continue;
+
+         debug_insns_with_starting_stack--;
+         subst_all_stack_regs_in_debug_insn (insn, &bi->stack_in);
+       }
+    }
+
   if (dump_file)
     {
       fprintf (dump_file, "Expected live registers [");
@@ -2915,12 +2999,12 @@ convert_regs_1 (basic_block block)
          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);
+         set = gen_rtx_SET (FP_MODE_REG (reg, SFmode), not_a_num);
          insn = emit_insn_after (set, insn);
          control_flow_insn_deleted |= subst_stack_regs (insn, &regstack);
        }
     }
-  
+
   /* Amongst the insns possibly deleted during the substitution process above,
      might have been the only trapping insn in the block.  We purge the now
      possibly dead EH edges here to avoid an ICE from fixup_abnormal_edges,
@@ -2939,30 +3023,34 @@ convert_regs_1 (basic_block block)
      place, still, but we don't have enough information at that time.  */
 
   if (control_flow_insn_deleted)
-    purge_dead_edges (block);
+    cfg_altered |= purge_dead_edges (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;
+
+  return cfg_altered;
 }
 
-/* Convert registers in all blocks reachable from BLOCK.  */
+/* Convert registers in all blocks reachable from BLOCK.  Return true if the
+   CFG has been modified in the process.  */
 
-static void
+static bool
 convert_regs_2 (basic_block block)
 {
   basic_block *stack, *sp;
+  bool cfg_altered = false;
 
   /* We process the blocks in a top-down manner, in a way such that one block
      is only processed after all its predecessors.  The number of predecessors
-     of every block has already been computed.  */ 
+     of every block has already been computed.  */
 
-  stack = XNEWVEC (basic_block, n_basic_blocks);
+  stack = XNEWVEC (basic_block, n_basic_blocks_for_fn (cfun));
   sp = stack;
 
   *sp++ = block;
@@ -2995,11 +3083,13 @@ convert_regs_2 (basic_block block)
              *sp++ = e->dest;
          }
 
-      convert_regs_1 (block);
+      cfg_altered |= convert_regs_1 (block);
     }
   while (sp != stack);
 
   free (stack);
+
+  return cfg_altered;
 }
 
 /* Traverse all basic blocks in a function, converting the register
@@ -3009,6 +3099,7 @@ convert_regs_2 (basic_block block)
 static void
 convert_regs (void)
 {
+  bool cfg_altered = false;
   int inserted;
   basic_block b;
   edge e;
@@ -3019,34 +3110,40 @@ convert_regs (void)
 
   /* Construct the desired stack for function exit.  */
   convert_regs_exit ();
-  BLOCK_INFO (EXIT_BLOCK_PTR)->done = 1;
+  BLOCK_INFO (EXIT_BLOCK_PTR_FOR_FN (cfun))->done = 1;
 
   /* ??? Future: process inner loops first, and give them arbitrary
      initial stacks which emit_swap_insn can modify.  This ought to
      prevent double fxch that often appears at the head of a loop.  */
 
   /* Process all blocks reachable from all entry points.  */
-  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
-    convert_regs_2 (e->dest);
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR_FOR_FN (cfun)->succs)
+    cfg_altered |= convert_regs_2 (e->dest);
 
   /* ??? Process all unreachable blocks.  Though there's no excuse
      for keeping these even when not optimizing.  */
-  FOR_EACH_BB (b)
+  FOR_EACH_BB_FN (b, cfun)
     {
       block_info bi = BLOCK_INFO (b);
 
       if (! bi->done)
-       convert_regs_2 (b);
+       cfg_altered |= convert_regs_2 (b);
     }
 
+  /* We must fix up abnormal edges before inserting compensation code
+     because both mechanisms insert insns on edges.  */
+  inserted |= fixup_abnormal_edges ();
+
   inserted |= compensate_edges ();
 
   clear_aux_for_blocks ();
 
-  fixup_abnormal_edges ();
   if (inserted)
     commit_edge_insertions ();
 
+  if (cfg_altered)
+    cleanup_cfg (0);
+
   if (dump_file)
     fputc ('\n', dump_file);
 }
@@ -3067,33 +3164,24 @@ reg_to_stack (void)
   int max_uid;
 
   /* Clean up previous run.  */
-  if (stack_regs_mentioned_data != NULL)
-    VEC_free (char, heap, stack_regs_mentioned_data);
+  stack_regs_mentioned_data.release ();
 
   /* 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 (PROP_DEATH_NOTES);
-    }
+  df_note_add_problem ();
+  df_analyze ();
+
   mark_dfs_back_edges ();
 
   /* Set up block info for each basic block.  */
   alloc_aux_for_blocks (sizeof (struct block_info_def));
-  FOR_EACH_BB (bb)
+  FOR_EACH_BB_FN (bb, cfun)
     {
       block_info bi = BLOCK_INFO (bb);
       edge_iterator ei;
@@ -3102,7 +3190,7 @@ reg_to_stack (void)
 
       FOR_EACH_EDGE (e, ei, bb->preds)
        if (!(e->flags & EDGE_DFS_BACK)
-           && e->src != ENTRY_BLOCK_PTR)
+           && e->src != ENTRY_BLOCK_PTR_FOR_FN (cfun))
          bi->predecessors++;
 
       /* Set current register status at last instruction `uninitialized'.  */
@@ -3111,9 +3199,9 @@ reg_to_stack (void)
       /* 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);
        }
     }
@@ -3121,7 +3209,7 @@ reg_to_stack (void)
   /* Create the replacement registers up front.  */
   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
     {
-      enum machine_mode mode;
+      machine_mode mode;
       for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
           mode != VOIDmode;
           mode = GET_MODE_WIDER_MODE (mode))
@@ -3139,21 +3227,25 @@ reg_to_stack (void)
      ??? 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 ();
-  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);
+  stack_regs_mentioned_data.create (max_uid + 1);
+  memset (stack_regs_mentioned_data.address (),
+         0, sizeof (char) * (max_uid + 1));
 
   convert_regs ();
 
@@ -3162,14 +3254,46 @@ reg_to_stack (void)
 }
 #endif /* STACK_REGS */
 \f
-static bool
-gate_handle_stack_regs (void)
+namespace {
+
+const pass_data pass_data_stack_regs =
+{
+  RTL_PASS, /* type */
+  "*stack_regs", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_REG_STACK, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  0, /* todo_flags_finish */
+};
+
+class pass_stack_regs : public rtl_opt_pass
 {
+public:
+  pass_stack_regs (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_stack_regs, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual bool gate (function *)
+    {
 #ifdef STACK_REGS
-  return 1;
+      return true;
 #else
-  return 0;
+      return false;
 #endif
+    }
+
+}; // class pass_stack_regs
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_stack_regs (gcc::context *ctxt)
+{
+  return new pass_stack_regs (ctxt);
 }
 
 /* Convert register usage from flat register file usage to a stack
@@ -3178,37 +3302,46 @@ static unsigned int
 rest_of_handle_stack_regs (void)
 {
 #ifdef STACK_REGS
-  if (reg_to_stack () && optimize)
-    {
-      regstack_completed = 1;
-      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);
-        }
-    }
-  else 
-    regstack_completed = 1;
+  reg_to_stack ();
+  regstack_completed = 1;
 #endif
   return 0;
 }
 
-struct tree_opt_pass pass_stack_regs =
+namespace {
+
+const pass_data pass_data_stack_regs_run =
 {
-  "stack",                              /* name */
-  gate_handle_stack_regs,               /* gate */
-  rest_of_handle_stack_regs,            /* 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 */
-  TODO_dump_func |
-  TODO_ggc_collect,                     /* todo_flags_finish */
-  'k'                                   /* letter */
+  RTL_PASS, /* type */
+  "stack", /* name */
+  OPTGROUP_NONE, /* optinfo_flags */
+  TV_REG_STACK, /* tv_id */
+  0, /* properties_required */
+  0, /* properties_provided */
+  0, /* properties_destroyed */
+  0, /* todo_flags_start */
+  TODO_df_finish, /* todo_flags_finish */
 };
+
+class pass_stack_regs_run : public rtl_opt_pass
+{
+public:
+  pass_stack_regs_run (gcc::context *ctxt)
+    : rtl_opt_pass (pass_data_stack_regs_run, ctxt)
+  {}
+
+  /* opt_pass methods: */
+  virtual unsigned int execute (function *)
+    {
+      return rest_of_handle_stack_regs ();
+    }
+
+}; // class pass_stack_regs_run
+
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_stack_regs_run (gcc::context *ctxt)
+{
+  return new pass_stack_regs_run (ctxt);
+}