OSDN Git Service

* i386/i386.c (output_fp_conditional_move): New function
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index cb6158c..73d89dc 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for Intel X86.
-   Copyright (C) 1988, 1992, 1994, 1995 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -15,7 +15,8 @@ GNU General Public License for more details.
 
 You should have received a copy of the GNU General Public License
 along with GNU CC; see the file COPYING.  If not, write to
-the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
+the Free Software Foundation, 59 Temple Place - Suite 330,
+Boston, MA 02111-1307, USA. */
 
 #include <stdio.h>
 #include <setjmp.h>
@@ -32,7 +33,23 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "insn-attr.h"
 #include "tree.h"
 #include "flags.h"
+#include "except.h"
 #include "function.h"
+#include "recog.h"
+#include "expr.h"
+#include "toplev.h"
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>                                                
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>                                                   
+#else                                                  
+#ifdef HAVE_STRINGS_H
+#include <strings.h>               
+#endif                                                                   
+#endif 
 
 #ifdef EXTRA_CONSTRAINT
 /* If EXTRA_CONSTRAINT is defined, then the 'S'
@@ -43,11 +60,69 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
    even if the conditional was untrue.  */
 #endif
 
-#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
+#ifndef CHECK_STACK_LIMIT
+#define CHECK_STACK_LIMIT -1
+#endif
+
+/* Type of an operand for ix86_{binary,unary}_operator_ok */
+enum reg_mem
+{
+  reg_p,
+  mem_p,
+  imm_p
+};
+
+/* Processor costs (relative to an add) */
+struct processor_costs i386_cost = {   /* 386 specific costs */
+  1,                                   /* cost of an add instruction */
+  1,                                   /* cost of a lea instruction */
+  3,                                   /* variable shift costs */
+  2,                                   /* constant shift costs */
+  6,                                   /* cost of starting a multiply */
+  1,                                   /* cost of multiply per each bit set */
+  23                                   /* cost of a divide/mod */
+};
+
+struct processor_costs i486_cost = {   /* 486 specific costs */
+  1,                                   /* cost of an add instruction */
+  1,                                   /* cost of a lea instruction */
+  3,                                   /* variable shift costs */
+  2,                                   /* constant shift costs */
+  12,                                  /* cost of starting a multiply */
+  1,                                   /* cost of multiply per each bit set */
+  40                                   /* cost of a divide/mod */
+};
+
+struct processor_costs pentium_cost = {
+  1,                                   /* cost of an add instruction */
+  1,                                   /* cost of a lea instruction */
+  4,                                   /* variable shift costs */
+  1,                                   /* constant shift costs */
+  11,                                  /* cost of starting a multiply */
+  0,                                   /* cost of multiply per each bit set */
+  25                                   /* cost of a divide/mod */
+};
+
+struct processor_costs pentiumpro_cost = {
+  1,                                   /* cost of an add instruction */
+  1,                                   /* cost of a lea instruction */
+  3,                                   /* variable shift costs */
+  1,                                   /* constant shift costs */
+  4,                                   /* cost of starting a multiply */
+  0,                                   /* cost of multiply per each bit set */
+  17                                   /* cost of a divide/mod */
+};
+
+struct processor_costs *ix86_cost = &pentium_cost;
+
+#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))
 
 extern FILE *asm_out_file;
 extern char *strcat ();
 
+static void ix86_epilogue PROTO((int));
+static void ix86_prologue PROTO((int));
+
 char *singlemove_string ();
 char *output_move_const_single ();
 char *output_fp_cc0_set ();
@@ -79,24 +154,48 @@ struct rtx_def *i386_compare_op0 = NULL_RTX;
 struct rtx_def *i386_compare_op1 = NULL_RTX;
 struct rtx_def *(*i386_compare_gen)(), *(*i386_compare_gen_eq)();
 
+/* which cpu are we scheduling for */
+enum processor_type ix86_cpu;
+
+/* which instruction set architecture to use.  */
+int ix86_arch;
+
+/* Strings to hold which cpu and instruction set architecture  to use.  */
+char *ix86_cpu_string;         /* for -mcpu=<xxx> */
+char *ix86_arch_string;                /* for -march=<xxx> */
+
 /* Register allocation order */
 char *i386_reg_alloc_order;
 static char regs_allocated[FIRST_PSEUDO_REGISTER];
 
 /* # of registers to use to pass arguments. */
-char *i386_regparm_string;                     /* # registers to use to pass args */
-int i386_regparm;                              /* i386_regparm_string as a number */
+char *i386_regparm_string;
 
-/* Alignment to use for loops and jumps */
-char *i386_align_loops_string;                 /* power of two alignment for loops */
-char *i386_align_jumps_string;                 /* power of two alignment for non-loop jumps */
-char *i386_align_funcs_string;                 /* power of two alignment for functions */
+/* i386_regparm_string as a number */
+int i386_regparm;
 
-int i386_align_loops;                          /* power of two alignment for loops */
-int i386_align_jumps;                          /* power of two alignment for non-loop jumps */
-int i386_align_funcs;                          /* power of two alignment for functions */
+/* Alignment to use for loops and jumps:  */
+
+/* Power of two alignment for loops. */
+char *i386_align_loops_string;
+
+/* Power of two alignment for non-loop jumps. */
+char *i386_align_jumps_string;
+
+/* Values 1-5: see jump.c */
+int i386_branch_cost;
+char *i386_branch_cost_string;
+
+/* Power of two alignment for functions. */
+int i386_align_funcs;
+char *i386_align_funcs_string;
+
+/* Power of two alignment for loops. */
+int i386_align_loops;
+
+/* Power of two alignment for non-loop jumps. */
+int i386_align_jumps;
 
-\f
 /* Sometimes certain combinations of command options do not make
    sense on a particular target machine.  You can define a macro
    `OVERRIDE_OPTIONS' to take account of this.  This macro, if
@@ -109,19 +208,39 @@ int i386_align_funcs;                             /* power of two alignment for functions */
 void
 override_options ()
 {
-  int ch, i, regno;
-  char *p;
+  int ch, i, j;
   int def_align;
 
+  static struct ptt
+    {
+      char *name;              /* Canonical processor name.  */
+      enum processor_type processor; /* Processor type enum value.  */
+      struct processor_costs *cost; /* Processor costs */
+      int target_enable;       /* Target flags to enable.  */
+      int target_disable;      /* Target flags to disable.  */
+    } processor_target_table[]
+      = {{PROCESSOR_I386_STRING, PROCESSOR_I386, &i386_cost, 0, 0},
+          {PROCESSOR_I486_STRING, PROCESSOR_I486, &i486_cost, 0, 0},
+          {PROCESSOR_I586_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
+          {PROCESSOR_PENTIUM_STRING, PROCESSOR_PENTIUM, &pentium_cost, 0, 0},
+          {PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentiumpro_cost,
+             0, 0},
+          {PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO,
+             &pentiumpro_cost, 0, 0}};
+
+  int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
+
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
-  /* Validate registers in register allocation order */
+  /* Validate registers in register allocation order */
   if (i386_reg_alloc_order)
     {
       for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
        {
+         int regno = 0;
+         
          switch (ch)
            {
            case 'a':   regno = 0;      break;
@@ -136,23 +255,75 @@ override_options ()
            }
 
          if (regs_allocated[regno])
-           fatal ("Register '%c' was already specified in the allocation order", ch);
+           fatal ("Register '%c' already specified in allocation order", ch);
 
          regs_allocated[regno] = 1;
        }
     }
 
-  /* Validate -mregparm= value */
+  if (ix86_arch_string == 0)
+    {
+      ix86_arch_string = PROCESSOR_PENTIUM_STRING;
+      if (ix86_cpu_string == 0)
+       ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
+    }
+  
+  for (i = 0; i < ptt_size; i++)
+    if (! strcmp (ix86_arch_string, processor_target_table[i].name))
+      {
+       ix86_arch = processor_target_table[i].processor;
+       if (ix86_cpu_string == 0)
+         ix86_cpu_string = processor_target_table[i].name;
+       break;
+      }
+
+  if (i == ptt_size)
+    {
+      error ("bad value (%s) for -march= switch", ix86_arch_string);
+      ix86_arch_string = PROCESSOR_PENTIUM_STRING;
+      ix86_arch = PROCESSOR_DEFAULT;
+    }
+
+  if (ix86_cpu_string == 0)
+    ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
+
+  for (j = 0; j < ptt_size; j++)
+    if (! strcmp (ix86_cpu_string, processor_target_table[j].name))
+      {
+       ix86_cpu = processor_target_table[j].processor;
+       ix86_cost = processor_target_table[j].cost;
+       if (i > j && (int) ix86_arch >= (int) PROCESSOR_PENTIUMPRO)
+         error ("-mcpu=%s does not support -march=%s",
+                ix86_cpu_string, ix86_arch_string);
+
+       target_flags |= processor_target_table[j].target_enable;
+       target_flags &= ~processor_target_table[j].target_disable;
+       break;
+      }
+
+  if (j == ptt_size)
+    {
+      error ("bad value (%s) for -mcpu= switch", ix86_cpu_string);
+      ix86_cpu_string = PROCESSOR_DEFAULT_STRING;
+      ix86_cpu = PROCESSOR_DEFAULT;
+    }
+
+  /* Validate -mregparm= value. */
   if (i386_regparm_string)
     {
       i386_regparm = atoi (i386_regparm_string);
       if (i386_regparm < 0 || i386_regparm > REGPARM_MAX)
-       fatal ("-mregparm=%d is not between 0 and %d", i386_regparm, REGPARM_MAX);
+       fatal ("-mregparm=%d is not between 0 and %d",
+              i386_regparm, REGPARM_MAX);
     }
 
-  def_align = (TARGET_386) ? 2 : 4;
+  /* The 486 suffers more from non-aligned cache line fills, and the
+     larger code size results in a larger cache foot-print and more misses.
+     The 486 has a 16 byte cache line, pentium and pentiumpro have a 32 byte
+     cache line.  */
+  def_align = (TARGET_486) ? 4 : 2;
 
-  /* Validate -malign-loops= value, or provide default */
+  /* Validate -malign-loops= value, or provide default */
   if (i386_align_loops_string)
     {
       i386_align_loops = atoi (i386_align_loops_string);
@@ -161,9 +332,13 @@ override_options ()
               i386_align_loops, MAX_CODE_ALIGN);
     }
   else
-    i386_align_loops = def_align;
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+    i386_align_loops = 4;
+#else
+    i386_align_loops = 2;
+#endif
 
-  /* Validate -malign-jumps= value, or provide default */
+  /* Validate -malign-jumps= value, or provide default */
   if (i386_align_jumps_string)
     {
       i386_align_jumps = atoi (i386_align_jumps_string);
@@ -172,9 +347,13 @@ override_options ()
               i386_align_jumps, MAX_CODE_ALIGN);
     }
   else
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+    i386_align_jumps = 4;
+#else
     i386_align_jumps = def_align;
+#endif
 
-  /* Validate -malign-functions= value, or provide default */
+  /* Validate -malign-functions= value, or provide default. */
   if (i386_align_funcs_string)
     {
       i386_align_funcs = atoi (i386_align_funcs_string);
@@ -184,6 +363,21 @@ override_options ()
     }
   else
     i386_align_funcs = def_align;
+
+  /* Validate -mbranch-cost= value, or provide default. */
+  if (i386_branch_cost_string)
+    {
+      i386_branch_cost = atoi (i386_branch_cost_string);
+      if (i386_branch_cost < 0 || i386_branch_cost > 5)
+       fatal ("-mbranch-cost=%d is not between 0 and 5",
+              i386_branch_cost);
+    }
+  else
+    i386_branch_cost = 1;
+
+  /* Keep nonleaf frame pointers.  */
+  if (TARGET_OMIT_LEAF_FRAME_POINTER)
+    flag_omit_frame_pointer = 1;
 }
 \f
 /* A C statement (sans semicolon) to choose the order in which to
@@ -202,13 +396,16 @@ override_options ()
 void
 order_regs_for_local_alloc ()
 {
-  int i, ch, order, regno;
+  int i, ch, order;
+
+  /* User specified the register allocation order.  */
 
-  /* User specified the register allocation order */
   if (i386_reg_alloc_order)
     {
       for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
        {
+         int regno = 0;
+         
          switch (ch)
            {
            case 'a':   regno = 0;      break;
@@ -225,59 +422,116 @@ order_regs_for_local_alloc ()
 
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        {
-         if (!regs_allocated[i])
+         if (! regs_allocated[i])
            reg_alloc_order[order++] = i;
        }
     }
 
-  /* If users did not specify a register allocation order, favor eax
-     normally except if DImode variables are used, in which case
-     favor edx before eax, which seems to cause less spill register
-     not found messages.  */
+  /* If user did not specify a register allocation order, use natural order. */
   else
     {
-      rtx insn;
-
       for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
        reg_alloc_order[i] = i;
+    }
+}
+\f
+void
+optimization_options (level, size)
+     int level;
+     int size;
+{
+  /* For -O2 and beyond, turn off -fschedule-insns by default.  It tends to
+     make the problem with not enough registers even worse.  */
+#ifdef INSN_SCHEDULING
+  if (level > 1)
+    flag_schedule_insns = 0;
+#endif
+}
+\f
+/* Sign-extend a 16-bit constant */
 
-      if (optimize)
-       {
-         int use_dca = FALSE;
+struct rtx_def *
+i386_sext16_if_const (op)
+     struct rtx_def *op;
+{
+  if (GET_CODE (op) == CONST_INT)
+    {
+      HOST_WIDE_INT val = INTVAL (op);
+      HOST_WIDE_INT sext_val;
+      if (val & 0x8000)
+       sext_val = val | ~0xffff;
+      else
+       sext_val = val & 0xffff;
+      if (sext_val != val)
+       op = GEN_INT (sext_val);
+    }
+  return op;
+}
+\f
+/* Return nonzero if the rtx is aligned */
 
-         for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
-           {
-             if (GET_CODE (insn) == INSN)
-               {
-                 rtx set = NULL_RTX;
-                 rtx pattern = PATTERN (insn);
-
-                 if (GET_CODE (pattern) == SET)
-                   set = pattern;
-
-                 else if ((GET_CODE (pattern) == PARALLEL
-                           || GET_CODE (pattern) == SEQUENCE)
-                          && GET_CODE (XVECEXP (pattern, 0, 0)) == SET)
-                   set = XVECEXP (pattern, 0, 0);
-
-                 if (set && GET_MODE (SET_SRC (set)) == DImode)
-                   {
-                     use_dca = TRUE;
-                     break;
-                   }
-               }
-           }
+static int
+i386_aligned_reg_p (regno)
+     int regno;
+{
+  return (regno == STACK_POINTER_REGNUM
+         || (! flag_omit_frame_pointer && regno == FRAME_POINTER_REGNUM));
+}
 
-         if (use_dca)
-           {
-             reg_alloc_order[0] = 1;   /* edx */
-             reg_alloc_order[1] = 2;   /* ecx */
-             reg_alloc_order[2] = 0;   /* eax */
-           }
-       }
+int
+i386_aligned_p (op)
+     rtx op;
+{
+  /* Registers and immediate operands are always "aligned". */
+  if (GET_CODE (op) != MEM)
+    return 1;
+
+  /* Don't even try to do any aligned optimizations with volatiles. */
+  if (MEM_VOLATILE_P (op))
+    return 0;
+
+  /* Get address of memory operand. */
+  op = XEXP (op, 0);
+
+  switch (GET_CODE (op))
+    {
+    case CONST_INT:
+      if (INTVAL (op) & 3)
+       break;
+      return 1;
+
+      /* Match "reg + offset" */
+    case PLUS:
+      if (GET_CODE (XEXP (op, 1)) != CONST_INT)
+       break;
+      if (INTVAL (XEXP (op, 1)) & 3)
+       break;
+
+      op = XEXP (op, 0);
+      if (GET_CODE (op) != REG)
+       break;
+
+      /* ... fall through ... */
+
+    case REG:
+      return i386_aligned_reg_p (REGNO (op));
+    
+    default:
+      break;
     }
+
+  return 0;
 }
+\f
+/* Return nonzero if INSN looks like it won't compute useful cc bits
+   as a side effect.  This information is only a hint. */
 
+int
+i386_cc_probably_useless_p (insn)
+     rtx insn;
+{
+  return ! next_cc0_user (insn);
+}
 \f
 /* Return nonzero if IDENTIFIER with arguments ARGS is a valid machine specific
    attribute for DECL.  The attributes in ATTRIBUTES have previously been
@@ -314,17 +568,17 @@ i386_valid_type_attribute_p (type, attributes, identifier, args)
   if (is_attribute_p ("stdcall", identifier))
     return (args == NULL_TREE);
 
-  /* Cdecl attribute says the callee is a normal C declaration */
+  /* Cdecl attribute says the callee is a normal C declaration. */
   if (is_attribute_p ("cdecl", identifier))
     return (args == NULL_TREE);
 
   /* Regparm attribute specifies how many integer arguments are to be
-     passed in registers */
+     passed in registers. */
   if (is_attribute_p ("regparm", identifier))
     {
       tree cst;
 
-      if (!args || TREE_CODE (args) != TREE_LIST
+      if (! args || TREE_CODE (args) != TREE_LIST
          || TREE_CHAIN (args) != NULL_TREE
          || TREE_VALUE (args) == NULL_TREE)
        return 0;
@@ -379,34 +633,28 @@ i386_return_pops_args (fundecl, funtype, size)
      tree fundecl;
      tree funtype;
      int size;
-{
-  int rtd = TARGET_RTD;
-
-  if (TREE_CODE (funtype) == IDENTIFIER_NODE)
+{ 
+  int rtd = TARGET_RTD && (!fundecl || TREE_CODE (fundecl) != IDENTIFIER_NODE);
+
+    /* Cdecl functions override -mrtd, and never pop the stack. */
+  if (! lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype))) {
+  
+    /* Stdcall functions will pop the stack if not variable args. */
+    if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
+      rtd = 1;
+  
+    if (rtd
+        && (TYPE_ARG_TYPES (funtype) == NULL_TREE
+           || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype)))
+               == void_type_node)))
+      return size;
+  }
+  
+  /* Lose any fake structure return argument.  */
+  if (aggregate_value_p (TREE_TYPE (funtype)))
+    return GET_MODE_SIZE (Pmode);
+  
     return 0;
-
-  if (fundecl && TREE_CODE_CLASS (TREE_CODE (fundecl)) == 'd')
-    {
-      /* Cdecl functions override -mrtd, and never pop the stack */
-      if (lookup_attribute ("cdecl", TYPE_ATTRIBUTES (funtype)))
-       return 0;
-
-      /* Stdcall functions will pop the stack if not variable args */
-      if (lookup_attribute ("stdcall", TYPE_ATTRIBUTES (funtype)))
-       rtd = 1;
-    }
-
-  if (rtd)
-    {
-      if (TYPE_ARG_TYPES (funtype) == NULL_TREE
-         || (TREE_VALUE (tree_last (TYPE_ARG_TYPES (funtype))) == void_type_node))
-       return size;
-
-      if (aggregate_value_p (TREE_TYPE (funtype)))
-       return GET_MODE_SIZE (Pmode);
-    }
-
-  return 0;
 }
 
 \f
@@ -418,7 +666,7 @@ i386_return_pops_args (fundecl, funtype, size)
 
 void
 init_cumulative_args (cum, fntype, libname)
-     CUMULATIVE_ARGS *cum;     /* argument info to initialize */
+     CUMULATIVE_ARGS *cum;     /* Argument info to initialize */
      tree fntype;              /* tree ptr for function decl */
      rtx libname;              /* SYMBOL_REF of library name or 0 */
 {
@@ -429,12 +677,9 @@ init_cumulative_args (cum, fntype, libname)
     {
       fprintf (stderr, "\ninit_cumulative_args (");
       if (fntype)
-       {
-         tree ret_type = TREE_TYPE (fntype);
-         fprintf (stderr, "fntype code = %s, ret code = %s",
-                  tree_code_name[ (int)TREE_CODE (fntype) ],
-                  tree_code_name[ (int)TREE_CODE (ret_type) ]);
-       }
+       fprintf (stderr, "fntype code = %s, ret code = %s",
+                tree_code_name[(int) TREE_CODE (fntype)],
+                tree_code_name[(int) TREE_CODE (TREE_TYPE (fntype))]);
       else
        fprintf (stderr, "no fntype");
 
@@ -449,6 +694,7 @@ init_cumulative_args (cum, fntype, libname)
   if (fntype)
     {
       tree attr = lookup_attribute ("regparm", TYPE_ATTRIBUTES (fntype));
+
       if (attr)
        cum->nregs = TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (attr)));
     }
@@ -461,11 +707,10 @@ init_cumulative_args (cum, fntype, libname)
   if (cum->nregs)
     {
       for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
-          param != (tree)0;
-          param = next_param)
+          param != 0; param = next_param)
        {
          next_param = TREE_CHAIN (param);
-         if (next_param == (tree)0 && TREE_VALUE (param) != void_type_node)
+         if (next_param == 0 && TREE_VALUE (param) != void_type_node)
            cum->nregs = 0;
        }
     }
@@ -487,12 +732,13 @@ function_arg_advance (cum, mode, type, named)
      tree type;                        /* type of the argument or 0 if lib support */
      int named;                        /* whether or not the argument was named */
 {
-  int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+  int bytes
+    = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
   int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
   if (TARGET_DEBUG_ARG)
     fprintf (stderr,
-            "function_adv( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d )\n\n",
+            "function_adv (sz=%d, wds=%2d, nregs=%d, mode=%s, named=%d)\n\n",
             words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
 
   cum->words += words;
@@ -529,12 +775,14 @@ function_arg (cum, mode, type, named)
      int named;                        /* != 0 for normal args, == 0 for ... args */
 {
   rtx ret   = NULL_RTX;
-  int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
+  int bytes
+    = (mode == BLKmode) ? int_size_in_bytes (type) : GET_MODE_SIZE (mode);
   int words = (bytes + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
 
   switch (mode)
     {
-    default:                   /* for now, pass fp/complex values on the stack */
+      /* For now, pass fp/complex values on the stack. */
+    default:
       break;
 
     case BLKmode:
@@ -543,14 +791,14 @@ function_arg (cum, mode, type, named)
     case HImode:
     case QImode:
       if (words <= cum->nregs)
-       ret = gen_rtx (REG, mode, cum->regno);
+       ret = gen_rtx_REG (mode, cum->regno);
       break;
     }
 
   if (TARGET_DEBUG_ARG)
     {
       fprintf (stderr,
-              "function_arg( size=%d, words=%2d, nregs=%d, mode=%4s, named=%d",
+              "function_arg (size=%d, wds=%2d, nregs=%d, mode=%4s, named=%d",
               words, cum->words, cum->nregs, GET_MODE_NAME (mode), named);
 
       if (ret)
@@ -577,7 +825,6 @@ function_arg_partial_nregs (cum, mode, type, named)
 {
   return 0;
 }
-
 \f
 /* Output an insn whose source is a 386 integer register.  SRC is the
    rtx for the register, and TEMPLATE is the op-code template.  SRC may
@@ -611,18 +858,19 @@ output_op_from_reg (src, template)
   if (size > UNITS_PER_WORD)
     {
       rtx high;
+
       if (size > 2 * UNITS_PER_WORD)
        {
-         high = gen_rtx (REG, SImode, REGNO (src) + 2);
+         high = gen_rtx_REG (SImode, REGNO (src) + 2);
          output_asm_insn (AS1 (push%L0,%0), &high);
        }
-      high = gen_rtx (REG, SImode, REGNO (src) + 1);
+
+      high = gen_rtx_REG (SImode, REGNO (src) + 1);
       output_asm_insn (AS1 (push%L0,%0), &high);
     }
-  output_asm_insn (AS1 (push%L0,%0), &src);
 
+  output_asm_insn (AS1 (push%L0,%0), &src);
   output_asm_insn (template, xops);
-
   output_asm_insn (AS2 (add%L3,%2,%3), xops);
 }
 \f
@@ -632,19 +880,25 @@ output_op_from_reg (src, template)
    otherwise a `fst' float store is done. */
 
 void
-output_to_reg (dest, dies)
+output_to_reg (dest, dies, scratch_mem)
      rtx dest;
      int dies;
+     rtx scratch_mem;
 {
   rtx xops[4];
   int size = GET_MODE_SIZE (GET_MODE (dest));
 
-  xops[0] = AT_SP (Pmode);
+  if (! scratch_mem)
+    xops[0] = AT_SP (Pmode);
+  else
+    xops[0] = scratch_mem;
+
   xops[1] = stack_pointer_rtx;
   xops[2] = GEN_INT (size);
   xops[3] = dest;
 
-  output_asm_insn (AS2 (sub%L1,%2,%1), xops);
+  if (! scratch_mem)
+    output_asm_insn (AS2 (sub%L1,%2,%1), xops);
 
   if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_INT)
     {
@@ -653,6 +907,7 @@ output_to_reg (dest, dies)
       else
        output_asm_insn (AS1 (fist%z3,%y0), xops);
     }
+
   else if (GET_MODE_CLASS (GET_MODE (dest)) == MODE_FLOAT)
     {
       if (dies)
@@ -668,19 +923,38 @@ output_to_reg (dest, dies)
            output_asm_insn (AS1 (fst%z3,%y0), xops);
        }
     }
+
   else
     abort ();
 
-  output_asm_insn (AS1 (pop%L0,%0), &dest);
+  if (! scratch_mem)
+    output_asm_insn (AS1 (pop%L0,%0), &dest);
+  else
+    output_asm_insn (AS2 (mov%L0,%0,%3), xops);
+
 
   if (size > UNITS_PER_WORD)
     {
-      dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
-      output_asm_insn (AS1 (pop%L0,%0), &dest);
+      dest = gen_rtx_REG (SImode, REGNO (dest) + 1);
+      if (! scratch_mem)
+       output_asm_insn (AS1 (pop%L0,%0), &dest);
+      else
+       {
+         xops[0] = adj_offsettable_operand (xops[0], 4);             
+         xops[3] = dest;
+         output_asm_insn (AS2 (mov%L0,%0,%3), xops);
+       }
+
       if (size > 2 * UNITS_PER_WORD)
        {
-         dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
-         output_asm_insn (AS1 (pop%L0,%0), &dest);
+         dest = gen_rtx_REG (SImode, REGNO (dest) + 1);
+         if (! scratch_mem)
+           output_asm_insn (AS1 (pop%L0,%0), &dest);
+         else
+           {
+             xops[0] = adj_offsettable_operand (xops[0], 4);         
+             output_asm_insn (AS2 (mov%L0,%0,%3), xops);
+           }
        }
     }
 }
@@ -698,9 +972,7 @@ singlemove_string (operands)
       return "push%L1 %1";
     }
   else if (GET_CODE (operands[1]) == CONST_DOUBLE)
-    {
-      return output_move_const_single (operands);
-    }
+    return output_move_const_single (operands);
   else if (GET_CODE (operands[0]) == REG || GET_CODE (operands[1]) == REG)
     return AS2 (mov%L0,%1,%0);
   else if (CONSTANT_P (operands[1]))
@@ -732,11 +1004,11 @@ find_addr_reg (addr)
       else
        abort ();
     }
+
   if (GET_CODE (addr) == REG)
     return addr;
   abort ();
 }
-
 \f
 /* Output an insn to add the constant N to the register X.  */
 
@@ -752,7 +1024,7 @@ asm_add (n, x)
     output_asm_insn (AS1 (dec%L0,%0), xops);
   else if (n == 1)
     output_asm_insn (AS1 (inc%L0,%0), xops);
-  else if (n < 0)
+  else if (n < 0 || n == 128)
     {
       xops[1] = GEN_INT (-n);
       output_asm_insn (AS2 (sub%L0,%1,%0), xops);
@@ -763,7 +1035,6 @@ asm_add (n, x)
       output_asm_insn (AS2 (add%L0,%1,%0), xops);
     }
 }
-
 \f
 /* Output assembler code to perform a doubleword move insn
    with operands OPERANDS.  */
@@ -830,11 +1101,11 @@ output_move_double (operands)
       operands[0] = XEXP (XEXP (operands[0], 0), 0);
       asm_add (-size, operands[0]);
       if (GET_MODE (operands[1]) == XFmode)
-        operands[0] = gen_rtx (MEM, XFmode, operands[0]);
+        operands[0] = gen_rtx_MEM (XFmode, operands[0]);
       else if (GET_MODE (operands[0]) == DFmode)
-        operands[0] = gen_rtx (MEM, DFmode, operands[0]);
+        operands[0] = gen_rtx_MEM (DFmode, operands[0]);
       else
-        operands[0] = gen_rtx (MEM, DImode, operands[0]);
+        operands[0] = gen_rtx_MEM (DImode, operands[0]);
       optype0 = OFFSOP;
     }
 
@@ -844,11 +1115,11 @@ output_move_double (operands)
       operands[1] = XEXP (XEXP (operands[1], 0), 0);
       asm_add (-size, operands[1]);
       if (GET_MODE (operands[1]) == XFmode)
-        operands[1] = gen_rtx (MEM, XFmode, operands[1]);
+        operands[1] = gen_rtx_MEM (XFmode, operands[1]);
       else if (GET_MODE (operands[1]) == DFmode)
-        operands[1] = gen_rtx (MEM, DFmode, operands[1]);
+        operands[1] = gen_rtx_MEM (DFmode, operands[1]);
       else
-        operands[1] = gen_rtx (MEM, DImode, operands[1]);
+        operands[1] = gen_rtx_MEM (DImode, operands[1]);
       optype1 = OFFSOP;
     }
 
@@ -874,8 +1145,8 @@ output_move_double (operands)
     {
       if (optype0 == REGOP)
        {
-         middlehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
-         latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 2);
+         middlehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
+         latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
        }
       else if (optype0 == OFFSOP)
        {
@@ -890,8 +1161,8 @@ output_move_double (operands)
     
       if (optype1 == REGOP)
        {
-          middlehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
-          latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 2);
+          middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
+          latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
        }
       else if (optype1 == OFFSOP)
        {
@@ -920,17 +1191,20 @@ output_move_double (operands)
          latehalf[1] = operands[1];
        }
     }
-  else /* size is not 12: */
+
+  else
     {
+      /* Size is not 12. */
+
       if (optype0 == REGOP)
-       latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+       latehalf[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 1);
       else if (optype0 == OFFSOP)
        latehalf[0] = adj_offsettable_operand (operands[0], 4);
       else
        latehalf[0] = operands[0];
 
       if (optype1 == REGOP)
-       latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
+       latehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
       else if (optype1 == OFFSOP)
        latehalf[1] = adj_offsettable_operand (operands[1], 4);
       else if (optype1 == CNSTOP)
@@ -962,34 +1236,34 @@ output_move_double (operands)
        {
          /* If both halves of dest are used in the src memory address,
             compute the address into latehalf of dest.  */
-compadr:
+       compadr:
          xops[0] = latehalf[0];
          xops[1] = XEXP (operands[1], 0);
          output_asm_insn (AS2 (lea%L0,%a1,%0), xops);
-         if( GET_MODE (operands[1]) == XFmode )
+         if (GET_MODE (operands[1]) == XFmode)
            {
-/*         abort (); */
-             operands[1] = gen_rtx (MEM, XFmode, latehalf[0]);
+             operands[1] = gen_rtx_MEM (XFmode, latehalf[0]);
              middlehalf[1] = adj_offsettable_operand (operands[1], size-8);
              latehalf[1] = adj_offsettable_operand (operands[1], size-4);
            }
          else
            {
-             operands[1] = gen_rtx (MEM, DImode, latehalf[0]);
+             operands[1] = gen_rtx_MEM (DImode, latehalf[0]);
              latehalf[1] = adj_offsettable_operand (operands[1], size-4);
            }
        }
+
       else if (size == 12
                 && reg_mentioned_p (middlehalf[0], XEXP (operands[1], 0)))
        {
          /* Check for two regs used by both source and dest. */
          if (reg_mentioned_p (operands[0], XEXP (operands[1], 0))
                || reg_mentioned_p (latehalf[0], XEXP (operands[1], 0)))
-               goto compadr;
+           goto compadr;
 
          /* JRV says this can't happen: */
          if (addreg0 || addreg1)
-             abort();
+             abort ();
 
          /* Only the middle reg conflicts; simply put it last. */
          output_asm_insn (singlemove_string (operands), operands);
@@ -997,6 +1271,7 @@ compadr:
          output_asm_insn (singlemove_string (middlehalf), middlehalf);
          return "";
        }
+
       else if (reg_mentioned_p (operands[0], XEXP (operands[1], 0)))
        /* If the low half of dest is mentioned in the source memory
           address, the arrange to emit the move late half first.  */
@@ -1011,12 +1286,13 @@ compadr:
      such overlap can't happen in memory unless the user explicitly
      sets it up, and that is an undefined circumstance.  */
 
-/*
+#if 0
   if (optype0 == PUSHOP || optype1 == PUSHOP
       || (optype0 == REGOP && optype1 == REGOP
          && REGNO (operands[0]) == REGNO (latehalf[1]))
       || dest_overlapped_low)
-*/
+#endif
+
   if (optype0 == PUSHOP || optype1 == PUSHOP
       || (optype0 == REGOP && optype1 == REGOP
          && ((middlehalf[1] && REGNO (operands[0]) == REGNO (middlehalf[1]))
@@ -1034,17 +1310,17 @@ compadr:
 
       /* Undo the adds we just did.  */
       if (addreg0)
-         asm_add (-4, addreg0);
+       asm_add (-4, addreg0);
       if (addreg1)
        asm_add (-4, addreg1);
 
       if (size == 12)
         {
-        output_asm_insn (singlemove_string (middlehalf), middlehalf);
-        if (addreg0)
-           asm_add (-4, addreg0);
-        if (addreg1)
-          asm_add (-4, addreg1);
+         output_asm_insn (singlemove_string (middlehalf), middlehalf);
+         if (addreg0)
+           asm_add (-4, addreg0);
+         if (addreg1)
+           asm_add (-4, addreg1);
        }
 
       /* Do low-numbered word.  */
@@ -1083,7 +1359,6 @@ compadr:
 
   return "";
 }
-
 \f
 #define MAX_TMPS 2             /* max temporary registers used */
 
@@ -1097,13 +1372,13 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
      int tmp_start;
      int n_operands;
 {
-
-  struct {
-    char *load;
-    char *push;
-    rtx   xops[2];
-  } tmp_info[MAX_TMPS];
-
+  struct
+    {
+      char *load;
+      char *push;
+      rtx   xops[2];
+    } tmp_info[MAX_TMPS];
+  
   rtx src = operands[1];
   int max_tmps = 0;
   int offset = 0;
@@ -1112,7 +1387,7 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
   int i, num_tmps;
   rtx xops[1];
 
-  if (!offsettable_memref_p (src))
+  if (! offsettable_memref_p (src))
     fatal_insn ("Source is not offsettable", insn);
 
   if ((length & 3) != 0)
@@ -1148,7 +1423,8 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
          {
            tmp_info[num_tmps].load    = AS2(mov%L0,%0,%1);
            tmp_info[num_tmps].push    = AS1(push%L0,%1);
-           tmp_info[num_tmps].xops[0] = adj_offsettable_operand (src, offset + stack_offset);
+           tmp_info[num_tmps].xops[0]
+             = adj_offsettable_operand (src, offset + stack_offset);
            offset -= 4;
          }
 
@@ -1164,9 +1440,7 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
 
   return "";
 }
-
 \f
-
 /* Output the appropriate code to move data between two memory locations */
 
 char *
@@ -1177,11 +1451,12 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
      int tmp_start;
      int n_operands;
 {
-  struct {
-    char *load;
-    char *store;
-    rtx   xops[3];
-  } tmp_info[MAX_TMPS];
+  struct
+    {
+      char *load;
+      char *store;
+      rtx   xops[3];
+    } tmp_info[MAX_TMPS];
 
   rtx dest = operands[0];
   rtx src  = operands[1];
@@ -1196,10 +1471,10 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
       && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
     return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
 
-  if (!offsettable_memref_p (src))
+  if (! offsettable_memref_p (src))
     fatal_insn ("Source is not offsettable", insn);
 
-  if (!offsettable_memref_p (dest))
+  if (! offsettable_memref_p (dest))
     fatal_insn ("Destination is not offsettable", insn);
 
   /* Figure out which temporary registers we have available */
@@ -1207,7 +1482,7 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
     {
       if (GET_CODE (operands[i]) == REG)
        {
-         if ((length & 1) != 0 && !qi_tmp && QI_REG_P (operands[i]))
+         if ((length & 1) != 0 && qi_tmp == 0 && QI_REG_P (operands[i]))
            qi_tmp = operands[i];
 
          if (reg_overlap_mentioned_p (operands[i], dest))
@@ -1216,19 +1491,21 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
          if (reg_overlap_mentioned_p (operands[i], src))
            fatal_insn ("Temporary register overlaps the source", insn);
 
-         tmp_info[ max_tmps++ ].xops[2] = operands[i];
+         tmp_info[max_tmps++].xops[2] = operands[i];
          if (max_tmps == MAX_TMPS)
            break;
        }
     }
 
   if (max_tmps == 0)
-    fatal_insn ("No scratch registers were found to do memory->memory moves", insn);
+    fatal_insn ("No scratch registers were found to do memory->memory moves",
+               insn);
 
   if ((length & 1) != 0)
     {
-      if (!qi_tmp)
-       fatal_insn ("No byte register found when moving odd # of bytes.", insn);
+      if (qi_tmp == 0)
+       fatal_insn ("No byte register found when moving odd # of bytes.",
+                   insn);
     }
 
   while (length > 1)
@@ -1239,17 +1516,24 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
            {
              tmp_info[num_tmps].load    = AS2(mov%L0,%1,%2);
              tmp_info[num_tmps].store   = AS2(mov%L0,%2,%0);
-             tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
-             tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+             tmp_info[num_tmps].xops[0]
+               = adj_offsettable_operand (dest, offset);
+             tmp_info[num_tmps].xops[1]
+               = adj_offsettable_operand (src, offset);
+
              offset += 4;
              length -= 4;
            }
+
          else if (length >= 2)
            {
              tmp_info[num_tmps].load    = AS2(mov%W0,%1,%2);
              tmp_info[num_tmps].store   = AS2(mov%W0,%2,%0);
-             tmp_info[num_tmps].xops[0] = adj_offsettable_operand (dest, offset);
-             tmp_info[num_tmps].xops[1] = adj_offsettable_operand (src, offset);
+             tmp_info[num_tmps].xops[0]
+               = adj_offsettable_operand (dest, offset);
+             tmp_info[num_tmps].xops[1]
+               = adj_offsettable_operand (src, offset);
+
              offset += 2;
              length -= 2;
            }
@@ -1275,7 +1559,6 @@ output_move_memory (operands, insn, length, tmp_start, n_operands)
 
   return "";
 }
-
 \f
 int
 standard_80387_constant_p (x)
@@ -1291,7 +1574,7 @@ standard_80387_constant_p (x)
 
   set_float_handler (handler);
   REAL_VALUE_FROM_CONST_DOUBLE (d, x);
-  is0 = REAL_VALUES_EQUAL (d, dconst0);
+  is0 = REAL_VALUES_EQUAL (d, dconst0) && !REAL_VALUE_MINUS_ZERO (d);
   is1 = REAL_VALUES_EQUAL (d, dconst1);
   set_float_handler (NULL_PTR);
 
@@ -1323,6 +1606,7 @@ output_move_const_single (operands)
       if (conval == 2)
        return "fld1";
     }
+
   if (GET_CODE (operands[1]) == CONST_DOUBLE)
     {
       REAL_VALUE_TYPE r; long l;
@@ -1334,6 +1618,7 @@ output_move_const_single (operands)
       REAL_VALUE_TO_TARGET_SINGLE (r, l);
       operands[1] = GEN_INT (l);
     }
+
   return singlemove_string (operands);
 }
 \f
@@ -1350,11 +1635,13 @@ symbolic_operand (op, mode)
     case SYMBOL_REF:
     case LABEL_REF:
       return 1;
+
     case CONST:
       op = XEXP (op, 0);
       return ((GET_CODE (XEXP (op, 0)) == SYMBOL_REF
               || GET_CODE (XEXP (op, 0)) == LABEL_REF)
              && GET_CODE (XEXP (op, 1)) == CONST_INT);
+
     default:
       return 0;
     }
@@ -1376,9 +1663,10 @@ call_insn_operand (op, mode)
           && general_operand (XEXP (op, 0), Pmode))
          || (GET_CODE (XEXP (op, 0)) == REG
              && XEXP (op, 0) != arg_pointer_rtx
-             && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
-                  && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
+             && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
+                   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
     return 1;
+
   return 0;
 }
 
@@ -1394,11 +1682,41 @@ expander_call_insn_operand (op, mode)
       && (CONSTANT_ADDRESS_P (XEXP (op, 0))
          || (GET_CODE (XEXP (op, 0)) == REG
              && XEXP (op, 0) != arg_pointer_rtx
-             && !(REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
-                  && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
+             && ! (REGNO (XEXP (op, 0)) >= FIRST_PSEUDO_REGISTER
+                   && REGNO (XEXP (op, 0)) <= LAST_VIRTUAL_REGISTER))))
     return 1;
+
   return 0;
 }
+
+/* Return 1 if OP is a comparison operator that can use the condition code
+   generated by an arithmetic operation. */
+
+int
+arithmetic_comparison_operator (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  enum rtx_code code;
+
+  if (mode != VOIDmode && mode != GET_MODE (op))
+    return 0;
+
+  code = GET_CODE (op);
+  if (GET_RTX_CLASS (code) != '<')
+    return 0;
+
+  return (code != GT && code != LE);
+}
+
+int
+ix86_logical_operator (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
+}
+
 \f
 /* Returns 1 if OP contains a symbol reference */
 
@@ -1423,6 +1741,7 @@ symbolic_reference_mentioned_p (op)
            if (symbolic_reference_mentioned_p (XVECEXP (op, i, j)))
              return 1;
        }
+
       else if (fmt[i] == 'e' && symbolic_reference_mentioned_p (XEXP (op, i)))
        return 1;
     }
@@ -1430,81 +1749,462 @@ symbolic_reference_mentioned_p (op)
   return 0;
 }
 \f
-/* This function generates the assembly code for function entry.
-   FILE is an stdio stream to output the code to.
-   SIZE is an int: how many units of temporary storage to allocate. */
+/* Attempt to expand a binary operator.  Make the expansion closer to the
+   actual machine, then just general_operand, which will allow 3 separate
+   memory references (one output, two input) in a single insn.  Return
+   whether the insn fails, or succeeds.  */
 
-void
-function_prologue (file, size)
-     FILE *file;
-     int size;
+int
+ix86_expand_binary_operator (code, mode, operands)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx operands[];
 {
-  register int regno;
-  int limit;
-  rtx xops[4];
-  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
-                                 || current_function_uses_const_pool);
+  int modified;
 
-  xops[0] = stack_pointer_rtx;
-  xops[1] = frame_pointer_rtx;
-  xops[2] = GEN_INT (size);
-  if (frame_pointer_needed)
+  /* Recognize <var1> = <value> <op> <var1> for commutative operators */
+  if (GET_RTX_CLASS (code) == 'c'
+      && (rtx_equal_p (operands[0], operands[2])
+         || immediate_operand (operands[1], mode)))
     {
-      output_asm_insn ("push%L1 %1", xops);
-      output_asm_insn (AS2 (mov%L0,%0,%1), xops);
+      rtx temp = operands[1];
+      operands[1] = operands[2];
+      operands[2] = temp;
     }
 
-  if (size)
-    output_asm_insn (AS2 (sub%L0,%2,%0), xops);
+  /* If optimizing, copy to regs to improve CSE */
+  if (TARGET_PSEUDO && optimize
+      && ((reload_in_progress | reload_completed) == 0))
+    {
+      if (GET_CODE (operands[1]) == MEM
+         && ! rtx_equal_p (operands[0], operands[1]))
+       operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
 
-  /* Note If use enter it is NOT reversed args.
-     This one is not reversed from intel!!
-     I think enter is slower.  Also sdb doesn't like it.
-     But if you want it the code is:
-     {
-     xops[3] = const0_rtx;
-     output_asm_insn ("enter %2,%3", xops);
-     }
-     */
-  limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
-  for (regno = limit - 1; regno >= 0; regno--)
-    if ((regs_ever_live[regno] && ! call_used_regs[regno])
-       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
-      {
-       xops[0] = gen_rtx (REG, SImode, regno);
-       output_asm_insn ("push%L0 %0", xops);
-      }
+      if (GET_CODE (operands[2]) == MEM)
+       operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
 
-  if (pic_reg_used)
-    {
-      xops[0] = pic_offset_table_rtx;
-      xops[1] = (rtx) gen_label_rtx ();
+      if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
+       {
+         rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
 
-      output_asm_insn (AS1 (call,%P1), xops);
-      ASM_OUTPUT_INTERNAL_LABEL (file, "L", CODE_LABEL_NUMBER (xops[1]));
-      output_asm_insn (AS1 (pop%L0,%0), xops);
-      output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
+         emit_move_insn (temp, operands[1]);
+         operands[1] = temp;
+         return TRUE;
+       }         
     }
-}
 
-/* Return 1 if it is appropriate to emit `ret' instructions in the
-   body of a function.  Do this only if the epilogue is simple, needing a
-   couple of insns.  Prior to reloading, we can't tell how many registers
-   must be saved, so return 0 then.
+  if (!ix86_binary_operator_ok (code, mode, operands))
+    {
+      /* If not optimizing, try to make a valid insn (optimize code
+        previously did this above to improve chances of CSE) */
 
-   If NON_SAVING_SETJMP is defined and true, then it is not possible
-   for the epilogue to be simple, so return 0.  This is a special case
-   since NON_SAVING_SETJMP will not cause regs_ever_live to change until
-   final, but jump_optimize may need to know sooner if a `return' is OK.  */
+      if ((! TARGET_PSEUDO || !optimize)
+         && ((reload_in_progress | reload_completed) == 0)
+         && (GET_CODE (operands[1]) == MEM || GET_CODE (operands[2]) == MEM))
+       {
+         modified = FALSE;
+         if (GET_CODE (operands[1]) == MEM
+             && ! rtx_equal_p (operands[0], operands[1]))
+           {
+             operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+             modified = TRUE;
+           }
 
-int
-simple_386_epilogue ()
-{
-  int regno;
-  int nregs = 0;
-  int reglimit = (frame_pointer_needed
-                 ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
-  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+         if (GET_CODE (operands[2]) == MEM)
+           {
+             operands[2] = force_reg (GET_MODE (operands[2]), operands[2]);
+             modified = TRUE;
+           }
+
+         if (GET_CODE (operands[1]) == CONST_INT && code == MINUS)
+           {
+             rtx temp = gen_reg_rtx (GET_MODE (operands[0]));
+
+             emit_move_insn (temp, operands[1]);
+             operands[1] = temp;
+             return TRUE;
+           }     
+
+         if (modified && ! ix86_binary_operator_ok (code, mode, operands))
+           return FALSE;
+       }
+      else
+       return FALSE;
+    }
+
+  return TRUE;
+}
+\f
+/* Return TRUE or FALSE depending on whether the binary operator meets the
+   appropriate constraints.  */
+
+int
+ix86_binary_operator_ok (code, mode, operands)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx operands[3];
+{
+  return (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)
+    && (GET_CODE (operands[1]) != CONST_INT || GET_RTX_CLASS (code) == 'c');
+}
+\f
+/* Attempt to expand a unary operator.  Make the expansion closer to the
+   actual machine, then just general_operand, which will allow 2 separate
+   memory references (one output, one input) in a single insn.  Return
+   whether the insn fails, or succeeds.  */
+
+int
+ix86_expand_unary_operator (code, mode, operands)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx operands[];
+{
+  /* If optimizing, copy to regs to improve CSE */
+  if (TARGET_PSEUDO
+      && optimize
+      && ((reload_in_progress | reload_completed) == 0)
+      && GET_CODE (operands[1]) == MEM)
+    operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+
+  if (! ix86_unary_operator_ok (code, mode, operands))
+    {
+      if ((! TARGET_PSEUDO || optimize == 0)
+         && ((reload_in_progress | reload_completed) == 0)
+         && GET_CODE (operands[1]) == MEM)
+       {
+         operands[1] = force_reg (GET_MODE (operands[1]), operands[1]);
+         if (! ix86_unary_operator_ok (code, mode, operands))
+           return FALSE;
+       }
+      else
+       return FALSE;
+    }
+
+  return TRUE;
+}
+\f
+/* Return TRUE or FALSE depending on whether the unary operator meets the
+   appropriate constraints.  */
+
+int
+ix86_unary_operator_ok (code, mode, operands)
+     enum rtx_code code;
+     enum machine_mode mode;
+     rtx operands[2];
+{
+  return TRUE;
+}
+\f
+static rtx pic_label_rtx;
+static char pic_label_name [256];
+static int pic_label_no = 0;
+
+/* This function generates code for -fpic that loads %ebx with
+   the return address of the caller and then returns.  */
+
+void
+asm_output_function_prefix (file, name)
+     FILE *file;
+     char *name;
+{
+  rtx xops[2];
+  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+                                 || current_function_uses_const_pool);
+  xops[0] = pic_offset_table_rtx;
+  xops[1] = stack_pointer_rtx;
+
+  /* Deep branch prediction favors having a return for every call. */
+  if (pic_reg_used && TARGET_DEEP_BRANCH_PREDICTION)
+    {
+      tree prologue_node;
+
+      if (pic_label_rtx == 0)
+       {
+         pic_label_rtx = gen_label_rtx ();
+         ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
+         LABEL_NAME (pic_label_rtx) = pic_label_name;
+       }
+
+      prologue_node = make_node (FUNCTION_DECL);
+      DECL_RESULT (prologue_node) = 0;
+#ifdef ASM_DECLARE_FUNCTION_NAME
+      ASM_DECLARE_FUNCTION_NAME (file, pic_label_name, prologue_node);
+#endif
+      output_asm_insn ("movl (%1),%0", xops);
+      output_asm_insn ("ret", xops);
+    }
+}
+
+/* Generate the assembly code for function entry.
+   FILE is an stdio stream to output the code to.
+   SIZE is an int: how many units of temporary storage to allocate. */
+
+void
+function_prologue (file, size)
+     FILE *file;
+     int size;
+{
+  if (TARGET_SCHEDULE_PROLOGUE)
+    {
+      pic_label_rtx = 0;
+      return;
+    }
+  
+  ix86_prologue (0);
+}
+
+/* Expand the prologue into a bunch of separate insns. */
+
+void
+ix86_expand_prologue ()
+{
+  if (! TARGET_SCHEDULE_PROLOGUE)
+      return;
+  ix86_prologue (1);
+}
+
+void
+load_pic_register (do_rtl)
+     int do_rtl;
+{
+  rtx xops[4];
+
+  if (TARGET_DEEP_BRANCH_PREDICTION)
+    {
+      xops[0] = pic_offset_table_rtx;
+      if (pic_label_rtx == 0)
+       {
+         pic_label_rtx = gen_label_rtx ();
+         ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
+         LABEL_NAME (pic_label_rtx) = pic_label_name;
+       }
+
+      xops[1] = gen_rtx_MEM (QImode,
+                        gen_rtx (SYMBOL_REF, Pmode,
+                                 LABEL_NAME (pic_label_rtx)));
+
+      if (do_rtl)
+       {
+         emit_insn (gen_prologue_get_pc (xops[0], xops[1]));
+         emit_insn (gen_prologue_set_got (xops[0], 
+                                          gen_rtx (SYMBOL_REF, Pmode,
+                                                   "$_GLOBAL_OFFSET_TABLE_"), 
+                                          xops[1]));
+       }
+      else
+       {
+         output_asm_insn (AS1 (call,%X1), xops);
+         output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_,%0", xops);
+         pic_label_rtx = 0;
+       }
+    }
+
+  else
+    {
+      xops[0] = pic_offset_table_rtx;
+      xops[1] = gen_label_rtx ();
+      if (do_rtl)
+       {
+         /* We can't put a raw CODE_LABEL into the RTL, and we can't emit
+            a new CODE_LABEL after reload, so we need a single pattern to
+            emit the 3 necessary instructions.  */
+         emit_insn (gen_prologue_get_pc_and_set_got (xops[0]));
+       }
+      else
+       {
+         output_asm_insn (AS1 (call,%P1), xops);
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", 
+                                    CODE_LABEL_NUMBER (xops[1]));
+         output_asm_insn (AS1 (pop%L0,%0), xops);
+         output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_+[.-%P1],%0", xops);
+       }
+    } 
+
+  /* When -fpic, we must emit a scheduling barrier, so that the instruction
+     that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get
+     moved before any instruction which implicitly uses the got.   */
+
+  if (do_rtl)
+    emit_insn (gen_blockage ());
+}
+
+static void
+ix86_prologue (do_rtl)
+     int do_rtl;
+{
+  register int regno;
+  int limit;
+  rtx xops[4];
+  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+                                 || current_function_uses_const_pool);
+  long tsize = get_frame_size ();
+  rtx insn;
+  int cfa_offset = INCOMING_FRAME_SP_OFFSET, cfa_store_offset = cfa_offset;
+  
+  xops[0] = stack_pointer_rtx;
+  xops[1] = frame_pointer_rtx;
+  xops[2] = GEN_INT (tsize);
+
+  if (frame_pointer_needed)
+    {
+      if (do_rtl)
+       {
+         insn = emit_insn (gen_rtx (SET, VOIDmode,
+                                    gen_rtx_MEM (SImode,
+                                             gen_rtx (PRE_DEC, SImode,
+                                                      stack_pointer_rtx)),
+                                    frame_pointer_rtx));
+
+         RTX_FRAME_RELATED_P (insn) = 1;
+         insn = emit_move_insn (xops[1], xops[0]);
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+
+      else
+       {
+         output_asm_insn ("push%L1 %1", xops); 
+#ifdef INCOMING_RETURN_ADDR_RTX
+         if (dwarf2out_do_frame ())
+           {
+             char *l = dwarf2out_cfi_label ();
+
+             cfa_store_offset += 4;
+             cfa_offset = cfa_store_offset;
+             dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
+             dwarf2out_reg_save (l, FRAME_POINTER_REGNUM, - cfa_store_offset);
+           }
+#endif
+
+         output_asm_insn (AS2 (mov%L0,%0,%1), xops); 
+#ifdef INCOMING_RETURN_ADDR_RTX
+         if (dwarf2out_do_frame ())
+           dwarf2out_def_cfa ("", FRAME_POINTER_REGNUM, cfa_offset);
+#endif
+       }
+    }
+
+  if (tsize == 0)
+    ;
+  else if (! TARGET_STACK_PROBE || tsize < CHECK_STACK_LIMIT)
+    {
+      if (do_rtl)
+       {
+         insn = emit_insn (gen_prologue_set_stack_ptr (xops[2]));
+         RTX_FRAME_RELATED_P (insn) = 1;
+       }
+      else 
+       {
+         output_asm_insn (AS2 (sub%L0,%2,%0), xops);
+#ifdef INCOMING_RETURN_ADDR_RTX
+         if (dwarf2out_do_frame ())
+           {
+             cfa_store_offset += tsize;
+             if (! frame_pointer_needed)
+               {
+                 cfa_offset = cfa_store_offset;
+                 dwarf2out_def_cfa ("", STACK_POINTER_REGNUM, cfa_offset);
+               }
+           }
+#endif
+       }
+    }
+  else 
+    {
+      xops[3] = gen_rtx_REG (SImode, 0);
+      if (do_rtl)
+      emit_move_insn (xops[3], xops[2]);
+      else
+       output_asm_insn (AS2 (mov%L0,%2,%3), xops);
+
+      xops[3] = gen_rtx_MEM (FUNCTION_MODE,
+                        gen_rtx (SYMBOL_REF, Pmode, "_alloca"));
+
+      if (do_rtl)
+       emit_call_insn (gen_rtx (CALL, VOIDmode, xops[3], const0_rtx));
+      else
+       output_asm_insn (AS1 (call,%P3), xops);
+    }
+
+  /* Note If use enter it is NOT reversed args.
+     This one is not reversed from intel!!
+     I think enter is slower.  Also sdb doesn't like it.
+     But if you want it the code is:
+     {
+     xops[3] = const0_rtx;
+     output_asm_insn ("enter %2,%3", xops);
+     }
+     */
+
+  limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+  for (regno = limit - 1; regno >= 0; regno--)
+    if ((regs_ever_live[regno] && ! call_used_regs[regno])
+       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+      {
+       xops[0] = gen_rtx_REG (SImode, regno);
+       if (do_rtl)
+         {
+           insn = emit_insn (gen_rtx (SET, VOIDmode,
+                                      gen_rtx_MEM (SImode,
+                                               gen_rtx (PRE_DEC, SImode,
+                                                        stack_pointer_rtx)),
+                                      xops[0]));
+
+           RTX_FRAME_RELATED_P (insn) = 1;
+         }
+       else
+         {
+           output_asm_insn ("push%L0 %0", xops);
+#ifdef INCOMING_RETURN_ADDR_RTX
+           if (dwarf2out_do_frame ())
+             {
+               char *l = dwarf2out_cfi_label ();
+
+               cfa_store_offset += 4;
+               if (! frame_pointer_needed)
+                 {
+                   cfa_offset = cfa_store_offset;
+                   dwarf2out_def_cfa (l, STACK_POINTER_REGNUM, cfa_offset);
+                 }
+
+               dwarf2out_reg_save (l, regno, - cfa_store_offset);
+             }
+#endif
+         }
+      }
+
+  if (pic_reg_used)
+    load_pic_register (do_rtl);
+
+  /* If we are profiling, make sure no instructions are scheduled before
+     the call to mcount.  However, if -fpic, the above call will have
+     done that.  */
+  if ((profile_flag || profile_block_flag)
+      && ! pic_reg_used && do_rtl)
+    emit_insn (gen_blockage ());
+}
+
+/* Return 1 if it is appropriate to emit `ret' instructions in the
+   body of a function.  Do this only if the epilogue is simple, needing a
+   couple of insns.  Prior to reloading, we can't tell how many registers
+   must be saved, so return 0 then.  Return 0 if there is no frame 
+   marker to de-allocate.
+
+   If NON_SAVING_SETJMP is defined and true, then it is not possible
+   for the epilogue to be simple, so return 0.  This is a special case
+   since NON_SAVING_SETJMP will not cause regs_ever_live to change
+   until final, but jump_optimize may need to know sooner if a
+   `return' is OK.  */
+
+int
+ix86_can_use_return_insn_p ()
+{
+  int regno;
+  int nregs = 0;
+  int reglimit = (frame_pointer_needed
+                 ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
+  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
                                  || current_function_uses_const_pool);
 
 #ifdef NON_SAVING_SETJMP
@@ -1523,7 +2223,6 @@ simple_386_epilogue ()
   return nregs == 0 || ! frame_pointer_needed;
 }
 
-\f
 /* This function generates the assembly code for function exit.
    FILE is an stdio stream to output the code to.
    SIZE is an int: how many units of temporary storage to deallocate. */
@@ -1533,18 +2232,32 @@ function_epilogue (file, size)
      FILE *file;
      int size;
 {
+    return;
+}
+
+/* Restore function stack, frame, and registers. */ 
+
+void
+ix86_expand_epilogue ()
+{
+  ix86_epilogue (1);
+}
+
+static void
+ix86_epilogue (do_rtl)
+     int do_rtl;
+{
   register int regno;
   register int nregs, limit;
   int offset;
   rtx xops[3];
   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
                                  || current_function_uses_const_pool);
+  long tsize = get_frame_size ();
 
   /* Compute the number of registers to pop */
 
-  limit = (frame_pointer_needed
-          ? FRAME_POINTER_REGNUM
-          : STACK_POINTER_REGNUM);
+  limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
 
   nregs = 0;
 
@@ -1553,66 +2266,115 @@ function_epilogue (file, size)
        || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
       nregs++;
 
-  /* sp is often  unreliable so we must go off the frame pointer,
-   */
+  /* sp is often  unreliable so we must go off the frame pointer.
 
-  /* In reality, we may not care if sp is unreliable, because we can
-     restore the register relative to the frame pointer.  In theory,
-     since each move is the same speed as a pop, and we don't need the
-     leal, this is faster.  For now restore multiple registers the old
-     way. */
+     In reality, we may not care if sp is unreliable, because we can restore
+     the register relative to the frame pointer.  In theory, since each move
+     is the same speed as a pop, and we don't need the leal, this is faster.
+     For now restore multiple registers the old way. */
 
-  offset = -size - (nregs * UNITS_PER_WORD);
+  offset = - tsize - (nregs * UNITS_PER_WORD);
 
   xops[2] = stack_pointer_rtx;
 
+  /* When -fpic, we must emit a scheduling barrier, so that the instruction
+     that restores %ebx (which is PIC_OFFSET_TABLE_REGNUM), does not get
+     moved before any instruction which implicitly uses the got.  This
+     includes any instruction which uses a SYMBOL_REF or a LABEL_REF.
+
+     Alternatively, this could be fixed by making the dependence on the
+     PIC_OFFSET_TABLE_REGNUM explicit in the RTL.  */
+
+  if (flag_pic || profile_flag || profile_block_flag)
+    emit_insn (gen_blockage ());
+
   if (nregs > 1 || ! frame_pointer_needed)
     {
       if (frame_pointer_needed)
        {
-         xops[0] = adj_offsettable_operand (AT_BP (Pmode), offset);
-         output_asm_insn (AS2 (lea%L2,%0,%2), xops);
+         xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
+         if (do_rtl)
+           emit_insn (gen_movsi_lea (xops[2], XEXP (xops[0], 0)));
+         else
+           output_asm_insn (AS2 (lea%L2,%0,%2), xops);
        }
 
       for (regno = 0; regno < limit; regno++)
        if ((regs_ever_live[regno] && ! call_used_regs[regno])
            || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
          {
-           xops[0] = gen_rtx (REG, SImode, regno);
-           output_asm_insn ("pop%L0 %0", xops);
+           xops[0] = gen_rtx_REG (SImode, regno);
+
+           if (do_rtl)
+             emit_insn (gen_pop (xops[0]));
+           else
+             output_asm_insn ("pop%L0 %0", xops);
          }
     }
+
   else
     for (regno = 0; regno < limit; regno++)
       if ((regs_ever_live[regno] && ! call_used_regs[regno])
          || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
        {
-         xops[0] = gen_rtx (REG, SImode, regno);
+         xops[0] = gen_rtx_REG (SImode, regno);
          xops[1] = adj_offsettable_operand (AT_BP (Pmode), offset);
-         output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+         if (do_rtl)
+           emit_move_insn (xops[0], xops[1]);
+         else
+           output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
          offset += 4;
        }
 
   if (frame_pointer_needed)
     {
-      /* On i486, mov & pop is faster than "leave". */
+      /* If not an i386, mov & pop is faster than "leave". */
 
-      if (!TARGET_386)
+      if (TARGET_USE_LEAVE)
        {
-         xops[0] = frame_pointer_rtx;
-         output_asm_insn (AS2 (mov%L2,%0,%2), xops);
-         output_asm_insn ("pop%L0 %0", xops);
+         if (do_rtl)
+           emit_insn (gen_leave());
+         else
+           output_asm_insn ("leave", xops);
        }
       else
-       output_asm_insn ("leave", xops);
+       {
+         xops[0] = frame_pointer_rtx;
+         xops[1] = stack_pointer_rtx;
+
+         if (do_rtl)
+           {
+             emit_insn (gen_epilogue_set_stack_ptr());
+             emit_insn (gen_pop (xops[0]));
+           }
+         else
+           {
+             output_asm_insn (AS2 (mov%L2,%0,%2), xops);
+             output_asm_insn ("pop%L0 %0", xops);
+           }
+       }
     }
-  else if (size)
+
+  else if (tsize)
     {
       /* If there is no frame pointer, we must still release the frame. */
+      xops[0] = GEN_INT (tsize);
+
+      if (do_rtl)
+       emit_insn (gen_rtx (SET, VOIDmode, xops[2],
+                           gen_rtx (PLUS, SImode, xops[2], xops[0])));
+      else
+       output_asm_insn (AS2 (add%L2,%0,%2), xops);
+    }
 
-      xops[0] = GEN_INT (size);
-      output_asm_insn (AS2 (add%L2,%0,%2), xops);
+#ifdef FUNCTION_BLOCK_PROFILER_EXIT
+  if (profile_block_flag == 2)
+    {
+      FUNCTION_BLOCK_PROFILER_EXIT(file);
     }
+#endif
 
   if (current_function_pops_args && current_function_args_size)
     {
@@ -1625,18 +2387,38 @@ function_epilogue (file, size)
       if (current_function_pops_args >= 32768)
        {
          /* ??? Which register to use here? */
-         xops[0] = gen_rtx (REG, SImode, 2);
-         output_asm_insn ("pop%L0 %0", xops);
-         output_asm_insn (AS2 (add%L2,%1,%2), xops);
-         output_asm_insn ("jmp %*%0", xops);
+         xops[0] = gen_rtx_REG (SImode, 2);
+
+         if (do_rtl)
+           {
+             emit_insn (gen_pop (xops[0]));
+             emit_insn (gen_rtx (SET, VOIDmode, xops[2],
+                                 gen_rtx (PLUS, SImode, xops[1], xops[2])));
+             emit_jump_insn (xops[0]);
+           }
+         else
+           {
+             output_asm_insn ("pop%L0 %0", xops);
+             output_asm_insn (AS2 (add%L2,%1,%2), xops);
+             output_asm_insn ("jmp %*%0", xops);
+           }
+       }
+      else 
+       {
+         if (do_rtl)
+           emit_jump_insn (gen_return_pop_internal (xops[1]));
+         else
+           output_asm_insn ("ret %1", xops);
        }
-      else
-         output_asm_insn ("ret %1", xops);
     }
   else
-    output_asm_insn ("ret", xops);
+    {
+      if (do_rtl)
+       emit_jump_insn (gen_return_internal ());
+      else
+       output_asm_insn ("ret", xops);
+    }
 }
-
 \f
 /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression
    that is a valid memory address for an instruction.
@@ -1686,14 +2468,14 @@ legitimate_address_p (mode, addr, strict)
   if (TARGET_DEBUG_ADDR)
     {
       fprintf (stderr,
-              "\n==========\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
+              "\n======\nGO_IF_LEGITIMATE_ADDRESS, mode = %s, strict = %d\n",
               GET_MODE_NAME (mode), strict);
 
       debug_rtx (addr);
     }
 
   if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
-      base = addr;                             /* base reg */
+      base = addr;
 
   else if (GET_CODE (addr) == PLUS)
     {
@@ -1706,13 +2488,13 @@ legitimate_address_p (mode, addr, strict)
        {
          if (code1 == REG || code1 == SUBREG)
            {
-             indx = op0;                       /* index + base */
+             indx = op0;       /* index + base */
              base = op1;
            }
 
          else
            {
-             base = op0;                       /* base + displacement */
+             base = op0;       /* base + displacement */
              disp = op1;
            }
        }
@@ -1723,10 +2505,10 @@ legitimate_address_p (mode, addr, strict)
          scale = XEXP (op0, 1);
 
          if (code1 == REG || code1 == SUBREG)
-           base = op1;                         /* index*scale + base */
+           base = op1;         /* index*scale + base */
 
          else
-           disp = op1;                         /* index*scale + disp */
+           disp = op1;         /* index*scale + disp */
        }
 
       else if (code0 == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
@@ -1739,7 +2521,7 @@ legitimate_address_p (mode, addr, strict)
 
       else if (code0 == PLUS)
        {
-         indx = XEXP (op0, 0);                 /* index + base + disp */
+         indx = XEXP (op0, 0); /* index + base + disp */
          base = XEXP (op0, 1);
          disp = op1;
        }
@@ -1753,12 +2535,12 @@ legitimate_address_p (mode, addr, strict)
 
   else if (GET_CODE (addr) == MULT)
     {
-      indx  = XEXP (addr, 0);                  /* index*scale */
+      indx  = XEXP (addr, 0);  /* index*scale */
       scale = XEXP (addr, 1);
     }
 
   else
-    disp = addr;                               /* displacement */
+    disp = addr;               /* displacement */
 
   /* Allow arg pointer and stack pointer as index if there is not scaling */
   if (base && indx && !scale
@@ -1769,10 +2551,12 @@ legitimate_address_p (mode, addr, strict)
       indx = tmp;
     }
 
-  /* Validate base register */
-  /* Don't allow SUBREG's here, it can lead to spill failures when the base
+  /* Validate base register:
+
+     Don't allow SUBREG's here, it can lead to spill failures when the base
      is one word out of a two word structure, which is represented internally
      as a DImode int.  */
+
   if (base)
     {
       if (GET_CODE (base) != REG)
@@ -1781,16 +2565,17 @@ legitimate_address_p (mode, addr, strict)
          return FALSE;
        }
 
-      if ((strict && !REG_OK_FOR_BASE_STRICT_P (base))
-         || (!strict && !REG_OK_FOR_BASE_NONSTRICT_P (base)))
+      if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
+         || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
        {
          ADDR_INVALID ("Base is not valid.\n", base);
          return FALSE;
        }
     }
 
-  /* Validate index register */
-  /* Don't allow SUBREG's here, it can lead to spill failures when the index
+  /* Validate index register:
+
+     Don't allow SUBREG's here, it can lead to spill failures when the index
      is one word out of a two word structure, which is represented internally
      as a DImode int.  */
   if (indx)
@@ -1801,17 +2586,17 @@ legitimate_address_p (mode, addr, strict)
          return FALSE;
        }
 
-      if ((strict && !REG_OK_FOR_INDEX_STRICT_P (indx))
-         || (!strict && !REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
+      if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (indx))
+         || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
        {
          ADDR_INVALID ("Index is not valid.\n", indx);
          return FALSE;
        }
     }
   else if (scale)
-    abort ();                                  /* scale w/o index invalid */
+    abort ();                  /* scale w/o index invalid */
 
-  /* Validate scale factor */
+  /* Validate scale factor: */
   if (scale)
     {
       HOST_WIDE_INT value;
@@ -1830,32 +2615,44 @@ legitimate_address_p (mode, addr, strict)
        }
     }
 
-  /* Validate displacement */
+  /* Validate displacement
+     Constant pool addresses must be handled special.  They are
+     considered legitimate addresses, but only if not used with regs.
+     When printed, the output routines know to print the reference with the
+     PIC reg, even though the PIC reg doesn't appear in the RTL. */
   if (disp)
     {
-      if (!CONSTANT_ADDRESS_P (disp))
+      if (GET_CODE (disp) == SYMBOL_REF
+         && CONSTANT_POOL_ADDRESS_P (disp)
+         && base == 0
+         && indx == 0)
+       ;
+
+      else if (!CONSTANT_ADDRESS_P (disp))
        {
          ADDR_INVALID ("Displacement is not valid.\n", disp);
          return FALSE;
        }
 
-      if (GET_CODE (disp) == CONST_DOUBLE)
+      else if (GET_CODE (disp) == CONST_DOUBLE)
        {
          ADDR_INVALID ("Displacement is a const_double.\n", disp);
          return FALSE;
        }
 
-      if (flag_pic && SYMBOLIC_CONST (disp) && base != pic_offset_table_rtx
-         && (indx != pic_offset_table_rtx || scale != NULL_RTX))
+      else if (flag_pic && SYMBOLIC_CONST (disp)
+              && base != pic_offset_table_rtx
+              && (indx != pic_offset_table_rtx || scale != NULL_RTX))
        {
          ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp);
          return FALSE;
        }
 
-      if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
-         && (base != NULL_RTX || indx != NULL_RTX))
+      else if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
+              && (base != NULL_RTX || indx != NULL_RTX))
        {
-         ADDR_INVALID ("Displacement is an invalid half-pic reference.\n", disp);
+         ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
+                       disp);
          return FALSE;
        }
     }
@@ -1866,7 +2663,6 @@ legitimate_address_p (mode, addr, strict)
   /* Everything looks valid, return true */
   return TRUE;
 }
-
 \f
 /* Return a legitimate reference for ORIG (an address) using the
    register REG.  If REG is 0, a new pseudo is generated.
@@ -1916,15 +2712,15 @@ legitimize_pic_address (orig, reg)
              || GET_CODE (addr) == LABEL_REF)
            new = gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig);
          else
-           new = gen_rtx (MEM, Pmode,
-                          gen_rtx (PLUS, Pmode,
-                                   pic_offset_table_rtx, orig));
+           new = gen_rtx_MEM (Pmode,
+                          gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig));
 
          emit_move_insn (reg, new);
        }
       current_function_uses_pic_offset_table = 1;
       return reg;
     }
+
   else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
     {
       rtx base;
@@ -1954,12 +2750,12 @@ legitimize_pic_address (orig, reg)
          base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
          addr = XEXP (addr, 1);
        }
-       return gen_rtx (PLUS, Pmode, base, addr);
+
+      return gen_rtx (PLUS, Pmode, base, addr);
     }
   return new;
 }
 \f
-
 /* Emit insns to move operands[1] into operands[0].  */
 
 void
@@ -1970,11 +2766,10 @@ emit_pic_move (operands, mode)
   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
 
   if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
-    operands[1] = (rtx) force_reg (SImode, operands[1]);
+    operands[1] = force_reg (SImode, operands[1]);
   else
     operands[1] = legitimize_pic_address (operands[1], temp);
 }
-
 \f
 /* Try machine-dependent ways of modifying an illegitimate address
    to be legitimate.  If we find one, return the new, valid address.
@@ -2008,7 +2803,8 @@ legitimize_address (x, oldx, mode)
 
   if (TARGET_DEBUG_ADDR)
     {
-      fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n", GET_MODE_NAME (mode));
+      fprintf (stderr, "\n==========\nLEGITIMIZE_ADDRESS, mode = %s\n",
+              GET_MODE_NAME (mode));
       debug_rtx (x);
     }
 
@@ -2021,14 +2817,14 @@ legitimize_address (x, oldx, mode)
       && (log = (unsigned)exact_log2 (INTVAL (XEXP (x, 1)))) < 4)
     {
       changed = 1;
-      x = gen_rtx (MULT, Pmode,
-                  force_reg (Pmode, XEXP (x, 0)),
+      x = gen_rtx (MULT, Pmode, force_reg (Pmode, XEXP (x, 0)),
                   GEN_INT (1 << log));
     }
 
   if (GET_CODE (x) == PLUS)
     {
-      /* Canonicalize shifts by 0, 1, 2, 3 into multiply */
+      /* Canonicalize shifts by 0, 1, 2, 3 into multiply. */
+
       if (GET_CODE (XEXP (x, 0)) == ASHIFT
          && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
          && (log = (unsigned)exact_log2 (INTVAL (XEXP (XEXP (x, 0), 1)))) < 4)
@@ -2049,7 +2845,7 @@ legitimize_address (x, oldx, mode)
                                 GEN_INT (1 << log));
        }
 
-      /* Put multiply first if it isn't already */
+      /* Put multiply first if it isn't already. */
       if (GET_CODE (XEXP (x, 1)) == MULT)
        {
          rtx tmp = XEXP (x, 0);
@@ -2066,18 +2862,21 @@ legitimize_address (x, oldx, mode)
        {
          changed = 1;
          x = gen_rtx (PLUS, Pmode,
-                      gen_rtx (PLUS, Pmode, XEXP (x, 0), XEXP (XEXP (x, 1), 0)),
+                      gen_rtx (PLUS, Pmode, XEXP (x, 0),
+                               XEXP (XEXP (x, 1), 0)),
                       XEXP (XEXP (x, 1), 1));
        }
 
-      /* Canonicalize (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
+      /* Canonicalize
+        (plus (plus (mult (reg) (const)) (plus (reg) (const))) const)
         into (plus (plus (mult (reg) (const)) (reg)) (const)).  */
       else if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 0)) == PLUS
               && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
               && GET_CODE (XEXP (XEXP (x, 0), 1)) == PLUS
               && CONSTANT_P (XEXP (x, 1)))
        {
-         rtx constant, other;
+         rtx constant;
+         rtx other = NULL_RTX;
 
          if (GET_CODE (XEXP (x, 1)) == CONST_INT)
            {
@@ -2156,7 +2955,6 @@ legitimize_address (x, oldx, mode)
 
   return x;
 }
-
 \f
 /* Print an integer constant expression in assembler syntax.  Addition
    and subtraction are the only arithmetic that may appear in these
@@ -2191,7 +2989,9 @@ output_pic_addr_const (file, x, code)
          assemble_name (asm_out_file, buf);
        }
 
-      if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
+      if (code == 'X')
+       ; /* No suffix, dammit. */
+      else if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
        fprintf (file, "@GOTOFF(%%ebx)");
       else if (code == 'P')
        fprintf (file, "@PLT");
@@ -2210,7 +3010,7 @@ output_pic_addr_const (file, x, code)
       break;
 
     case CONST_INT:
-      fprintf (file, "%d", INTVAL (x));
+      fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x));
       break;
 
     case CONST:
@@ -2224,10 +3024,11 @@ output_pic_addr_const (file, x, code)
        {
          /* We can use %d if the number is <32 bits and positive.  */
          if (CONST_DOUBLE_HIGH (x) || CONST_DOUBLE_LOW (x) < 0)
-           fprintf (file, "0x%x%08x",
-                    CONST_DOUBLE_HIGH (x), CONST_DOUBLE_LOW (x));
+           fprintf (file, "0x%lx%08lx",
+                    (unsigned long) CONST_DOUBLE_HIGH (x),
+                    (unsigned long) CONST_DOUBLE_LOW (x));
          else
-           fprintf (file, "%d", CONST_DOUBLE_LOW (x));
+           fprintf (file, HOST_WIDE_INT_PRINT_DEC, CONST_DOUBLE_LOW (x));
        }
       else
        /* We can't handle floating point constants;
@@ -2236,25 +3037,25 @@ output_pic_addr_const (file, x, code)
       break;
 
     case PLUS:
-      /* Some assemblers need integer constants to appear last (eg masm).  */
+      /* Some assemblers need integer constants to appear first.  */
       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
        {
-         output_pic_addr_const (file, XEXP (x, 1), code);
-         if (INTVAL (XEXP (x, 0)) >= 0)
-           fprintf (file, "+");
-         output_pic_addr_const (file, XEXP (x, 0), code);
-       }
-      else
-       {
          output_pic_addr_const (file, XEXP (x, 0), code);
          if (INTVAL (XEXP (x, 1)) >= 0)
            fprintf (file, "+");
          output_pic_addr_const (file, XEXP (x, 1), code);
        }
-      break;
-
-    case MINUS:
-      output_pic_addr_const (file, XEXP (x, 0), code);
+      else
+       {
+         output_pic_addr_const (file, XEXP (x, 1), code);
+         if (INTVAL (XEXP (x, 0)) >= 0)
+           fprintf (file, "+");
+         output_pic_addr_const (file, XEXP (x, 0), code);
+       }
+      break;
+
+    case MINUS:
+      output_pic_addr_const (file, XEXP (x, 0), code);
       fprintf (file, "-");
       output_pic_addr_const (file, XEXP (x, 1), code);
       break;
@@ -2264,16 +3065,138 @@ output_pic_addr_const (file, x, code)
     }
 }
 \f
+/* Append the correct conditional move suffix which corresponds to CODE.  */
+
+static void
+put_condition_code (code, reverse_cc, mode, file)
+     enum rtx_code code;
+     int  reverse_cc;
+     enum mode_class mode;
+     FILE * file;
+{
+  int ieee = (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387)
+             && ! (cc_prev_status.flags & CC_FCOMI));
+  if (reverse_cc && ! ieee)
+    code = reverse_condition (code);
+
+  if (mode == MODE_INT)
+    switch (code)
+      {
+      case NE: 
+       if (cc_prev_status.flags & CC_Z_IN_NOT_C)
+         fputs ("b", file);
+       else
+         fputs ("ne", file);
+       return;
+
+      case EQ:
+       if (cc_prev_status.flags & CC_Z_IN_NOT_C)
+         fputs ("ae", file);
+       else
+         fputs ("e", file);
+       return;
+
+      case GE:
+       if (cc_prev_status.flags & CC_NO_OVERFLOW)
+         fputs ("ns", file);
+       else
+         fputs ("ge", file);
+       return;
+
+      case GT:
+       fputs ("g", file);
+       return;
+
+      case LE:
+       fputs ("le", file);
+       return;
+
+      case LT:
+       if (cc_prev_status.flags & CC_NO_OVERFLOW)
+         fputs ("s", file);
+       else
+         fputs ("l", file);
+       return;
+
+      case GEU:
+       fputs ("ae", file);
+       return;
+
+      case GTU:
+       fputs ("a", file);
+       return;
+
+      case LEU:
+       fputs ("be", file);
+       return;
+
+      case LTU:
+       fputs ("b", file);
+       return;
+
+      default:
+       output_operand_lossage ("Invalid %%C operand");
+      }
+
+  else if (mode == MODE_FLOAT)
+    switch (code)
+      {
+      case NE: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "ne", file);
+       return;
+      case EQ: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "e", file);
+       return;
+      case GE: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
+       return;
+      case GT: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
+       return;
+      case LE: 
+       fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
+       return;
+      case LT: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
+       return;
+      case GEU: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
+       return;
+      case GTU: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
+       return;
+      case LEU: 
+       fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
+       return;
+      case LTU: 
+       fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
+       return;
+      default:
+       output_operand_lossage ("Invalid %%C operand");
+    }
+}
+
 /* Meaning of CODE:
-   f -- float insn (print a CONST_DOUBLE as a float rather than in hex).
-   D,L,W,B,Q,S -- print the opcode suffix for specified size of operand.
+   L,W,B,Q,S,T -- print the opcode suffix for specified size of operand.
+   C -- print opcode suffix for set/cmov insn.
+   c -- like C, but print reversed condition
+   F -- print opcode suffix for fcmov insn.
+   f -- like C, but print reversed condition
    R -- print the prefix for register names.
    z -- print the opcode suffix for the size of the current operand.
    * -- print a star (in certain assembler syntax)
    w -- print the operand as if it's a "word" (HImode) even if it isn't.
    c -- don't print special prefixes before constant operands.
    J -- print the appropriate jump operand.
-*/
+   s -- print a shift double count, followed by the assemblers argument
+       delimiter.
+   b -- print the QImode name of the register for the indicated operand.
+       %b0 would print %al if operands[0] is reg 0.
+   w --  likewise, print the HImode name of the register.
+   k --  likewise, print the SImode name of the register.
+   h --  print the QImode name for a "high" register, either ah, bh, ch or dh.
+   y --  print "st(0)" instead of "st" as a register.
+   P --  print as a PIC constant */
 
 void
 print_operand (file, x, code)
@@ -2367,23 +3290,57 @@ print_operand (file, x, code)
        case 'h':
        case 'y':
        case 'P':
+       case 'X':
          break;
 
        case 'J':
          switch (GET_CODE (x))
            {
+             /* These conditions are appropriate for testing the result
+                of an arithmetic operation, not for a compare operation.
+                Cases GE, LT assume CC_NO_OVERFLOW true. All cases assume
+                CC_Z_IN_NOT_C false and not floating point.  */
            case NE:  fputs ("jne", file); return;
            case EQ:  fputs ("je",  file); return;
-           case GE:  fputs ("jge", file); return;
-           case GT:  fputs ("jg",  file); return;
-           case LE:  fputs ("jle", file); return;
-           case LT:  fputs ("jl",  file); return;
-           case GEU: fputs ("jae", file); return;
-           case GTU: fputs ("ja",  file); return;
-           case LEU: fputs ("jbe", file); return;
-           case LTU: fputs ("jb",  file); return;
+           case GE:  fputs ("jns", file); return;
+           case LT:  fputs ("js",  file); return;
+           case GEU: fputs ("jmp", file); return;
+           case GTU: fputs ("jne",  file); return;
+           case LEU: fputs ("je", file); return;
+           case LTU: fputs ("#branch never",  file); return;
+           
+           /* no matching branches for GT nor LE */
+           
+           default:
+             abort ();
            }
-         abort ();
+
+       case 's':
+         if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT)
+           {
+             PRINT_OPERAND (file, x, 0);
+             fputs (AS2C (,) + 1, file);
+           }
+
+         return;
+
+         /* This is used by the conditional move instructions.  */
+       case 'C':
+         put_condition_code (GET_CODE (x), 0, MODE_INT, file);
+         return;
+
+         /* Like above, but reverse condition */
+       case 'c':
+         put_condition_code (GET_CODE (x), 1, MODE_INT, file); return;
+
+       case 'F':
+         put_condition_code (GET_CODE (x), 0, MODE_FLOAT, file);
+         return;
+
+         /* Like above, but reverse condition */
+       case 'f':
+         put_condition_code (GET_CODE (x), 1, MODE_FLOAT, file);
+         return;
 
        default:
          {
@@ -2394,10 +3351,12 @@ print_operand (file, x, code)
          }
        }
     }
+
   if (GET_CODE (x) == REG)
     {
       PRINT_REG (x, code, file);
     }
+
   else if (GET_CODE (x) == MEM)
     {
       PRINT_PTR (x, file);
@@ -2411,25 +3370,34 @@ print_operand (file, x, code)
       else
        output_address (XEXP (x, 0));
     }
+
   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == SFmode)
     {
-      REAL_VALUE_TYPE r; long l;
+      REAL_VALUE_TYPE r;
+      long l;
+
       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
       REAL_VALUE_TO_TARGET_SINGLE (r, l);
       PRINT_IMMED_PREFIX (file);
       fprintf (file, "0x%x", l);
     }
+
  /* These float cases don't actually occur as immediate operands. */
  else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == DFmode)
     {
-      REAL_VALUE_TYPE r; char dstr[30];
+      REAL_VALUE_TYPE r;
+      char dstr[30];
+
       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
       fprintf (file, "%s", dstr);
     }
+
   else if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) == XFmode)
     {
-      REAL_VALUE_TYPE r; char dstr[30];
+      REAL_VALUE_TYPE r;
+      char dstr[30];
+
       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
       fprintf (file, "%s", dstr);
@@ -2486,38 +3454,35 @@ print_operand_address (file, addr)
          offset = XEXP (addr, 1);
          addr = XEXP (addr, 0);
        }
-      if (GET_CODE (addr) != PLUS) ;
+
+      if (GET_CODE (addr) != PLUS)
+       ;
       else if (GET_CODE (XEXP (addr, 0)) == MULT)
-       {
-         reg1 = XEXP (addr, 0);
-         addr = XEXP (addr, 1);
-       }
+       reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
       else if (GET_CODE (XEXP (addr, 1)) == MULT)
-       {
-         reg1 = XEXP (addr, 1);
-         addr = XEXP (addr, 0);
-       }
+       reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
       else if (GET_CODE (XEXP (addr, 0)) == REG)
-       {
-         reg1 = XEXP (addr, 0);
-         addr = XEXP (addr, 1);
-       }
+       reg1 = XEXP (addr, 0), addr = XEXP (addr, 1);
       else if (GET_CODE (XEXP (addr, 1)) == REG)
-       {
-         reg1 = XEXP (addr, 1);
-         addr = XEXP (addr, 0);
-       }
+       reg1 = XEXP (addr, 1), addr = XEXP (addr, 0);
+
       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
        {
-         if (reg1 == 0) reg1 = addr;
-         else reg2 = addr;
+         if (reg1 == 0)
+           reg1 = addr;
+         else
+           reg2 = addr;
+
          addr = 0;
        }
+
       if (offset != 0)
        {
-         if (addr != 0) abort ();
+         if (addr != 0)
+           abort ();
          addr = offset;
        }
+
       if ((reg1 && GET_CODE (reg1) == MULT)
          || (reg2 != 0 && REGNO_OK_FOR_BASE_P (REGNO (reg2))))
        {
@@ -2538,10 +3503,8 @@ print_operand_address (file, addr)
            {
              if (flag_pic)
                output_pic_addr_const (file, addr, 0);
-
              else if (GET_CODE (addr) == LABEL_REF)
                output_asm_label (addr);
-
              else
                output_addr_const (file, addr);
            }
@@ -2572,6 +3535,7 @@ print_operand_address (file, addr)
     case MULT:
       {
        int scale;
+
        if (GET_CODE (XEXP (addr, 0)) == CONST_INT)
          {
            scale = INTVAL (XEXP (addr, 0));
@@ -2582,8 +3546,9 @@ print_operand_address (file, addr)
            scale = INTVAL (XEXP (addr, 1));
            ireg = XEXP (addr, 0);
          }
+
        output_addr_const (file, const0_rtx);
-       PRINT_B_I_S ((rtx) 0, ireg, scale, file);
+       PRINT_B_I_S (NULL_RTX, ireg, scale, file);
       }
       break;
 
@@ -2591,7 +3556,7 @@ print_operand_address (file, addr)
       if (GET_CODE (addr) == CONST_INT
          && INTVAL (addr) < 0x8000
          && INTVAL (addr) >= -0x8000)
-       fprintf (file, "%d", INTVAL (addr));
+       fprintf (file, "%d", (int) INTVAL (addr));
       else
        {
          if (flag_pic)
@@ -2604,7 +3569,7 @@ print_operand_address (file, addr)
 \f
 /* Set the cc_status for the results of an insn whose pattern is EXP.
    On the 80386, we assume that only test and compare insns, as well
-   as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, ASHIFT,
+   as SI, HI, & DI mode ADD, SUB, NEG, AND, IOR, XOR, BSF, ASHIFT,
    ASHIFTRT, and LSHIFTRT instructions set the condition codes usefully.
    Also, we assume that jumps, moves and sCOND don't affect the condition
    codes.  All else clobbers the condition codes, by assumption.
@@ -2624,6 +3589,7 @@ notice_update_cc (exp)
       /* Jumps do not alter the cc's.  */
       if (SET_DEST (exp) == pc_rtx)
        return;
+
       /* Moving register or memory into a register:
         it doesn't alter the cc's, but it might invalidate
         the RTX's which we remember the cc's came from.
@@ -2635,29 +3601,37 @@ notice_update_cc (exp)
          if (cc_status.value1
              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
            cc_status.value1 = 0;
+
          if (cc_status.value2
              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
            cc_status.value2 = 0;
+
          return;
        }
+
       /* Moving register into memory doesn't alter the cc's.
         It may invalidate the RTX's which we remember the cc's came from.  */
       if (GET_CODE (SET_DEST (exp)) == MEM
          && (REG_P (SET_SRC (exp))
              || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
        {
-         if (cc_status.value1 && GET_CODE (cc_status.value1) == MEM)
+         if (cc_status.value1
+             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
            cc_status.value1 = 0;
-         if (cc_status.value2 && GET_CODE (cc_status.value2) == MEM)
+         if (cc_status.value2
+             && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value2))
            cc_status.value2 = 0;
+
          return;
        }
+
       /* Function calls clobber the cc's.  */
       else if (GET_CODE (SET_SRC (exp)) == CALL)
        {
          CC_STATUS_INIT;
          return;
        }
+
       /* Tests and compares set the cc's in predictable ways.  */
       else if (SET_DEST (exp) == cc0_rtx)
        {
@@ -2665,14 +3639,14 @@ notice_update_cc (exp)
          cc_status.value1 = SET_SRC (exp);
          return;
        }
+
       /* Certain instructions effect the condition codes. */
       else if (GET_MODE (SET_SRC (exp)) == SImode
               || GET_MODE (SET_SRC (exp)) == HImode
               || GET_MODE (SET_SRC (exp)) == QImode)
        switch (GET_CODE (SET_SRC (exp)))
          {
-         case ASHIFTRT: case LSHIFTRT:
-         case ASHIFT:
+         case ASHIFTRT: case LSHIFTRT: case ASHIFT:
            /* Shifts on the 386 don't set the condition codes if the
               shift count is zero. */
            if (GET_CODE (XEXP (SET_SRC (exp), 1)) != CONST_INT)
@@ -2680,6 +3654,7 @@ notice_update_cc (exp)
                CC_STATUS_INIT;
                break;
              }
+
            /* We assume that the CONST_INT is non-zero (this rtx would
               have been deleted if it were zero. */
 
@@ -2690,6 +3665,18 @@ notice_update_cc (exp)
            cc_status.value2 = SET_DEST (exp);
            break;
 
+           /* This is the bsf pattern used by ffs.  */
+         case UNSPEC:
+           if (XINT (SET_SRC (exp), 1) == 5)
+             {
+               /* Only the Z flag is defined after bsf.  */
+               cc_status.flags
+                 = CC_NOT_POSITIVE | CC_NOT_NEGATIVE | CC_NO_OVERFLOW;
+               cc_status.value1 = XVECEXP (SET_SRC (exp), 0, 0);
+               break;
+             }
+           /* FALLTHRU */
+
          default:
            CC_STATUS_INIT;
          }
@@ -2704,14 +3691,21 @@ notice_update_cc (exp)
       if (SET_DEST (XVECEXP (exp, 0, 0)) == pc_rtx)
        return;
       if (SET_DEST (XVECEXP (exp, 0, 0)) == cc0_rtx)
+
        {
          CC_STATUS_INIT;
-         if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
-           cc_status.flags |= CC_IN_80387;
+          if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
+           {
+              cc_status.flags |= CC_IN_80387;
+             if (0 && TARGET_CMOVE && stack_regs_mentioned_p
+                 (XEXP (SET_SRC (XVECEXP (exp, 0, 0)), 1)))
+               cc_status.flags |= CC_FCOMI;
+           }
          else
            cc_status.value1 = SET_SRC (XVECEXP (exp, 0, 0));
          return;
        }
+
       CC_STATUS_INIT;
     }
   else
@@ -2734,19 +3728,20 @@ split_di (operands, num, lo_half, hi_half)
 {
   while (num--)
     {
-      if (GET_CODE (operands[num]) == REG)
-       {
-         lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
-         hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
-       }
-      else if (CONSTANT_P (operands[num]))
+      rtx op = operands[num];
+      if (GET_CODE (op) == REG)
        {
-         split_double (operands[num], &lo_half[num], &hi_half[num]);
+         lo_half[num] = gen_rtx_REG (SImode, REGNO (op));
+         hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1);
        }
-      else if (offsettable_memref_p (operands[num]))
+      else if (CONSTANT_P (op))
+       split_double (op, &lo_half[num], &hi_half[num]);
+      else if (offsettable_memref_p (op))
        {
-         lo_half[num] = operands[num];
-         hi_half[num] = adj_offsettable_operand (operands[num], 4);
+         rtx lo_addr = XEXP (op, 0);
+         rtx hi_addr = XEXP (adj_offsettable_operand (op, 4), 0);
+         lo_half[num] = change_address (op, SImode, lo_addr);
+         hi_half[num] = change_address (op, SImode, hi_addr);
        }
       else
        abort();
@@ -2776,7 +3771,6 @@ binary_387_op (op, mode)
       return 0;
     }
 }
-
 \f
 /* Return 1 if this is a valid shift or rotate operation on a 386.
    OP is the expression matched, and MODE is its mode. */
@@ -2887,16 +3881,22 @@ output_387_binary_op (insn, operands)
       if (NON_STACK_REG_P (operands[1]))
        {
          output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
-         RET;
+         return "";
        }
+
       else if (NON_STACK_REG_P (operands[2]))
        {
          output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
-         RET;
+         return "";
        }
 
       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
-       return strcat (buf, AS2 (p,%2,%0));
+       {
+         if (STACK_TOP_P (operands[0]))
+           return strcat (buf, AS2 (p,%0,%2));
+         else
+           return strcat (buf, AS2 (p,%2,%0));
+       }
 
       if (STACK_TOP_P (operands[0]))
        return strcat (buf, AS2C (%y2,%0));
@@ -2914,22 +3914,33 @@ output_387_binary_op (insn, operands)
       if (NON_STACK_REG_P (operands[1]))
        {
          output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1)));
-         RET;
+         return "";
        }
+
       else if (NON_STACK_REG_P (operands[2]))
        {
          output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
-         RET;
+         return "";
        }
 
       if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
        abort ();
 
       if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
-       return strcat (buf, AS2 (rp,%2,%0));
+       {
+         if (STACK_TOP_P (operands[0]))
+           return strcat (buf, AS2 (p,%0,%2));
+         else
+           return strcat (buf, AS2 (rp,%2,%0));
+       }
 
       if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
-       return strcat (buf, AS2 (p,%1,%0));
+       {
+         if (STACK_TOP_P (operands[0]))
+           return strcat (buf, AS2 (rp,%0,%1));
+         else
+           return strcat (buf, AS2 (p,%1,%0));
+       }
 
       if (STACK_TOP_P (operands[0]))
        {
@@ -2962,8 +3973,7 @@ output_fix_trunc (insn, operands)
   int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
   rtx xops[2];
 
-  if (! STACK_TOP_P (operands[1]) ||
-      (GET_MODE (operands[0]) == DImode && ! stack_top_dies))
+  if (! STACK_TOP_P (operands[1]))
     abort ();
 
   xops[0] = GEN_INT (12);
@@ -2976,11 +3986,23 @@ output_fix_trunc (insn, operands)
   output_asm_insn (AS1 (fldc%W3,%3), operands);
 
   if (NON_STACK_REG_P (operands[0]))
-    output_to_reg (operands[0], stack_top_dies);
+    output_to_reg (operands[0], stack_top_dies, operands[3]);
+
   else if (GET_CODE (operands[0]) == MEM)
     {
       if (stack_top_dies)
        output_asm_insn (AS1 (fistp%z0,%0), operands);
+      else if (GET_MODE (operands[0]) == DImode && ! stack_top_dies)
+       {
+         /* There is no DImode version of this without a stack pop, so
+            we must emulate it.  It doesn't matter much what the second
+            instruction is, because the value being pushed on the FP stack
+            is not used except for the following stack popping store.
+            This case can only happen without optimization, so it doesn't
+            matter that it is inefficient.  */
+         output_asm_insn (AS1 (fistp%z0,%0), operands);
+         output_asm_insn (AS1 (fild%z0,%0), operands);
+       }
       else
        output_asm_insn (AS1 (fist%z0,%0), operands);
     }
@@ -3003,7 +4025,22 @@ output_float_compare (insn, operands)
   int stack_top_dies;
   rtx body = XVECEXP (PATTERN (insn), 0, 0);
   int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
+  rtx tmp;
 
+  if (0 && TARGET_CMOVE && STACK_REG_P (operands[1]))
+    {
+      cc_status.flags |= CC_FCOMI;
+      cc_prev_status.flags &= ~CC_TEST_AX;
+    }
+
+  if (! STACK_TOP_P (operands[0]))
+    {
+      tmp = operands[0];
+      operands[0] = operands[1];
+      operands[1] = tmp;
+      cc_status.flags |= CC_REVERSED;
+    }
+    
   if (! STACK_TOP_P (operands[0]))
     abort ();
 
@@ -3019,9 +4056,27 @@ output_float_compare (insn, operands)
         `fcompp' float compare */
 
       if (unordered_compare)
-       output_asm_insn ("fucompp", operands);
+       {
+         if (cc_status.flags & CC_FCOMI)
+           {
+             output_asm_insn (AS2 (fucomip,%y1,%0), operands);
+             output_asm_insn (AS1 (fstp, %y0), operands);
+             return "";
+           }
+         else
+           output_asm_insn ("fucompp", operands);
+       }
       else
-       output_asm_insn ("fcompp", operands);
+       {
+         if (cc_status.flags & CC_FCOMI)
+           {
+             output_asm_insn (AS2 (fcomip, %y1,%0), operands);
+             output_asm_insn (AS1 (fstp, %y0), operands);
+             return "";
+           }
+         else
+           output_asm_insn ("fcompp", operands);
+       }
     }
   else
     {
@@ -3031,9 +4086,9 @@ output_float_compare (insn, operands)
         unordered float compare. */
 
       if (unordered_compare)
-       strcpy (buf, "fucom");
+       strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom");
       else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
-       strcpy (buf, "fcom");
+       strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom");
       else
        strcpy (buf, "ficom");
 
@@ -3044,6 +4099,11 @@ output_float_compare (insn, operands)
 
       if (NON_STACK_REG_P (operands[1]))
        output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
+      else if (cc_status.flags & CC_FCOMI) 
+       {
+         output_asm_insn (strcat (buf, AS2 (%z1,%y1,%0)), operands);
+         return "";
+       }
       else
         output_asm_insn (strcat (buf, AS1 (%z1,%y1)), operands);
     }
@@ -3063,15 +4123,39 @@ output_fp_cc0_set (insn)
      rtx insn;
 {
   rtx xops[3];
-  rtx unordered_label;
   rtx next;
   enum rtx_code code;
 
-  xops[0] = gen_rtx (REG, HImode, 0);
+  xops[0] = gen_rtx_REG (HImode, 0);
   output_asm_insn (AS1 (fnsts%W0,%0), xops);
 
   if (! TARGET_IEEE_FP)
-    return "sahf";
+    {
+      if (!(cc_status.flags & CC_REVERSED))
+        {
+          next = next_cc0_user (insn);
+        
+          if (GET_CODE (next) == JUMP_INSN
+              && GET_CODE (PATTERN (next)) == SET
+              && SET_DEST (PATTERN (next)) == pc_rtx
+              && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
+           code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+          else if (GET_CODE (PATTERN (next)) == SET)
+           code = GET_CODE (SET_SRC (PATTERN (next)));
+          else
+           return "sahf";
+
+         if (code == GT || code == LT || code == EQ || code == NE
+             || code == LE || code == GE)
+           {
+             /* We will test eax directly. */
+              cc_status.flags |= CC_TEST_AX;
+             return "";
+            }
+        }
+
+      return "sahf";
+    }
 
   next = next_cc0_user (insn);
   if (next == NULL_RTX)
@@ -3081,17 +4165,27 @@ output_fp_cc0_set (insn)
       && GET_CODE (PATTERN (next)) == SET
       && SET_DEST (PATTERN (next)) == pc_rtx
       && GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
+    code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+  else if (GET_CODE (PATTERN (next)) == SET)
     {
-      code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+      if (GET_CODE (SET_SRC (PATTERN (next))) == IF_THEN_ELSE)
+       code = GET_CODE (XEXP (SET_SRC (PATTERN (next)), 0));
+      else
+       code = GET_CODE (SET_SRC (PATTERN (next)));
     }
-  else if (GET_CODE (PATTERN (next)) == SET)
+
+  else if (GET_CODE (PATTERN (next)) == PARALLEL
+          && GET_CODE (XVECEXP (PATTERN (next), 0, 0)) == SET)
     {
-      code = GET_CODE (SET_SRC (PATTERN (next)));
+      if (GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0))) == IF_THEN_ELSE)
+       code = GET_CODE (XEXP (SET_SRC (XVECEXP (PATTERN (next), 0, 0)), 0));
+      else
+       code = GET_CODE (SET_SRC (XVECEXP (PATTERN (next), 0, 0)));
     }
   else
     abort ();
 
-  xops[0] = gen_rtx (REG, QImode, 0);
+  xops[0] = gen_rtx_REG (QImode, 0);
 
   switch (code)
     {
@@ -3147,7 +4241,8 @@ output_fp_cc0_set (insn)
     default:
       abort ();
     }
-  RET;
+
+  return "";
 }
 \f
 #define MAX_386_STACK_LOCALS 2
@@ -3158,6 +4253,8 @@ static rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
 struct machine_function
 {
   rtx i386_stack_locals[(int) MAX_MACHINE_MODE][MAX_386_STACK_LOCALS];
+  rtx pic_label_rtx;
+  char pic_label_name[256];
 };
 
 /* Functions to save and restore i386_stack_locals.
@@ -3168,9 +4265,12 @@ void
 save_386_machine_status (p)
      struct function *p;
 {
-  p->machine = (struct machine_function *) xmalloc (sizeof i386_stack_locals);
+  p->machine
+    = (struct machine_function *) xmalloc (sizeof (struct machine_function));
   bcopy ((char *) i386_stack_locals, (char *) p->machine->i386_stack_locals,
         sizeof i386_stack_locals);
+  p->machine->pic_label_rtx = pic_label_rtx;
+  bcopy (pic_label_name, p->machine->pic_label_name, 256);
 }
 
 void
@@ -3179,7 +4279,10 @@ restore_386_machine_status (p)
 {
   bcopy ((char *) p->machine->i386_stack_locals, (char *) i386_stack_locals,
         sizeof i386_stack_locals);
+  pic_label_rtx = p->machine->pic_label_rtx;
+  bcopy (p->machine->pic_label_name, pic_label_name, 256);
   free (p->machine);
+  p->machine = NULL;
 }
 
 /* Clear stack slot assignments remembered from previous functions.
@@ -3197,6 +4300,8 @@ clear_386_stack_locals ()
     for (n = 0; n < MAX_386_STACK_LOCALS; n++)
       i386_stack_locals[(int) mode][n] = NULL_RTX;
 
+  pic_label_rtx = NULL_RTX;
+  bzero (pic_label_name, 256);
   /* Arrange to save and restore i386_stack_locals around nested functions.  */
   save_machine_status = save_386_machine_status;
   restore_machine_status = restore_386_machine_status;
@@ -3222,3 +4327,935 @@ assign_386_stack_local (mode, n)
 
   return i386_stack_locals[(int) mode][n];
 }
+\f
+int is_mul(op,mode)
+    register rtx op;
+    enum machine_mode mode;
+{
+  return (GET_CODE (op) == MULT);
+}
+
+int is_div(op,mode)
+    register rtx op;
+    enum machine_mode mode;
+{
+  return (GET_CODE (op) == DIV);
+}
+\f
+#ifdef NOTYET
+/* Create a new copy of an rtx.
+   Recursively copies the operands of the rtx,
+   except for those few rtx codes that are sharable.
+   Doesn't share CONST  */
+
+rtx
+copy_all_rtx (orig)
+     register rtx orig;
+{
+  register rtx copy;
+  register int i, j;
+  register RTX_CODE code;
+  register char *format_ptr;
+
+  code = GET_CODE (orig);
+
+  switch (code)
+    {
+    case REG:
+    case QUEUED:
+    case CONST_INT:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case CODE_LABEL:
+    case PC:
+    case CC0:
+    case SCRATCH:
+      /* SCRATCH must be shared because they represent distinct values. */
+      return orig;
+
+#if 0
+    case CONST:
+      /* CONST can be shared if it contains a SYMBOL_REF.  If it contains
+        a LABEL_REF, it isn't sharable.  */
+      if (GET_CODE (XEXP (orig, 0)) == PLUS
+         && GET_CODE (XEXP (XEXP (orig, 0), 0)) == SYMBOL_REF
+         && GET_CODE (XEXP (XEXP (orig, 0), 1)) == CONST_INT)
+       return orig;
+      break;
+#endif
+      /* A MEM with a constant address is not sharable.  The problem is that
+        the constant address may need to be reloaded.  If the mem is shared,
+        then reloading one copy of this mem will cause all copies to appear
+        to have been reloaded.  */
+    }
+
+  copy = rtx_alloc (code);
+  PUT_MODE (copy, GET_MODE (orig));
+  copy->in_struct = orig->in_struct;
+  copy->volatil = orig->volatil;
+  copy->unchanging = orig->unchanging;
+  copy->integrated = orig->integrated;
+  /* intel1 */
+  copy->is_spill_rtx = orig->is_spill_rtx;
+  
+  format_ptr = GET_RTX_FORMAT (GET_CODE (copy));
+
+  for (i = 0; i < GET_RTX_LENGTH (GET_CODE (copy)); i++)
+    {
+      switch (*format_ptr++)
+       {
+       case 'e':
+         XEXP (copy, i) = XEXP (orig, i);
+         if (XEXP (orig, i) != NULL)
+           XEXP (copy, i) = copy_rtx (XEXP (orig, i));
+         break;
+
+       case '0':
+       case 'u':
+         XEXP (copy, i) = XEXP (orig, i);
+         break;
+
+       case 'E':
+       case 'V':
+         XVEC (copy, i) = XVEC (orig, i);
+         if (XVEC (orig, i) != NULL)
+           {
+             XVEC (copy, i) = rtvec_alloc (XVECLEN (orig, i));
+             for (j = 0; j < XVECLEN (copy, i); j++)
+               XVECEXP (copy, i, j) = copy_rtx (XVECEXP (orig, i, j));
+           }
+         break;
+
+       case 'w':
+         XWINT (copy, i) = XWINT (orig, i);
+         break;
+
+       case 'i':
+         XINT (copy, i) = XINT (orig, i);
+         break;
+
+       case 's':
+       case 'S':
+         XSTR (copy, i) = XSTR (orig, i);
+         break;
+
+       default:
+         abort ();
+       }
+    }
+  return copy;
+}
+
+\f
+/* Try to rewrite a memory address to make it valid */
+
+void 
+rewrite_address (mem_rtx)
+     rtx mem_rtx;
+{
+  rtx index_rtx, base_rtx, offset_rtx, scale_rtx, ret_rtx;
+  int scale = 1;
+  int offset_adjust = 0;
+  int was_only_offset = 0;
+  rtx mem_addr = XEXP (mem_rtx, 0);
+  char *storage = oballoc (0);
+  int in_struct = 0;
+  int is_spill_rtx = 0;
+
+  in_struct = MEM_IN_STRUCT_P (mem_rtx);
+  is_spill_rtx = RTX_IS_SPILL_P (mem_rtx);
+
+  if (GET_CODE (mem_addr) == PLUS
+      && GET_CODE (XEXP (mem_addr, 1)) == PLUS
+      && GET_CODE (XEXP (XEXP (mem_addr, 1), 0)) == REG)
+    {
+      /* This part is utilized by the combiner. */
+      ret_rtx
+       = gen_rtx (PLUS, GET_MODE (mem_addr),
+                  gen_rtx (PLUS, GET_MODE (XEXP (mem_addr, 1)),
+                           XEXP (mem_addr, 0), XEXP (XEXP (mem_addr, 1), 0)),
+                  XEXP (XEXP (mem_addr, 1), 1));
+
+      if (memory_address_p (GET_MODE (mem_rtx), ret_rtx))
+       {
+         XEXP (mem_rtx, 0) = ret_rtx;
+         RTX_IS_SPILL_P (ret_rtx) = is_spill_rtx;
+         return;
+       }
+
+      obfree (storage);
+    }
+
+  /* This part is utilized by loop.c.  
+     If the address contains PLUS (reg,const) and this pattern is invalid
+     in this case - try to rewrite the address to make it valid. */
+  storage = oballoc (0);
+  index_rtx = base_rtx = offset_rtx = NULL;
+
+  /* Find the base index and offset elements of the memory address. */
+  if (GET_CODE (mem_addr) == PLUS)
+    {
+      if (GET_CODE (XEXP (mem_addr, 0)) == REG)
+       {
+         if (GET_CODE (XEXP (mem_addr, 1)) == REG)
+           base_rtx = XEXP (mem_addr, 1), index_rtx = XEXP (mem_addr, 0);
+         else
+           base_rtx = XEXP (mem_addr, 0), offset_rtx = XEXP (mem_addr, 1);
+       }
+
+      else if (GET_CODE (XEXP (mem_addr, 0)) == MULT)
+       {
+         index_rtx = XEXP (mem_addr, 0);
+         if (GET_CODE (XEXP (mem_addr, 1)) == REG)
+           base_rtx = XEXP (mem_addr, 1);
+         else
+           offset_rtx = XEXP (mem_addr, 1);
+       }
+
+      else if (GET_CODE (XEXP (mem_addr, 0)) == PLUS)
+       {
+         if (GET_CODE (XEXP (XEXP (mem_addr, 0), 0)) == PLUS
+             && GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0)) == MULT
+             && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 0))
+                 == REG)
+             && (GET_CODE (XEXP (XEXP (XEXP (XEXP (mem_addr, 0), 0), 0), 1))
+                 == CONST_INT)
+             && (GET_CODE (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1))
+                 == CONST_INT)
+             && GET_CODE (XEXP (XEXP (mem_addr, 0), 1)) == REG
+             && GET_CODE (XEXP (mem_addr, 1)) == SYMBOL_REF)
+           {
+             index_rtx = XEXP (XEXP (XEXP (mem_addr, 0), 0), 0);
+             offset_rtx = XEXP (mem_addr, 1);
+             base_rtx = XEXP (XEXP (mem_addr, 0), 1);
+             offset_adjust = INTVAL (XEXP (XEXP (XEXP (mem_addr, 0), 0), 1));
+           }
+         else
+           {
+             offset_rtx = XEXP (mem_addr, 1);
+             index_rtx = XEXP (XEXP (mem_addr, 0), 0);
+             base_rtx = XEXP (XEXP (mem_addr, 0), 1);
+           }
+       }
+
+      else if (GET_CODE (XEXP (mem_addr, 0)) == CONST_INT)
+       {
+         was_only_offset = 1;
+         index_rtx = NULL;
+         base_rtx = NULL;
+         offset_rtx = XEXP (mem_addr, 1);
+         offset_adjust = INTVAL (XEXP (mem_addr, 0));
+         if (offset_adjust == 0)
+           {
+             XEXP (mem_rtx, 0) = offset_rtx;
+             RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
+             return;
+           }
+       }
+      else
+       {
+         obfree (storage);
+         return;
+       }
+    }
+  else if (GET_CODE (mem_addr) == MULT)
+    index_rtx = mem_addr;
+  else
+    {
+      obfree (storage);
+      return;
+    }
+
+  if (index_rtx != 0 && GET_CODE (index_rtx) == MULT)
+    {
+      if (GET_CODE (XEXP (index_rtx, 1)) != CONST_INT)
+       {
+         obfree (storage);
+         return;
+       }
+
+      scale_rtx = XEXP (index_rtx, 1);
+      scale = INTVAL (scale_rtx);
+      index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
+    }
+
+  /* Now find which of the elements are invalid and try to fix them. */
+  if (index_rtx && GET_CODE (index_rtx) == CONST_INT && base_rtx == NULL)
+    {
+      offset_adjust = INTVAL (index_rtx) * scale;
+
+      if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
+       offset_rtx = plus_constant (offset_rtx, offset_adjust);
+      else if (offset_rtx == 0)
+       offset_rtx = const0_rtx;
+
+      RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
+      XEXP (mem_rtx, 0) = offset_rtx;
+      return;
+    }
+
+  if (base_rtx && GET_CODE (base_rtx) == PLUS
+      && GET_CODE (XEXP (base_rtx, 0)) == REG
+      && GET_CODE (XEXP (base_rtx, 1)) == CONST_INT)
+    {
+      offset_adjust += INTVAL (XEXP (base_rtx, 1));
+      base_rtx = copy_all_rtx (XEXP (base_rtx, 0));
+    }
+
+  else if (base_rtx && GET_CODE (base_rtx) == CONST_INT)
+    {
+      offset_adjust += INTVAL (base_rtx);
+      base_rtx = NULL;
+    }
+
+  if (index_rtx && GET_CODE (index_rtx) == PLUS
+      && GET_CODE (XEXP (index_rtx, 0)) == REG
+      && GET_CODE (XEXP (index_rtx, 1)) == CONST_INT)
+    {
+      offset_adjust += INTVAL (XEXP (index_rtx, 1)) * scale;
+      index_rtx = copy_all_rtx (XEXP (index_rtx, 0));
+    }
+
+  if (index_rtx)
+    {
+      if (! LEGITIMATE_INDEX_P (index_rtx)
+         && ! (index_rtx == stack_pointer_rtx && scale == 1
+               && base_rtx == NULL))
+       {
+         obfree (storage);
+         return;
+       }
+    }
+
+  if (base_rtx)
+    {
+      if (! LEGITIMATE_INDEX_P (base_rtx) && GET_CODE (base_rtx) != REG)
+       {
+         obfree (storage);
+         return;
+       }
+    }
+
+  if (offset_adjust != 0)
+    {
+      if (offset_rtx != 0 && CONSTANT_P (offset_rtx))
+       offset_rtx = plus_constant (offset_rtx, offset_adjust);
+      else
+       offset_rtx = const0_rtx;
+
+      if (index_rtx)
+       {
+         if (base_rtx)
+           {
+             if (scale != 1)
+               {
+                 ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx),
+                                    gen_rtx (MULT, GET_MODE (index_rtx),
+                                             index_rtx, scale_rtx),
+                                    base_rtx);
+
+                 if (GET_CODE (offset_rtx) != CONST_INT
+                     || INTVAL (offset_rtx) != 0)
+                   ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
+                                      ret_rtx, offset_rtx);
+               }
+             else
+               {
+                 ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
+                                    index_rtx, base_rtx);
+
+                 if (GET_CODE (offset_rtx) != CONST_INT
+                     || INTVAL (offset_rtx) != 0)
+                   ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
+                                      ret_rtx, offset_rtx);
+               }
+           }
+         else
+           {
+             if (scale != 1)
+               {
+                 ret_rtx = gen_rtx (MULT, GET_MODE (index_rtx),
+                                    index_rtx, scale_rtx);
+
+                 if (GET_CODE (offset_rtx) != CONST_INT
+                     || INTVAL (offset_rtx) != 0)
+                   ret_rtx = gen_rtx (PLUS, GET_MODE (ret_rtx),
+                                      ret_rtx, offset_rtx);
+               }
+             else
+               {
+                 if (GET_CODE (offset_rtx) == CONST_INT
+                     && INTVAL (offset_rtx) == 0)
+                   ret_rtx = index_rtx;
+                 else
+                   ret_rtx = gen_rtx (PLUS, GET_MODE (index_rtx),
+                                      index_rtx, offset_rtx);
+               }
+           }
+       }
+      else
+       {
+         if (base_rtx)
+           {
+             if (GET_CODE (offset_rtx) == CONST_INT
+                 && INTVAL (offset_rtx) == 0)
+               ret_rtx = base_rtx;
+             else
+               ret_rtx = gen_rtx (PLUS, GET_MODE (base_rtx), base_rtx,
+                                  offset_rtx);
+           }
+         else if (was_only_offset)
+           ret_rtx = offset_rtx;
+         else
+           {
+             obfree (storage);
+             return;
+           }
+       }
+
+      XEXP (mem_rtx, 0) = ret_rtx;
+      RTX_IS_SPILL_P (XEXP (mem_rtx, 0)) = is_spill_rtx;
+      return;
+    }
+  else
+    {
+      obfree (storage);
+      return;
+    }
+}
+#endif /* NOTYET */
+\f
+/* Return 1 if the first insn to set cc before INSN also sets the register
+   REG_RTX; otherwise return 0. */
+int
+last_to_set_cc (reg_rtx, insn)
+     rtx reg_rtx, insn;
+{
+  rtx prev_insn = PREV_INSN (insn);
+
+  while (prev_insn)
+    {
+      if (GET_CODE (prev_insn) == NOTE)
+       ;
+
+      else if (GET_CODE (prev_insn) == INSN)
+       {
+         if (GET_CODE (PATTERN (prev_insn)) != SET)
+           return (0);
+
+         if (rtx_equal_p (SET_DEST (PATTERN (prev_insn)), reg_rtx))
+           {
+             if (sets_condition_code (SET_SRC (PATTERN (prev_insn))))
+               return (1);
+
+             return (0);
+           }
+
+         else if (! doesnt_set_condition_code (SET_SRC (PATTERN (prev_insn))))
+           return (0);
+       }
+
+      else
+       return (0);
+
+      prev_insn = PREV_INSN (prev_insn);
+    }
+
+  return (0);
+}
+\f
+int
+doesnt_set_condition_code (pat)
+     rtx pat;
+{
+  switch (GET_CODE (pat))
+    {
+    case MEM:
+    case REG:
+      return 1;
+
+    default:
+      return 0;
+
+    }
+}
+\f
+int
+sets_condition_code (pat)
+     rtx pat;
+{
+  switch (GET_CODE (pat))
+    {
+    case PLUS:
+    case MINUS:
+    case AND:
+    case IOR:
+    case XOR:
+    case NOT:
+    case NEG:
+    case MULT:
+    case DIV:
+    case MOD:
+    case UDIV:
+    case UMOD:
+      return 1;
+
+    default:
+      return (0);
+    }
+}
+\f
+int
+str_immediate_operand (op, mode)
+     register rtx op;
+     enum machine_mode mode;
+{
+  if (GET_CODE (op) == CONST_INT && INTVAL (op) <= 32 && INTVAL (op) >= 0)
+    return 1;
+
+  return 0;
+}
+\f
+int
+is_fp_insn (insn)
+     rtx insn;
+{
+  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
+      && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
+         || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
+         || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode))
+    return 1;
+
+  return 0;
+}
+
+/* Return 1 if the mode of the SET_DEST of insn is floating point
+   and it is not an fld or a move from memory to memory.
+   Otherwise return 0 */
+
+int
+is_fp_dest (insn)
+     rtx insn;
+{
+  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
+      && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
+         || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
+         || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
+      && GET_CODE (SET_DEST (PATTERN (insn))) == REG
+      && REGNO (SET_DEST (PATTERN (insn))) >= FIRST_FLOAT_REG
+      && GET_CODE (SET_SRC (insn)) != MEM)
+    return 1;
+
+  return 0;
+}
+
+/* Return 1 if the mode of the SET_DEST of INSN is floating point and is
+   memory and the source is a register.  */
+
+int
+is_fp_store (insn)
+     rtx insn;
+{
+  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
+      && (GET_MODE (SET_DEST (PATTERN (insn))) == DFmode
+         || GET_MODE (SET_DEST (PATTERN (insn))) == SFmode
+         || GET_MODE (SET_DEST (PATTERN (insn))) == XFmode)
+      && GET_CODE (SET_DEST (PATTERN (insn))) == MEM
+      && GET_CODE (SET_SRC (PATTERN (insn))) == REG)
+    return 1;
+
+  return 0;
+}
+\f
+/* Return 1 if DEP_INSN sets a register which INSN uses as a base
+   or index to reference memory.
+   otherwise return 0 */
+
+int
+agi_dependent (insn, dep_insn)
+     rtx insn, dep_insn;
+{
+  if (GET_CODE (dep_insn) == INSN
+      && GET_CODE (PATTERN (dep_insn)) == SET
+      && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG)
+    return reg_mentioned_in_mem (SET_DEST (PATTERN (dep_insn)), insn);
+
+  if (GET_CODE (dep_insn) == INSN && GET_CODE (PATTERN (dep_insn)) == SET
+      && GET_CODE (SET_DEST (PATTERN (dep_insn))) == MEM
+      && push_operand (SET_DEST (PATTERN (dep_insn)),
+                       GET_MODE (SET_DEST (PATTERN (dep_insn)))))
+    return reg_mentioned_in_mem (stack_pointer_rtx, insn);
+
+  return 0;
+}
+\f
+/* Return 1 if reg is used in rtl as a base or index for a memory ref
+   otherwise return 0. */
+
+int
+reg_mentioned_in_mem (reg, rtl)
+     rtx reg, rtl;
+{
+  register char *fmt;
+  register int i, j;
+  register enum rtx_code code;
+
+  if (rtl == NULL)
+    return 0;
+
+  code = GET_CODE (rtl);
+
+  switch (code)
+    {
+    case HIGH:
+    case CONST_INT:
+    case CONST:
+    case CONST_DOUBLE:
+    case SYMBOL_REF:
+    case LABEL_REF:
+    case PC:
+    case CC0:
+    case SUBREG:
+      return 0;
+    default:
+      break;
+    }
+
+  if (code == MEM && reg_mentioned_p (reg, rtl))
+    return 1;
+
+  fmt = GET_RTX_FORMAT (code);
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+       {
+         for (j = XVECLEN (rtl, i) - 1; j >= 0; j--)
+           if (reg_mentioned_in_mem (reg, XVECEXP (rtl, i, j)))
+             return 1;
+       }
+
+      else if (fmt[i] == 'e' && reg_mentioned_in_mem (reg, XEXP (rtl, i)))
+       return 1;
+    }
+
+  return 0;
+}
+\f
+/* Output the appropriate insns for doing strlen if not just doing repnz; scasb
+
+   operands[0] = result, initialized with the startaddress
+   operands[1] = alignment of the address.
+   operands[2] = scratch register, initialized with the startaddress when
+                not aligned, otherwise undefined
+
+   This is just the body. It needs the initialisations mentioned above and
+   some address computing at the end.  These things are done in i386.md.  */
+
+char *
+output_strlen_unroll (operands)
+     rtx operands[];
+{
+  rtx xops[18];
+
+  xops[0] = operands[0];               /* Result */
+  /*        operands[1];                 * Alignment */
+  xops[1] = operands[2];               /* Scratch */
+  xops[2] = GEN_INT (0);
+  xops[3] = GEN_INT (2);
+  xops[4] = GEN_INT (3);
+  xops[5] = GEN_INT (4);
+  /* xops[6] = gen_label_rtx ();        * label when aligned to 3-byte */
+  /* xops[7] = gen_label_rtx ();        * label when aligned to 2-byte */
+  xops[8] = gen_label_rtx ();          /* label of main loop */
+
+  if (TARGET_USE_Q_REG && QI_REG_P (xops[1]))
+    xops[9] = gen_label_rtx ();                /* pentium optimisation */
+
+  xops[10] = gen_label_rtx ();         /* end label 2 */
+  xops[11] = gen_label_rtx ();         /* end label 1 */
+  xops[12] = gen_label_rtx ();         /* end label */
+  /* xops[13]                           * Temporary used */
+  xops[14] = GEN_INT (0xff);
+  xops[15] = GEN_INT (0xff00);
+  xops[16] = GEN_INT (0xff0000);
+  xops[17] = GEN_INT (0xff000000);
+
+  /* Loop to check 1..3 bytes for null to get an aligned pointer.  */
+
+  /* Is there a known alignment and is it less than 4?  */
+  if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) < 4)
+    {
+      /* Is there a known alignment and is it not 2? */
+      if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
+       {
+         xops[6] = gen_label_rtx (); /* Label when aligned to 3-byte */
+         xops[7] = gen_label_rtx (); /* Label when aligned to 2-byte */
+
+         /* Leave just the 3 lower bits.
+            If this is a q-register, then the high part is used later
+            therefore use andl rather than andb. */
+         output_asm_insn (AS2 (and%L1,%4,%1), xops);
+
+         /* Is aligned to 4-byte address when zero */
+         output_asm_insn (AS1 (je,%l8), xops);
+
+         /* Side-effect even Parity when %eax == 3 */
+         output_asm_insn (AS1 (jp,%6), xops);
+
+         /* Is it aligned to 2 bytes ? */
+         if (QI_REG_P (xops[1]))
+           output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
+         else
+           output_asm_insn (AS2 (cmp%L1,%3,%1), xops);
+
+         output_asm_insn (AS1 (je,%7), xops);
+       }
+      else
+        {
+         /* Since the alignment is 2, we have to check 2 or 0 bytes;
+            check if is aligned to 4 - byte.  */
+         output_asm_insn (AS2 (and%L1,%3,%1), xops);
+
+         /* Is aligned to 4-byte address when zero */
+         output_asm_insn (AS1 (je,%l8), xops);
+        }
+
+      xops[13] = gen_rtx_MEM (QImode, xops[0]);
+
+      /* Now compare the bytes; compare with the high part of a q-reg
+        gives shorter code. */
+      if (QI_REG_P (xops[1]))
+        {
+         /* Compare the first n unaligned byte on a byte per byte basis. */
+          output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+
+         /* When zero we reached the end. */
+          output_asm_insn (AS1 (je,%l12), xops);
+
+         /* Increment the address. */
+          output_asm_insn (AS1 (inc%L0,%0), xops);
+
+         /* Not needed with an alignment of 2 */
+         if (GET_CODE (operands[1]) != CONST_INT || INTVAL (operands[1]) != 2)
+           {
+             ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                        CODE_LABEL_NUMBER (xops[7]));
+             output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+             output_asm_insn (AS1 (je,%l12), xops);
+             output_asm_insn (AS1 (inc%L0,%0), xops);
+
+             ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                        CODE_LABEL_NUMBER (xops[6]));
+           }
+
+          output_asm_insn (AS2 (cmp%B1,%h1,%13), xops);
+        }
+      else
+        {
+          output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+          output_asm_insn (AS1 (je,%l12), xops);
+          output_asm_insn (AS1 (inc%L0,%0), xops);
+
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                    CODE_LABEL_NUMBER (xops[7]));
+          output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+          output_asm_insn (AS1 (je,%l12), xops);
+          output_asm_insn (AS1 (inc%L0,%0), xops);
+
+         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                    CODE_LABEL_NUMBER (xops[6]));
+          output_asm_insn (AS2 (cmp%B13,%2,%13), xops);
+        }
+
+      output_asm_insn (AS1 (je,%l12), xops);
+      output_asm_insn (AS1 (inc%L0,%0), xops);
+    }
+
+    /* Generate loop to check 4 bytes at a time.  It is not a good idea to
+       align this loop.  It gives only huge programs, but does not help to
+       speed up.  */
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8]));
+
+  xops[13] = gen_rtx_MEM (SImode, xops[0]);
+  output_asm_insn (AS2 (mov%L1,%13,%1), xops);
+
+  if (QI_REG_P (xops[1]))
+    {
+      /* On i586 it is faster to combine the hi- and lo- part as
+        a kind of lookahead.  If anding both yields zero, then one
+        of both *could* be zero, otherwise none of both is zero;
+        this saves one instruction, on i486 this is slower
+        tested with P-90, i486DX2-66, AMD486DX2-66  */
+      if (TARGET_PENTIUM)
+        {
+         output_asm_insn (AS2 (test%B1,%h1,%b1), xops);
+         output_asm_insn (AS1 (jne,%l9), xops);
+        }
+
+      /* Check first byte. */
+      output_asm_insn (AS2 (test%B1,%b1,%b1), xops);
+      output_asm_insn (AS1 (je,%l12), xops);
+
+      /* Check second byte. */
+      output_asm_insn (AS2 (test%B1,%h1,%h1), xops);
+      output_asm_insn (AS1 (je,%l11), xops);
+
+      if (TARGET_PENTIUM)
+       ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L",
+                                  CODE_LABEL_NUMBER (xops[9]));
+    }
+
+  else
+    {
+      /* Check first byte. */
+      output_asm_insn (AS2 (test%L1,%14,%1), xops);
+      output_asm_insn (AS1 (je,%l12), xops);
+
+      /* Check second byte. */
+      output_asm_insn (AS2 (test%L1,%15,%1), xops);
+      output_asm_insn (AS1 (je,%l11), xops);
+    }
+
+  /* Check third byte. */
+  output_asm_insn (AS2 (test%L1,%16,%1), xops);
+  output_asm_insn (AS1 (je,%l10), xops);
+  
+  /* Check fourth byte and increment address. */
+  output_asm_insn (AS2 (add%L0,%5,%0), xops);
+  output_asm_insn (AS2 (test%L1,%17,%1), xops);
+  output_asm_insn (AS1 (jne,%l8), xops);
+
+  /* Now generate fixups when the compare stops within a 4-byte word. */
+  output_asm_insn (AS2 (sub%L0,%4,%0), xops);
+
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[10]));
+  output_asm_insn (AS1 (inc%L0,%0), xops);
+
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[11]));
+  output_asm_insn (AS1 (inc%L0,%0), xops);
+
+  ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[12]));
+
+  return "";
+}
+
+char *
+output_fp_conditional_move (which_alternative, operands)
+     int which_alternative;
+     rtx operands[];
+{
+  int code = GET_CODE (operands[1]);
+
+  /* This is very tricky. We have to do it right. For a code segement
+     like:
+
+       int foo;
+       double bar;
+       ....
+       foo = foo - x;
+       if (foo >= 0)
+         bar = y;
+
+     final_scan_insn () may delete the insn which sets CC. We have to
+     tell final_scan_insn () if it should be reinserted. When CODE is
+     GT or LE, we have to check the CC_NO_OVERFLOW bit and return
+     NULL_PTR to tell final to reinsert the test insn because the
+     conditional move cannot be handled properly without it. */
+  if ((code == GT || code == LE)
+      && (cc_prev_status.flags & CC_NO_OVERFLOW))
+    return NULL_PTR;
+
+  switch (which_alternative)
+    {
+    case 0:
+      /* r <- cond ? arg : r */
+      output_asm_insn (AS2 (fcmov%F1,%2,%0), operands);
+      break;
+  
+    case 1:
+      /* r <- cond ? r : arg */
+      output_asm_insn (AS2 (fcmov%f1,%3,%0), operands);
+      break;
+
+    case 2:
+      /* r <- cond ? r : arg */
+      output_asm_insn (AS2 (fcmov%F1,%2,%0), operands);
+      output_asm_insn (AS2 (fcmov%f1,%3,%0), operands);
+      break;
+
+    default:
+      abort ();
+    }
+
+  return "";
+}
+
+char *
+output_int_conditional_move (which_alternative, operands)
+     int which_alternative;
+     rtx operands[];
+{
+  int code = GET_CODE (operands[1]);
+  enum machine_mode mode;
+  rtx xops[4];
+
+  /* This is very tricky. We have to do it right. For a code segement
+     like:
+
+       int foo, bar;
+       ....
+       foo = foo - x;
+       if (foo >= 0)
+         bar = y;
+
+     final_scan_insn () may delete the insn which sets CC. We have to
+     tell final_scan_insn () if it should be reinserted. When CODE is
+     GT or LE, we have to check the CC_NO_OVERFLOW bit and return
+     NULL_PTR to tell final to reinsert the test insn because the
+     conditional move cannot be handled properly without it. */
+  if ((code == GT || code == LE)
+      && (cc_prev_status.flags & CC_NO_OVERFLOW))
+    return NULL_PTR;
+
+  mode = GET_MODE (operands [0]);
+  if (mode == DImode)
+    {
+      xops [0] = gen_rtx_SUBREG (SImode, operands [0], 1);
+      xops [1] = operands [1];
+      xops [2] = gen_rtx_SUBREG (SImode, operands [2], 1);
+      xops [3] = gen_rtx_SUBREG (SImode, operands [3], 1);
+    }
+
+  switch (which_alternative)
+    {
+    case 0:
+      /* r <- cond ? arg : r */
+      output_asm_insn (AS2 (cmov%C1,%2,%0), operands);
+      if (mode == DImode)
+       output_asm_insn (AS2 (cmov%C1,%2,%0), xops);
+      break;
+
+    case 1:
+      /* r <- cond ? r : arg */
+      output_asm_insn (AS2 (cmov%c1,%3,%0), operands);
+      if (mode == DImode)
+       output_asm_insn (AS2 (cmov%c1,%3,%0), xops);
+      break;
+
+    case 2:
+      /* rm <- cond ? arg1 : arg2 */
+      output_asm_insn (AS2 (cmov%C1,%2,%0), operands);
+      output_asm_insn (AS2 (cmov%c1,%3,%0), operands);
+      if (mode == DImode)
+       {
+         output_asm_insn (AS2 (cmov%C1,%2,%0), xops);
+         output_asm_insn (AS2 (cmov%c1,%3,%0), xops);
+       }
+      break;
+
+    default:
+      abort ();
+    }
+
+  return "";
+}