]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/reg-stack.c
[testsuite] Add missing dg-require-effective-target label_values
[thirdparty/gcc.git] / gcc / reg-stack.c
index 60835c75528d0c09a9472bf89fe9d6ad06a715dc..8c934aaf936e945a30e46d34106f3eeafd155544 100644 (file)
@@ -1,7 +1,5 @@
 /* Register to Stack convert for GNU compiler.
-   Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-   2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2010
-   Free Software Foundation, Inc.
+   Copyright (C) 1992-2019 Free Software Foundation, Inc.
 
    This file is part of GCC.
 
@@ -99,6 +97,9 @@
        All implicitly popped input regs must be closer to the top of
        the reg-stack than any input that is not implicitly popped.
 
+       All explicitly referenced input operands may not "skip" a reg.
+       Otherwise we can have holes in the stack.
+
    3. It is possible that if an input dies in an insn, reload might
       use the input reg for an output reload.  Consider this example:
 
 #include "config.h"
 #include "system.h"
 #include "coretypes.h"
-#include "tm.h"
+#include "backend.h"
+#include "target.h"
+#include "rtl.h"
 #include "tree.h"
-#include "rtl-error.h"
-#include "tm_p.h"
-#include "function.h"
+#include "df.h"
 #include "insn-config.h"
+#include "memmodel.h"
 #include "regs.h"
-#include "hard-reg-set.h"
-#include "flags.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 "cfglayout.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 "df.h"
-#include "vecprim.h"
-#include "emit-rtl.h"  /* FIXME: Can go away once crtl is moved to rtl.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)
 
@@ -204,7 +203,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.  */
@@ -249,28 +248,28 @@ static rtx not_a_num;
 /* Forward declarations */
 
 static int stack_regs_mentioned_p (const_rtx pat);
-static void pop_stack (stack, int);
+static void pop_stack (stack_ptr, int);
 static rtx *get_true_reg (rtx *);
 
-static int check_asm_stack_operands (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, bool);
+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.  */
 
@@ -309,25 +308,25 @@ 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;
@@ -335,8 +334,8 @@ stack_regs_mentioned (const_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.  */
@@ -349,15 +348,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;
@@ -380,7 +379,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,8 +414,9 @@ get_true_reg (rtx *pat)
        /* Eliminate FP subregister accesses in favor of the
           actual FP register in use.  */
        {
-         rtx subreg;
-         if (FP_REG_P (subreg = SUBREG_REG (*pat)))
+         rtx subreg = SUBREG_REG (*pat);
+
+         if (STACK_REG_P (subreg))
            {
              int regno_off = subreg_regno_offset (REGNO (subreg),
                                                   GET_MODE (subreg),
@@ -426,24 +426,27 @@ get_true_reg (rtx *pat)
                                  GET_MODE (subreg));
              return pat;
            }
+         pat = &XEXP (*pat, 0);
+         break;
        }
+
+      case FLOAT_TRUNCATE:
+       if (!flag_unsafe_math_optimizations)
+         return pat;
+       /* FALLTHRU */
+
       case FLOAT:
       case FIX:
       case FLOAT_EXTEND:
-       pat = & XEXP (*pat, 0);
+       pat = &XEXP (*pat, 0);
        break;
 
       case UNSPEC:
-       if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP)
-         pat = & XVECEXP (*pat, 0, 0);
+       if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP
+           || XINT (*pat, 1) == UNSPEC_FILD_ATOMIC)
+         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;
       }
@@ -457,7 +460,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;
@@ -466,28 +469,27 @@ check_asm_stack_operands (rtx insn)
 
   char reg_used_as_output[FIRST_PSEUDO_REGISTER];
   char implicitly_dies[FIRST_PSEUDO_REGISTER];
-  int alt;
+  char explicitly_used[FIRST_PSEUDO_REGISTER];
 
   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);
 
   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++)
@@ -531,7 +533,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;
@@ -543,7 +545,8 @@ check_asm_stack_operands (rtx insn)
            for (j = 0; j < n_clobbers; j++)
              if (REGNO (recog_data.operand[i]) == REGNO (clobber_reg[j]))
                {
-                 error_for_asm (insn, "output constraint %d cannot be specified together with \"%s\" clobber",
+                 error_for_asm (insn, "output constraint %d cannot be "
+                                "specified together with %qs clobber",
                                 i, reg_names [REGNO (clobber_reg[j])]);
                  malformed_asm = 1;
                  break;
@@ -566,7 +569,7 @@ check_asm_stack_operands (rtx insn)
 
   if (i != LAST_STACK_REG + 1)
     {
-      error_for_asm (insn, "output regs must be grouped at top of stack");
+      error_for_asm (insn, "output registers must be grouped at top of stack");
       malformed_asm = 1;
     }
 
@@ -575,6 +578,7 @@ check_asm_stack_operands (rtx insn)
      popped.  */
 
   memset (implicitly_dies, 0, sizeof (implicitly_dies));
+  memset (explicitly_used, 0, sizeof (explicitly_used));
   for (i = n_outputs; i < n_outputs + n_inputs; i++)
     if (STACK_REG_P (recog_data.operand[i]))
       {
@@ -586,8 +590,10 @@ 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;
+       else if (reg_class_size[(int) op_alt[i].cl] == 1)
+         explicitly_used[REGNO (recog_data.operand[i])] = 1;
       }
 
   /* Search for first non-popped reg.  */
@@ -603,7 +609,26 @@ check_asm_stack_operands (rtx insn)
   if (i != LAST_STACK_REG + 1)
     {
       error_for_asm (insn,
-                    "implicitly popped regs must be grouped at top of stack");
+                    "implicitly popped registers must be grouped "
+                    "at top of stack");
+      malformed_asm = 1;
+    }
+
+  /* Search for first not-explicitly used reg.  */
+  for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++)
+    if (! implicitly_dies[i] && ! explicitly_used[i])
+      break;
+
+  /* If there are any other explicitly used regs, that's an error.  */
+  for (; i < LAST_STACK_REG + 1; i++)
+    if (explicitly_used[i])
+      break;
+
+  if (i != LAST_STACK_REG + 1)
+    {
+      error_for_asm (insn,
+                    "explicitly used registers must be grouped "
+                    "at top of stack");
       malformed_asm = 1;
     }
 
@@ -614,7 +639,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 (STACK_REG_P (recog_data.operand[i]) && op_alt[i].matches == -1)
       {
        int j;
 
@@ -690,7 +715,7 @@ replace_reg (rtx *reg, int regno)
   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))
+  gcc_assert (GET_MODE_CLASS (GET_MODE (*reg)) == MODE_FLOAT
              || GET_MODE_CLASS (GET_MODE (*reg)) == MODE_COMPLEX_FLOAT);
 
   *reg = FP_MODE_REG (regno, GET_MODE (*reg));
@@ -700,7 +725,7 @@ 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;
 
@@ -723,7 +748,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;
 
@@ -743,20 +768,23 @@ 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;
+  machine_mode raw_mode = reg_raw_mode[FIRST_STACK_REG];
+  rtx_insn *pop_insn;
+  rtx pop_rtx;
   int hard_regno;
 
   /* For complex types take care to pop both halves.  These may survive in
      CLOBBER and USE expressions.  */
   if (COMPLEX_MODE_P (GET_MODE (reg)))
     {
-      rtx reg1 = FP_MODE_REG (REGNO (reg), DFmode);
-      rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, DFmode);
+      rtx reg1 = FP_MODE_REG (REGNO (reg), raw_mode);
+      rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, raw_mode);
 
-      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)
@@ -769,15 +797,15 @@ 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),
-                        FP_MODE_REG (FIRST_STACK_REG, DFmode));
+  pop_rtx = gen_rtx_SET (FP_MODE_REG (hard_regno, raw_mode),
+                        FP_MODE_REG (FIRST_STACK_REG, raw_mode));
 
   if (where == EMIT_AFTER)
     pop_insn = emit_insn_after (pop_rtx, insn);
   else
     pop_insn = emit_insn_before (pop_rtx, insn);
 
-  add_reg_note (pop_insn, REG_DEAD, FP_MODE_REG (FIRST_STACK_REG, DFmode));
+  add_reg_note (pop_insn, REG_DEAD, FP_MODE_REG (FIRST_STACK_REG, raw_mode));
 
   regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
     = regstack->reg[regstack->top];
@@ -795,12 +823,11 @@ 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);
@@ -820,18 +847,15 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg)
   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)
@@ -869,6 +893,84 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg)
          && REG_P (i1src) && REGNO (i1src) == FIRST_STACK_REG
          && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX)
        return;
+
+      /* Instead of
+          fld a
+          fld b
+          fxch %st(1)
+        just use
+          fld b
+          fld a
+        if possible.  Similarly for fld1, fldz, fldpi etc. instead of any
+        of the loads or for float extension from memory.  */
+
+      i1src = SET_SRC (i1set);
+      if (GET_CODE (i1src) == FLOAT_EXTEND)
+       i1src = XEXP (i1src, 0);
+      if (REG_P (i1dest)
+         && REGNO (i1dest) == FIRST_STACK_REG
+         && (MEM_P (i1src) || GET_CODE (i1src) == CONST_DOUBLE)
+         && !side_effects_p (i1src)
+         && hard_regno == FIRST_STACK_REG + 1
+         && i1 != BB_HEAD (current_block))
+       {
+         /* i1 is the last insn that involves stack regs before insn, and
+            is known to be a load without other side-effects, i.e. fld b
+            in the above comment.  */
+         rtx_insn *i2 = NULL;
+         rtx i2set;
+         rtx_insn *tmp = PREV_INSN (i1);
+         rtx_insn *limit = PREV_INSN (BB_HEAD (current_block));
+         /* Find the previous insn involving stack regs, but don't pass a
+            block boundary.  */
+         while (tmp != limit)
+           {
+             if (LABEL_P (tmp)
+                 || CALL_P (tmp)
+                 || NOTE_INSN_BASIC_BLOCK_P (tmp)
+                 || (NONJUMP_INSN_P (tmp)
+                     && stack_regs_mentioned (tmp)))
+               {
+                 i2 = tmp;
+                 break;
+               }
+             tmp = PREV_INSN (tmp);
+           }
+         if (i2 != NULL_RTX
+             && (i2set = single_set (i2)) != NULL_RTX)
+           {
+             rtx i2dest = *get_true_reg (&SET_DEST (i2set));
+             rtx i2src = SET_SRC (i2set);
+             if (GET_CODE (i2src) == FLOAT_EXTEND)
+               i2src = XEXP (i2src, 0);
+             /* If the last two insns before insn that involve
+                stack regs are loads, where the latter (i1)
+                pushes onto the register stack and thus
+                moves the value from the first load (i2) from
+                %st to %st(1), consider swapping them.  */
+             if (REG_P (i2dest)
+                 && REGNO (i2dest) == FIRST_STACK_REG
+                 && (MEM_P (i2src) || GET_CODE (i2src) == CONST_DOUBLE)
+                 /* Ensure i2 doesn't have other side-effects.  */
+                 && !side_effects_p (i2src)
+                 /* And that the two instructions can actually be
+                    swapped, i.e. there shouldn't be any stores
+                    in between i2 and i1 that might alias with
+                    the i1 memory, and the memory address can't
+                    use registers set in between i2 and i1.  */
+                 && !modified_between_p (SET_SRC (i1set), i2, i1))
+               {
+                 /* Move i1 (fld b above) right before i2 (fld a
+                    above.  */
+                 remove_insn (i1);
+                 SET_PREV_INSN (i1) = NULL_RTX;
+                 SET_NEXT_INSN (i1) = NULL_RTX;
+                 set_block_for_insn (i1, NULL);
+                 emit_insn_before (i1, i2);
+                 return;
+               }
+           }
+       }
     }
 
   /* Avoid emitting the swap if this is the first register stack insn
@@ -881,9 +983,13 @@ emit_swap_insn (rtx insn, stack regstack, rtx reg)
       return;
     }
 
-  swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode),
-                        FP_MODE_REG (FIRST_STACK_REG, XFmode));
-
+  machine_mode raw_mode = reg_raw_mode[FIRST_STACK_REG];
+  rtx op1 = FP_MODE_REG (hard_regno, raw_mode);
+  rtx op2 = FP_MODE_REG (FIRST_STACK_REG, raw_mode);
+  rtx swap_rtx
+    = gen_rtx_PARALLEL (VOIDmode,
+                       gen_rtvec (2, gen_rtx_SET (op1, op2),
+                                  gen_rtx_SET (op2, op1)));
   if (i1)
     emit_insn_after (swap_rtx, i1);
   else if (current_block)
@@ -902,10 +1008,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 +1023,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 +1034,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 +1045,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));
@@ -1013,13 +1115,16 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
        }
 
       /* The destination ought to be dead.  */
-      gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
-
-      replace_reg (psrc, get_hard_regnum (regstack, src));
+      if (get_hard_regnum (regstack, dest) >= FIRST_STACK_REG)
+       gcc_assert (any_malformed_asm);
+      else
+       {
+         replace_reg (psrc, get_hard_regnum (regstack, src));
 
-      regstack->reg[++regstack->top] = REGNO (dest);
-      SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
-      replace_reg (pdest, FIRST_STACK_REG);
+         regstack->reg[++regstack->top] = REGNO (dest);
+         SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+         replace_reg (pdest, FIRST_STACK_REG);
+       }
     }
   else if (STACK_REG_P (src))
     {
@@ -1078,7 +1183,8 @@ move_for_stack_reg (rtx insn, stack regstack, rtx pat)
          && 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 (get_hard_regnum (regstack, dest) < FIRST_STACK_REG
+                   || any_malformed_asm);
 
       gcc_assert (regstack->top < REG_STACK_SIZE);
 
@@ -1094,12 +1200,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;
 
@@ -1142,7 +1248,7 @@ swap_rtx_condition_1 (rtx pat)
 }
 
 static int
-swap_rtx_condition (rtx insn)
+swap_rtx_condition (rtx_insn *insn)
 {
   rtx pat = PATTERN (insn);
 
@@ -1233,7 +1339,8 @@ 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, bool can_pop_second_op)
 {
   rtx *src1, *src2;
   rtx src1_note, src2_note;
@@ -1248,10 +1355,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));
@@ -1277,8 +1381,18 @@ compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
 
   if (src1_note)
     {
-      pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
-      replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+      if (*src2 == CONST0_RTX (GET_MODE (*src2)))
+       {
+         /* This is `ftst' insn that can't pop register.  */
+         remove_regno_note (insn, REG_DEAD, REGNO (XEXP (src1_note, 0)));
+         emit_pop_insn (insn, regstack, XEXP (src1_note, 0),
+                        EMIT_AFTER);
+       }
+      else
+       {
+         pop_stack (regstack, REGNO (XEXP (src1_note, 0)));
+         replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+       }
     }
 
   /* If the second operand dies, handle that.  But if the operands are
@@ -1295,7 +1409,7 @@ compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
         at top (FIRST_STACK_REG) now.  */
 
       if (get_hard_regnum (regstack, XEXP (src2_note, 0)) == FIRST_STACK_REG
-         && src1_note)
+         && src1_note && can_pop_second_op)
        {
          pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
          replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
@@ -1305,39 +1419,41 @@ 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 new registers in LOC, which is part of a debug insn.
-   REGSTACK is the current register layout.  */
+/* 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 int
-subst_stack_regs_in_debug_insn (rtx *loc, void *data)
+static void
+subst_all_stack_regs_in_debug_insn (rtx_insn *insn, struct stack_def *regstack)
 {
-  rtx *tloc = get_true_reg (loc);
-  stack regstack = (stack)data;
-  int hard_regno;
-
-  if (!STACK_REG_P (*tloc))
-    return 0;
-
-  if (tloc != loc)
-    return 0;
-
-  hard_regno = get_hard_regnum (regstack, *loc);
-  gcc_assert (hard_regno >= FIRST_STACK_REG);
+  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);
 
-  replace_reg (loc, hard_regno);
+         /* 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;
+           }
 
-  return -1;
+         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
@@ -1345,7 +1461,7 @@ subst_stack_regs_in_debug_insn (rtx *loc, void *data)
    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;
@@ -1422,7 +1538,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);
                          }
@@ -1450,7 +1566,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;
@@ -1458,15 +1574,10 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
 
        switch (GET_CODE (pat_src))
          {
-         case COMPARE:
-           compare_for_stack_reg (insn, regstack, pat_src);
-           break;
-
          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);
@@ -1558,14 +1669,14 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                if (src1_hard_regnum == -1)
                  {
                    rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src1);
-                   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, *src1);
                  }
                if (src2_hard_regnum == -1)
                  {
                    rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src2);
-                   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, *src2);
                  }
@@ -1656,6 +1767,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:
@@ -1709,7 +1821,6 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
              case UNSPEC_FRNDINT_FLOOR:
              case UNSPEC_FRNDINT_CEIL:
              case UNSPEC_FRNDINT_TRUNC:
-             case UNSPEC_FRNDINT_MASK_PM:
 
                /* Above insns operate on the top of the stack.  */
 
@@ -1862,31 +1973,35 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
                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.  */
-
-               pat_src = XVECEXP (pat_src, 0, 0);
-               gcc_assert (GET_CODE (pat_src) == UNSPEC);
-               gcc_assert (XINT (pat_src, 1) == UNSPEC_FNSTSW);
-               /* Fall through.  */
-
              case UNSPEC_FNSTSW:
                /* Combined fcomp+fnstsw generated for doing well with
                   CSE.  When optimizing this would have been broken
                   up before now.  */
 
                pat_src = XVECEXP (pat_src, 0, 0);
-               gcc_assert (GET_CODE (pat_src) == COMPARE);
+               if (GET_CODE (pat_src) == COMPARE)
+                 goto do_compare;
 
-               compare_for_stack_reg (insn, regstack, pat_src);
-               break;
+               /* Fall through.  */
+
+             case UNSPEC_NOTRAP:
+
+               pat_src = XVECEXP (pat_src, 0, 0);
+               gcc_assert (GET_CODE (pat_src) == COMPARE);
+               goto do_compare;
 
              default:
                gcc_unreachable ();
              }
            break;
 
+         case COMPARE:
+         do_compare:
+           /* `fcomi' insn can't pop two regs.  */
+           compare_for_stack_reg (insn, regstack, pat_src,
+                                  REGNO (*dest) != FLAGS_REG);
+           break;
+
          case IF_THEN_ELSE:
            /* This insn requires the top of stack to be the destination.  */
 
@@ -1992,10 +2107,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 */
@@ -2017,16 +2131,13 @@ 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 ();
 
   get_asm_operands_in_out (body, &n_outputs, &n_inputs);
 
-  gcc_assert (alt >= 0);
-
   /* Strip SUBREGs here to make the following code simpler.  */
   for (i = 0; i < recog_data.n_operands; i++)
     if (GET_CODE (recog_data.operand[i]) == SUBREG
@@ -2048,6 +2159,8 @@ subst_asm_stack_regs (rtx insn, stack regstack)
   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);
 
@@ -2105,9 +2218,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
@@ -2126,15 +2238,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]);
          }
       }
 
@@ -2173,13 +2283,7 @@ subst_asm_stack_regs (rtx insn, stack regstack)
       int regnum = get_hard_regnum (regstack, clobber_reg[i]);
 
       if (regnum >= 0)
-       {
-         /* Sigh - clobbers always have QImode.  But replace_reg knows
-            that these regs can't be MODE_INT and will assert.  Just put
-            the right reg there without calling replace_reg.  */
-
-         *clobber_loc[i] = FP_MODE_REG (regnum, DFmode);
-       }
+       replace_reg (clobber_loc[i], regnum);
     }
 
   /* Now remove from REGSTACK any inputs that the asm implicitly popped.  */
@@ -2195,7 +2299,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
@@ -2275,7 +2379,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;
@@ -2343,7 +2447,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.
@@ -2387,10 +2491,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_stack, 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;
+  machine_mode raw_mode = reg_raw_mode[FIRST_STACK_REG];
+  rtx_insn *update_end = NULL;
   int i;
 
   /* Stack adjustments for the first insn in a block update the
@@ -2412,7 +2518,7 @@ change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
   if (where == EMIT_AFTER)
     {
       if (current_block && BB_END (current_block) == insn)
-       update_end = 1;
+       update_end = insn;
       insn = NEXT_INSN (insn);
     }
 
@@ -2423,15 +2529,15 @@ change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
       {
        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);
+       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.  */
+     to pop registers that minimizes the number of fxchs below.  */
   if (new_stack->top > 0)
     {
       bool slots[REG_STACK_SIZE];
@@ -2491,7 +2597,7 @@ change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
                next--;
              dest = next--;
            }
-         emit_pop_insn (insn, old, FP_MODE_REG (old->reg[dest], DFmode),
+         emit_pop_insn (insn, old, FP_MODE_REG (old->reg[dest], raw_mode),
                         EMIT_BEFORE);
        }
     }
@@ -2513,11 +2619,11 @@ change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
          {
            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_pop_insn (insn, old, FP_MODE_REG (old->reg[next], raw_mode),
                           EMIT_BEFORE);
          }
        else
-         emit_pop_insn (insn, old, FP_MODE_REG (old->reg[old->top], DFmode),
+         emit_pop_insn (insn, old, FP_MODE_REG (old->reg[old->top], raw_mode),
                         EMIT_BEFORE);
     }
 
@@ -2564,7 +2670,7 @@ change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
                gcc_assert (reg != -1);
 
                emit_swap_insn (insn, old,
-                               FP_MODE_REG (old->reg[reg], DFmode));
+                               FP_MODE_REG (old->reg[reg], raw_mode));
              }
 
            /* See if any regs remain incorrect.  If so, bring an
@@ -2575,7 +2681,7 @@ change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
              if (new_stack->reg[reg] != old->reg[reg])
                {
                  emit_swap_insn (insn, old,
-                                 FP_MODE_REG (old->reg[reg], DFmode));
+                                 FP_MODE_REG (old->reg[reg], raw_mode));
                  break;
                }
          } while (reg >= 0);
@@ -2587,13 +2693,22 @@ change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
     }
 
   if (update_end)
-    BB_END (current_block) = PREV_INSN (insn);
+    {
+      for (update_end = NEXT_INSN (update_end); update_end != insn;
+          update_end = NEXT_INSN (update_end))
+       {
+         set_block_for_insn (update_end, current_block);
+         if (INSN_P (update_end))
+           df_insn_rescan (update_end);
+       }
+      BB_END (current_block) = PREV_INSN (insn);
+    }
 }
 \f
 /* Print stack configuration.  */
 
 static void
-print_stack (FILE *file, stack s)
+print_stack (FILE *file, stack_ptr s)
 {
   if (! file)
     return;
@@ -2636,7 +2751,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);
@@ -2649,8 +2764,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;
@@ -2669,7 +2783,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);
@@ -2677,10 +2791,10 @@ convert_regs_exit (void)
   if (retvalue)
     {
       value_reg_low = REGNO (retvalue);
-      value_reg_high = END_HARD_REGNO (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
@@ -2702,8 +2816,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
@@ -2729,8 +2843,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;
 
@@ -2802,7 +2916,8 @@ compensate_edge (edge e)
     }
   else
     {
-      rtx seq, after;
+      rtx_insn *seq;
+      rtx_note *after;
 
       current_block = NULL;
       start_sequence ();
@@ -2833,8 +2948,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;
@@ -2856,14 +2971,9 @@ better_edge (edge e1, edge e2)
   if (!e1)
     return e2;
 
-  if (EDGE_FREQUENCY (e1) > EDGE_FREQUENCY (e2))
+  if (e1->count () > e2->count ())
     return e1;
-  if (EDGE_FREQUENCY (e1) < EDGE_FREQUENCY (e2))
-    return e2;
-
-  if (e1->count > e2->count)
-    return e1;
-  if (e1->count < e2->count)
+  if (e1->count () < e2->count ())
     return e2;
 
   /* Prefer critical edges to minimize inserting compensation code on
@@ -2885,7 +2995,7 @@ 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;
@@ -2941,14 +3051,13 @@ 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 (DEBUG_INSN_P (insn))
+      if (DEBUG_BIND_INSN_P (insn))
        {
          if (starting_stack_p)
            debug_insns_with_starting_stack++;
          else
            {
-             for_each_rtx (&PATTERN (insn), subst_stack_regs_in_debug_insn,
-                           &regstack);
+             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
@@ -2982,12 +3091,11 @@ convert_regs_1 (basic_block block)
       for (insn = BB_HEAD (block); debug_insns_with_starting_stack;
           insn = NEXT_INSN (insn))
        {
-         if (!DEBUG_INSN_P (insn))
+         if (!DEBUG_BIND_INSN_P (insn))
            continue;
 
          debug_insns_with_starting_stack--;
-         for_each_rtx (&PATTERN (insn), subst_stack_regs_in_debug_insn,
-                       &bi->stack_in);
+         subst_all_stack_regs_in_debug_insn (insn, &bi->stack_in);
        }
     }
 
@@ -3019,7 +3127,7 @@ 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);
        }
@@ -3070,7 +3178,7 @@ convert_regs_2 (basic_block block)
      is only processed after all its predecessors.  The number of predecessors
      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;
@@ -3130,19 +3238,19 @@ 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)
+  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);
 
@@ -3184,8 +3292,7 @@ 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.  */
@@ -3202,7 +3309,7 @@ reg_to_stack (void)
 
   /* 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;
@@ -3211,7 +3318,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'.  */
@@ -3230,14 +3337,10 @@ reg_to_stack (void)
   /* Create the replacement registers up front.  */
   for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
     {
-      enum machine_mode mode;
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_FLOAT);
-          mode != VOIDmode;
-          mode = GET_MODE_WIDER_MODE (mode))
+      machine_mode mode;
+      FOR_EACH_MODE_IN_CLASS (mode, MODE_FLOAT)
        FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
-      for (mode = GET_CLASS_NARROWEST_MODE (MODE_COMPLEX_FLOAT);
-          mode != VOIDmode;
-          mode = GET_MODE_WIDER_MODE (mode))
+      FOR_EACH_MODE_IN_CLASS (mode, MODE_COMPLEX_FLOAT)
        FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
     }
 
@@ -3258,14 +3361,14 @@ reg_to_stack (void)
       REAL_VALUE_TYPE r;
 
       real_nan (&r, "", 1, SFmode);
-      not_a_num = CONST_DOUBLE_FROM_REAL_VALUE (r, 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),
+  stack_regs_mentioned_data.create (max_uid + 1);
+  memset (stack_regs_mentioned_data.address (),
          0, sizeof (char) * (max_uid + 1));
 
   convert_regs ();
@@ -3275,34 +3378,47 @@ 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
 
-struct rtl_opt_pass pass_stack_regs =
+} // anon namespace
+
+rtl_opt_pass *
+make_pass_stack_regs (gcc::context *ctxt)
 {
- {
-  RTL_PASS,
-  "*stack_regs",                        /* 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 */
- }
-};
+  return new pass_stack_regs (ctxt);
+}
 
 /* Convert register usage from flat register file usage to a stack
    register file.  */
@@ -3316,23 +3432,40 @@ rest_of_handle_stack_regs (void)
   return 0;
 }
 
-struct rtl_opt_pass pass_stack_regs_run =
+namespace {
+
+const pass_data pass_data_stack_regs_run =
 {
- {
-  RTL_PASS,
-  "stack",                              /* name */
-  NULL,                                 /* 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_df_finish | TODO_verify_rtl_sharing |
-  TODO_dump_func |
-  TODO_ggc_collect                      /* todo_flags_finish */
- }
+  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);
+}