OSDN Git Service

* i386/i386.c (output_fp_conditional_move): New function
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 8516911..73d89dc 100644 (file)
@@ -1,5 +1,5 @@
 /* Subroutines for insn-output.c for Intel X86.
-   Copyright (C) 1988, 92, 94, 95, 96, 1997 Free Software Foundation, Inc.
+   Copyright (C) 1988, 92, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -35,7 +35,21 @@ Boston, MA 02111-1307, USA. */
 #include "flags.h"
 #include "except.h"
 #include "function.h"
-#include "dwarf2.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'
@@ -101,7 +115,7 @@ struct processor_costs pentiumpro_cost = {
 
 struct processor_costs *ix86_cost = &pentium_cost;
 
-#define AT_BP(mode) (gen_rtx (MEM, (mode), frame_pointer_rtx))
+#define AT_BP(mode) (gen_rtx_MEM ((mode), frame_pointer_rtx))
 
 extern FILE *asm_out_file;
 extern char *strcat ();
@@ -194,8 +208,7 @@ int i386_align_jumps;
 void
 override_options ()
 {
-  int ch, i, j, regno;
-  char *p;
+  int ch, i, j;
   int def_align;
 
   static struct ptt
@@ -226,6 +239,8 @@ override_options ()
     {
       for (i = 0; (ch = i386_reg_alloc_order[i]) != '\0'; i++)
        {
+         int regno = 0;
+         
          switch (ch)
            {
            case 'a':   regno = 0;      break;
@@ -317,7 +332,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)
@@ -328,7 +347,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)
@@ -373,7 +396,7 @@ override_options ()
 void
 order_regs_for_local_alloc ()
 {
-  int i, ch, order, regno;
+  int i, ch, order;
 
   /* User specified the register allocation order.  */
 
@@ -381,6 +404,8 @@ 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;
@@ -411,8 +436,9 @@ order_regs_for_local_alloc ()
 }
 \f
 void
-optimization_options (level)
+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.  */
@@ -489,6 +515,9 @@ i386_aligned_p (op)
 
     case REG:
       return i386_aligned_reg_p (REGNO (op));
+    
+    default:
+      break;
     }
 
   return 0;
@@ -762,7 +791,7 @@ 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;
     }
 
@@ -832,11 +861,11 @@ output_op_from_reg (src, template)
 
       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);
     }
 
@@ -906,7 +935,7 @@ output_to_reg (dest, dies, scratch_mem)
 
   if (size > UNITS_PER_WORD)
     {
-      dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
+      dest = gen_rtx_REG (SImode, REGNO (dest) + 1);
       if (! scratch_mem)
        output_asm_insn (AS1 (pop%L0,%0), &dest);
       else
@@ -918,7 +947,7 @@ output_to_reg (dest, dies, scratch_mem)
 
       if (size > 2 * UNITS_PER_WORD)
        {
-         dest = gen_rtx (REG, SImode, REGNO (dest) + 1);
+         dest = gen_rtx_REG (SImode, REGNO (dest) + 1);
          if (! scratch_mem)
            output_asm_insn (AS1 (pop%L0,%0), &dest);
          else
@@ -1072,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;
     }
 
@@ -1086,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;
     }
 
@@ -1116,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)
        {
@@ -1132,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)
        {
@@ -1168,14 +1197,14 @@ output_move_double (operands)
       /* 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)
@@ -1213,13 +1242,13 @@ output_move_double (operands)
          output_asm_insn (AS2 (lea%L0,%a1,%0), xops);
          if (GET_MODE (operands[1]) == XFmode)
            {
-             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);
            }
        }
@@ -1679,6 +1708,15 @@ arithmetic_comparison_operator (op, mode)
 
   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 */
 
@@ -1722,8 +1760,6 @@ ix86_expand_binary_operator (code, mode, operands)
      enum machine_mode mode;
      rtx operands[];
 {
-  rtx insn;
-  int i;
   int modified;
 
   /* Recognize <var1> = <value> <op> <var1> for commutative operators */
@@ -1823,8 +1859,6 @@ ix86_expand_unary_operator (code, mode, operands)
      enum machine_mode mode;
      rtx operands[];
 {
-  rtx insn;
-
   /* If optimizing, copy to regs to improve CSE */
   if (TARGET_PSEUDO
       && optimize
@@ -1866,7 +1900,7 @@ 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)
@@ -1887,7 +1921,7 @@ 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;
        }
 
@@ -1942,11 +1976,11 @@ 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;
        }
 
-      xops[1] = gen_rtx (MEM, QImode,
+      xops[1] = gen_rtx_MEM (QImode,
                         gen_rtx (SYMBOL_REF, Pmode,
                                  LABEL_NAME (pic_label_rtx)));
 
@@ -1960,7 +1994,7 @@ load_pic_register (do_rtl)
        }
       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;
        }
@@ -1973,12 +2007,10 @@ load_pic_register (do_rtl)
  
       if (do_rtl)
        {
-         emit_insn (gen_prologue_get_pc (xops[0], xops[1]));
-         emit_insn (gen_pop (xops[0]));
-         emit_insn (gen_prologue_set_got
-                    (xops[0],
-                     gen_rtx (SYMBOL_REF, Pmode, "$_GLOBAL_OFFSET_TABLE_"), 
-                     xops[1]));
+         /* 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
        {
@@ -2020,7 +2052,7 @@ ix86_prologue (do_rtl)
       if (do_rtl)
        {
          insn = emit_insn (gen_rtx (SET, VOIDmode,
-                                    gen_rtx (MEM, SImode,
+                                    gen_rtx_MEM (SImode,
                                              gen_rtx (PRE_DEC, SImode,
                                                       stack_pointer_rtx)),
                                     frame_pointer_rtx));
@@ -2080,13 +2112,13 @@ ix86_prologue (do_rtl)
     }
   else 
     {
-      xops[3] = gen_rtx (REG, SImode, 0);
+      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,
+      xops[3] = gen_rtx_MEM (FUNCTION_MODE,
                         gen_rtx (SYMBOL_REF, Pmode, "_alloca"));
 
       if (do_rtl)
@@ -2110,11 +2142,11 @@ ix86_prologue (do_rtl)
     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);
        if (do_rtl)
          {
            insn = emit_insn (gen_rtx (SET, VOIDmode,
-                                      gen_rtx (MEM, SImode,
+                                      gen_rtx_MEM (SImode,
                                                gen_rtx (PRE_DEC, SImode,
                                                         stack_pointer_rtx)),
                                       xops[0]));
@@ -2271,7 +2303,7 @@ ix86_epilogue (do_rtl)
        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);
 
            if (do_rtl)
              emit_insn (gen_pop (xops[0]));
@@ -2285,7 +2317,7 @@ ix86_epilogue (do_rtl)
       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);
 
          if (do_rtl)
@@ -2355,7 +2387,7 @@ ix86_epilogue (do_rtl)
       if (current_function_pops_args >= 32768)
        {
          /* ??? Which register to use here? */
-         xops[0] = gen_rtx (REG, SImode, 2);
+         xops[0] = gen_rtx_REG (SImode, 2);
 
          if (do_rtl)
            {
@@ -2680,7 +2712,7 @@ 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,
+           new = gen_rtx_MEM (Pmode,
                           gen_rtx (PLUS, Pmode, pic_offset_table_rtx, orig));
 
          emit_move_insn (reg, new);
@@ -2843,7 +2875,8 @@ legitimize_address (x, oldx, mode)
               && 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)
            {
@@ -2956,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");
@@ -2975,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:
@@ -2989,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;
@@ -3061,7 +3097,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:
@@ -3073,7 +3112,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:
@@ -3248,6 +3290,7 @@ print_operand (file, x, code)
        case 'h':
        case 'y':
        case 'P':
+       case 'X':
          break;
 
        case 'J':
@@ -3265,10 +3308,12 @@ 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 ();
            }
-         abort ();
 
        case 's':
          if (GET_CODE (x) == CONST_INT || ! SHIFT_DOUBLE_OMITS_COUNT)
@@ -3511,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)
@@ -3524,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.
@@ -3545,15 +3590,6 @@ notice_update_cc (exp)
       if (SET_DEST (exp) == pc_rtx)
        return;
 
-#ifdef IS_STACK_MODE
-      /* Moving into a memory of stack_mode may have been moved
-         in between the use and set of cc0 by loop_spl(). So
-         old value of cc.status must be retained */
-      if (GET_CODE(SET_DEST(exp)) == MEM 
-         && IS_STACK_MODE (GET_MODE (SET_DEST (exp))))
-       return;
-#endif
-
       /* 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.
@@ -3629,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;
          }
@@ -3649,7 +3697,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;
            }
@@ -3680,17 +3728,20 @@ split_di (operands, num, lo_half, hi_half)
 {
   while (num--)
     {
-      if (GET_CODE (operands[num]) == REG)
+      rtx op = operands[num];
+      if (GET_CODE (op) == REG)
        {
-         lo_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]));
-         hi_half[num] = gen_rtx (REG, SImode, REGNO (operands[num]) + 1);
+         lo_half[num] = gen_rtx_REG (SImode, REGNO (op));
+         hi_half[num] = gen_rtx_REG (SImode, REGNO (op) + 1);
        }
-      else if (CONSTANT_P (operands[num]))
-       split_double (operands[num], &lo_half[num], &hi_half[num]);
-      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();
@@ -3840,7 +3891,12 @@ output_387_binary_op (insn, operands)
        }
 
       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));
@@ -3871,10 +3927,20 @@ output_387_binary_op (insn, operands)
        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]))
        {
@@ -3907,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);
@@ -3927,6 +3992,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);
     }
@@ -3951,7 +4027,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;
@@ -4047,11 +4123,10 @@ 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)
@@ -4110,7 +4185,7 @@ output_fp_cc0_set (insn)
   else
     abort ();
 
-  xops[0] = gen_rtx (REG, QImode, 0);
+  xops[0] = gen_rtx_REG (QImode, 0);
 
   switch (code)
     {
@@ -4178,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.
@@ -4188,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
@@ -4199,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.
@@ -4217,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;
@@ -4832,6 +4917,8 @@ reg_mentioned_in_mem (reg, rtl)
     case CC0:
     case SUBREG:
       return 0;
+    default:
+      break;
     }
 
   if (code == MEM && reg_mentioned_p (reg, rtl))
@@ -4841,9 +4928,11 @@ reg_mentioned_in_mem (reg, rtl)
   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;
+       {
+         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;
@@ -4852,7 +4941,7 @@ reg_mentioned_in_mem (reg, rtl)
   return 0;
 }
 \f
-/* Output the approprate insns for doing strlen if not just doing repnz; scasb
+/* 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.
@@ -4907,7 +4996,7 @@ output_strlen_unroll (operands)
             therefore use andl rather than andb. */
          output_asm_insn (AS2 (and%L1,%4,%1), xops);
 
-         /* Is aligned to 4-byte adress when zero */
+         /* Is aligned to 4-byte address when zero */
          output_asm_insn (AS1 (je,%l8), xops);
 
          /* Side-effect even Parity when %eax == 3 */
@@ -4927,11 +5016,11 @@ output_strlen_unroll (operands)
             check if is aligned to 4 - byte.  */
          output_asm_insn (AS2 (and%L1,%3,%1), xops);
 
-         /* Is aligned to 4-byte adress when zero */
+         /* Is aligned to 4-byte address when zero */
          output_asm_insn (AS1 (je,%l8), xops);
         }
 
-      xops[13] = gen_rtx (MEM, QImode, xops[0]);
+      xops[13] = gen_rtx_MEM (QImode, xops[0]);
 
       /* Now compare the bytes; compare with the high part of a q-reg
         gives shorter code. */
@@ -4987,7 +5076,7 @@ output_strlen_unroll (operands)
        speed up.  */
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (xops[8]));
 
-  xops[13] = gen_rtx (MEM, SImode, xops[0]);
+  xops[13] = gen_rtx_MEM (SImode, xops[0]);
   output_asm_insn (AS2 (mov%L1,%13,%1), xops);
 
   if (QI_REG_P (xops[1]))
@@ -5049,3 +5138,124 @@ output_strlen_unroll (operands)
 
   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 "";
+}