diff gcc/reg-stack.c @ 0:a06113de4d67

first commit
author kent <kent@cr.ie.u-ryukyu.ac.jp>
date Fri, 17 Jul 2009 14:47:48 +0900
parents
children 58ad6c70ea60
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/gcc/reg-stack.c	Fri Jul 17 14:47:48 2009 +0900
@@ -0,0 +1,3270 @@
+/* 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
+   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 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with 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.
+
+   * The form of the input:
+
+   On input, the function consists of insn that have had their
+   registers fully allocated to a set of "virtual" registers.  Note that
+   the word "virtual" is used differently here than elsewhere in gcc: for
+   each virtual stack reg, there is a hard reg, but the mapping between
+   them is not known until this pass is run.  On output, hard register
+   numbers have been substituted, and various pop and exchange insns have
+   been emitted.  The hard register numbers and the virtual register
+   numbers completely overlap - before this pass, all stack register
+   numbers are virtual, and afterward they are all hard.
+
+   The virtual registers can be manipulated normally by gcc, and their
+   semantics are the same as for normal registers.  After the hard
+   register numbers are substituted, the semantics of an insn containing
+   stack-like regs are not the same as for an insn with normal regs: for
+   instance, it is not safe to delete an insn that appears to be a no-op
+   move.  In general, no insn containing hard regs should be changed
+   after this pass is done.
+
+   * The form of the output:
+
+   After this pass, hard register numbers represent the distance from
+   the current top of stack to the desired register.  A reference to
+   FIRST_STACK_REG references the top of stack, FIRST_STACK_REG + 1,
+   represents the register just below that, and so forth.  Also, REG_DEAD
+   notes indicate whether or not a stack register should be popped.
+
+   A "swap" insn looks like a parallel of two patterns, where each
+   pattern is a SET: one sets A to B, the other B to A.
+
+   A "push" or "load" insn is a SET whose SET_DEST is FIRST_STACK_REG
+   and whose SET_DEST is REG or MEM.  Any other SET_DEST, such as PLUS,
+   will replace the existing stack top, not push a new value.
+
+   A store insn is a SET whose SET_DEST is FIRST_STACK_REG, and whose
+   SET_SRC is REG or MEM.
+
+   The case where the SET_SRC and SET_DEST are both FIRST_STACK_REG
+   appears ambiguous.  As a special case, the presence of a REG_DEAD note
+   for FIRST_STACK_REG differentiates between a load insn and a pop.
+
+   If a REG_DEAD is present, the insn represents a "pop" that discards
+   the top of the register stack.  If there is no REG_DEAD note, then the
+   insn represents a "dup" or a push of the current top of stack onto the
+   stack.
+
+   * Methodology:
+
+   Existing REG_DEAD and REG_UNUSED notes for stack registers are
+   deleted and recreated from scratch.  REG_DEAD is never created for a
+   SET_DEST, only REG_UNUSED.
+
+   * asm_operands:
+
+   There are several rules on the usage of stack-like regs in
+   asm_operands insns.  These rules apply only to the operands that are
+   stack-like regs:
+
+   1. Given a set of input regs that die in an asm_operands, it is
+      necessary to know which are implicitly popped by the asm, and
+      which must be explicitly popped by gcc.
+
+	An input reg that is implicitly popped by the asm must be
+	explicitly clobbered, unless it is constrained to match an
+	output operand.
+
+   2. For any input reg that is implicitly popped by an asm, it is
+      necessary to know how to adjust the stack to compensate for the pop.
+      If any non-popped input is closer to the top of the reg-stack than
+      the implicitly popped reg, it would not be possible to know what the
+      stack looked like - it's not clear how the rest of the stack "slides
+      up".
+
+	All implicitly popped input regs must be closer to the top of
+	the reg-stack than any input that is not implicitly popped.
+
+   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:
+
+		asm ("foo" : "=t" (a) : "f" (b));
+
+      This asm says that input B is not popped by the asm, and that
+      the asm pushes a result onto the reg-stack, i.e., the stack is one
+      deeper after the asm than it was before.  But, it is possible that
+      reload will think that it can use the same reg for both the input and
+      the output, if input B dies in this insn.
+
+	If any input operand uses the "f" constraint, all output reg
+	constraints must use the "&" earlyclobber.
+
+      The asm above would be written as
+
+		asm ("foo" : "=&t" (a) : "f" (b));
+
+   4. Some operands need to be in particular places on the stack.  All
+      output operands fall in this category - there is no other way to
+      know which regs the outputs appear in unless the user indicates
+      this in the constraints.
+
+	Output operands must specifically indicate which reg an output
+	appears in after an asm.  "=f" is not allowed: the operand
+	constraints must select a class with a single reg.
+
+   5. Output operands may not be "inserted" between existing stack regs.
+      Since no 387 opcode uses a read/write operand, all output operands
+      are dead before the asm_operands, and are pushed by the asm_operands.
+      It makes no sense to push anywhere but the top of the reg-stack.
+
+	Output operands must start at the top of the reg-stack: output
+	operands may not "skip" a reg.
+
+   6. Some asm statements may need extra stack space for internal
+      calculations.  This can be guaranteed by clobbering stack registers
+      unrelated to the inputs and outputs.
+
+   Here are a couple of reasonable asms to want to write.  This asm
+   takes one input, which is internally popped, and produces two outputs.
+
+	asm ("fsincos" : "=t" (cos), "=u" (sin) : "0" (inp));
+
+   This asm takes two inputs, which are popped by the fyl2xp1 opcode,
+   and replaces them with one output.  The user must code the "st(1)"
+   clobber for reg-stack.c to know that fyl2xp1 pops both inputs.
+
+	asm ("fyl2xp1" : "=t" (result) : "0" (x), "u" (y) : "st(1)");
+
+*/
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "tm_p.h"
+#include "function.h"
+#include "insn-config.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "flags.h"
+#include "toplev.h"
+#include "recog.h"
+#include "output.h"
+#include "basic-block.h"
+#include "cfglayout.h"
+#include "varray.h"
+#include "reload.h"
+#include "ggc.h"
+#include "timevar.h"
+#include "tree-pass.h"
+#include "target.h"
+#include "df.h"
+#include "vecprim.h"
+
+#ifdef STACK_REGS
+
+/* We use this array to cache info about insns, because otherwise we
+   spend too much time in stack_regs_mentioned_p.
+
+   Indexed by insn UIDs.  A value of zero is uninitialized, one indicates
+   the insn uses stack registers, two indicates the insn does not use
+   stack registers.  */
+static VEC(char,heap) *stack_regs_mentioned_data;
+
+#define REG_STACK_SIZE (LAST_STACK_REG - FIRST_STACK_REG + 1)
+
+int regstack_completed = 0;
+
+/* This is the basic stack record.  TOP is an index into REG[] such
+   that REG[TOP] is the top of stack.  If TOP is -1 the stack is empty.
+
+   If TOP is -2, REG[] is not yet initialized.  Stack initialization
+   consists of placing each live reg in array `reg' and setting `top'
+   appropriately.
+
+   REG_SET indicates which registers are live.  */
+
+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;
+
+/* This is used to carry information about basic blocks.  It is
+   attached to the AUX field of the standard CFG block.  */
+
+typedef struct block_info_def
+{
+  struct stack_def stack_in;	/* Input stack configuration.  */
+  struct stack_def stack_out;	/* Output stack configuration.  */
+  HARD_REG_SET out_reg_set;	/* Stack regs live on output.  */
+  int done;			/* True if block already converted.  */
+  int predecessors;		/* Number of predecessors that need
+				   to be visited.  */
+} *block_info;
+
+#define BLOCK_INFO(B)	((block_info) (B)->aux)
+
+/* Passed to change_stack to indicate where to emit insns.  */
+enum emit_where
+{
+  EMIT_AFTER,
+  EMIT_BEFORE
+};
+
+/* The block we're currently working on.  */
+static basic_block current_block;
+
+/* In the current_block, whether we're processing the first register
+   stack or call instruction, i.e. the regstack is currently the
+   same as BLOCK_INFO(current_block)->stack_in.  */
+static bool starting_stack_p;
+
+/* This is the register file for all register after conversion.  */
+static rtx
+  FP_mode_reg[LAST_STACK_REG+1-FIRST_STACK_REG][(int) MAX_MACHINE_MODE];
+
+#define FP_MODE_REG(regno,mode)	\
+  (FP_mode_reg[(regno)-FIRST_STACK_REG][(int) (mode)])
+
+/* Used to initialize uninitialized registers.  */
+static rtx not_a_num;
+
+/* Forward declarations */
+
+static int stack_regs_mentioned_p (const_rtx pat);
+static void pop_stack (stack, int);
+static rtx *get_true_reg (rtx *);
+
+static int check_asm_stack_operands (rtx);
+static int get_asm_operand_n_inputs (rtx);
+static rtx stack_result (tree);
+static void replace_reg (rtx *, int);
+static void remove_regno_note (rtx, enum reg_note, unsigned int);
+static int get_hard_regnum (stack, rtx);
+static rtx emit_pop_insn (rtx, stack, rtx, enum emit_where);
+static void 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 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);
+
+/* Return nonzero if any stack register is mentioned somewhere within PAT.  */
+
+static int
+stack_regs_mentioned_p (const_rtx pat)
+{
+  const char *fmt;
+  int i;
+
+  if (STACK_REG_P (pat))
+    return 1;
+
+  fmt = GET_RTX_FORMAT (GET_CODE (pat));
+  for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+	{
+	  int j;
+
+	  for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+	    if (stack_regs_mentioned_p (XVECEXP (pat, i, j)))
+	      return 1;
+	}
+      else if (fmt[i] == 'e' && stack_regs_mentioned_p (XEXP (pat, i)))
+	return 1;
+    }
+
+  return 0;
+}
+
+/* Return nonzero if INSN mentions stacked registers, else return zero.  */
+
+int
+stack_regs_mentioned (const_rtx insn)
+{
+  unsigned int uid, max;
+  int test;
+
+  if (! INSN_P (insn) || !stack_regs_mentioned_data)
+    return 0;
+
+  uid = INSN_UID (insn);
+  max = VEC_length (char, stack_regs_mentioned_data);
+  if (uid >= max)
+    {
+      /* Allocate some extra size to avoid too many reallocs, but
+	 do not grow too quickly.  */
+      max = uid + uid / 20 + 1;
+      VEC_safe_grow_cleared (char, heap, stack_regs_mentioned_data, max);
+    }
+
+  test = VEC_index (char, stack_regs_mentioned_data, uid);
+  if (test == 0)
+    {
+      /* This insn has yet to be examined.  Do so now.  */
+      test = stack_regs_mentioned_p (PATTERN (insn)) ? 1 : 2;
+      VEC_replace (char, stack_regs_mentioned_data, uid, test);
+    }
+
+  return test == 1;
+}
+
+static rtx ix86_flags_rtx;
+
+static rtx
+next_flags_user (rtx insn)
+{
+  /* Search forward looking for the first use of this value.
+     Stop at block boundaries.  */
+
+  while (insn != BB_END (current_block))
+    {
+      insn = NEXT_INSN (insn);
+
+      if (INSN_P (insn) && reg_mentioned_p (ix86_flags_rtx, PATTERN (insn)))
+	return insn;
+
+      if (CALL_P (insn))
+	return NULL_RTX;
+    }
+  return NULL_RTX;
+}
+
+/* Reorganize the stack into ascending numbers, before this insn.  */
+
+static void
+straighten_stack (rtx insn, stack regstack)
+{
+  struct stack_def temp_stack;
+  int top;
+
+  /* If there is only a single register on the stack, then the stack is
+     already in increasing order and no reorganization is needed.
+
+     Similarly if the stack is empty.  */
+  if (regstack->top <= 0)
+    return;
+
+  COPY_HARD_REG_SET (temp_stack.reg_set, regstack->reg_set);
+
+  for (top = temp_stack.top = regstack->top; top >= 0; top--)
+    temp_stack.reg[top] = FIRST_STACK_REG + temp_stack.top - top;
+
+  change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
+}
+
+/* Pop a register from the stack.  */
+
+static void
+pop_stack (stack regstack, int regno)
+{
+  int top = regstack->top;
+
+  CLEAR_HARD_REG_BIT (regstack->reg_set, regno);
+  regstack->top--;
+  /* If regno was not at the top of stack then adjust stack.  */
+  if (regstack->reg [top] != regno)
+    {
+      int i;
+      for (i = regstack->top; i >= 0; i--)
+	if (regstack->reg [i] == regno)
+	  {
+	    int j;
+	    for (j = i; j < top; j++)
+	      regstack->reg [j] = regstack->reg [j + 1];
+	    break;
+	  }
+    }
+}
+
+/* Return a pointer to the REG expression within PAT.  If PAT is not a
+   REG, possible enclosed by a conversion rtx, return the inner part of
+   PAT that stopped the search.  */
+
+static rtx *
+get_true_reg (rtx *pat)
+{
+  for (;;)
+    switch (GET_CODE (*pat))
+      {
+      case SUBREG:
+	/* Eliminate FP subregister accesses in favor of the
+	   actual FP register in use.  */
+	{
+	  rtx subreg;
+	  if (FP_REG_P (subreg = SUBREG_REG (*pat)))
+	    {
+	      int regno_off = subreg_regno_offset (REGNO (subreg),
+						   GET_MODE (subreg),
+						   SUBREG_BYTE (*pat),
+						   GET_MODE (*pat));
+	      *pat = FP_MODE_REG (REGNO (subreg) + regno_off,
+				  GET_MODE (subreg));
+	      return pat;
+	    }
+	}
+      case FLOAT:
+      case FIX:
+      case FLOAT_EXTEND:
+	pat = & XEXP (*pat, 0);
+	break;
+
+      case UNSPEC:
+	if (XINT (*pat, 1) == UNSPEC_TRUNC_NOOP)
+	  pat = & XVECEXP (*pat, 0, 0);
+	return pat;
+
+      case FLOAT_TRUNCATE:
+	if (!flag_unsafe_math_optimizations)
+	  return pat;
+	pat = & XEXP (*pat, 0);
+	break;
+
+      default:
+	return pat;
+      }
+}
+
+/* Set if we find any malformed asms in a block.  */
+static bool any_malformed_asm;
+
+/* There are many rules that an asm statement for stack-like regs must
+   follow.  Those rules are explained at the top of this file: the rule
+   numbers below refer to that explanation.  */
+
+static int
+check_asm_stack_operands (rtx insn)
+{
+  int i;
+  int n_clobbers;
+  int malformed_asm = 0;
+  rtx body = PATTERN (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;
+
+  preprocess_constraints ();
+
+  n_inputs = get_asm_operand_n_inputs (body);
+  n_outputs = recog_data.n_operands - n_inputs;
+
+  if (alt < 0)
+    {
+      malformed_asm = 1;
+      /* Avoid further trouble with this insn.  */
+      PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
+      return 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
+	&& REG_P (SUBREG_REG (recog_data.operand[i])))
+      recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
+
+  /* Set up CLOBBER_REG.  */
+
+  n_clobbers = 0;
+
+  if (GET_CODE (body) == PARALLEL)
+    {
+      clobber_reg = XALLOCAVEC (rtx, XVECLEN (body, 0));
+
+      for (i = 0; i < XVECLEN (body, 0); i++)
+	if (GET_CODE (XVECEXP (body, 0, i)) == CLOBBER)
+	  {
+	    rtx clobber = XVECEXP (body, 0, i);
+	    rtx reg = XEXP (clobber, 0);
+
+	    if (GET_CODE (reg) == SUBREG && REG_P (SUBREG_REG (reg)))
+	      reg = SUBREG_REG (reg);
+
+	    if (STACK_REG_P (reg))
+	      {
+		clobber_reg[n_clobbers] = reg;
+		n_clobbers++;
+	      }
+	  }
+    }
+
+  /* Enforce rule #4: Output operands must specifically indicate which
+     reg an output appears in after an asm.  "=f" is not allowed: the
+     operand constraints must select a class with a single reg.
+
+     Also enforce rule #5: Output operands must start at the top of
+     the reg-stack: output operands may not "skip" a reg.  */
+
+  memset (reg_used_as_output, 0, sizeof (reg_used_as_output));
+  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)
+	  {
+	    error_for_asm (insn, "output constraint %d must specify a single register", i);
+	    malformed_asm = 1;
+	  }
+	else
+	  {
+	    int j;
+
+	    for (j = 0; j < n_clobbers; j++)
+	      if (REGNO (recog_data.operand[i]) == REGNO (clobber_reg[j]))
+		{
+		  error_for_asm (insn, "output constraint %d cannot be specified together with \"%s\" clobber",
+				 i, reg_names [REGNO (clobber_reg[j])]);
+		  malformed_asm = 1;
+		  break;
+		}
+	    if (j == n_clobbers)
+	      reg_used_as_output[REGNO (recog_data.operand[i])] = 1;
+	  }
+      }
+
+
+  /* Search for first non-popped reg.  */
+  for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++)
+    if (! reg_used_as_output[i])
+      break;
+
+  /* If there are any other popped regs, that's an error.  */
+  for (; i < LAST_STACK_REG + 1; i++)
+    if (reg_used_as_output[i])
+      break;
+
+  if (i != LAST_STACK_REG + 1)
+    {
+      error_for_asm (insn, "output regs must be grouped at top of stack");
+      malformed_asm = 1;
+    }
+
+  /* Enforce rule #2: All implicitly popped input regs must be closer
+     to the top of the reg-stack than any input that is not implicitly
+     popped.  */
+
+  memset (implicitly_dies, 0, sizeof (implicitly_dies));
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_data.operand[i]))
+      {
+	/* An input reg is implicitly popped if it is tied to an
+	   output, or if there is a CLOBBER for it.  */
+	int j;
+
+	for (j = 0; j < n_clobbers; j++)
+	  if (operands_match_p (clobber_reg[j], recog_data.operand[i]))
+	    break;
+
+	if (j < n_clobbers || recog_op_alt[i][alt].matches >= 0)
+	  implicitly_dies[REGNO (recog_data.operand[i])] = 1;
+      }
+
+  /* Search for first non-popped reg.  */
+  for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++)
+    if (! implicitly_dies[i])
+      break;
+
+  /* If there are any other popped regs, that's an error.  */
+  for (; i < LAST_STACK_REG + 1; i++)
+    if (implicitly_dies[i])
+      break;
+
+  if (i != LAST_STACK_REG + 1)
+    {
+      error_for_asm (insn,
+		     "implicitly popped regs must be grouped at top of stack");
+      malformed_asm = 1;
+    }
+
+  /* Enforce rule #3: If any input operand uses the "f" constraint, all
+     output constraints must use the "&" earlyclobber.
+
+     ??? Detect this more deterministically by having constrain_asm_operands
+     record any earlyclobber.  */
+
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (recog_op_alt[i][alt].matches == -1)
+      {
+	int j;
+
+	for (j = 0; j < n_outputs; j++)
+	  if (operands_match_p (recog_data.operand[j], recog_data.operand[i]))
+	    {
+	      error_for_asm (insn,
+			     "output operand %d must use %<&%> constraint", j);
+	      malformed_asm = 1;
+	    }
+      }
+
+  if (malformed_asm)
+    {
+      /* Avoid further trouble with this insn.  */
+      PATTERN (insn) = gen_rtx_USE (VOIDmode, const0_rtx);
+      any_malformed_asm = true;
+      return 0;
+    }
+
+  return 1;
+}
+
+/* Calculate the number of inputs and outputs in BODY, an
+   asm_operands.  N_OPERANDS is the total number of operands, and
+   N_INPUTS and N_OUTPUTS are pointers to ints into which the results are
+   placed.  */
+
+static int
+get_asm_operand_n_inputs (rtx body)
+{
+  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 ();
+    }
+}
+
+/* If current function returns its result in an fp stack register,
+   return the REG.  Otherwise, return 0.  */
+
+static rtx
+stack_result (tree decl)
+{
+  rtx result;
+
+  /* If the value is supposed to be returned in memory, then clearly
+     it is not returned in a stack register.  */
+  if (aggregate_value_p (DECL_RESULT (decl), decl))
+    return 0;
+
+  result = DECL_RTL_IF_SET (DECL_RESULT (decl));
+  if (result != 0)
+    result = targetm.calls.function_value (TREE_TYPE (DECL_RESULT (decl)),
+					   decl, true);
+
+  return result != 0 && STACK_REG_P (result) ? result : 0;
+}
+
+
+/*
+ * This section deals with stack register substitution, and forms the second
+ * pass over the RTL.
+ */
+
+/* Replace REG, which is a pointer to a stack reg RTX, with an RTX for
+   the desired hard REGNO.  */
+
+static void
+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))
+	      || GET_MODE_CLASS (GET_MODE (*reg)) == MODE_COMPLEX_FLOAT);
+
+  *reg = FP_MODE_REG (regno, GET_MODE (*reg));
+}
+
+/* Remove a note of type NOTE, which must be found, for register
+   number REGNO from INSN.  Remove only one such note.  */
+
+static void
+remove_regno_note (rtx insn, enum reg_note note, unsigned int regno)
+{
+  rtx *note_link, this_rtx;
+
+  note_link = &REG_NOTES (insn);
+  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_rtx, 1);
+	return;
+      }
+    else
+      note_link = &XEXP (this_rtx, 1);
+
+  gcc_unreachable ();
+}
+
+/* Find the hard register number of virtual register REG in REGSTACK.
+   The hard register number is relative to the top of the stack.  -1 is
+   returned if the register is not found.  */
+
+static int
+get_hard_regnum (stack regstack, rtx reg)
+{
+  int i;
+
+  gcc_assert (STACK_REG_P (reg));
+
+  for (i = regstack->top; i >= 0; i--)
+    if (regstack->reg[i] == REGNO (reg))
+      break;
+
+  return i >= 0 ? (FIRST_STACK_REG + regstack->top - i) : -1;
+}
+
+/* Emit an insn to pop virtual register REG before or after INSN.
+   REGSTACK is the stack state after INSN and is updated to reflect this
+   pop.  WHEN is either emit_insn_before or emit_insn_after.  A pop insn
+   is represented as a SET whose destination is the register to be popped
+   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)
+{
+  rtx pop_insn, pop_rtx;
+  int hard_regno;
+
+  /* For complex types take care to pop both halves.  These may survive in
+     CLOBBER and USE expressions.  */
+  if (COMPLEX_MODE_P (GET_MODE (reg)))
+    {
+      rtx reg1 = FP_MODE_REG (REGNO (reg), DFmode);
+      rtx reg2 = FP_MODE_REG (REGNO (reg) + 1, DFmode);
+
+      pop_insn = NULL_RTX;
+      if (get_hard_regnum (regstack, reg1) >= 0)
+	pop_insn = emit_pop_insn (insn, regstack, reg1, where);
+      if (get_hard_regnum (regstack, reg2) >= 0)
+	pop_insn = emit_pop_insn (insn, regstack, reg2, where);
+      gcc_assert (pop_insn);
+      return pop_insn;
+    }
+
+  hard_regno = get_hard_regnum (regstack, reg);
+
+  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));
+
+  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));
+
+  regstack->reg[regstack->top - (hard_regno - FIRST_STACK_REG)]
+    = regstack->reg[regstack->top];
+  regstack->top -= 1;
+  CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (reg));
+
+  return pop_insn;
+}
+
+/* Emit an insn before or after INSN to swap virtual register REG with
+   the top of stack.  REGSTACK is the stack state before the swap, and
+   is updated to reflect the swap.  A swap insn is represented as a
+   PARALLEL of two patterns: each pattern moves one reg to the other.
+
+   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)
+{
+  int hard_regno;
+  rtx swap_rtx;
+  int tmp, other_reg;		/* swap regno temps */
+  rtx i1;			/* the stack-reg insn prior to INSN */
+  rtx i1set = NULL_RTX;		/* the SET rtx within I1 */
+
+  hard_regno = get_hard_regnum (regstack, 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;
+
+  /* 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));
+      while (tmp != limit)
+	{
+	  if (LABEL_P (tmp)
+	      || CALL_P (tmp)
+	      || NOTE_INSN_BASIC_BLOCK_P (tmp)
+	      || (NONJUMP_INSN_P (tmp)
+		  && stack_regs_mentioned (tmp)))
+	    {
+	      i1 = tmp;
+	      break;
+	    }
+	  tmp = PREV_INSN (tmp);
+	}
+    }
+
+  if (i1 != NULL_RTX
+      && (i1set = single_set (i1)) != NULL_RTX)
+    {
+      rtx i1src = *get_true_reg (&SET_SRC (i1set));
+      rtx i1dest = *get_true_reg (&SET_DEST (i1set));
+
+      /* If the previous register stack push was from the reg we are to
+	 swap with, omit the swap.  */
+
+      if (REG_P (i1dest) && REGNO (i1dest) == FIRST_STACK_REG
+	  && REG_P (i1src)
+	  && REGNO (i1src) == (unsigned) hard_regno - 1
+	  && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX)
+	return;
+
+      /* If the previous insn wrote to the reg we are to swap with,
+	 omit the swap.  */
+
+      if (REG_P (i1dest) && REGNO (i1dest) == (unsigned) hard_regno
+	  && REG_P (i1src) && REGNO (i1src) == FIRST_STACK_REG
+	  && find_regno_note (i1, REG_DEAD, FIRST_STACK_REG) == NULL_RTX)
+	return;
+    }
+
+  /* Avoid emitting the swap if this is the first register stack insn
+     of the current_block.  Instead update the current_block's stack_in
+     and let compensate edges take care of this for us.  */
+  if (current_block && starting_stack_p)
+    {
+      BLOCK_INFO (current_block)->stack_in = *regstack;
+      starting_stack_p = false;
+      return;
+    }
+
+  swap_rtx = gen_swapxf (FP_MODE_REG (hard_regno, XFmode),
+			 FP_MODE_REG (FIRST_STACK_REG, XFmode));
+
+  if (i1)
+    emit_insn_after (swap_rtx, i1);
+  else if (current_block)
+    emit_insn_before (swap_rtx, BB_HEAD (current_block));
+  else
+    emit_insn_before (swap_rtx, insn);
+}
+
+/* Emit an insns before INSN to swap virtual register SRC1 with
+   the top of stack and virtual register SRC2 with second stack
+   slot. REGSTACK is the stack state before the swaps, and
+   is updated to reflect the swaps.  A swap insn is represented as a
+   PARALLEL of two patterns: each pattern moves one reg to the other.
+
+   If SRC1 and/or SRC2 are already at the right place, no swap insn
+   is emitted.  */
+
+static void
+swap_to_top (rtx insn, stack regstack, rtx src1, rtx src2)
+{
+  struct stack_def temp_stack;
+  int regno, j, k, temp;
+
+  temp_stack = *regstack;
+
+  /* Place operand 1 at the top of stack.  */
+  regno = get_hard_regnum (&temp_stack, src1);
+  gcc_assert (regno >= 0);
+  if (regno != FIRST_STACK_REG)
+    {
+      k = temp_stack.top - (regno - FIRST_STACK_REG);
+      j = temp_stack.top;
+
+      temp = temp_stack.reg[k];
+      temp_stack.reg[k] = temp_stack.reg[j];
+      temp_stack.reg[j] = temp;
+    }
+
+  /* Place operand 2 next on the stack.  */
+  regno = get_hard_regnum (&temp_stack, src2);
+  gcc_assert (regno >= 0);
+  if (regno != FIRST_STACK_REG + 1)
+    {
+      k = temp_stack.top - (regno - FIRST_STACK_REG);
+      j = temp_stack.top - 1;
+
+      temp = temp_stack.reg[k];
+      temp_stack.reg[k] = temp_stack.reg[j];
+      temp_stack.reg[j] = temp;
+    }
+
+  change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
+}
+
+/* Handle a move to or from a stack register in PAT, which is in INSN.
+   REGSTACK is the current stack.  Return whether a control flow insn
+   was deleted in the process.  */
+
+static bool
+move_for_stack_reg (rtx insn, stack regstack, rtx pat)
+{
+  rtx *psrc =  get_true_reg (&SET_SRC (pat));
+  rtx *pdest = get_true_reg (&SET_DEST (pat));
+  rtx src, dest;
+  rtx note;
+  bool control_flow_insn_deleted = false;
+
+  src = *psrc; dest = *pdest;
+
+  if (STACK_REG_P (src) && STACK_REG_P (dest))
+    {
+      /* Write from one stack reg to another.  If SRC dies here, then
+	 just change the register mapping and delete the insn.  */
+
+      note = find_regno_note (insn, REG_DEAD, REGNO (src));
+      if (note)
+	{
+	  int i;
+
+	  /* If this is a no-op move, there must not be a REG_DEAD note.  */
+	  gcc_assert (REGNO (src) != REGNO (dest));
+
+	  for (i = regstack->top; i >= 0; i--)
+	    if (regstack->reg[i] == REGNO (src))
+	      break;
+
+	  /* The destination must be dead, or life analysis is borked.  */
+	  gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
+
+	  /* If the source is not live, this is yet another case of
+	     uninitialized variables.  Load up a NaN instead.  */
+	  if (i < 0)
+	    return move_nan_for_stack_reg (insn, regstack, dest);
+
+	  /* It is possible that the dest is unused after this insn.
+	     If so, just pop the src.  */
+
+	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
+	    emit_pop_insn (insn, regstack, src, EMIT_AFTER);
+	  else
+	    {
+	      regstack->reg[i] = REGNO (dest);
+	      SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+	      CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
+	    }
+
+	  control_flow_insn_deleted |= control_flow_insn_p (insn);
+	  delete_insn (insn);
+	  return control_flow_insn_deleted;
+	}
+
+      /* The source reg does not die.  */
+
+      /* If this appears to be a no-op move, delete it, or else it
+	 will confuse the machine description output patterns. But if
+	 it is REG_UNUSED, we must pop the reg now, as per-insn processing
+	 for REG_UNUSED will not work for deleted insns.  */
+
+      if (REGNO (src) == REGNO (dest))
+	{
+	  if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
+	    emit_pop_insn (insn, regstack, dest, EMIT_AFTER);
+
+	  control_flow_insn_deleted |= control_flow_insn_p (insn);
+	  delete_insn (insn);
+	  return control_flow_insn_deleted;
+	}
+
+      /* The destination ought to be dead.  */
+      gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
+
+      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);
+    }
+  else if (STACK_REG_P (src))
+    {
+      /* Save from a stack reg to MEM, or possibly integer reg.  Since
+	 only top of stack may be saved, emit an exchange first if
+	 needs be.  */
+
+      emit_swap_insn (insn, regstack, src);
+
+      note = find_regno_note (insn, REG_DEAD, REGNO (src));
+      if (note)
+	{
+	  replace_reg (&XEXP (note, 0), FIRST_STACK_REG);
+	  regstack->top--;
+	  CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (src));
+	}
+      else if ((GET_MODE (src) == XFmode)
+	       && regstack->top < REG_STACK_SIZE - 1)
+	{
+	  /* A 387 cannot write an XFmode value to a MEM without
+	     clobbering the source reg.  The output code can handle
+	     this by reading back the value from the MEM.
+	     But it is more efficient to use a temp register if one is
+	     available.  Push the source value here if the register
+	     stack is not full, and then write the value to memory via
+	     a pop.  */
+	  rtx push_rtx;
+	  rtx top_stack_reg = FP_MODE_REG (FIRST_STACK_REG, GET_MODE (src));
+
+	  push_rtx = gen_movxf (top_stack_reg, top_stack_reg);
+	  emit_insn_before (push_rtx, insn);
+	  add_reg_note (insn, REG_DEAD, top_stack_reg);
+	}
+
+      replace_reg (psrc, FIRST_STACK_REG);
+    }
+  else
+    {
+      rtx pat = PATTERN (insn);
+
+      gcc_assert (STACK_REG_P (dest));
+
+      /* Load from MEM, or possibly integer REG or constant, into the
+	 stack regs.  The actual target is always the top of the
+	 stack. The stack mapping is changed to reflect that DEST is
+	 now at top of stack.  */
+
+      /* The destination ought to be dead.  However, there is a
+	 special case with i387 UNSPEC_TAN, where destination is live
+	 (an argument to fptan) but inherent load of 1.0 is modelled
+	 as a load from a constant.  */
+      if (GET_CODE (pat) == PARALLEL
+	  && XVECLEN (pat, 0) == 2
+	  && GET_CODE (XVECEXP (pat, 0, 1)) == SET
+	  && GET_CODE (SET_SRC (XVECEXP (pat, 0, 1))) == UNSPEC
+	  && XINT (SET_SRC (XVECEXP (pat, 0, 1)), 1) == UNSPEC_TAN)
+	emit_swap_insn (insn, regstack, dest);
+      else
+	gcc_assert (get_hard_regnum (regstack, dest) < FIRST_STACK_REG);
+
+      gcc_assert (regstack->top < REG_STACK_SIZE);
+
+      regstack->reg[++regstack->top] = REGNO (dest);
+      SET_HARD_REG_BIT (regstack->reg_set, REGNO (dest));
+      replace_reg (pdest, FIRST_STACK_REG);
+    }
+
+  return control_flow_insn_deleted;
+}
+
+/* A helper function which replaces INSN with a pattern that loads up
+   a NaN into DEST, then invokes move_for_stack_reg.  */
+
+static bool
+move_nan_for_stack_reg (rtx insn, stack regstack, rtx dest)
+{
+  rtx pat;
+
+  dest = FP_MODE_REG (REGNO (dest), SFmode);
+  pat = gen_rtx_SET (VOIDmode, dest, not_a_num);
+  PATTERN (insn) = pat;
+  INSN_CODE (insn) = -1;
+
+  return move_for_stack_reg (insn, regstack, pat);
+}
+
+/* Swap the condition on a branch, if there is one.  Return true if we
+   found a condition to swap.  False if the condition was not used as
+   such.  */
+
+static int
+swap_rtx_condition_1 (rtx pat)
+{
+  const char *fmt;
+  int i, r = 0;
+
+  if (COMPARISON_P (pat))
+    {
+      PUT_CODE (pat, swap_condition (GET_CODE (pat)));
+      r = 1;
+    }
+  else
+    {
+      fmt = GET_RTX_FORMAT (GET_CODE (pat));
+      for (i = GET_RTX_LENGTH (GET_CODE (pat)) - 1; i >= 0; i--)
+	{
+	  if (fmt[i] == 'E')
+	    {
+	      int j;
+
+	      for (j = XVECLEN (pat, i) - 1; j >= 0; j--)
+		r |= swap_rtx_condition_1 (XVECEXP (pat, i, j));
+	    }
+	  else if (fmt[i] == 'e')
+	    r |= swap_rtx_condition_1 (XEXP (pat, i));
+	}
+    }
+
+  return r;
+}
+
+static int
+swap_rtx_condition (rtx insn)
+{
+  rtx pat = PATTERN (insn);
+
+  /* We're looking for a single set to cc0 or an HImode temporary.  */
+
+  if (GET_CODE (pat) == SET
+      && REG_P (SET_DEST (pat))
+      && REGNO (SET_DEST (pat)) == FLAGS_REG)
+    {
+      insn = next_flags_user (insn);
+      if (insn == NULL_RTX)
+	return 0;
+      pat = PATTERN (insn);
+    }
+
+  /* See if this is, or ends in, a fnstsw.  If so, we're not doing anything
+     with the cc value right now.  We may be able to search for one
+     though.  */
+
+  if (GET_CODE (pat) == SET
+      && GET_CODE (SET_SRC (pat)) == UNSPEC
+      && XINT (SET_SRC (pat), 1) == UNSPEC_FNSTSW)
+    {
+      rtx dest = SET_DEST (pat);
+
+      /* Search forward looking for the first use of this value.
+	 Stop at block boundaries.  */
+      while (insn != BB_END (current_block))
+	{
+	  insn = NEXT_INSN (insn);
+	  if (INSN_P (insn) && reg_mentioned_p (dest, insn))
+	    break;
+	  if (CALL_P (insn))
+	    return 0;
+	}
+
+      /* We haven't found it.  */
+      if (insn == BB_END (current_block))
+	return 0;
+
+      /* So we've found the insn using this value.  If it is anything
+	 other than sahf or the value does not die (meaning we'd have
+	 to search further), then we must give up.  */
+      pat = PATTERN (insn);
+      if (GET_CODE (pat) != SET
+	  || GET_CODE (SET_SRC (pat)) != UNSPEC
+	  || XINT (SET_SRC (pat), 1) != UNSPEC_SAHF
+	  || ! dead_or_set_p (insn, dest))
+	return 0;
+
+      /* Now we are prepared to handle this as a normal cc0 setter.  */
+      insn = next_flags_user (insn);
+      if (insn == NULL_RTX)
+	return 0;
+      pat = PATTERN (insn);
+    }
+
+  if (swap_rtx_condition_1 (pat))
+    {
+      int fail = 0;
+      INSN_CODE (insn) = -1;
+      if (recog_memoized (insn) == -1)
+	fail = 1;
+      /* In case the flags don't die here, recurse to try fix
+         following user too.  */
+      else if (! dead_or_set_p (insn, ix86_flags_rtx))
+	{
+	  insn = next_flags_user (insn);
+	  if (!insn || !swap_rtx_condition (insn))
+	    fail = 1;
+	}
+      if (fail)
+	{
+	  swap_rtx_condition_1 (pat);
+	  return 0;
+	}
+      return 1;
+    }
+  return 0;
+}
+
+/* Handle a comparison.  Special care needs to be taken to avoid
+   causing comparisons that a 387 cannot do correctly, such as EQ.
+
+   Also, a pop insn may need to be emitted.  The 387 does have an
+   `fcompp' insn that can pop two regs, but it is sometimes too expensive
+   to do this - a `fcomp' followed by a `fstpl %st(0)' may be easier to
+   set up.  */
+
+static void
+compare_for_stack_reg (rtx insn, stack regstack, rtx pat_src)
+{
+  rtx *src1, *src2;
+  rtx src1_note, src2_note;
+
+  src1 = get_true_reg (&XEXP (pat_src, 0));
+  src2 = get_true_reg (&XEXP (pat_src, 1));
+
+  /* ??? If fxch turns out to be cheaper than fstp, give priority to
+     registers that die in this insn - move those to stack top first.  */
+  if ((! STACK_REG_P (*src1)
+       || (STACK_REG_P (*src2)
+	   && 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;
+
+      src1 = get_true_reg (&XEXP (pat_src, 0));
+      src2 = get_true_reg (&XEXP (pat_src, 1));
+
+      INSN_CODE (insn) = -1;
+    }
+
+  /* We will fix any death note later.  */
+
+  src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+  if (STACK_REG_P (*src2))
+    src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+  else
+    src2_note = NULL_RTX;
+
+  emit_swap_insn (insn, regstack, *src1);
+
+  replace_reg (src1, FIRST_STACK_REG);
+
+  if (STACK_REG_P (*src2))
+    replace_reg (src2, get_hard_regnum (regstack, *src2));
+
+  if (src1_note)
+    {
+      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
+     the same stack register, don't bother, because only one death is
+     needed, and it was just handled.  */
+
+  if (src2_note
+      && ! (STACK_REG_P (*src1) && STACK_REG_P (*src2)
+	    && REGNO (*src1) == REGNO (*src2)))
+    {
+      /* As a special case, two regs may die in this insn if src2 is
+	 next to top of stack and the top of stack also dies.  Since
+	 we have already popped src1, "next to top of stack" is really
+	 at top (FIRST_STACK_REG) now.  */
+
+      if (get_hard_regnum (regstack, XEXP (src2_note, 0)) == FIRST_STACK_REG
+	  && src1_note)
+	{
+	  pop_stack (regstack, REGNO (XEXP (src2_note, 0)));
+	  replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
+	}
+      else
+	{
+	  /* 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);
+	}
+    }
+}
+
+/* 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)
+{
+  rtx *dest, *src;
+  bool control_flow_insn_deleted = false;
+
+  switch (GET_CODE (pat))
+    {
+    case USE:
+      /* Deaths in USE insns can happen in non optimizing compilation.
+	 Handle them by popping the dying register.  */
+      src = get_true_reg (&XEXP (pat, 0));
+      if (STACK_REG_P (*src)
+	  && find_regno_note (insn, REG_DEAD, REGNO (*src)))
+	{
+	  /* 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 might happen for functions returning uninitialized
+         value.  We will properly initialize the USE on the edge to EXIT_BLOCK,
+	 so it is safe to ignore the use here. This is consistent with behavior
+	 of dataflow analyzer that ignores USE too.  (This also imply that 
+	 forcibly initializing the register to NaN here would lead to ICE later,
+	 since the REG_DEAD notes are not issued.)  */
+      break;
+
+    case CLOBBER:
+      {
+	rtx note;
+
+	dest = get_true_reg (&XEXP (pat, 0));
+	if (STACK_REG_P (*dest))
+	  {
+	    note = find_reg_note (insn, REG_DEAD, *dest);
+
+	    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.  */
+
+		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);
+		replace_reg (dest, FIRST_STACK_REG + 1);
+	      }
+	    else
+	      {
+		/* A top-level clobber with no REG_DEAD, and no hard-regnum
+		   indicates an uninitialized value.  Because reload removed
+		   all other clobbers, this must be due to a function
+		   returning without a value.  Load up a NaN.  */
+
+		if (!note)
+		  {
+		    rtx t = *dest;
+		    if (COMPLEX_MODE_P (GET_MODE (t)))
+		      {
+			rtx u = FP_MODE_REG (REGNO (t) + 1, SFmode);
+			if (get_hard_regnum (regstack, u) == -1)
+			  {
+			    rtx pat2 = gen_rtx_CLOBBER (VOIDmode, u);
+			    rtx insn2 = emit_insn_before (pat2, insn);
+			    control_flow_insn_deleted
+			      |= move_nan_for_stack_reg (insn2, regstack, u);
+			  }
+		      }
+		    if (get_hard_regnum (regstack, t) == -1)
+		      control_flow_insn_deleted
+			|= move_nan_for_stack_reg (insn, regstack, t);
+		  }
+	      }
+	  }
+	break;
+      }
+
+    case SET:
+      {
+	rtx *src1 = (rtx *) 0, *src2;
+	rtx src1_note, src2_note;
+	rtx pat_src;
+
+	dest = get_true_reg (&SET_DEST (pat));
+	src  = get_true_reg (&SET_SRC (pat));
+	pat_src = SET_SRC (pat);
+
+	/* See if this is a `movM' pattern, and handle elsewhere if so.  */
+	if (STACK_REG_P (*src)
+	    || (STACK_REG_P (*dest)
+		&& (REG_P (*src) || MEM_P (*src)
+		    || GET_CODE (*src) == CONST_DOUBLE)))
+	  {
+	    control_flow_insn_deleted |= move_for_stack_reg (insn, regstack, pat);
+	    break;
+	  }
+
+	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;)
+		{
+		  regstack->reg[++regstack->top] = REGNO (*dest) + count;
+		  SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest) + count);
+		}
+	    }
+	    replace_reg (dest, FIRST_STACK_REG);
+	    break;
+
+	  case REG:
+	    /* This is a `tstM2' case.  */
+	    gcc_assert (*dest == cc0_rtx);
+	    src1 = src;
+
+	    /* Fall through.  */
+
+	  case FLOAT_TRUNCATE:
+	  case SQRT:
+	  case ABS:
+	  case NEG:
+	    /* These insns only operate on the top of the stack. DEST might
+	       be cc0_rtx if we're processing a tstM pattern. Also, it's
+	       possible that the tstM case results in a REG_DEAD note on the
+	       source.  */
+
+	    if (src1 == 0)
+	      src1 = get_true_reg (&XEXP (pat_src, 0));
+
+	    emit_swap_insn (insn, regstack, *src1);
+
+	    src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+	    if (STACK_REG_P (*dest))
+	      replace_reg (dest, FIRST_STACK_REG);
+
+	    if (src1_note)
+	      {
+		replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+		regstack->top--;
+		CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
+	      }
+
+	    replace_reg (src1, FIRST_STACK_REG);
+	    break;
+
+	  case MINUS:
+	  case DIV:
+	    /* On i386, reversed forms of subM3 and divM3 exist for
+	       MODE_FLOAT, so the same code that works for addM3 and mulM3
+	       can be used.  */
+	  case MULT:
+	  case PLUS:
+	    /* These insns can accept the top of stack as a destination
+	       from a stack reg or mem, or can use the top of stack as a
+	       source and some other stack register (possibly top of stack)
+	       as a destination.  */
+
+	    src1 = get_true_reg (&XEXP (pat_src, 0));
+	    src2 = get_true_reg (&XEXP (pat_src, 1));
+
+	    /* We will fix any death note later.  */
+
+	    if (STACK_REG_P (*src1))
+	      src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+	    else
+	      src1_note = NULL_RTX;
+	    if (STACK_REG_P (*src2))
+	      src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+	    else
+	      src2_note = NULL_RTX;
+
+	    /* If either operand is not a stack register, then the dest
+	       must be top of stack.  */
+
+	    if (! STACK_REG_P (*src1) || ! STACK_REG_P (*src2))
+	      emit_swap_insn (insn, regstack, *dest);
+	    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.  */
+
+		int src1_hard_regnum, src2_hard_regnum;
+
+		src1_hard_regnum = get_hard_regnum (regstack, *src1);
+		src2_hard_regnum = get_hard_regnum (regstack, *src2);
+
+		/* If the source is not live, this is yet another case of
+		   uninitialized variables.  Load up a NaN instead.  */
+		if (src1_hard_regnum == -1)
+		  {
+		    rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src1);
+		    rtx insn2 = emit_insn_before (pat2, insn);
+		    control_flow_insn_deleted
+		      |= move_nan_for_stack_reg (insn2, regstack, *src1);
+		  }
+		if (src2_hard_regnum == -1)
+		  {
+		    rtx pat2 = gen_rtx_CLOBBER (VOIDmode, *src2);
+		    rtx insn2 = emit_insn_before (pat2, insn);
+		    control_flow_insn_deleted
+		      |= move_nan_for_stack_reg (insn2, regstack, *src2);
+		  }
+
+		if (src1_hard_regnum != FIRST_STACK_REG
+		    && src2_hard_regnum != FIRST_STACK_REG)
+		  emit_swap_insn (insn, regstack, *dest);
+	      }
+
+	    if (STACK_REG_P (*src1))
+	      replace_reg (src1, get_hard_regnum (regstack, *src1));
+	    if (STACK_REG_P (*src2))
+	      replace_reg (src2, get_hard_regnum (regstack, *src2));
+
+	    if (src1_note)
+	      {
+		rtx src1_reg = XEXP (src1_note, 0);
+
+		/* If the register that dies is at the top of stack, then
+		   the destination is somewhere else - merely substitute it.
+		   But if the reg that dies is not at top of stack, then
+		   move the top of stack to the dead reg, as though we had
+		   done the insn and then a store-with-pop.  */
+
+		if (REGNO (src1_reg) == regstack->reg[regstack->top])
+		  {
+		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		    replace_reg (dest, get_hard_regnum (regstack, *dest));
+		  }
+		else
+		  {
+		    int regno = get_hard_regnum (regstack, src1_reg);
+
+		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		    replace_reg (dest, regno);
+
+		    regstack->reg[regstack->top - (regno - FIRST_STACK_REG)]
+		      = regstack->reg[regstack->top];
+		  }
+
+		CLEAR_HARD_REG_BIT (regstack->reg_set,
+				    REGNO (XEXP (src1_note, 0)));
+		replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+		regstack->top--;
+	      }
+	    else if (src2_note)
+	      {
+		rtx src2_reg = XEXP (src2_note, 0);
+		if (REGNO (src2_reg) == regstack->reg[regstack->top])
+		  {
+		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		    replace_reg (dest, get_hard_regnum (regstack, *dest));
+		  }
+		else
+		  {
+		    int regno = get_hard_regnum (regstack, src2_reg);
+
+		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		    replace_reg (dest, regno);
+
+		    regstack->reg[regstack->top - (regno - FIRST_STACK_REG)]
+		      = regstack->reg[regstack->top];
+		  }
+
+		CLEAR_HARD_REG_BIT (regstack->reg_set,
+				    REGNO (XEXP (src2_note, 0)));
+		replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG);
+		regstack->top--;
+	      }
+	    else
+	      {
+		SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		replace_reg (dest, get_hard_regnum (regstack, *dest));
+	      }
+
+	    /* Keep operand 1 matching with destination.  */
+	    if (COMMUTATIVE_ARITH_P (pat_src)
+		&& REG_P (*src1) && REG_P (*src2)
+		&& REGNO (*src1) != REGNO (*dest))
+	     {
+		int tmp = REGNO (*src1);
+		replace_reg (src1, REGNO (*src2));
+		replace_reg (src2, tmp);
+	     }
+	    break;
+
+	  case UNSPEC:
+	    switch (XINT (pat_src, 1))
+	      {
+	      case UNSPEC_FIST:
+
+	      case UNSPEC_FIST_FLOOR:
+	      case UNSPEC_FIST_CEIL:
+
+		/* These insns only operate on the top of the stack.  */
+
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+		emit_swap_insn (insn, regstack, *src1);
+
+		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+		if (STACK_REG_P (*dest))
+		  replace_reg (dest, FIRST_STACK_REG);
+
+		if (src1_note)
+		  {
+		    replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+		    regstack->top--;
+		    CLEAR_HARD_REG_BIT (regstack->reg_set, REGNO (*src1));
+		  }
+
+		replace_reg (src1, FIRST_STACK_REG);
+		break;
+
+	      case UNSPEC_FXAM:
+
+		/* This insn only operate on the top of the stack.  */
+
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+		emit_swap_insn (insn, regstack, *src1);
+
+		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+		replace_reg (src1, FIRST_STACK_REG);
+
+		if (src1_note)
+		  {
+		    remove_regno_note (insn, REG_DEAD,
+				       REGNO (XEXP (src1_note, 0)));
+		    emit_pop_insn (insn, regstack, XEXP (src1_note, 0),
+				   EMIT_AFTER);
+		  }
+
+		break;
+
+	      case UNSPEC_SIN:
+	      case UNSPEC_COS:
+	      case UNSPEC_FRNDINT:
+	      case UNSPEC_F2XM1:
+
+	      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.  */
+
+	      case UNSPEC_SINCOS_COS:
+	      case UNSPEC_XTRACT_FRACT:
+
+		/* Above insns operate on the top two stack slots,
+		   first part of one input, double output insn.  */
+
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+
+		emit_swap_insn (insn, regstack, *src1);
+
+		/* Input should never die, it is replaced with output.  */
+		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+		gcc_assert (!src1_note);
+
+		if (STACK_REG_P (*dest))
+		  replace_reg (dest, FIRST_STACK_REG);
+
+		replace_reg (src1, FIRST_STACK_REG);
+		break;
+
+	      case UNSPEC_SINCOS_SIN:
+	      case UNSPEC_XTRACT_EXP:
+
+		/* These insns operate on the top two stack slots,
+		   second part of one input, double output insn.  */
+
+		regstack->top++;
+		/* FALLTHRU */
+
+	      case UNSPEC_TAN:
+
+		/* For UNSPEC_TAN, regstack->top is already increased
+		   by inherent load of constant 1.0.  */
+
+		/* Output value is generated in the second stack slot.
+		   Move current value from second slot to the top.  */
+		regstack->reg[regstack->top]
+		  = regstack->reg[regstack->top - 1];
+
+		gcc_assert (STACK_REG_P (*dest));
+
+		regstack->reg[regstack->top - 1] = REGNO (*dest);
+		SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		replace_reg (dest, FIRST_STACK_REG + 1);
+
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+
+		replace_reg (src1, FIRST_STACK_REG);
+		break;
+
+	      case UNSPEC_FPATAN:
+	      case UNSPEC_FYL2X:
+	      case UNSPEC_FYL2XP1:
+		/* These insns operate on the top two stack slots.  */
+
+		src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+		src2 = get_true_reg (&XVECEXP (pat_src, 0, 1));
+
+		src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+		src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+
+		swap_to_top (insn, regstack, *src1, *src2);
+
+		replace_reg (src1, FIRST_STACK_REG);
+		replace_reg (src2, FIRST_STACK_REG + 1);
+
+		if (src1_note)
+		  replace_reg (&XEXP (src1_note, 0), FIRST_STACK_REG);
+		if (src2_note)
+		  replace_reg (&XEXP (src2_note, 0), FIRST_STACK_REG + 1);
+
+		/* Pop both input operands from the stack.  */
+		CLEAR_HARD_REG_BIT (regstack->reg_set,
+				    regstack->reg[regstack->top]);
+		CLEAR_HARD_REG_BIT (regstack->reg_set,
+				    regstack->reg[regstack->top - 1]);
+		regstack->top -= 2;
+
+		/* Push the result back onto the stack.  */
+		regstack->reg[++regstack->top] = REGNO (*dest);
+		SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		replace_reg (dest, FIRST_STACK_REG);
+		break;
+
+	      case UNSPEC_FSCALE_FRACT:
+	      case UNSPEC_FPREM_F:
+	      case UNSPEC_FPREM1_F:
+		/* 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));
+		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. Empty stack slot
+		   will be filled in second part of insn.  */
+		if (STACK_REG_P (*dest))
+		  {
+		    regstack->reg[regstack->top] = REGNO (*dest);
+		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		    replace_reg (dest, FIRST_STACK_REG);
+		  }
+
+		replace_reg (src1, FIRST_STACK_REG);
+		replace_reg (src2, FIRST_STACK_REG + 1);
+		break;
+
+	      case UNSPEC_FSCALE_EXP:
+	      case UNSPEC_FPREM_U:
+	      case UNSPEC_FPREM1_U:
+		/* 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));
+
+		/* Push the result back onto stack. Fill empty slot from
+		   first part of insn and fix top of stack pointer.  */
+		if (STACK_REG_P (*dest))
+		  {
+		    regstack->reg[regstack->top - 1] = REGNO (*dest);
+		    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+		    replace_reg (dest, FIRST_STACK_REG + 1);
+		  }
+
+		replace_reg (src1, FIRST_STACK_REG);
+		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.  */
+
+		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);
+
+		compare_for_stack_reg (insn, regstack, pat_src);
+		break;
+
+	      default:
+		gcc_unreachable ();
+	      }
+	    break;
+
+	  case IF_THEN_ELSE:
+	    /* This insn requires the top of stack to be the destination.  */
+
+	    src1 = get_true_reg (&XEXP (pat_src, 1));
+	    src2 = get_true_reg (&XEXP (pat_src, 2));
+
+	    src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+	    src2_note = find_regno_note (insn, REG_DEAD, REGNO (*src2));
+
+	    /* If the comparison operator is an FP comparison operator,
+	       it is handled correctly by compare_for_stack_reg () who
+	       will move the destination to the top of stack. But if the
+	       comparison operator is not an FP comparison operator, we
+	       have to handle it here.  */
+	    if (get_hard_regnum (regstack, *dest) >= FIRST_STACK_REG
+		&& REGNO (*dest) != regstack->reg[regstack->top])
+	      {
+		/* In case one of operands is the top of stack and the operands
+		   dies, it is safe to make it the destination operand by
+		   reversing the direction of cmove and avoid fxch.  */
+		if ((REGNO (*src1) == regstack->reg[regstack->top]
+		     && src1_note)
+		    || (REGNO (*src2) == regstack->reg[regstack->top]
+			&& src2_note))
+		  {
+		    int idx1 = (get_hard_regnum (regstack, *src1)
+				- FIRST_STACK_REG);
+		    int idx2 = (get_hard_regnum (regstack, *src2)
+				- FIRST_STACK_REG);
+
+		    /* Make reg-stack believe that the operands are already
+		       swapped on the stack */
+		    regstack->reg[regstack->top - idx1] = REGNO (*src2);
+		    regstack->reg[regstack->top - idx2] = REGNO (*src1);
+
+		    /* Reverse condition to compensate the operand swap.
+		       i386 do have comparison always reversible.  */
+		    PUT_CODE (XEXP (pat_src, 0),
+			      reversed_comparison_code (XEXP (pat_src, 0), insn));
+		  }
+		else
+	          emit_swap_insn (insn, regstack, *dest);
+	      }
+
+	    {
+	      rtx src_note [3];
+	      int i;
+
+	      src_note[0] = 0;
+	      src_note[1] = src1_note;
+	      src_note[2] = src2_note;
+
+	      if (STACK_REG_P (*src1))
+		replace_reg (src1, get_hard_regnum (regstack, *src1));
+	      if (STACK_REG_P (*src2))
+		replace_reg (src2, get_hard_regnum (regstack, *src2));
+
+	      for (i = 1; i <= 2; i++)
+		if (src_note [i])
+		  {
+		    int regno = REGNO (XEXP (src_note[i], 0));
+
+		    /* If the register that dies is not at the top of
+		       stack, then move the top of stack to the dead reg.
+		       Top of stack should never die, as it is the
+		       destination.  */
+		    gcc_assert (regno != regstack->reg[regstack->top]);
+		    remove_regno_note (insn, REG_DEAD, regno);
+		    emit_pop_insn (insn, regstack, XEXP (src_note[i], 0),
+				    EMIT_AFTER);
+		  }
+	    }
+
+	    /* Make dest the top of stack.  Add dest to regstack if
+	       not present.  */
+	    if (get_hard_regnum (regstack, *dest) < FIRST_STACK_REG)
+	      regstack->reg[++regstack->top] = REGNO (*dest);
+	    SET_HARD_REG_BIT (regstack->reg_set, REGNO (*dest));
+	    replace_reg (dest, FIRST_STACK_REG);
+	    break;
+
+	  default:
+	    gcc_unreachable ();
+	  }
+	break;
+      }
+
+    default:
+      break;
+    }
+
+  return control_flow_insn_deleted;
+}
+
+/* Substitute hard regnums for any stack regs in INSN, which has
+   N_INPUTS inputs and N_OUTPUTS outputs.  REGSTACK is the stack info
+   before the insn, and is updated with changes made here.
+
+   There are several requirements and assumptions about the use of
+   stack-like regs in asm statements.  These rules are enforced by
+   record_asm_stack_regs; see comments there for details.  Any
+   asm_operands left in the RTL at this point may be assume to meet the
+   requirements, since record_asm_stack_regs removes any problem asm.  */
+
+static void
+subst_asm_stack_regs (rtx insn, stack regstack)
+{
+  rtx body = PATTERN (insn);
+  int alt;
+
+  rtx *note_reg;		/* Array of note contents */
+  rtx **note_loc;		/* Address of REG field of each note */
+  enum reg_note *note_kind;	/* The type of each note */
+
+  rtx *clobber_reg = 0;
+  rtx **clobber_loc = 0;
+
+  struct stack_def temp_stack;
+  int n_notes;
+  int n_clobbers;
+  rtx note;
+  int i;
+  int n_inputs, n_outputs;
+
+  if (! check_asm_stack_operands (insn))
+    return;
+
+  /* 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;
+
+  preprocess_constraints ();
+
+  n_inputs = get_asm_operand_n_inputs (body);
+  n_outputs = recog_data.n_operands - 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
+	&& REG_P (SUBREG_REG (recog_data.operand[i])))
+      {
+	recog_data.operand_loc[i] = & SUBREG_REG (recog_data.operand[i]);
+	recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]);
+      }
+
+  /* Set up NOTE_REG, NOTE_LOC and NOTE_KIND.  */
+
+  for (i = 0, note = REG_NOTES (insn); note; note = XEXP (note, 1))
+    i++;
+
+  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))
+    {
+      rtx reg = XEXP (note, 0);
+      rtx *loc = & XEXP (note, 0);
+
+      if (GET_CODE (reg) == SUBREG && REG_P (SUBREG_REG (reg)))
+	{
+	  loc = & SUBREG_REG (reg);
+	  reg = SUBREG_REG (reg);
+	}
+
+      if (STACK_REG_P (reg)
+	  && (REG_NOTE_KIND (note) == REG_DEAD
+	      || REG_NOTE_KIND (note) == REG_UNUSED))
+	{
+	  note_reg[n_notes] = reg;
+	  note_loc[n_notes] = loc;
+	  note_kind[n_notes] = REG_NOTE_KIND (note);
+	  n_notes++;
+	}
+    }
+
+  /* Set up CLOBBER_REG and CLOBBER_LOC.  */
+
+  n_clobbers = 0;
+
+  if (GET_CODE (body) == PARALLEL)
+    {
+      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)
+	  {
+	    rtx clobber = XVECEXP (body, 0, i);
+	    rtx reg = XEXP (clobber, 0);
+	    rtx *loc = & XEXP (clobber, 0);
+
+	    if (GET_CODE (reg) == SUBREG && REG_P (SUBREG_REG (reg)))
+	      {
+		loc = & SUBREG_REG (reg);
+		reg = SUBREG_REG (reg);
+	      }
+
+	    if (STACK_REG_P (reg))
+	      {
+		clobber_reg[n_clobbers] = reg;
+		clobber_loc[n_clobbers] = loc;
+		n_clobbers++;
+	      }
+	  }
+    }
+
+  temp_stack = *regstack;
+
+  /* Put the input regs into the desired place in TEMP_STACK.  */
+
+  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)
+      {
+	/* If an operand needs to be in a particular reg in
+	   FLOAT_REGS, the constraint was either 't' or 'u'.  Since
+	   these constraints are for single register classes, and
+	   reload guaranteed that operand[i] is already in that class,
+	   we can just use REGNO (recog_data.operand[i]) to know which
+	   actual reg this operand needs to be in.  */
+
+	int regno = get_hard_regnum (&temp_stack, recog_data.operand[i]);
+
+	gcc_assert (regno >= 0);
+
+	if ((unsigned int) regno != REGNO (recog_data.operand[i]))
+	  {
+	    /* recog_data.operand[i] is not in the right place.  Find
+	       it and swap it with whatever is already in I's place.
+	       K is where recog_data.operand[i] is now.  J is where it
+	       should be.  */
+	    int j, k, temp;
+
+	    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;
+	  }
+      }
+
+  /* Emit insns before INSN to make sure the reg-stack is in the right
+     order.  */
+
+  change_stack (insn, regstack, &temp_stack, EMIT_BEFORE);
+
+  /* Make the needed input register substitutions.  Do death notes and
+     clobbers too, because these are for inputs, not outputs.  */
+
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_data.operand[i]))
+      {
+	int regnum = get_hard_regnum (regstack, recog_data.operand[i]);
+
+	gcc_assert (regnum >= 0);
+
+	replace_reg (recog_data.operand_loc[i], regnum);
+      }
+
+  for (i = 0; i < n_notes; i++)
+    if (note_kind[i] == REG_DEAD)
+      {
+	int regnum = get_hard_regnum (regstack, note_reg[i]);
+
+	gcc_assert (regnum >= 0);
+
+	replace_reg (note_loc[i], regnum);
+      }
+
+  for (i = 0; i < n_clobbers; i++)
+    {
+      /* It's OK for a CLOBBER to reference a reg that is not live.
+         Don't try to replace it in that case.  */
+      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);
+	}
+    }
+
+  /* Now remove from REGSTACK any inputs that the asm implicitly popped.  */
+
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_data.operand[i]))
+      {
+	/* An input reg is implicitly popped if it is tied to an
+	   output, or if there is a CLOBBER for it.  */
+	int j;
+
+	for (j = 0; j < n_clobbers; j++)
+	  if (operands_match_p (clobber_reg[j], recog_data.operand[i]))
+	    break;
+
+	if (j < n_clobbers || recog_op_alt[i][alt].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
+	       right number of regs off of the top of the reg-stack.
+	       record_asm_stack_regs guaranteed that all implicitly
+	       popped regs were grouped at the top of the reg-stack.  */
+
+	    CLEAR_HARD_REG_BIT (regstack->reg_set,
+				regstack->reg[regstack->top]);
+	    regstack->top--;
+	  }
+      }
+
+  /* Now add to REGSTACK any outputs that the asm implicitly pushed.
+     Note that there isn't any need to substitute register numbers.
+     ???  Explain why this is true.  */
+
+  for (i = LAST_STACK_REG; i >= FIRST_STACK_REG; i--)
+    {
+      /* See if there is an output for this hard reg.  */
+      int j;
+
+      for (j = 0; j < n_outputs; j++)
+	if (STACK_REG_P (recog_data.operand[j])
+	    && REGNO (recog_data.operand[j]) == (unsigned) i)
+	  {
+	    regstack->reg[++regstack->top] = i;
+	    SET_HARD_REG_BIT (regstack->reg_set, i);
+	    break;
+	  }
+    }
+
+  /* Now emit a pop insn for any REG_UNUSED output, or any REG_DEAD
+     input that the asm didn't implicitly pop.  If the asm didn't
+     implicitly pop an input reg, that reg will still be live.
+
+     Note that we can't use find_regno_note here: the register numbers
+     in the death notes have already been substituted.  */
+
+  for (i = 0; i < n_outputs; i++)
+    if (STACK_REG_P (recog_data.operand[i]))
+      {
+	int j;
+
+	for (j = 0; j < n_notes; j++)
+	  if (REGNO (recog_data.operand[i]) == REGNO (note_reg[j])
+	      && note_kind[j] == REG_UNUSED)
+	    {
+	      insn = emit_pop_insn (insn, regstack, recog_data.operand[i],
+				    EMIT_AFTER);
+	      break;
+	    }
+      }
+
+  for (i = n_outputs; i < n_outputs + n_inputs; i++)
+    if (STACK_REG_P (recog_data.operand[i]))
+      {
+	int j;
+
+	for (j = 0; j < n_notes; j++)
+	  if (REGNO (recog_data.operand[i]) == REGNO (note_reg[j])
+	      && note_kind[j] == REG_DEAD
+	      && TEST_HARD_REG_BIT (regstack->reg_set,
+				    REGNO (recog_data.operand[i])))
+	    {
+	      insn = emit_pop_insn (insn, regstack, recog_data.operand[i],
+				    EMIT_AFTER);
+	      break;
+	    }
+      }
+}
+
+/* Substitute stack hard reg numbers for stack virtual registers in
+   INSN.  Non-stack register numbers are not changed.  REGSTACK is the
+   current stack content.  Insns may be emitted as needed to arrange the
+   stack for the 387 based on the contents of the insn.  Return whether
+   a control flow insn was deleted in the process.  */
+
+static bool
+subst_stack_regs (rtx insn, stack regstack)
+{
+  rtx *note_link, note;
+  bool control_flow_insn_deleted = false;
+  int i;
+
+  if (CALL_P (insn))
+    {
+      int top = regstack->top;
+
+      /* If there are any floating point parameters to be passed in
+	 registers for this call, make sure they are in the right
+	 order.  */
+
+      if (top >= 0)
+	{
+	  straighten_stack (insn, regstack);
+
+	  /* Now mark the arguments as dead after the call.  */
+
+	  while (regstack->top >= 0)
+	    {
+	      CLEAR_HARD_REG_BIT (regstack->reg_set, FIRST_STACK_REG + regstack->top);
+	      regstack->top--;
+	    }
+	}
+    }
+
+  /* Do the actual substitution if any stack regs are mentioned.
+     Since we only record whether entire insn mentions stack regs, and
+     subst_stack_regs_pat only works for patterns that contain stack regs,
+     we must check each pattern in a parallel here.  A call_value_pop could
+     fail otherwise.  */
+
+  if (stack_regs_mentioned (insn))
+    {
+      int n_operands = asm_noperands (PATTERN (insn));
+      if (n_operands >= 0)
+	{
+	  /* This insn is an `asm' with operands.  Decode the operands,
+	     decide how many are inputs, and do register substitution.
+	     Any REG_UNUSED notes will be handled by subst_asm_stack_regs.  */
+
+	  subst_asm_stack_regs (insn, regstack);
+	  return control_flow_insn_deleted;
+	}
+
+      if (GET_CODE (PATTERN (insn)) == PARALLEL)
+	for (i = 0; i < XVECLEN (PATTERN (insn), 0); i++)
+	  {
+	    if (stack_regs_mentioned_p (XVECEXP (PATTERN (insn), 0, i)))
+	      {
+	        if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == CLOBBER)
+	           XVECEXP (PATTERN (insn), 0, i)
+		     = shallow_copy_rtx (XVECEXP (PATTERN (insn), 0, i));
+		control_flow_insn_deleted
+		  |= subst_stack_regs_pat (insn, regstack,
+					   XVECEXP (PATTERN (insn), 0, i));
+	      }
+	  }
+      else
+	control_flow_insn_deleted
+	  |= subst_stack_regs_pat (insn, regstack, PATTERN (insn));
+    }
+
+  /* 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))
+    return control_flow_insn_deleted;
+
+  /* If this a noreturn call, we can't insert pop insns after it.
+     Instead, reset the stack state to empty.  */
+  if (CALL_P (insn)
+      && find_reg_note (insn, REG_NORETURN, NULL))
+    {
+      regstack->top = -1;
+      CLEAR_HARD_REG_SET (regstack->reg_set);
+      return control_flow_insn_deleted;
+    }
+
+  /* If there is a REG_UNUSED note on a stack register on this insn,
+     the indicated reg must be popped.  The REG_UNUSED note is removed,
+     since the form of the newly emitted pop insn references the reg,
+     making it no longer `unset'.  */
+
+  note_link = &REG_NOTES (insn);
+  for (note = *note_link; note; note = XEXP (note, 1))
+    if (REG_NOTE_KIND (note) == REG_UNUSED && STACK_REG_P (XEXP (note, 0)))
+      {
+	*note_link = XEXP (note, 1);
+	insn = emit_pop_insn (insn, regstack, XEXP (note, 0), EMIT_AFTER);
+      }
+    else
+      note_link = &XEXP (note, 1);
+
+  return control_flow_insn_deleted;
+}
+
+/* Change the organization of the stack so that it fits a new basic
+   block.  Some registers might have to be popped, but there can never be
+   a register live in the new block that is not now live.
+
+   Insert any needed insns before or after INSN, as indicated by
+   WHERE.  OLD is the original stack layout, and NEW is the desired
+   form.  OLD is updated to reflect the code emitted, i.e., it will be
+   the same as NEW upon return.
+
+   This function will not preserve block_end[].  But that information
+   is no longer needed once this has executed.  */
+
+static void
+change_stack (rtx insn, stack old, stack new_stack, enum emit_where where)
+{
+  int reg;
+  int update_end = 0;
+  int i;
+
+  /* Stack adjustments for the first insn in a block update the
+     current_block's stack_in instead of inserting insns directly.
+     compensate_edges will add the necessary code later.  */
+  if (current_block
+      && starting_stack_p
+      && where == EMIT_BEFORE)
+    {
+      BLOCK_INFO (current_block)->stack_in = *new_stack;
+      starting_stack_p = false;
+      *old = *new_stack;
+      return;
+    }
+
+  /* We will be inserting new insns "backwards".  If we are to insert
+     after INSN, find the next insn, and insert before it.  */
+
+  if (where == EMIT_AFTER)
+    {
+      if (current_block && BB_END (current_block) == insn)
+	update_end = 1;
+      insn = NEXT_INSN (insn);
+    }
+
+  /* Initialize partially dead variables.  */
+  for (i = FIRST_STACK_REG; i < LAST_STACK_REG + 1; i++)
+    if (TEST_HARD_REG_BIT (new_stack->reg_set, i)
+	&& !TEST_HARD_REG_BIT (old->reg_set, i))
+      {
+	old->reg[++old->top] = i;
+        SET_HARD_REG_BIT (old->reg_set, i);
+	emit_insn_before (gen_rtx_SET (VOIDmode,
+				       FP_MODE_REG (i, SFmode), not_a_num), insn);
+      }
+
+  /* Pop any registers that are not needed in the new block.  */
+
+  /* If the destination block's stack already has a specified layout
+     and contains two or more registers, use a more intelligent algorithm
+     to pop registers that minimizes the number number of fxchs below.  */
+  if (new_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_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_stack->top; reg--)
+	if (TEST_HARD_REG_BIT (new_stack->reg_set, old->reg[reg]))
+	  {
+	    dest = -1;
+	    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_stack->top)
+		    topsrc = reg;
+		  slots[next] = true;
+		  dest = next;
+		  break;
+		}
+	    pops[reg] = dest;
+	  }
+	else
+	  pops[reg] = reg;
+
+      /* Intentionally, avoid placing the top of stack in it's correct
+	 location, if we still need to permute the stack below and we
+	 can usefully place it somewhere else.  This is the case if any
+	 slot is still unallocated, in which case we should place the
+	 top of stack there.  */
+      if (topsrc != -1)
+	for (reg = 0; reg < new_stack->top; reg++)
+	  if (!slots[reg])
+	    {
+	      pops[topsrc] = reg;
+	      slots[new_stack->top] = false;
+	      slots[reg] = true;
+	      break;
+	    }
+
+      /* Third pass allocates remaining slots and emits pop insns.  */
+      next = new_stack->top;
+      for (reg = old->top; reg > new_stack->top; reg--)
+	{
+	  dest = pops[reg];
+	  if (dest == -1)
+	    {
+	      /* Find next free slot.  */
+	      while (slots[next])
+		next--;
+	      dest = next--;
+	    }
+	  emit_pop_insn (insn, old, FP_MODE_REG (old->reg[dest], DFmode),
+			 EMIT_BEFORE);
+	}
+    }
+  else
+    {
+      /* The following loop attempts to maximize the number of times we
+	 pop the top of the stack, as this permits the use of the faster
+	 ffreep instruction on platforms that support it.  */
+      int live, next;
+
+      live = 0;
+      for (reg = 0; reg <= old->top; 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_stack->reg_set, old->reg[old->top]))
+	  {
+	    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);
+	  }
+	else
+	  emit_pop_insn (insn, old, FP_MODE_REG (old->reg[old->top], DFmode),
+			 EMIT_BEFORE);
+    }
+
+  if (new_stack->top == -2)
+    {
+      /* If the new block has never been processed, then it can inherit
+	 the old stack order.  */
+
+      new_stack->top = old->top;
+      memcpy (new_stack->reg, old->reg, sizeof (new_stack->reg));
+    }
+  else
+    {
+      /* This block has been entered before, and we must match the
+	 previously selected stack order.  */
+
+      /* By now, the only difference should be the order of the stack,
+	 not their depth or liveliness.  */
+
+      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_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
+	 depth of the stack.  In some cases, the reg at the top of
+	 stack may be correct, but swapped anyway in order to fix
+	 other regs.  But since we never swap any other reg away from
+	 its correct slot, this algorithm will converge.  */
+
+      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_stack->reg[new_stack->top])
+	      {
+		for (reg = new_stack->top; reg >= 0; reg--)
+		  if (new_stack->reg[reg] == old->reg[old->top])
+		    break;
+
+		gcc_assert (reg != -1);
+
+		emit_swap_insn (insn, old,
+				FP_MODE_REG (old->reg[reg], DFmode));
+	      }
+
+	    /* See if any regs remain incorrect.  If so, bring an
+	     incorrect reg to the top of stack, and let the while loop
+	     above fix it.  */
+
+	    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));
+		  break;
+		}
+	  } while (reg >= 0);
+
+      /* At this point there must be no differences.  */
+
+      for (reg = old->top; reg >= 0; reg--)
+	gcc_assert (old->reg[reg] == new_stack->reg[reg]);
+    }
+
+  if (update_end)
+    BB_END (current_block) = PREV_INSN (insn);
+}
+
+/* Print stack configuration.  */
+
+static void
+print_stack (FILE *file, stack s)
+{
+  if (! file)
+    return;
+
+  if (s->top == -2)
+    fprintf (file, "uninitialized\n");
+  else if (s->top == -1)
+    fprintf (file, "empty\n");
+  else
+    {
+      int i;
+      fputs ("[ ", file);
+      for (i = 0; i <= s->top; ++i)
+	fprintf (file, "%d ", s->reg[i]);
+      fputs ("]\n", file);
+    }
+}
+
+/* This function was doing life analysis.  We now let the regular live
+   code do it's job, so we only need to check some extra invariants
+   that reg-stack expects.  Primary among these being that all registers
+   are initialized before use.
+
+   The function returns true when code was emitted to CFG edges and
+   commit_edge_insertions needs to be called.  */
+
+static int
+convert_regs_entry (void)
+{
+  int inserted = 0;
+  edge e;
+  edge_iterator ei;
+
+  /* Load something into each stack register live at function entry.
+     Such live registers can be caused by uninitialized variables or
+     functions not returning values on all paths.  In order to keep
+     the push/pop code happy, and to not scrog the register stack, we
+     must put something in these registers.  Use a QNaN.
+
+     Note that we are inserting converted code here.  This code is
+     never seen by the convert_regs pass.  */
+
+  FOR_EACH_EDGE (e, ei, ENTRY_BLOCK_PTR->succs)
+    {
+      basic_block block = e->dest;
+      block_info bi = BLOCK_INFO (block);
+      int reg, top = -1;
+
+      for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; --reg)
+	if (TEST_HARD_REG_BIT (bi->stack_in.reg_set, reg))
+	  {
+	    rtx init;
+
+	    bi->stack_in.reg[++top] = reg;
+
+	    init = gen_rtx_SET (VOIDmode,
+				FP_MODE_REG (FIRST_STACK_REG, SFmode),
+				not_a_num);
+	    insert_insn_on_edge (init, e);
+	    inserted = 1;
+	  }
+
+      bi->stack_in.top = top;
+    }
+
+  return inserted;
+}
+
+/* Construct the desired stack for function exit.  This will either
+   be `empty', or the function return value at top-of-stack.  */
+
+static void
+convert_regs_exit (void)
+{
+  int value_reg_low, value_reg_high;
+  stack output_stack;
+  rtx retvalue;
+
+  retvalue = stack_result (current_function_decl);
+  value_reg_low = value_reg_high = -1;
+  if (retvalue)
+    {
+      value_reg_low = REGNO (retvalue);
+      value_reg_high = END_HARD_REGNO (retvalue) - 1;
+    }
+
+  output_stack = &BLOCK_INFO (EXIT_BLOCK_PTR)->stack_in;
+  if (value_reg_low == -1)
+    output_stack->top = -1;
+  else
+    {
+      int reg;
+
+      output_stack->top = value_reg_high - value_reg_low;
+      for (reg = value_reg_low; reg <= value_reg_high; ++reg)
+	{
+	  output_stack->reg[value_reg_high - reg] = reg;
+	  SET_HARD_REG_BIT (output_stack->reg_set, reg);
+	}
+    }
+}
+
+/* Copy the stack info from the end of edge E's source block to the
+   start of E's destination block.  */
+
+static void
+propagate_stack (edge e)
+{
+  stack src_stack = &BLOCK_INFO (e->src)->stack_out;
+  stack dest_stack = &BLOCK_INFO (e->dest)->stack_in;
+  int reg;
+
+  /* Preserve the order of the original stack, but check whether
+     any pops are needed.  */
+  dest_stack->top = -1;
+  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;
+}
+
+
+/* Adjust the stack of edge E's source block on exit to match the stack
+   of it's target block upon input.  The stack layouts of both blocks
+   should have been defined by now.  */
+
+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;
+  struct stack_def regstack;
+  int reg;
+
+  if (dump_file)
+    fprintf (dump_file, "Edge %d->%d: ", source->index, target->index);
+
+  gcc_assert (target_stack->top != -2);
+
+  /* Check whether stacks are identical.  */
+  if (target_stack->top == source_stack->top)
+    {
+      for (reg = target_stack->top; reg >= 0; --reg)
+	if (target_stack->reg[reg] != source_stack->reg[reg])
+	  break;
+
+      if (reg == -1)
+	{
+	  if (dump_file)
+	    fprintf (dump_file, "no changes needed\n");
+	  return false;
+	}
+    }
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "correcting stack to ");
+      print_stack (dump_file, target_stack);
+    }
+
+  /* Abnormal calls may appear to have values live in st(0), but the
+     abnormal return path will not have actually loaded the values.  */
+  if (e->flags & EDGE_ABNORMAL_CALL)
+    {
+      /* Assert that the lifetimes are as we expect -- one value
+         live at st(0) on the end of the source block, and no
+         values live at the beginning of the destination block.
+	 For complex return values, we may have st(1) live as well.  */
+      gcc_assert (source_stack->top == 0 || source_stack->top == 1);
+      gcc_assert (target_stack->top == -1);
+      return false;
+    }
+
+  /* Handle non-call EH edges specially.  The normal return path have
+     values in registers.  These will be popped en masse by the unwind
+     library.  */
+  if (e->flags & EDGE_EH)
+    {
+      gcc_assert (target_stack->top == -1);
+      return false;
+    }
+
+  /* We don't support abnormal edges.  Global takes care to
+     avoid any live register across them, so we should never
+     have to insert instructions on such edges.  */
+  gcc_assert (! (e->flags & EDGE_ABNORMAL));
+
+  /* Make a copy of source_stack as change_stack is destructive.  */
+  regstack = *source_stack;
+
+  /* It is better to output directly to the end of the block
+     instead of to the edge, because emit_swap can do minimal
+     insn scheduling.  We can do this when there is only one
+     edge out, and it is not abnormal.  */
+  if (EDGE_COUNT (source->succs) == 1)
+    {
+      current_block = source;
+      change_stack (BB_END (source), &regstack, target_stack,
+		    (JUMP_P (BB_END (source)) ? EMIT_BEFORE : EMIT_AFTER));
+    }
+  else
+    {
+      rtx seq, after;
+
+      current_block = NULL;
+      start_sequence ();
+
+      /* ??? change_stack needs some point to emit insns after.  */
+      after = emit_note (NOTE_INSN_DELETED);
+
+      change_stack (after, &regstack, target_stack, EMIT_BEFORE);
+
+      seq = get_insns ();
+      end_sequence ();
+
+      insert_insn_on_edge (seq, e);
+      return true;
+    }
+  return false;
+}
+
+/* Traverse all non-entry edges in the CFG, and emit the necessary
+   edge compensation code to change the stack from stack_out of the
+   source block to the stack_in of the destination block.  */
+
+static bool
+compensate_edges (void)
+{
+  bool inserted = false;
+  basic_block bb;
+
+  starting_stack_p = false;
+
+  FOR_EACH_BB (bb)
+    if (bb != ENTRY_BLOCK_PTR)
+      {
+        edge e;
+        edge_iterator ei;
+
+        FOR_EACH_EDGE (e, ei, bb->succs)
+	  inserted |= compensate_edge (e);
+      }
+  return inserted;
+}
+
+/* Select the better of two edges E1 and E2 to use to determine the
+   stack layout for their shared destination basic block.  This is
+   typically the more frequently executed.  The edge E1 may be NULL
+   (in which case E2 is returned), but E2 is always non-NULL.  */
+
+static edge
+better_edge (edge e1, edge e2)
+{
+  if (!e1)
+    return e2;
+
+  if (EDGE_FREQUENCY (e1) > EDGE_FREQUENCY (e2))
+    return e1;
+  if (EDGE_FREQUENCY (e1) < EDGE_FREQUENCY (e2))
+    return e2;
+
+  if (e1->count > e2->count)
+    return e1;
+  if (e1->count < e2->count)
+    return e2;
+
+  /* Prefer critical edges to minimize inserting compensation code on
+     critical edges.  */
+
+  if (EDGE_CRITICAL_P (e1) != EDGE_CRITICAL_P (e2))
+    return EDGE_CRITICAL_P (e1) ? e1 : e2;
+
+  /* Avoid non-deterministic behavior.  */
+  return (e1->src->index < e2->src->index) ? e1 : e2;
+}
+
+/* Convert stack register references in one block.  */
+
+static void
+convert_regs_1 (basic_block block)
+{
+  struct stack_def regstack;
+  block_info bi = BLOCK_INFO (block);
+  int reg;
+  rtx insn, next;
+  bool control_flow_insn_deleted = false;
+
+  any_malformed_asm = false;
+
+  /* Choose an initial stack layout, if one hasn't already been chosen.  */
+  if (bi->stack_in.top == -2)
+    {
+      edge e, beste = NULL;
+      edge_iterator ei;
+
+      /* Select the best incoming edge (typically the most frequent) to
+	 use as a template for this basic block.  */
+      FOR_EACH_EDGE (e, ei, block->preds)
+	if (BLOCK_INFO (e->src)->done)
+	  beste = better_edge (beste, e);
+
+      if (beste)
+	propagate_stack (beste);
+      else
+	{
+	  /* No predecessors.  Create an arbitrary input stack.  */
+	  bi->stack_in.top = -1;
+	  for (reg = LAST_STACK_REG; reg >= FIRST_STACK_REG; --reg)
+	    if (TEST_HARD_REG_BIT (bi->stack_in.reg_set, reg))
+	      bi->stack_in.reg[++bi->stack_in.top] = reg;
+	}
+    }
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\nBasic block %d\nInput stack: ", block->index);
+      print_stack (dump_file, &bi->stack_in);
+    }
+
+  /* Process all insns in this block.  Keep track of NEXT so that we
+     don't process insns emitted while substituting in INSN.  */
+  current_block = block;
+  next = BB_HEAD (block);
+  regstack = bi->stack_in;
+  starting_stack_p = true;
+
+  do
+    {
+      insn = next;
+      next = NEXT_INSN (insn);
+
+      /* Ensure we have not missed a block boundary.  */
+      gcc_assert (next);
+      if (insn == BB_END (block))
+	next = NULL;
+
+      /* 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 (dump_file)
+	    {
+	      fprintf (dump_file, "  insn %d input stack: ",
+		       INSN_UID (insn));
+	      print_stack (dump_file, &regstack);
+	    }
+	  control_flow_insn_deleted |= subst_stack_regs (insn, &regstack);
+	  starting_stack_p = false;
+	}
+    }
+  while (next);
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "Expected live registers [");
+      for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
+	if (TEST_HARD_REG_BIT (bi->out_reg_set, reg))
+	  fprintf (dump_file, " %d", reg);
+      fprintf (dump_file, " ]\nOutput stack: ");
+      print_stack (dump_file, &regstack);
+    }
+
+  insn = BB_END (block);
+  if (JUMP_P (insn))
+    insn = PREV_INSN (insn);
+
+  /* If the function is declared to return a value, but it returns one
+     in only some cases, some registers might come live here.  Emit
+     necessary moves for them.  */
+
+  for (reg = FIRST_STACK_REG; reg <= LAST_STACK_REG; ++reg)
+    {
+      if (TEST_HARD_REG_BIT (bi->out_reg_set, reg)
+	  && ! TEST_HARD_REG_BIT (regstack.reg_set, reg))
+	{
+	  rtx set;
+
+	  if (dump_file)
+	    fprintf (dump_file, "Emitting insn initializing reg %d\n", reg);
+
+	  set = gen_rtx_SET (VOIDmode, FP_MODE_REG (reg, SFmode), not_a_num);
+	  insn = emit_insn_after (set, insn);
+	  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,
+     called at the end of convert_regs.  The order in which we process the
+     blocks ensures that we never delete an already processed edge.
+
+     Note that, at this point, the CFG may have been damaged by the emission
+     of instructions after an abnormal call, which moves the basic block end
+     (and is the reason why we call fixup_abnormal_edges later).  So we must
+     be sure that the trapping insn has been deleted before trying to purge
+     dead edges, otherwise we risk purging valid edges.
+
+     ??? We are normally supposed not to delete trapping insns, so we pretend
+     that the insns deleted above don't actually trap.  It would have been
+     better to detect this earlier and avoid creating the EH edge in the first
+     place, still, but we don't have enough information at that time.  */
+
+  if (control_flow_insn_deleted)
+    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.  */
+     
+  gcc_assert (hard_reg_set_equal_p (regstack.reg_set, bi->out_reg_set)
+	      || any_malformed_asm);
+  bi->stack_out = regstack;
+  bi->done = true;
+}
+
+/* Convert registers in all blocks reachable from BLOCK.  */
+
+static void
+convert_regs_2 (basic_block block)
+{
+  basic_block *stack, *sp;
+
+  /* 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.  */ 
+
+  stack = XNEWVEC (basic_block, n_basic_blocks);
+  sp = stack;
+
+  *sp++ = block;
+
+  do
+    {
+      edge e;
+      edge_iterator ei;
+
+      block = *--sp;
+
+      /* Processing BLOCK is achieved by convert_regs_1, which may purge
+	 some dead EH outgoing edge after the deletion of the trapping
+	 insn inside the block.  Since the number of predecessors of
+	 BLOCK's successors was computed based on the initial edge set,
+	 we check the necessity to process some of these successors
+	 before such an edge deletion may happen.  However, there is
+	 a pitfall: if BLOCK is the only predecessor of a successor and
+	 the edge between them happens to be deleted, the successor
+	 becomes unreachable and should not be processed.  The problem
+	 is that there is no way to preventively detect this case so we
+	 stack the successor in all cases and hand over the task of
+	 fixing up the discrepancy to convert_regs_1.  */
+
+      FOR_EACH_EDGE (e, ei, block->succs)
+	if (! (e->flags & EDGE_DFS_BACK))
+	  {
+	    BLOCK_INFO (e->dest)->predecessors--;
+	    if (!BLOCK_INFO (e->dest)->predecessors)
+	      *sp++ = e->dest;
+	  }
+
+      convert_regs_1 (block);
+    }
+  while (sp != stack);
+
+  free (stack);
+}
+
+/* Traverse all basic blocks in a function, converting the register
+   references in each insn from the "flat" register file that gcc uses,
+   to the stack-like registers the 387 uses.  */
+
+static void
+convert_regs (void)
+{
+  int inserted;
+  basic_block b;
+  edge e;
+  edge_iterator ei;
+
+  /* Initialize uninitialized registers on function entry.  */
+  inserted = convert_regs_entry ();
+
+  /* Construct the desired stack for function exit.  */
+  convert_regs_exit ();
+  BLOCK_INFO (EXIT_BLOCK_PTR)->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);
+
+  /* ??? Process all unreachable blocks.  Though there's no excuse
+     for keeping these even when not optimizing.  */
+  FOR_EACH_BB (b)
+    {
+      block_info bi = BLOCK_INFO (b);
+
+      if (! bi->done)
+	convert_regs_2 (b);
+    }
+
+  inserted |= compensate_edges ();
+
+  clear_aux_for_blocks ();
+
+  fixup_abnormal_edges ();
+  if (inserted)
+    commit_edge_insertions ();
+
+  if (dump_file)
+    fputc ('\n', dump_file);
+}
+
+/* Convert register usage from "flat" register file usage to a "stack
+   register file.  FILE is the dump file, if used.
+
+   Construct a CFG and run life analysis.  Then convert each insn one
+   by one.  Run a last cleanup_cfg pass, if optimizing, to eliminate
+   code duplication created when the converter inserts pop insns on
+   the edges.  */
+
+static bool
+reg_to_stack (void)
+{
+  basic_block bb;
+  int i;
+  int max_uid;
+
+  /* Clean up previous run.  */
+  if (stack_regs_mentioned_data != NULL)
+    VEC_free (char, heap, stack_regs_mentioned_data);
+
+  /* See if there is something to do.  Flow analysis is quite
+     expensive so we might save some compilation time.  */
+  for (i = FIRST_STACK_REG; i <= LAST_STACK_REG; i++)
+    if (df_regs_ever_live_p (i))
+      break;
+  if (i > LAST_STACK_REG)
+    return false;
+
+  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)
+    {
+      block_info bi = BLOCK_INFO (bb);
+      edge_iterator ei;
+      edge e;
+      int reg;
+
+      FOR_EACH_EDGE (e, ei, bb->preds)
+	if (!(e->flags & EDGE_DFS_BACK)
+	    && e->src != ENTRY_BLOCK_PTR)
+	  bi->predecessors++;
+
+      /* Set current register status at last instruction `uninitialized'.  */
+      bi->stack_in.top = -2;
+
+      /* 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 (DF_LR_OUT (bb), reg))
+	    SET_HARD_REG_BIT (bi->out_reg_set, reg);
+	  if (REGNO_REG_SET_P (DF_LR_IN (bb), reg))
+	    SET_HARD_REG_BIT (bi->stack_in.reg_set, reg);
+	}
+    }
+
+  /* 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))
+	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))
+	FP_MODE_REG (i, mode) = gen_rtx_REG (mode, i);
+    }
+
+  ix86_flags_rtx = gen_rtx_REG (CCmode, FLAGS_REG);
+
+  /* A QNaN for initializing uninitialized variables.
+
+     ??? 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 `fldz'.  */
+
+  if ((flag_pic && !TARGET_64BIT)
+      || ix86_cmodel == CM_LARGE || ix86_cmodel == CM_LARGE_PIC)
+    not_a_num = CONST0_RTX (SFmode);
+  else
+    {
+      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));
+
+  convert_regs ();
+
+  free_aux_for_blocks ();
+  return true;
+}
+#endif /* STACK_REGS */
+
+static bool
+gate_handle_stack_regs (void)
+{
+#ifdef STACK_REGS
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+struct rtl_opt_pass pass_stack_regs =
+{
+ {
+  RTL_PASS,
+  NULL,                                 /* name */
+  gate_handle_stack_regs,               /* gate */
+  NULL,					/* execute */
+  NULL,                                 /* sub */
+  NULL,                                 /* next */
+  0,                                    /* static_pass_number */
+  TV_REG_STACK,                         /* tv_id */
+  0,                                    /* properties_required */
+  0,                                    /* properties_provided */
+  0,                                    /* properties_destroyed */
+  0,                                    /* todo_flags_start */
+  0                                     /* todo_flags_finish */
+ }
+};
+
+/* Convert register usage from flat register file usage to a stack
+   register file.  */
+static unsigned int
+rest_of_handle_stack_regs (void)
+{
+#ifdef STACK_REGS
+  reg_to_stack ();
+  regstack_completed = 1;
+#endif
+  return 0;
+}
+
+struct rtl_opt_pass pass_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 */
+ }
+};