OSDN Git Service

* i386.md (ashlsi patterns): Call output_ashl instead of output_ashlsi3.
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 1232b4a..50acbb1 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for Intel X86.
-   Copyright (C) 1988, 92, 94-97, 1998 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 94-98, 1999 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -18,10 +18,9 @@ along with GNU CC; see the file COPYING.  If not, write to
 the Free Software Foundation, 59 Temple Place - Suite 330,
 Boston, MA 02111-1307, USA. */
 
-#include <stdio.h>
 #include <setjmp.h>
-#include <ctype.h>
 #include "config.h"
+#include "system.h"
 #include "rtl.h"
 #include "regs.h"
 #include "hard-reg-set.h"
@@ -36,18 +35,8 @@ Boston, MA 02111-1307, USA. */
 #include "except.h"
 #include "function.h"
 #include "recog.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 
+#include "expr.h"
+#include "toplev.h"
 
 #ifdef EXTRA_CONSTRAINT
 /* If EXTRA_CONSTRAINT is defined, then the 'S'
@@ -111,8 +100,37 @@ struct processor_costs pentiumpro_cost = {
   17                                   /* cost of a divide/mod */
 };
 
+struct processor_costs k6_cost = {
+  1,                                   /* cost of an add instruction */
+  1,                                   /* cost of a lea instruction */
+  1,                                   /* variable shift costs */
+  1,                                   /* constant shift costs */
+  2,                                   /* cost of starting a multiply */
+  0,                                   /* cost of multiply per each bit set */
+  18                                   /* cost of a divide/mod */
+};
+
 struct processor_costs *ix86_cost = &pentium_cost;
 
+/* Processor feature/optimization bitmasks.  */
+#define m_386 (1<<PROCESSOR_I386)
+#define m_486 (1<<PROCESSOR_I486)
+#define m_PENT (1<<PROCESSOR_PENTIUM)
+#define m_PPRO (1<<PROCESSOR_PENTIUMPRO)
+#define m_K6  (1<<PROCESSOR_K6)
+
+const int x86_use_leave = m_386 | m_K6;
+const int x86_push_memory = m_386 | m_K6;
+const int x86_zero_extend_with_and = m_486 | m_PENT;
+const int x86_movx = m_386 | m_PPRO | m_K6;
+const int x86_double_with_add = ~(m_386 | m_PENT | m_PPRO);
+const int x86_use_bit_test = m_386;
+const int x86_unroll_strlen = m_486 | m_PENT | m_PPRO;
+const int x86_use_q_reg = m_PENT | m_PPRO | m_K6;
+const int x86_use_any_reg = m_486;
+const int x86_cmove = m_PPRO;
+const int x86_deep_branch = m_PPRO| m_K6;
+
 #define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))
 
 extern FILE *asm_out_file;
@@ -140,7 +158,7 @@ enum reg_class regclass_map[FIRST_PSEUDO_REGISTER] =
   SIREG, DIREG, INDEX_REGS, GENERAL_REGS,
   /* FP registers */
   FP_TOP_REG, FP_SECOND_REG, FLOAT_REGS, FLOAT_REGS,
-  FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,       
+  FLOAT_REGS, FLOAT_REGS, FLOAT_REGS, FLOAT_REGS,
   /* arg pointer */
   INDEX_REGS
 };
@@ -224,7 +242,8 @@ override_options ()
           {PROCESSOR_I686_STRING, PROCESSOR_PENTIUMPRO, &pentiumpro_cost,
              0, 0},
           {PROCESSOR_PENTIUMPRO_STRING, PROCESSOR_PENTIUMPRO,
-             &pentiumpro_cost, 0, 0}};
+             &pentiumpro_cost, 0, 0},
+          {PROCESSOR_K6_STRING, PROCESSOR_K6, &k6_cost, 0, 0}};
 
   int ptt_size = sizeof (processor_target_table) / sizeof (struct ptt);
 
@@ -238,7 +257,7 @@ override_options ()
       for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
        {
          int regno = 0;
-         
+
          switch (ch)
            {
            case 'a':   regno = 0;      break;
@@ -265,7 +284,7 @@ override_options ()
       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))
       {
@@ -290,7 +309,7 @@ override_options ()
       {
        ix86_cpu = processor_target_table[j].processor;
        ix86_cost = processor_target_table[j].cost;
-       if (i > j && (int) ix86_arch >= (int) PROCESSOR_PENTIUMPRO)
+       if (i > j && (int) ix86_arch >= (int) PROCESSOR_K6)
          error ("-mcpu=%s does not support -march=%s",
                 ix86_cpu_string, ix86_arch_string);
 
@@ -330,7 +349,11 @@ override_options ()
               i386_align_loops, MAX_CODE_ALIGN);
     }
   else
+#ifdef ASM_OUTPUT_MAX_SKIP_ALIGN
+    i386_align_loops = 4;
+#else
     i386_align_loops = 2;
+#endif
 
   /* Validate -malign-jumps= value, or provide default.  */
   if (i386_align_jumps_string)
@@ -341,7 +364,11 @@ 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. */
   if (i386_align_funcs_string)
@@ -395,7 +422,7 @@ order_regs_for_local_alloc ()
       for (i = order = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
        {
          int regno = 0;
-         
+
          switch (ch)
            {
            case 'a':   regno = 0;      break;
@@ -428,7 +455,7 @@ order_regs_for_local_alloc ()
 void
 optimization_options (level, size)
      int level;
-     int size;
+     int size ATTRIBUTE_UNUSED;
 {
   /* For -O2 and beyond, turn off -fschedule-insns by default.  It tends to
      make the problem with not enough registers even worse.  */
@@ -505,7 +532,7 @@ i386_aligned_p (op)
 
     case REG:
       return i386_aligned_reg_p (REGNO (op));
-    
+
     default:
       break;
     }
@@ -529,10 +556,10 @@ i386_cc_probably_useless_p (insn)
 
 int
 i386_valid_decl_attribute_p (decl, attributes, identifier, args)
-     tree decl;
-     tree attributes;
-     tree identifier;
-     tree args;
+     tree decl ATTRIBUTE_UNUSED;
+     tree attributes ATTRIBUTE_UNUSED;
+     tree identifier ATTRIBUTE_UNUSED;
+     tree args ATTRIBUTE_UNUSED;
 {
   return 0;
 }
@@ -544,11 +571,12 @@ i386_valid_decl_attribute_p (decl, attributes, identifier, args)
 int
 i386_valid_type_attribute_p (type, attributes, identifier, args)
      tree type;
-     tree attributes;
+     tree attributes ATTRIBUTE_UNUSED;
      tree identifier;
      tree args;
 {
   if (TREE_CODE (type) != FUNCTION_TYPE
+      && TREE_CODE (type) != METHOD_TYPE
       && TREE_CODE (type) != FIELD_DECL
       && TREE_CODE (type) != TYPE_DECL)
     return 0;
@@ -597,6 +625,16 @@ i386_comp_type_attributes (type1, type2)
      tree type1;
      tree type2;
 {
+  /* Check for mismatch of non-default calling convention. */
+  char *rtdstr = TARGET_RTD ? "cdecl" : "stdcall";
+
+  if (TREE_CODE (type1) != FUNCTION_TYPE)
+    return 1;
+
+  /* Check for mismatched return types (cdecl vs stdcall).  */
+  if (!lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type1))
+      != !lookup_attribute (rtdstr, TYPE_ATTRIBUTES (type2)))
+    return 0;
   return 1;
 }
 
@@ -623,27 +661,27 @@ i386_return_pops_args (fundecl, funtype, size)
      tree fundecl;
      tree funtype;
      int size;
-{ 
+{
   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;
 }
 
@@ -808,62 +846,14 @@ function_arg (cum, mode, type, named)
 
 int
 function_arg_partial_nregs (cum, mode, type, named)
-     CUMULATIVE_ARGS *cum    /* current arg information */
-     enum machine_mode mode  /* current arg mode */
-     tree type;                        /* type of the argument or 0 if lib support */
-     int named;                        /* != 0 for normal args, == 0 for ... args */
+     CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED;    /* current arg information */
+     enum machine_mode mode ATTRIBUTE_UNUSED;  /* current arg mode */
+     tree type ATTRIBUTE_UNUSED;               /* type of the argument or 0 if lib support */
+     int named ATTRIBUTE_UNUSED;               /* != 0 for normal args, == 0 for ... args */
 {
   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
-   be either SImode or DImode.
-
-   The template will be output with operands[0] as SRC, and operands[1]
-   as a pointer to the top of the 386 stack.  So a call from floatsidf2
-   would look like this:
-
-      output_op_from_reg (operands[1], AS1 (fild%z0,%1));
-
-   where %z0 corresponds to the caller's operands[1], and is used to
-   emit the proper size suffix.
-
-   ??? Extend this to handle HImode - a 387 can load and store HImode
-   values directly. */
-
-void
-output_op_from_reg (src, template)
-     rtx src;
-     char *template;
-{
-  rtx xops[4];
-  int size = GET_MODE_SIZE (GET_MODE (src));
-
-  xops[0] = src;
-  xops[1] = AT_SP (Pmode);
-  xops[2] = GEN_INT (size);
-  xops[3] = stack_pointer_rtx;
-
-  if (size > UNITS_PER_WORD)
-    {
-      rtx high;
-
-      if (size > 2 * UNITS_PER_WORD)
-       {
-         high = gen_rtx_REG (SImode, REGNO (src) + 2);
-         output_asm_insn (AS1 (push%L0,%0), &high);
-       }
-
-      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 (template, xops);
-  output_asm_insn (AS2 (add%L3,%2,%3), xops);
-}
-\f
 /* Output an insn to pop an value from the 387 top-of-stack to 386
    register DEST. The 387 register stack is popped if DIES is true.  If
    the mode of DEST is an integer mode, a `fist' integer store is done,
@@ -894,6 +884,17 @@ output_to_reg (dest, dies, scratch_mem)
     {
       if (dies)
        output_asm_insn (AS1 (fistp%z3,%y0), xops);
+      else if (GET_MODE (xops[3]) == DImode && ! 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%z3,%0), xops);
+         output_asm_insn (AS1 (fild%z3,%0), xops);
+       }
       else
        output_asm_insn (AS1 (fist%z3,%y0), xops);
     }
@@ -930,7 +931,7 @@ output_to_reg (dest, dies, scratch_mem)
        output_asm_insn (AS1 (pop%L0,%0), &dest);
       else
        {
-         xops[0] = adj_offsettable_operand (xops[0], 4);             
+         xops[0] = adj_offsettable_operand (xops[0], 4);
          xops[3] = dest;
          output_asm_insn (AS2 (mov%L0,%0,%3), xops);
        }
@@ -942,7 +943,7 @@ output_to_reg (dest, dies, scratch_mem)
            output_asm_insn (AS1 (pop%L0,%0), &dest);
          else
            {
-             xops[0] = adj_offsettable_operand (xops[0], 4);         
+             xops[0] = adj_offsettable_operand (xops[0], 4);
              output_asm_insn (AS2 (mov%L0,%0,%3), xops);
            }
        }
@@ -1148,7 +1149,7 @@ output_move_double (operands)
          middlehalf[0] = operands[0];
          latehalf[0] = operands[0];
        }
-    
+
       if (optype1 == REGOP)
        {
           middlehalf[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 1);
@@ -1368,7 +1369,7 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
       char *push;
       rtx   xops[2];
     } tmp_info[MAX_TMPS];
-  
+
   rtx src = operands[1];
   int max_tmps = 0;
   int offset = 0;
@@ -1431,125 +1432,6 @@ output_move_pushmem (operands, insn, length, tmp_start, n_operands)
   return "";
 }
 \f
-/* Output the appropriate code to move data between two memory locations */
-
-char *
-output_move_memory (operands, insn, length, tmp_start, n_operands)
-     rtx operands[];
-     rtx insn;
-     int length;
-     int tmp_start;
-     int n_operands;
-{
-  struct
-    {
-      char *load;
-      char *store;
-      rtx   xops[3];
-    } tmp_info[MAX_TMPS];
-
-  rtx dest = operands[0];
-  rtx src  = operands[1];
-  rtx qi_tmp = NULL_RTX;
-  int max_tmps = 0;
-  int offset = 0;
-  int i, num_tmps;
-  rtx xops[3];
-
-  if (GET_CODE (dest) == MEM
-      && GET_CODE (XEXP (dest, 0)) == PRE_INC
-      && XEXP (XEXP (dest, 0), 0) == stack_pointer_rtx)
-    return output_move_pushmem (operands, insn, length, tmp_start, n_operands);
-
-  if (! offsettable_memref_p (src))
-    fatal_insn ("Source is not offsettable", insn);
-
-  if (! offsettable_memref_p (dest))
-    fatal_insn ("Destination is not offsettable", insn);
-
-  /* Figure out which temporary registers we have available */
-  for (i = tmp_start; i < n_operands; i++)
-    {
-      if (GET_CODE (operands[i]) == REG)
-       {
-         if ((length & 1) != 0 && qi_tmp == 0 && QI_REG_P (operands[i]))
-           qi_tmp = operands[i];
-
-         if (reg_overlap_mentioned_p (operands[i], dest))
-           fatal_insn ("Temporary register overlaps the destination", insn);
-
-         if (reg_overlap_mentioned_p (operands[i], src))
-           fatal_insn ("Temporary register overlaps the source", insn);
-
-         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);
-
-  if ((length & 1) != 0)
-    {
-      if (qi_tmp == 0)
-       fatal_insn ("No byte register found when moving odd # of bytes.",
-                   insn);
-    }
-
-  while (length > 1)
-    {
-      for (num_tmps = 0; num_tmps < max_tmps; num_tmps++)
-       {
-         if (length >= 4)
-           {
-             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);
-
-             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);
-
-             offset += 2;
-             length -= 2;
-           }
-         else
-           break;
-       }
-
-      for (i = 0; i < num_tmps; i++)
-       output_asm_insn (tmp_info[i].load, tmp_info[i].xops);
-
-      for (i = 0; i < num_tmps; i++)
-       output_asm_insn (tmp_info[i].store, tmp_info[i].xops);
-    }
-
-  if (length == 1)
-    {
-      xops[0] = adj_offsettable_operand (dest, offset);
-      xops[1] = adj_offsettable_operand (src, offset);
-      xops[2] = qi_tmp;
-      output_asm_insn (AS2(mov%B0,%1,%2), xops);
-      output_asm_insn (AS2(mov%B0,%2,%0), xops);
-    }
-
-  return "";
-}
-\f
 int
 standard_80387_constant_p (x)
      rtx x;
@@ -1577,6 +1459,7 @@ standard_80387_constant_p (x)
   /* Note that on the 80387, other constants, such as pi,
      are much slower to load as standard constants
      than to load from doubles in memory!  */
+  /* ??? Not true on K6: all constants are equal cost.  */
 #endif
 
   return 0;
@@ -1618,7 +1501,7 @@ output_move_const_single (operands)
 int
 symbolic_operand (op, mode)
      register rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   switch (GET_CODE (op))
     {
@@ -1637,6 +1520,17 @@ symbolic_operand (op, mode)
     }
 }
 
+/* Return nonzero if OP is a constant shift count small enough to
+   encode into an lea instruction.  */
+
+int
+small_shift_operand (op, mode)
+     rtx op;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+{
+  return (GET_CODE (op) == CONST_INT && INTVAL (op) > 0 && INTVAL (op) < 4);
+}
+
 /* Test for a valid operand for a call instruction.
    Don't allow the arg pointer register or virtual regs
    since they may change into reg + const, which the patterns
@@ -1645,7 +1539,7 @@ symbolic_operand (op, mode)
 int
 call_insn_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) == MEM
       && ((CONSTANT_ADDRESS_P (XEXP (op, 0))
@@ -1666,7 +1560,7 @@ call_insn_operand (op, mode)
 int
 expander_call_insn_operand (op, mode)
      rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) == MEM
       && (CONSTANT_ADDRESS_P (XEXP (op, 0))
@@ -1702,7 +1596,7 @@ arithmetic_comparison_operator (op, mode)
 int
 ix86_logical_operator (op, mode)
      register rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return GET_CODE (op) == AND || GET_CODE (op) == IOR || GET_CODE (op) == XOR;
 }
@@ -1780,7 +1674,7 @@ ix86_expand_binary_operator (code, mode, operands)
          emit_move_insn (temp, operands[1]);
          operands[1] = temp;
          return TRUE;
-       }         
+       }
     }
 
   if (!ix86_binary_operator_ok (code, mode, operands))
@@ -1813,7 +1707,7 @@ ix86_expand_binary_operator (code, mode, operands)
              emit_move_insn (temp, operands[1]);
              operands[1] = temp;
              return TRUE;
-           }     
+           }
 
          if (modified && ! ix86_binary_operator_ok (code, mode, operands))
            return FALSE;
@@ -1831,7 +1725,7 @@ ix86_expand_binary_operator (code, mode, operands)
 int
 ix86_binary_operator_ok (code, mode, operands)
      enum rtx_code code;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
      rtx operands[3];
 {
   return (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)
@@ -1878,9 +1772,9 @@ ix86_expand_unary_operator (code, mode, operands)
 
 int
 ix86_unary_operator_ok (code, mode, operands)
-     enum rtx_code code;
-     enum machine_mode mode;
-     rtx operands[2];
+     enum rtx_code code ATTRIBUTE_UNUSED;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
+     rtx operands[2] ATTRIBUTE_UNUSED;
 {
   return TRUE;
 }
@@ -1890,12 +1784,12 @@ static char pic_label_name [256];
 static int pic_label_no = 0;
 
 /* This function generates code for -fpic that loads %ebx with
-   with the return address of the caller and then returns.  */
+   the return address of the caller and then returns.  */
 
 void
 asm_output_function_prefix (file, name)
      FILE *file;
-     char *name;
+     char *name ATTRIBUTE_UNUSED;
 {
   rtx xops[2];
   int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
@@ -1911,15 +1805,22 @@ asm_output_function_prefix (file, name)
       if (pic_label_rtx == 0)
        {
          pic_label_rtx = gen_label_rtx ();
-         sprintf (pic_label_name, "LPR%d", pic_label_no++);
+         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
+
+      /* This used to call ASM_DECLARE_FUNCTION_NAME() but since it's an
+        internal (non-global) label that's being emitted, it didn't make
+        sense to have .type information for local labels.   This caused
+        the SCO OpenServer 5.0.4 ELF assembler grief (why are you giving
+        me debug info for a label that you're declaring non-global?) this
+        was changed to call ASM_OUTPUT_LABEL() instead. */
+
+
+      ASM_OUTPUT_LABEL (file, pic_label_name); 
       output_asm_insn ("movl (%1),%0", xops);
       output_asm_insn ("ret", xops);
     }
@@ -1931,15 +1832,15 @@ asm_output_function_prefix (file, name)
 
 void
 function_prologue (file, size)
-     FILE *file;
-     int size;
+     FILE *file ATTRIBUTE_UNUSED;
+     int size ATTRIBUTE_UNUSED;
 {
   if (TARGET_SCHEDULE_PROLOGUE)
     {
       pic_label_rtx = 0;
       return;
     }
-  
+
   ix86_prologue (0);
 }
 
@@ -1950,7 +1851,7 @@ ix86_expand_prologue ()
 {
   if (! TARGET_SCHEDULE_PROLOGUE)
       return;
+
   ix86_prologue (1);
 }
 
@@ -1966,7 +1867,7 @@ load_pic_register (do_rtl)
       if (pic_label_rtx == 0)
        {
          pic_label_rtx = gen_label_rtx ();
-         sprintf (pic_label_name, "LPR%d", pic_label_no++);
+         ASM_GENERATE_INTERNAL_LABEL (pic_label_name, "LPR", pic_label_no++);
          LABEL_NAME (pic_label_rtx) = pic_label_name;
        }
 
@@ -1977,14 +1878,14 @@ load_pic_register (do_rtl)
       if (do_rtl)
        {
          emit_insn (gen_prologue_get_pc (xops[0], xops[1]));
-         emit_insn (gen_prologue_set_got (xops[0], 
+         emit_insn (gen_prologue_set_got (xops[0],
                                           gen_rtx (SYMBOL_REF, Pmode,
-                                                   "$_GLOBAL_OFFSET_TABLE_"), 
+                                                   "$_GLOBAL_OFFSET_TABLE_"),
                                           xops[1]));
        }
       else
        {
-         output_asm_insn (AS1 (call,%P1), xops);
+         output_asm_insn (AS1 (call,%X1), xops);
          output_asm_insn ("addl $_GLOBAL_OFFSET_TABLE_,%0", xops);
          pic_label_rtx = 0;
        }
@@ -1994,7 +1895,7 @@ load_pic_register (do_rtl)
     {
       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
@@ -2005,12 +1906,12 @@ load_pic_register (do_rtl)
       else
        {
          output_asm_insn (AS1 (call,%P1), xops);
-         ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", 
+         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
@@ -2020,6 +1921,62 @@ load_pic_register (do_rtl)
     emit_insn (gen_blockage ());
 }
 
+/* Compute the size of local storage taking into consideration the
+   desired stack alignment which is to be maintained.  Also determine
+   the number of registers saved below the local storage.  */
+
+HOST_WIDE_INT
+ix86_compute_frame_size (size, nregs_on_stack)
+     HOST_WIDE_INT size;
+     int *nregs_on_stack;
+{
+  int limit;
+  int nregs;
+  int regno;
+  int padding;
+  int pic_reg_used = flag_pic && (current_function_uses_pic_offset_table
+                                 || current_function_uses_const_pool);
+  HOST_WIDE_INT total_size;
+
+  limit = frame_pointer_needed
+         ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;
+
+  nregs = 0;
+
+  for (regno = limit - 1; regno >= 0; regno--)
+    if ((regs_ever_live[regno] && ! call_used_regs[regno])
+       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
+      nregs++;
+
+  padding = 0;
+  total_size = size + (nregs * UNITS_PER_WORD);
+
+#ifdef PREFERRED_STACK_BOUNDARY
+  {
+    int offset;
+    int preferred_alignment = PREFERRED_STACK_BOUNDARY / BITS_PER_UNIT;
+
+    offset = 4;
+    if (frame_pointer_needed)
+      offset += UNITS_PER_WORD;
+
+    total_size += offset;
+    
+    padding = ((total_size + preferred_alignment - 1)
+              & -preferred_alignment) - total_size;
+
+    if (padding < (((offset + preferred_alignment - 1)
+                   & -preferred_alignment) - offset))
+      padding += preferred_alignment;
+  }
+#endif
+
+  if (nregs_on_stack)
+    *nregs_on_stack = nregs;
+
+  return size + padding;
+}
+
 static void
 ix86_prologue (do_rtl)
      int do_rtl;
@@ -2029,10 +1986,10 @@ ix86_prologue (do_rtl)
   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 ();
+  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), (int *)0);
   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);
@@ -2054,7 +2011,7 @@ ix86_prologue (do_rtl)
 
       else
        {
-         output_asm_insn ("push%L1 %1", xops); 
+         output_asm_insn ("push%L1 %1", xops);
 #ifdef INCOMING_RETURN_ADDR_RTX
          if (dwarf2out_do_frame ())
            {
@@ -2067,7 +2024,7 @@ ix86_prologue (do_rtl)
            }
 #endif
 
-         output_asm_insn (AS2 (mov%L0,%0,%1), xops); 
+         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);
@@ -2084,7 +2041,7 @@ ix86_prologue (do_rtl)
          insn = emit_insn (gen_prologue_set_stack_ptr (xops[2]));
          RTX_FRAME_RELATED_P (insn) = 1;
        }
-      else 
+      else
        {
          output_asm_insn (AS2 (sub%L0,%2,%0), xops);
 #ifdef INCOMING_RETURN_ADDR_RTX
@@ -2100,7 +2057,7 @@ ix86_prologue (do_rtl)
 #endif
        }
     }
-  else 
+  else
     {
       xops[3] = gen_rtx_REG (SImode, 0);
       if (do_rtl)
@@ -2164,6 +2121,10 @@ ix86_prologue (do_rtl)
          }
       }
 
+#ifdef SUBTARGET_PROLOGUE
+  SUBTARGET_PROLOGUE;
+#endif  
+
   if (pic_reg_used)
     load_pic_register (do_rtl);
 
@@ -2178,7 +2139,7 @@ ix86_prologue (do_rtl)
 /* 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 
+   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
@@ -2219,13 +2180,13 @@ ix86_can_use_return_insn_p ()
 
 void
 function_epilogue (file, size)
-     FILE *file;
-     int size;
+     FILE *file ATTRIBUTE_UNUSED;
+     int size ATTRIBUTE_UNUSED;
 {
     return;
 }
 
-/* Restore function stack, frame, and registers. */ 
+/* Restore function stack, frame, and registers. */
 
 void
 ix86_expand_epilogue ()
@@ -2238,32 +2199,18 @@ ix86_epilogue (do_rtl)
      int do_rtl;
 {
   register int regno;
-  register int nregs, limit;
-  int offset;
+  register int limit;
+  int nregs;
   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 */
+  int sp_valid = !frame_pointer_needed || current_function_sp_is_unchanging;
+  HOST_WIDE_INT offset;
+  HOST_WIDE_INT tsize = ix86_compute_frame_size (get_frame_size (), &nregs);
 
-  limit = (frame_pointer_needed ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM);
-
-  nregs = 0;
-
-  for (regno = limit - 1; regno >= 0; regno--)
-    if ((regs_ever_live[regno] && ! call_used_regs[regno])
-       || (regno == PIC_OFFSET_TABLE_REGNUM && pic_reg_used))
-      nregs++;
+  /* sp is often unreliable so we may have to 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. */
-
-  offset = - tsize - (nregs * UNITS_PER_WORD);
+  offset = -(tsize + nregs * UNITS_PER_WORD);
 
   xops[2] = stack_pointer_rtx;
 
@@ -2278,9 +2225,17 @@ ix86_epilogue (do_rtl)
   if (flag_pic || profile_flag || profile_block_flag)
     emit_insn (gen_blockage ());
 
-  if (nregs > 1 || ! frame_pointer_needed)
+  /* If we're only restoring one register and sp is not valid then
+     using a move instruction to restore the register since it's
+     less work than reloading sp and popping the register.  Otherwise,
+     restore sp (if necessary) and pop the registers. */
+
+  limit = frame_pointer_needed
+         ? FRAME_POINTER_REGNUM : STACK_POINTER_REGNUM;
+
+  if (nregs > 1 || sp_valid)
     {
-      if (frame_pointer_needed)
+      if ( !sp_valid )
        {
          xops[0] = adj_offsettable_operand (AT_BP (QImode), offset);
          if (do_rtl)
@@ -2349,14 +2304,57 @@ ix86_epilogue (do_rtl)
 
   else if (tsize)
     {
-      /* If there is no frame pointer, we must still release the frame. */
-      xops[0] = GEN_INT (tsize);
+      /* Intel's docs say that for 4 or 8 bytes of stack frame one should
+        use `pop' and not `add'.  */
+      int use_pop = tsize == 4;
 
-      if (do_rtl)
-       emit_insn (gen_rtx (SET, VOIDmode, xops[2],
-                           gen_rtx (PLUS, SImode, xops[2], xops[0])));
+      /* Use two pops only for the Pentium processors.  */
+      if (tsize == 8 && !TARGET_386 && !TARGET_486)
+       {
+         rtx retval = current_function_return_rtx;
+
+         xops[1] = gen_rtx_REG (SImode, 1);    /* %edx */
+
+         /* This case is a bit more complex.  Since we cannot pop into
+            %ecx twice we need a second register.  But this is only
+            available if the return value is not of DImode in which
+            case the %edx register is not available.  */
+         use_pop = (retval == NULL
+                    || ! reg_overlap_mentioned_p (xops[1], retval));
+       }
+
+      if (use_pop)
+       {
+         xops[0] = gen_rtx_REG (SImode, 2);    /* %ecx */
+
+         if (do_rtl)
+           {
+             /* We have to prevent the two pops here from being scheduled.
+                GCC otherwise would try in some situation to put other
+                instructions in between them which has a bad effect.  */
+             emit_insn (gen_blockage ());
+             emit_insn (gen_pop (xops[0]));
+             if (tsize == 8)
+               emit_insn (gen_pop (xops[1]));
+           }
+         else
+           {
+             output_asm_insn ("pop%L0 %0", xops);
+             if (tsize == 8)
+               output_asm_insn ("pop%L1 %1", xops);
+           }
+       }
       else
-       output_asm_insn (AS2 (add%L2,%0,%2), xops);
+       {
+         /* 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);
+       }
     }
 
 #ifdef FUNCTION_BLOCK_PROFILER_EXIT
@@ -2393,7 +2391,7 @@ ix86_epilogue (do_rtl)
              output_asm_insn ("jmp %*%0", xops);
            }
        }
-      else 
+      else
        {
          if (do_rtl)
            emit_jump_insn (gen_return_pop_internal (xops[1]));
@@ -2445,6 +2443,37 @@ do {                                                                     \
 } while (0)
 
 int
+legitimate_pic_address_disp_p (disp)
+     register rtx disp;
+{
+  if (GET_CODE (disp) != CONST)
+    return 0;
+  disp = XEXP (disp, 0);
+
+  if (GET_CODE (disp) == PLUS)
+    {
+      if (GET_CODE (XEXP (disp, 1)) != CONST_INT)
+       return 0;
+      disp = XEXP (disp, 0);
+    }
+
+  if (GET_CODE (disp) != UNSPEC
+      || XVECLEN (disp, 0) != 1)
+    return 0;
+
+  /* Must be @GOT or @GOTOFF.  */
+  if (XINT (disp, 1) != 6
+      && XINT (disp, 1) != 7)
+    return 0;
+
+  if (GET_CODE (XVECEXP (disp, 0, 0)) != SYMBOL_REF
+      && GET_CODE (XVECEXP (disp, 0, 0)) != LABEL_REF)
+    return 0;
+
+  return 1;
+}
+
+int
 legitimate_address_p (mode, addr, strict)
      enum machine_mode mode;
      register rtx addr;
@@ -2465,7 +2494,7 @@ legitimate_address_p (mode, addr, strict)
     }
 
   if (GET_CODE (addr) == REG || GET_CODE (addr) == SUBREG)
-      base = addr;
+    base = addr;
 
   else if (GET_CODE (addr) == PLUS)
     {
@@ -2555,6 +2584,12 @@ legitimate_address_p (mode, addr, strict)
          return FALSE;
        }
 
+      if (GET_MODE (base) != Pmode)
+       {
+         ADDR_INVALID ("Base is not in Pmode.\n", base);
+         return FALSE;
+       }
+
       if ((strict && ! REG_OK_FOR_BASE_STRICT_P (base))
          || (! strict && ! REG_OK_FOR_BASE_NONSTRICT_P (base)))
        {
@@ -2576,6 +2611,12 @@ legitimate_address_p (mode, addr, strict)
          return FALSE;
        }
 
+      if (GET_MODE (indx) != Pmode)
+       {
+         ADDR_INVALID ("Index is not in Pmode.\n", indx);
+         return FALSE;
+       }
+
       if ((strict && ! REG_OK_FOR_INDEX_STRICT_P (indx))
          || (! strict && ! REG_OK_FOR_INDEX_NONSTRICT_P (indx)))
        {
@@ -2605,20 +2646,10 @@ legitimate_address_p (mode, addr, strict)
        }
     }
 
-  /* 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. */
+  /* Validate displacement.  */
   if (disp)
     {
-      if (GET_CODE (disp) == SYMBOL_REF
-         && CONSTANT_POOL_ADDRESS_P (disp)
-         && base == 0
-         && indx == 0)
-       ;
-
-      else if (!CONSTANT_ADDRESS_P (disp))
+      if (!CONSTANT_ADDRESS_P (disp))
        {
          ADDR_INVALID ("Displacement is not valid.\n", disp);
          return FALSE;
@@ -2630,20 +2661,32 @@ legitimate_address_p (mode, addr, strict)
          return FALSE;
        }
 
-      else if (flag_pic && SYMBOLIC_CONST (disp)
-              && base != pic_offset_table_rtx
-              && (indx != pic_offset_table_rtx || scale != NULL_RTX))
+      if (flag_pic && SYMBOLIC_CONST (disp))
        {
-         ADDR_INVALID ("Displacement is an invalid pic reference.\n", disp);
-         return FALSE;
-       }
+         if (! legitimate_pic_address_disp_p (disp))
+           {
+             ADDR_INVALID ("Displacement is an invalid PIC construct.\n",
+                           disp);
+             return FALSE;
+           }
 
-      else if (HALF_PIC_P () && HALF_PIC_ADDRESS_P (disp)
-              && (base != NULL_RTX || indx != NULL_RTX))
+         if (base != pic_offset_table_rtx
+             && (indx != pic_offset_table_rtx || scale != NULL_RTX))
+           {
+             ADDR_INVALID ("PIC displacement against invalid base.\n", disp);
+             return FALSE;
+           }
+       }
+
+      else if (HALF_PIC_P ())
        {
-         ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
-                       disp);
-         return FALSE;
+         if (! HALF_PIC_ADDRESS_P (disp)
+             || (base != NULL_RTX || indx != NULL_RTX))
+           {
+             ADDR_INVALID ("Displacement is an invalid half-pic reference.\n",
+                           disp);
+             return FALSE;
+           }
        }
     }
 
@@ -2657,29 +2700,20 @@ legitimate_address_p (mode, addr, strict)
 /* Return a legitimate reference for ORIG (an address) using the
    register REG.  If REG is 0, a new pseudo is generated.
 
-   There are three types of references that must be handled:
+   There are two types of references that must be handled:
 
    1. Global data references must load the address from the GOT, via
       the PIC reg.  An insn is emitted to do this load, and the reg is
       returned.
 
-   2. Static data references must compute the address as an offset
-      from the GOT, whose base is in the PIC reg.  An insn is emitted to
-      compute the address into a reg, and the reg is returned.  Static
-      data objects have SYMBOL_REF_FLAG set to differentiate them from
-      global data objects.
-
-   3. 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.
+   2. Static data references, constant pool addresses, and code labels
+      compute the address as an offset from the GOT, whose base is in
+      the PIC reg.  Static data objects have SYMBOL_REF_FLAG set to
+      differentiate them from global data objects.  The returned
+      address is the PIC reg + an unspec constant.
 
    GO_IF_LEGITIMATE_ADDRESS rejects symbolic references unless the PIC
-   reg also appears in the address (except for constant pool references,
-   noted above).
-
-   "switch" statements also require special handling when generating
-   PIC code.  See comments by the `casesi' insn in i386.md for details.  */
+   reg also appears in the address.  */
 
 rtx
 legitimize_pic_address (orig, reg)
@@ -2688,60 +2722,99 @@ legitimize_pic_address (orig, reg)
 {
   rtx addr = orig;
   rtx new = orig;
+  rtx base;
 
-  if (GET_CODE (addr) == SYMBOL_REF || GET_CODE (addr) == LABEL_REF)
+  if (GET_CODE (addr) == LABEL_REF
+      || (GET_CODE (addr) == SYMBOL_REF
+         && (CONSTANT_POOL_ADDRESS_P (addr)
+             || SYMBOL_REF_FLAG (addr))))
     {
-      if (GET_CODE (addr) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (addr))
-       reg = new = orig;
-      else
-       {
-         if (reg == 0)
-           reg = gen_reg_rtx (Pmode);
+      /* This symbol may be referenced via a displacement from the PIC
+        base address (@GOTOFF).  */
 
-         if ((GET_CODE (addr) == SYMBOL_REF && SYMBOL_REF_FLAG (addr))
-             || 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));
+      current_function_uses_pic_offset_table = 1;
+      new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 7);
+      new = gen_rtx_CONST (VOIDmode, new);
+      new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
 
+      if (reg != 0)
+       {
          emit_move_insn (reg, new);
+         new = reg;
        }
-      current_function_uses_pic_offset_table = 1;
-      return reg;
     }
-
-  else if (GET_CODE (addr) == CONST || GET_CODE (addr) == PLUS)
+  else if (GET_CODE (addr) == SYMBOL_REF)
     {
-      rtx base;
+      /* This symbol must be referenced via a load from the
+        Global Offset Table (@GOT). */
 
+      current_function_uses_pic_offset_table = 1;
+      new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, addr), 6);
+      new = gen_rtx_CONST (VOIDmode, new);
+      new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
+      new = gen_rtx_MEM (Pmode, new);
+      RTX_UNCHANGING_P (new) = 1;
+
+      if (reg == 0)
+       reg = gen_reg_rtx (Pmode);
+      emit_move_insn (reg, new);
+      new = reg;
+    }      
+  else
+    {
       if (GET_CODE (addr) == CONST)
        {
          addr = XEXP (addr, 0);
-         if (GET_CODE (addr) != PLUS)
-           abort ();
+         if (GET_CODE (addr) == UNSPEC)
+           {
+             /* Check that the unspec is one of the ones we generate?  */
+           }
+         else if (GET_CODE (addr) != PLUS)
+           abort();
        }
+      if (GET_CODE (addr) == PLUS)
+       {
+         rtx op0 = XEXP (addr, 0), op1 = XEXP (addr, 1);
+
+         /* Check first to see if this is a constant offset from a @GOTOFF
+            symbol reference.  */
+         if ((GET_CODE (op0) == LABEL_REF
+              || (GET_CODE (op0) == SYMBOL_REF
+                  && (CONSTANT_POOL_ADDRESS_P (op0)
+                      || SYMBOL_REF_FLAG (op0))))
+             && GET_CODE (op1) == CONST_INT)
+           {
+             current_function_uses_pic_offset_table = 1;
+             new = gen_rtx_UNSPEC (VOIDmode, gen_rtvec (1, op0), 7);
+             new = gen_rtx_PLUS (VOIDmode, new, op1);
+             new = gen_rtx_CONST (VOIDmode, new);
+             new = gen_rtx_PLUS (Pmode, pic_offset_table_rtx, new);
 
-      if (XEXP (addr, 0) == pic_offset_table_rtx)
-       return orig;
-
-      if (reg == 0)
-       reg = gen_reg_rtx (Pmode);
-
-      base = legitimize_pic_address (XEXP (addr, 0), reg);
-      addr = legitimize_pic_address (XEXP (addr, 1),
-                                    base == reg ? NULL_RTX : reg);
-
-      if (GET_CODE (addr) == CONST_INT)
-       return plus_constant (base, INTVAL (addr));
+             if (reg != 0)
+               {
+                 emit_move_insn (reg, new);
+                 new = reg;
+               }
+           }
+         else
+           {
+             base = legitimize_pic_address (XEXP (addr, 0), reg);
+             new  = legitimize_pic_address (XEXP (addr, 1),
+                                            base == reg ? NULL_RTX : reg);
 
-      if (GET_CODE (addr) == PLUS && CONSTANT_P (XEXP (addr, 1)))
-       {
-         base = gen_rtx (PLUS, Pmode, base, XEXP (addr, 0));
-         addr = XEXP (addr, 1);
+             if (GET_CODE (new) == CONST_INT)
+               new = plus_constant (base, INTVAL (new));
+             else
+               {
+                 if (GET_CODE (new) == PLUS && CONSTANT_P (XEXP (new, 1)))
+                   {
+                     base = gen_rtx_PLUS (Pmode, base, XEXP (new, 0));
+                     new = XEXP (new, 1);
+                   }
+                 new = gen_rtx_PLUS (Pmode, base, new);
+               }
+           }
        }
-
-      return gen_rtx (PLUS, Pmode, base, addr);
     }
   return new;
 }
@@ -2751,12 +2824,12 @@ legitimize_pic_address (orig, reg)
 void
 emit_pic_move (operands, mode)
      rtx *operands;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   rtx temp = reload_in_progress ? operands[0] : gen_reg_rtx (Pmode);
 
   if (GET_CODE (operands[0]) == MEM && SYMBOLIC_CONST (operands[1]))
-    operands[1] = force_reg (SImode, operands[1]);
+    operands[1] = force_reg (Pmode, operands[1]);
   else
     operands[1] = legitimize_pic_address (operands[1], temp);
 }
@@ -2785,7 +2858,7 @@ emit_pic_move (operands, mode)
 rtx
 legitimize_address (x, oldx, mode)
      register rtx x;
-     register rtx oldx;
+     register rtx oldx ATTRIBUTE_UNUSED;
      enum machine_mode mode;
 {
   int changed = 0;
@@ -2807,8 +2880,8 @@ 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)),
-                  GEN_INT (1 << log));
+      x = gen_rtx_MULT (Pmode, force_reg (Pmode, XEXP (x, 0)),
+                       GEN_INT (1 << log));
     }
 
   if (GET_CODE (x) == PLUS)
@@ -2969,29 +3042,14 @@ output_pic_addr_const (file, x, code)
       break;
 
     case SYMBOL_REF:
-    case LABEL_REF:
-      if (GET_CODE (x) == SYMBOL_REF)
-       assemble_name (file, XSTR (x, 0));
-      else
-       {
-         ASM_GENERATE_INTERNAL_LABEL (buf, "L",
-                                      CODE_LABEL_NUMBER (XEXP (x, 0)));
-         assemble_name (asm_out_file, buf);
-       }
-
-      if (GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
-       fprintf (file, "@GOTOFF(%%ebx)");
-      else if (code == 'P')
-       fprintf (file, "@PLT");
-      else if (GET_CODE (x) == LABEL_REF)
-       fprintf (file, "@GOTOFF");
-      else if (! SYMBOL_REF_FLAG (x))
-       fprintf (file, "@GOT");
-      else
-       fprintf (file, "@GOTOFF");
-
+      assemble_name (file, XSTR (x, 0));
+      if (code == 'P' && ! SYMBOL_REF_FLAG (x))
+       fputs ("@PLT", file);
       break;
 
+    case LABEL_REF:
+      x = XEXP (x, 0);
+      /* FALLTHRU */
     case CODE_LABEL:
       ASM_GENERATE_INTERNAL_LABEL (buf, "L", CODE_LABEL_NUMBER (x));
       assemble_name (asm_out_file, buf);
@@ -3029,17 +3087,17 @@ output_pic_addr_const (file, x, code)
       if (GET_CODE (XEXP (x, 0)) == CONST_INT)
        {
          output_pic_addr_const (file, XEXP (x, 0), code);
-         if (INTVAL (XEXP (x, 1)) >= 0)
-           fprintf (file, "+");
+         fprintf (file, "+");
          output_pic_addr_const (file, XEXP (x, 1), code);
        }
-      else
+      else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
        {
          output_pic_addr_const (file, XEXP (x, 1), code);
-         if (INTVAL (XEXP (x, 0)) >= 0)
-           fprintf (file, "+");
+         fprintf (file, "+");
          output_pic_addr_const (file, XEXP (x, 0), code);
        }
+      else
+       abort ();
       break;
 
     case MINUS:
@@ -3048,11 +3106,140 @@ output_pic_addr_const (file, x, code)
       output_pic_addr_const (file, XEXP (x, 1), code);
       break;
 
+     case UNSPEC:
+       if (XVECLEN (x, 0) != 1)
+       abort ();
+       output_pic_addr_const (file, XVECEXP (x, 0, 0), code);
+       switch (XINT (x, 1))
+       {
+       case 6:
+         fputs ("@GOT", file);
+         break;
+       case 7:
+         fputs ("@GOTOFF", file);
+         break;
+       case 8:
+         fputs ("@PLT", file);
+         break;
+       default:
+         output_operand_lossage ("invalid UNSPEC as operand");
+         break;
+       }
+       break;
+
     default:
       output_operand_lossage ("invalid expression as operand");
     }
 }
 \f
+static void
+put_jump_code (code, reverse, file)
+     enum rtx_code code;
+     int reverse;
+     FILE *file;
+{
+  int flags = cc_prev_status.flags;
+  int ieee = (TARGET_IEEE_FP && (flags & CC_IN_80387));
+  const char *suffix;
+
+  if (flags & CC_Z_IN_NOT_C)
+    switch (code)
+      {
+      case EQ:
+       fputs (reverse ? "c" : "nc", file);
+       return;
+
+      case NE:
+       fputs (reverse ? "nc" : "c", file);
+       return;
+
+      default:
+       abort ();
+      }
+  if (ieee)
+    {
+      switch (code)
+       {
+       case LE:
+         suffix = reverse ? "ae" : "b";
+         break;
+       case GT:
+       case LT:
+       case GE:
+         suffix = reverse ? "ne" : "e";
+         break;
+       case EQ:
+         suffix = reverse ? "ne" : "e";
+         break;
+       case NE:
+         suffix = reverse ? "e" : "ne";
+         break;
+       default:
+         abort ();
+       }
+      fputs (suffix, file);
+      return;
+    }
+  if (flags & CC_TEST_AX)
+    abort();
+  if ((flags & CC_NO_OVERFLOW) && (code == LE || code == GT))
+    abort ();
+  if (reverse)
+    code = reverse_condition (code);
+  switch (code)
+    {
+    case EQ:
+      suffix = "e";
+      break;
+
+    case NE:
+      suffix = "ne";
+      break;
+
+    case GT:
+      suffix = flags & CC_IN_80387 ? "a" : "g";
+      break;
+
+    case GTU:
+      suffix = "a";
+      break;
+
+    case LT:
+      if (flags & CC_NO_OVERFLOW)
+       suffix = "s";
+      else
+       suffix = flags & CC_IN_80387 ? "b" : "l";
+      break;
+
+    case LTU:
+      suffix = "b";
+      break;
+
+    case GE:
+      if (flags & CC_NO_OVERFLOW)
+       suffix = "ns";
+      else
+       suffix = flags & CC_IN_80387 ? "ae" : "ge";
+      break;
+
+    case GEU:
+      suffix = "ae";
+      break;
+
+    case LE:
+      suffix = flags & CC_IN_80387 ? "be" : "le";
+      break;
+
+    case LEU:
+      suffix = "be";
+      break;
+
+    default:
+      abort ();
+    }
+  fputs (suffix, file);
+}
+
 /* Append the correct conditional move suffix which corresponds to CODE.  */
 
 static void
@@ -3070,7 +3257,7 @@ put_condition_code (code, reverse_cc, mode, file)
   if (mode == MODE_INT)
     switch (code)
       {
-      case NE: 
+      case NE:
        if (cc_prev_status.flags & CC_Z_IN_NOT_C)
          fputs ("b", file);
        else
@@ -3085,7 +3272,10 @@ put_condition_code (code, reverse_cc, mode, file)
        return;
 
       case GE:
-       fputs ("ge", file);
+       if (cc_prev_status.flags & CC_NO_OVERFLOW)
+         fputs ("ns", file);
+       else
+         fputs ("ge", file);
        return;
 
       case GT:
@@ -3097,7 +3287,10 @@ put_condition_code (code, reverse_cc, mode, file)
        return;
 
       case LT:
-       fputs ("l", file);
+       if (cc_prev_status.flags & CC_NO_OVERFLOW)
+         fputs ("s", file);
+       else
+         fputs ("l", file);
        return;
 
       case GEU:
@@ -3123,34 +3316,34 @@ put_condition_code (code, reverse_cc, mode, file)
   else if (mode == MODE_FLOAT)
     switch (code)
       {
-      case NE: 
+      case NE:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "ne", file);
        return;
-      case EQ: 
+      case EQ:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "e", file);
        return;
-      case GE: 
+      case GE:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
        return;
-      case GT: 
+      case GT:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
        return;
-      case LE: 
+      case LE:
        fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
        return;
-      case LT: 
+      case LT:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
        return;
-      case GEU: 
+      case GEU:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "nb", file);
        return;
-      case GTU: 
+      case GTU:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "nbe", file);
        return;
-      case LEU: 
+      case LEU:
        fputs (ieee ? (reverse_cc ? "nb" : "b") : "be", file);
        return;
-      case LTU: 
+      case LTU:
        fputs (ieee ? (reverse_cc ? "ne" : "e") : "b", file);
        return;
       default:
@@ -3163,12 +3356,13 @@ put_condition_code (code, reverse_cc, mode, file)
    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
+   f -- like F, but print reversed condition
+   D -- print the opcode suffix for a jump
+   d -- like D, 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.
@@ -3272,6 +3466,7 @@ print_operand (file, x, code)
        case 'h':
        case 'y':
        case 'P':
+       case 'X':
          break;
 
        case 'J':
@@ -3289,9 +3484,9 @@ print_operand (file, x, code)
            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 ();
            }
@@ -3305,6 +3500,14 @@ print_operand (file, x, code)
 
          return;
 
+       case 'D':
+         put_jump_code (GET_CODE (x), 0, file);
+         return;
+
+       case 'd':
+         put_jump_code (GET_CODE (x), 1, file);
+         return;
+
          /* This is used by the conditional move instructions.  */
        case 'C':
          put_condition_code (GET_CODE (x), 0, MODE_INT, file);
@@ -3360,7 +3563,7 @@ print_operand (file, x, code)
       REAL_VALUE_FROM_CONST_DOUBLE (r, x);
       REAL_VALUE_TO_TARGET_SINGLE (r, l);
       PRINT_IMMED_PREFIX (file);
-      fprintf (file, "0x%x", l);
+      fprintf (file, "0x%lx", l);
     }
 
  /* These float cases don't actually occur as immediate operands. */
@@ -3383,7 +3586,7 @@ print_operand (file, x, code)
       REAL_VALUE_TO_DECIMAL (r, "%.22e", dstr);
       fprintf (file, "%s", dstr);
     }
-  else 
+  else
     {
       if (code != 'P')
        {
@@ -3413,6 +3616,11 @@ print_operand_address (file, addr)
   switch (GET_CODE (addr))
     {
     case REG:
+      /* ESI addressing makes instruction vector decoded on the K6.  We can
+        avoid this by ESI+0 addressing.  */
+      if (REGNO_REG_CLASS (REGNO (addr)) == SIREG
+         && ix86_cpu == PROCESSOR_K6 && !optimize_size)
+       output_addr_const (file, const0_rtx);
       ADDR_BEG (file);
       fprintf (file, "%se", RP);
       fputs (hi_reg_name[REGNO (addr)], file);
@@ -3528,8 +3736,16 @@ print_operand_address (file, addr)
            ireg = XEXP (addr, 0);
          }
 
-       output_addr_const (file, const0_rtx);
-       PRINT_B_I_S (NULL_RTX, ireg, scale, file);
+       /* (reg,reg,) is shorter than (,reg,2).  */
+       if (scale == 2)
+         {
+           PRINT_B_I_S (ireg, ireg, 1, file);
+         } 
+       else 
+         {
+           output_addr_const (file, const0_rtx);
+           PRINT_B_I_S (NULL_RTX, ireg, scale, file);
+         }
       }
       break;
 
@@ -3550,7 +3766,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.
@@ -3577,7 +3793,8 @@ notice_update_cc (exp)
         (Note that moving a constant 0 or 1 MAY set the cc's).  */
       if (REG_P (SET_DEST (exp))
          && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM
-             || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'))
+             || GET_RTX_CLASS (GET_CODE (SET_SRC (exp))) == '<'
+             || GET_CODE (SET_SRC (exp)) == IF_THEN_ELSE))
        {
          if (cc_status.value1
              && reg_overlap_mentioned_p (SET_DEST (exp), cc_status.value1))
@@ -3654,6 +3871,7 @@ notice_update_cc (exp)
                cc_status.flags
                  = CC_NOT_POSITIVE | CC_NOT_NEGATIVE | CC_NO_OVERFLOW;
                cc_status.value1 = XVECEXP (SET_SRC (exp), 0, 0);
+               cc_status.value2 = 0;
                break;
              }
            /* FALLTHRU */
@@ -3678,7 +3896,7 @@ notice_update_cc (exp)
           if (stack_regs_mentioned_p (SET_SRC (XVECEXP (exp, 0, 0))))
            {
               cc_status.flags |= CC_IN_80387;
-             if (TARGET_CMOVE && stack_regs_mentioned_p
+             if (0 && TARGET_CMOVE && stack_regs_mentioned_p
                  (XEXP (SET_SRC (XVECEXP (exp, 0, 0)), 1)))
                cc_status.flags |= CC_FCOMI;
            }
@@ -3710,7 +3928,12 @@ split_di (operands, num, lo_half, hi_half)
   while (num--)
     {
       rtx op = operands[num];
-      if (GET_CODE (op) == REG)
+      if (! reload_completed)
+       {
+         lo_half[num] = gen_lowpart (SImode, op);
+         hi_half[num] = gen_highpart (SImode, op);
+       }
+      else if (GET_CODE (op) == REG)
        {
          lo_half[num] = gen_rtx_REG (SImode, REGNO (op));
          hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1);
@@ -3783,7 +4006,7 @@ shift_op (op, mode)
 int
 VOIDmode_compare_op (op, mode)
     register rtx op;
-    enum machine_mode mode;
+    enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return GET_CODE (op) == COMPARE && GET_MODE (op) == VOIDmode;
 }
@@ -3808,35 +4031,19 @@ output_387_binary_op (insn, operands)
   switch (GET_CODE (operands[3]))
     {
     case PLUS:
-      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
-         || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
-       base_op = "fiadd";
-      else
-       base_op = "fadd";
+      base_op = "fadd";
       break;
 
     case MINUS:
-      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
-         || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
-       base_op = "fisub";
-      else
-       base_op = "fsub";
+      base_op = "fsub";
       break;
 
     case MULT:
-      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
-         || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
-       base_op = "fimul";
-      else
-       base_op = "fmul";
+      base_op = "fmul";
       break;
 
     case DIV:
-      if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_INT
-         || GET_MODE_CLASS (GET_MODE (operands[2])) == MODE_INT)
-       base_op = "fidiv";
-      else
-       base_op = "fdiv";
+      base_op = "fdiv";
       break;
 
     default:
@@ -3859,21 +4066,17 @@ output_387_binary_op (insn, operands)
       if (GET_CODE (operands[2]) == MEM)
        return strcat (buf, AS1 (%z2,%2));
 
-      if (NON_STACK_REG_P (operands[1]))
-       {
-         output_op_from_reg (operands[1], strcat (buf, AS1 (%z0,%1)));
-         return "";
-       }
+      if (! STACK_REG_P (operands[1]) || ! STACK_REG_P (operands[2]))
+       abort ();
 
-      else if (NON_STACK_REG_P (operands[2]))
+      if (find_regno_note (insn, REG_DEAD, REGNO (operands[2])))
        {
-         output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
-         return "";
+         if (STACK_TOP_P (operands[0]))
+           return strcat (buf, AS2 (p,%0,%2));
+         else
+           return strcat (buf, AS2 (p,%2,%0));
        }
 
-      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, AS2C (%y2,%0));
       else
@@ -3887,26 +4090,24 @@ output_387_binary_op (insn, operands)
       if (GET_CODE (operands[2]) == MEM)
        return strcat (buf, AS1 (%z2,%2));
 
-      if (NON_STACK_REG_P (operands[1]))
-       {
-         output_op_from_reg (operands[1], strcat (buf, AS1 (r%z0,%1)));
-         return "";
-       }
-
-      else if (NON_STACK_REG_P (operands[2]))
-       {
-         output_op_from_reg (operands[2], strcat (buf, AS1 (%z0,%1)));
-         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]))
        {
@@ -3939,8 +4140,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);
@@ -3959,6 +4159,17 @@ output_fix_trunc (insn, operands)
     {
       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);
     }
@@ -3968,6 +4179,66 @@ output_fix_trunc (insn, operands)
   return AS1 (fldc%W2,%2);
 }
 \f
+/* Output code for INSN to extend a float.  OPERANDS are the insn
+   operands.  The output may be DFmode or XFmode and the input operand
+   may be SFmode or DFmode.  Operands 2 and 3 are scratch memory and
+   are only necessary if operands 0 or 1 are non-stack registers.  */
+
+void
+output_float_extend (insn, operands)
+     rtx insn;
+     rtx *operands;
+{
+  int stack_top_dies = find_regno_note (insn, REG_DEAD, FIRST_STACK_REG) != 0;
+  rtx xops[2];
+
+  if (! STACK_TOP_P (operands[0]) && ! STACK_TOP_P (operands[1]))
+    abort ();
+
+  if (STACK_TOP_P (operands[0]) && STACK_TOP_P (operands[1]) && stack_top_dies)
+    return;
+
+  if (STACK_TOP_P (operands[0]) )
+    {
+      if (NON_STACK_REG_P (operands[1]))
+       {
+         if (GET_MODE (operands[1]) == SFmode)
+           output_asm_insn (AS2 (mov%L0,%1,%2), operands);
+         else
+           {
+             xops[0] = operands[2];
+             xops[1] = operands[1];
+             output_asm_insn (output_move_double (xops), xops);
+           }
+       }
+
+      xops[0] = NON_STACK_REG_P (operands[1]) ? operands[2] : operands[1];
+
+      output_asm_insn (AS1 (fld%z0,%y0), xops);
+    }
+  else
+    {
+      xops[0] = NON_STACK_REG_P (operands[0]) ? operands[3] : operands[0];
+
+      if (stack_top_dies
+         || (GET_CODE (xops[0]) == MEM && GET_MODE (xops[0]) == XFmode))
+       {
+         output_asm_insn (AS1 (fstp%z0,%y0), xops);
+         if (! stack_top_dies)
+           output_asm_insn (AS1 (fld%z0,%y0), xops);
+       }
+      else
+       output_asm_insn (AS1 (fst%z0,%y0), xops);
+
+      if (NON_STACK_REG_P (operands[0]))
+       {
+         xops[0] = operands[0];
+         xops[1] = operands[3];
+         output_asm_insn (output_move_double (xops), xops);
+       }
+    }
+}
+\f
 /* Output code for INSN to compare OPERANDS.  The two operands might
    not have the same mode: one might be within a FLOAT or FLOAT_EXTEND
    expression.  If the compare is in mode CCFPEQmode, use an opcode that
@@ -3983,7 +4254,7 @@ output_float_compare (insn, operands)
   int unordered_compare = GET_MODE (SET_SRC (body)) == CCFPEQmode;
   rtx tmp;
 
-  if (TARGET_CMOVE && STACK_REG_P (operands[1]))
+  if (0 && TARGET_CMOVE && STACK_REG_P (operands[1]))
     {
       cc_status.flags |= CC_FCOMI;
       cc_prev_status.flags &= ~CC_TEST_AX;
@@ -3996,7 +4267,7 @@ output_float_compare (insn, operands)
       operands[1] = tmp;
       cc_status.flags |= CC_REVERSED;
     }
-    
+
   if (! STACK_TOP_P (operands[0]))
     abort ();
 
@@ -4038,24 +4309,19 @@ output_float_compare (insn, operands)
     {
       static char buf[100];
 
-      /* Decide if this is the integer or float compare opcode, or the
-        unordered float compare. */
+      /* Decide if this is a float compare or an unordered float compare. */
 
       if (unordered_compare)
        strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fucomi" : "fucom");
-      else if (GET_MODE_CLASS (GET_MODE (operands[1])) == MODE_FLOAT)
-       strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom");
       else
-       strcpy (buf, "ficom");
+       strcpy (buf, (cc_status.flags & CC_FCOMI) ? "fcomi" : "fcom");
 
       /* Modify the opcode if the 387 stack is to be popped. */
 
       if (stack_top_dies)
        strcat (buf, "p");
 
-      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) 
+      if (cc_status.flags & CC_FCOMI)
        {
          output_asm_insn (strcat (buf, AS2 (%z1,%y1,%0)), operands);
          return "";
@@ -4090,7 +4356,7 @@ output_fp_cc0_set (insn)
       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
@@ -4286,14 +4552,14 @@ assign_386_stack_local (mode, n)
 \f
 int is_mul(op,mode)
     register rtx op;
-    enum machine_mode mode;
+    enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return (GET_CODE (op) == MULT);
 }
 
 int is_div(op,mode)
     register rtx op;
-    enum machine_mode mode;
+    enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   return (GET_CODE (op) == DIV);
 }
@@ -4353,7 +4619,7 @@ copy_all_rtx (orig)
   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++)
@@ -4405,7 +4671,7 @@ copy_all_rtx (orig)
 \f
 /* Try to rewrite a memory address to make it valid */
 
-void 
+void
 rewrite_address (mem_rtx)
      rtx mem_rtx;
 {
@@ -4442,7 +4708,7 @@ rewrite_address (mem_rtx)
       obfree (storage);
     }
 
-  /* This part is utilized by loop.c.  
+  /* 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);
@@ -4764,7 +5030,7 @@ sets_condition_code (pat)
 int
 str_immediate_operand (op, mode)
      register rtx op;
-     enum machine_mode mode;
+     enum machine_mode mode ATTRIBUTE_UNUSED;
 {
   if (GET_CODE (op) == CONST_INT && INTVAL (op) <= 32 && INTVAL (op) >= 0)
     return 1;
@@ -4799,7 +5065,7 @@ is_fp_dest (insn)
          || 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)
+      && GET_CODE (SET_SRC (PATTERN (insn))) != MEM)
     return 1;
 
   return 0;
@@ -4831,16 +5097,36 @@ int
 agi_dependent (insn, dep_insn)
      rtx insn, dep_insn;
 {
+  int push = 0, push_dep = 0;
   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);
+      && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG
+      && reg_mentioned_in_mem (SET_DEST (PATTERN (dep_insn)), insn))
+    return 1;
+
+  if (GET_CODE (insn) == INSN && GET_CODE (PATTERN (insn)) == SET
+      && GET_CODE (SET_DEST (PATTERN (insn))) == MEM
+      && push_operand (SET_DEST (PATTERN (insn)),
+                       GET_MODE (SET_DEST (PATTERN (insn)))))
+    push = 1;
 
   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);
+    push_dep = 1;
+
+  /* CPUs contain special hardware to allow two pushes.  */
+  if (push && push_dep) 
+    return 0;
+
+  /* Push operation implicitly change stack pointer causing AGI stalls.  */
+  if (push_dep && reg_mentioned_in_mem (stack_pointer_rtx, insn))
+    return 1;
+
+  /* Push also implicitly read stack pointer.  */
+  if (push && modified_in_p (stack_pointer_rtx, dep_insn))
+    return 1;
 
   return 0;
 }
@@ -5075,7 +5361,7 @@ output_strlen_unroll (operands)
   /* 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);
@@ -5094,3 +5380,421 @@ output_strlen_unroll (operands)
 
   return "";
 }
+
+char *
+output_fp_conditional_move (which_alternative, operands)
+     int which_alternative;
+     rtx operands[];
+{
+  enum rtx_code code = GET_CODE (operands[1]);
+
+  /* This should never happen.  */
+  if (!(cc_prev_status.flags & CC_IN_80387)
+      && (code == GT || code == LE || code == GE || code == LT))
+    abort ();
+
+  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;
+
+    default:
+      abort ();
+    }
+
+  return "";
+}
+
+char *
+output_int_conditional_move (which_alternative, operands)
+     int which_alternative;
+     rtx operands[];
+{
+  enum rtx_code code = GET_CODE (operands[1]);
+
+  /* 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;
+
+  switch (which_alternative)
+    {
+    case 0:
+      /* r <- cond ? arg : r */
+      output_asm_insn (AS2 (cmov%C1,%2,%0), operands);
+      break;
+
+    case 1:
+      /* r <- cond ? r : arg */
+      output_asm_insn (AS2 (cmov%c1,%3,%0), operands);
+      break;
+
+    default:
+      abort ();
+    }
+
+  return "";
+}
+
+int
+x86_adjust_cost (insn, link, dep_insn, cost)
+     rtx insn, link, dep_insn;
+     int cost;
+{
+  rtx next_inst;
+
+  if (GET_CODE (dep_insn) == CALL_INSN || GET_CODE (insn) == JUMP_INSN)
+    return 0;
+
+  if (GET_CODE (dep_insn) == INSN
+      && GET_CODE (PATTERN (dep_insn)) == SET
+      && GET_CODE (SET_DEST (PATTERN (dep_insn))) == REG
+      && GET_CODE (insn) == INSN
+      && GET_CODE (PATTERN (insn)) == SET
+      && !reg_overlap_mentioned_p (SET_DEST (PATTERN (dep_insn)),
+                                  SET_SRC (PATTERN (insn))))
+    return 0;  /* ??? */
+
+
+  switch (ix86_cpu)
+    {
+    case PROCESSOR_PENTIUM:
+      if (cost != 0 && is_fp_insn (insn) && is_fp_insn (dep_insn)
+         && !is_fp_dest (dep_insn))
+       return 0;
+
+      if (agi_dependent (insn, dep_insn))
+       return cost ? cost + 1 : 2;
+
+      if (GET_CODE (insn) == INSN
+         && GET_CODE (PATTERN (insn)) == SET
+         && SET_DEST (PATTERN (insn)) == cc0_rtx
+         && (next_inst = next_nonnote_insn (insn))
+         && GET_CODE (next_inst) == JUMP_INSN)
+       /* compare probably paired with jump */
+       return 0;
+      break;
+
+      /* Stores stalls one cycle longer than other insns.  */
+      if (is_fp_insn (insn) && cost && is_fp_store (dep_insn))
+       cost++;
+
+    case PROCESSOR_K6:
+    default:
+      if (!is_fp_dest (dep_insn))
+       {
+         if(!agi_dependent (insn, dep_insn))
+           return 0;
+         if (TARGET_486)
+           return 2;
+       }
+      else
+       if (is_fp_store (insn) && is_fp_insn (dep_insn)
+           && NEXT_INSN (insn) && NEXT_INSN (NEXT_INSN (insn))
+           && NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))
+           && (GET_CODE (NEXT_INSN (insn)) == INSN)
+           && (GET_CODE (NEXT_INSN (NEXT_INSN (insn))) == JUMP_INSN)
+           && (GET_CODE (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn)))) == NOTE)
+           && (NOTE_LINE_NUMBER (NEXT_INSN (NEXT_INSN (NEXT_INSN (insn))))
+               == NOTE_INSN_LOOP_END))
+         return 3;
+      break;
+    }
+
+  return cost;
+}
+
+/* Output assembly code for a left shift.
+
+   Always use "sal" when shifting a memory operand or for a non constant
+   shift count.
+
+   When optimizing for size, we know that src == dest, and we should always
+   use "sal".  If src != dest, then copy src to dest and use "sal".
+   
+   Pentium and PPro (speed):
+
+     When src == dest, use "add" for a shift counts of one, else use
+     "sal".  If we modeled Pentium AGI stalls and U/V pipelining better we
+     would want to generate lea for some shifts on the Pentium.
+
+     When src != dest, use "lea" for small shift counts.  Otherwise,
+     copy src to dest and use the normal shifting code.  Exception for
+     TARGET_DOUBLE_WITH_ADD.  */
+
+char *
+output_ashl (insn, operands)
+     rtx insn, *operands;
+{
+  /* Handle case where srcreg != dstreg.  */
+  if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
+    {
+      if (TARGET_DOUBLE_WITH_ADD && INTVAL (operands[2]) == 1)
+       switch (GET_MODE (operands[0]))
+         {
+         case SImode:
+           output_asm_insn (AS2 (mov%L0,%1,%0), operands);
+           return AS2 (add%L0,%1,%0);
+         case HImode:
+           output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
+           if (i386_cc_probably_useless_p (insn))
+             {
+               CC_STATUS_INIT;
+               return AS2 (add%L0,%k1,%k0);
+             }
+           return AS2 (add%W0,%k1,%k0);
+         case QImode:
+           output_asm_insn (AS2 (mov%B0,%1,%0), operands);
+           return AS2 (add%B0,%1,%0);
+         default:
+           abort ();
+         }
+      else
+       {
+         CC_STATUS_INIT;
+
+         /* This should be extremely rare (impossible?).  We can not encode a
+            shift of the stack pointer using an lea instruction.  So copy the
+            stack pointer into the destination register and use an lea.  */
+         if (operands[1] == stack_pointer_rtx)
+           {
+             output_asm_insn (AS2 (mov%L0,%k1,%k0), operands);
+             operands[1] = operands[0];
+           }
+
+         /* For shifts up to and including 3 bits, use lea.  */
+         operands[1] = gen_rtx_MULT (SImode,
+                                     gen_rtx_REG (SImode, REGNO (operands[1])),
+                                     GEN_INT (1 << INTVAL (operands[2])));
+         return AS2 (lea%L0,%a1,%k0);
+       }
+    }
+
+  /* Source and destination match.  */
+
+  /* Handle variable shift.  */
+  if (REG_P (operands[2]))
+    switch (GET_MODE (operands[0]))
+      {
+      case SImode:
+       return AS2 (sal%L0,%b2,%0);
+      case HImode:
+       if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+         {
+           CC_STATUS_INIT;
+           return AS2 (sal%L0,%b2,%k0);
+         }
+       else
+         return AS2 (sal%W0,%b2,%0);
+      case QImode:
+       return AS2 (sal%B0,%b2,%0);
+      default:
+       abort ();
+      }
+
+  /* Always perform shift by 1 using an add instruction.  */
+  if (REG_P (operands[0]) && operands[2] == const1_rtx)
+    switch (GET_MODE (operands[0]))
+      {
+      case SImode:
+       return AS2 (add%L0,%0,%0);
+      case HImode:
+       if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+         {
+           CC_STATUS_INIT;
+           return AS2 (add%L0,%k0,%k0);
+         }
+       else
+         return AS2 (add%W0,%0,%0);
+      case QImode:
+         return AS2 (add%B0,%0,%0);
+      default:
+         abort ();
+      }
+
+#if 0
+  /* ??? Currently disabled.  Because our model of Pentium is far from being
+     exact, this change will need some benchmarking.  */
+  /* Shift reg by 2 or 3 use an lea instruction for Pentium if this is
+     insn is expected to issue into the V pipe (the insn's mode will be
+     TImode for a U pipe, and !TImode for a V pipe instruction).  */
+  if (! optimize_size
+      && REG_P (operands[0])
+      && GET_CODE (operands[2]) == CONST_INT
+      && INTVAL (operands[2]) <= 3
+      && (int)ix86_cpu == (int)PROCESSOR_PENTIUM
+      && GET_MODE (insn) != TImode)
+    {
+      CC_STATUS_INIT;
+      operands[1] = gen_rtx_MULT (SImode, gen_rtx_REG (SImode, REGNO (operands[1])),
+                                 GEN_INT (1 << INTVAL (operands[2])));
+      return AS2 (lea%L0,%a1,%0);
+    }
+#endif
+
+  /* Otherwise use a shift instruction.  */
+  switch (GET_MODE (operands[0]))
+    {
+    case SImode:
+      return AS2 (sal%L0,%2,%0);
+    case HImode:
+      if (REG_P (operands[0]) && i386_cc_probably_useless_p (insn))
+       {
+         CC_STATUS_INIT;
+         return AS2 (sal%L0,%2,%k0);
+       }
+      else
+       return AS2 (sal%W0,%2,%0);
+    case QImode:
+      return AS2 (sal%B0,%2,%0);
+    default:
+      abort ();
+    }
+}
+
+/* Given the memory address ADDR, calculate the length of the address or
+   the length of just the displacement (controlled by DISP_LENGTH).
+  
+   The length returned does not include the one-byte modrm, opcode,
+   or prefix.  */
+
+int
+memory_address_info (addr, disp_length)
+     rtx addr;
+     int disp_length;
+{
+  rtx base, index, disp, scale;
+  rtx op0, op1;
+  int len;
+
+  if (GET_CODE (addr) == PRE_DEC
+      || GET_CODE (addr) == POST_INC)
+    return 0;
+
+  /* Register Indirect.  */
+  if (register_operand (addr, Pmode))
+    {
+      /* Special cases: ebp and esp need the two-byte modrm form. 
+
+        We change [ESI] to [ESI+0] on the K6 when not optimizing
+        for size.  */
+      if (addr == stack_pointer_rtx
+         || addr == arg_pointer_rtx
+         || addr == frame_pointer_rtx
+         || (REGNO_REG_CLASS (REGNO (addr)) == SIREG
+             && ix86_cpu == PROCESSOR_K6 && !optimize_size))
+       return 1;
+      else
+       return 0;
+    }
+
+  /* Direct Addressing.  */
+  if (CONSTANT_P (addr))
+    return 4;
+
+  index = base = disp = scale = NULL_RTX;
+  op0 = XEXP (addr, 0);
+  op1 = XEXP (addr, 1);
+
+  if (GET_CODE (addr) == PLUS)
+    {
+      if (register_operand (op0, Pmode))
+       {
+         if (register_operand (op1, Pmode))
+           index = op0, base = op1;
+         else
+           base = op0, disp = op1;
+       }
+      else if (GET_CODE (op0) == MULT)
+       {
+         index = XEXP (op0, 0);
+         scale = XEXP (op0, 1);
+         if (register_operand (op1, Pmode))
+           base = op1;
+         else
+           disp = op1;
+       }
+      else if (GET_CODE (op0) == PLUS && GET_CODE (XEXP (op0, 0)) == MULT)
+       {
+         index = XEXP (XEXP (op0, 0), 0);
+         scale = XEXP (XEXP (op0, 0), 1);
+         base = XEXP (op0, 1);
+         disp = op1;
+       }
+      else if (GET_CODE (op0) == PLUS)
+       {
+         index = XEXP (op0, 0);
+         base = XEXP (op0, 1);
+         disp = op1;
+       }
+      else
+       abort ();
+    }
+  else if (GET_CODE (addr) == MULT
+          /* We're called for lea too, which implements ashift on occasion.  */
+          || GET_CODE (addr) == ASHIFT)
+    {
+      index = XEXP (addr, 0);
+      scale = XEXP (addr, 1);
+    }
+  else
+    abort ();
+      
+  /* Allow arg pointer and stack pointer as index if there is not scaling */
+  if (base && index && !scale
+      && (index == stack_pointer_rtx
+         || index == arg_pointer_rtx
+         || index == frame_pointer_rtx))
+    {
+      rtx tmp = base;
+      base = index;
+      index = tmp;
+    }
+
+  /* Special case: ebp cannot be encoded as a base without a displacement.  */
+  if (base == frame_pointer_rtx && !disp)
+    disp = const0_rtx;
+
+  /* Scaling can not be encoded without base or displacement.  
+     Except for scale == 1 where we can encode reg + reg instead of reg * 2.  */
+  if (!base && index && scale != 1)
+    disp = const0_rtx;
+
+  /* Find the length of the displacement constant.  */
+  len = 0;
+  if (disp)
+    {
+      if (GET_CODE (disp) == CONST_INT
+         && CONST_OK_FOR_LETTER_P (INTVAL (disp), 'K'))
+       len = 1;
+      else
+       len = 4;
+    }
+
+  /* An index requires the two-byte modrm form.  Not important
+     if we are computing just length of the displacement.  */
+  if (index && ! disp_length)
+    len += 1;
+
+  return len;
+}