OSDN Git Service

* config/i386/i386.c (ix86_tune_features
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index 7106e87..2e0586b 100644 (file)
@@ -1026,8 +1026,7 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   m_486 | m_PENT | m_PPRO | m_ATHLON_K8_AMDFAM10 | m_K6 | m_CORE2 | m_GENERIC,
 
   /* X86_TUNE_DEEP_BRANCH_PREDICTION */
-  m_PPRO | m_K6_GEODE | m_ATHLON_K8_AMDFAM10 | m_PENT4
-  | m_NOCONA | m_CORE2 | m_GENERIC,
+  m_PPRO | m_K6_GEODE | m_ATHLON_K8_AMDFAM10 | m_PENT4 | m_GENERIC,
 
   /* X86_TUNE_BRANCH_PREDICTION_HINTS: Branch hints were put in P4 based
      on simulation result. But after P4 was made, no performance benefit
@@ -1037,7 +1036,7 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
 
   /* X86_TUNE_DOUBLE_WITH_ADD */
   ~m_386,
-  
+
   /* X86_TUNE_USE_SAHF */
   m_PPRO | m_K6_GEODE | m_K8 | m_AMDFAM10 | m_PENT4
   | m_NOCONA | m_CORE2 | m_GENERIC,
@@ -1059,7 +1058,7 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
 
   /* X86_TUNE_PARTIAL_FLAG_REG_STALL */
   m_CORE2 | m_GENERIC,
-  
+
   /* X86_TUNE_USE_HIMODE_FIOP */
   m_386 | m_486 | m_K6_GEODE,
 
@@ -1068,7 +1067,7 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
 
   /* X86_TUNE_USE_MOV0 */
   m_K6,
-  
+
   /* X86_TUNE_USE_CLTD */
   ~(m_PENT | m_K6 | m_CORE2 | m_GENERIC),
 
@@ -1093,10 +1092,10 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
 
   /* X86_TUNE_SINGLE_STRINGOP */
   m_386 | m_PENT4 | m_NOCONA,
-  
+
   /* X86_TUNE_QIMODE_MATH */
   ~0,
-  
+
   /* X86_TUNE_HIMODE_MATH: On PPro this flag is meant to avoid partial
      register stalls.  Just like X86_TUNE_PARTIAL_REG_STALL this option
      might be considered for Generic32 if our scheme for avoiding partial
@@ -1186,7 +1185,7 @@ unsigned int ix86_tune_features[X86_TUNE_LAST] = {
   m_ATHLON_K8_AMDFAM10,
 
   /* X86_TUNE_USE_INCDEC */
-  ~(m_PENT4 | m_NOCONA | m_CORE2 | m_GENERIC),
+  ~(m_PENT4 | m_NOCONA | m_GENERIC),
 
   /* X86_TUNE_PAD_RETURNS */
   m_ATHLON_K8_AMDFAM10 | m_CORE2 | m_GENERIC,
@@ -1571,22 +1570,32 @@ ix86_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED, int value)
     case OPT_msse:
       if (!value)
        {
-         target_flags &= ~(MASK_SSE2 | MASK_SSE3 | MASK_SSE4A);
-         target_flags_explicit |= MASK_SSE2 | MASK_SSE3 | MASK_SSE4A;
+         target_flags &= ~(MASK_SSE2 | MASK_SSE3 | MASK_SSSE3
+                           | MASK_SSE4A);
+         target_flags_explicit |= (MASK_SSE2 | MASK_SSE3 | MASK_SSSE3
+                                   | MASK_SSE4A);
        }
       return true;
 
     case OPT_msse2:
       if (!value)
        {
-         target_flags &= ~(MASK_SSE3 | MASK_SSE4A);
-         target_flags_explicit |= MASK_SSE3 | MASK_SSE4A;
+         target_flags &= ~(MASK_SSE3 | MASK_SSSE3 | MASK_SSE4A);
+         target_flags_explicit |= MASK_SSE3 | MASK_SSSE3 | MASK_SSE4A;
        }
       return true;
 
     case OPT_msse3:
       if (!value)
        {
+         target_flags &= ~(MASK_SSSE3 | MASK_SSE4A);
+         target_flags_explicit |= MASK_SSSE3 | MASK_SSE4A;
+       }
+      return true;
+
+    case OPT_mssse3:
+      if (!value)
+       {
          target_flags &= ~MASK_SSE4A;
          target_flags_explicit |= MASK_SSE4A;
        }
@@ -2095,6 +2104,13 @@ override_options (void)
               ix86_tls_dialect_string);
     }
 
+  if (ix87_precision_string)
+    {
+      i = atoi (ix87_precision_string);
+      if (i != 32 && i != 64 && i != 80)
+       error ("pc%d is not valid precision setting (32, 64 or 80)", i);
+    }
+
   /* Keep nonleaf frame pointers.  */
   if (flag_omit_frame_pointer)
     target_flags &= ~MASK_OMIT_LEAF_FRAME_POINTER;
@@ -2878,12 +2894,15 @@ ix86_eax_live_at_start_p (void)
 static bool
 type_has_variadic_args_p (tree type)
 {
-  tree t;
+  tree n, t = TYPE_ARG_TYPES (type);
 
-  for (t = TYPE_ARG_TYPES (type); t; t = TREE_CHAIN (t))
-    if (t == void_list_node)
-      return false;
-  return true;
+  if (t == NULL)
+    return false;
+
+  while ((n = TREE_CHAIN (t)) != NULL)
+    t = n;
+
+  return TREE_VALUE (t) != void_type_node;
 }
 
 /* Value is the number of bytes of arguments automatically
@@ -4164,27 +4183,21 @@ function_value_32 (enum machine_mode orig_mode, enum machine_mode mode,
           || (VECTOR_MODE_P (mode) && GET_MODE_SIZE (mode) == 16))
     regno = TARGET_SSE ? FIRST_SSE_REG : 0;
 
-  /* Decimal floating point values can go in %eax, unlike other float modes.  */
-  else if (DECIMAL_FLOAT_MODE_P (mode))
-    regno = 0;
-
-  /* Most things go in %eax, except (unless -mno-fp-ret-in-387) fp values.  */
-  else if (!SCALAR_FLOAT_MODE_P (mode) || !TARGET_FLOAT_RETURNS_IN_80387)
+  /* Floating point return values in %st(0) (unless -mno-fp-ret-in-387).  */
+  else if (X87_FLOAT_MODE_P (mode) && TARGET_FLOAT_RETURNS_IN_80387)
+    regno = FIRST_FLOAT_REG;
+  else
+    /* Most things go in %eax.  */
     regno = 0;
-
-  /* Floating point return values in %st(0), except for local functions when
+  
+  /* Override FP return register with %xmm0 for local functions when
      SSE math is enabled or for functions with sseregparm attribute.  */
-  else
+  if ((fn || fntype) && (mode == SFmode || mode == DFmode))
     {
-      regno = FIRST_FLOAT_REG;
-
-      if ((fn || fntype) && (mode == SFmode || mode == DFmode))
-       {
-         int sse_level = ix86_function_sseregparm (fntype, fn);
-         if ((sse_level >= 1 && mode == SFmode)
-             || (sse_level == 2 && mode == DFmode))
-           regno = FIRST_SSE_REG;
-       }
+      int sse_level = ix86_function_sseregparm (fntype, fn);
+      if ((sse_level >= 1 && mode == SFmode)
+         || (sse_level == 2 && mode == DFmode))
+       regno = FIRST_SSE_REG;
     }
 
   return gen_rtx_REG (orig_mode, regno);
@@ -4959,21 +4972,23 @@ init_ext_80387_constants (void)
 int
 standard_80387_constant_p (rtx x)
 {
+  enum machine_mode mode = GET_MODE (x);
+
   REAL_VALUE_TYPE r;
 
-  if (GET_CODE (x) != CONST_DOUBLE || !FLOAT_MODE_P (GET_MODE (x)))
+  if (!(X87_FLOAT_MODE_P (mode) && (GET_CODE (x) == CONST_DOUBLE)))
     return -1;
 
-  if (x == CONST0_RTX (GET_MODE (x)))
+  if (x == CONST0_RTX (mode))
     return 1;
-  if (x == CONST1_RTX (GET_MODE (x)))
+  if (x == CONST1_RTX (mode))
     return 2;
 
   REAL_VALUE_FROM_CONST_DOUBLE (r, x);
 
   /* For XFmode constants, try to find a special 80387 instruction when
      optimizing for size or on those CPUs that benefit from them.  */
-  if (GET_MODE (x) == XFmode
+  if (mode == XFmode
       && (optimize_size || TARGET_EXT_80387_CONSTANTS))
     {
       int i;
@@ -9244,6 +9259,7 @@ output_fix_trunc (rtx insn, rtx *operands, int fisttp)
 
   gcc_assert (STACK_TOP_P (operands[1]));
   gcc_assert (MEM_P (operands[0]));
+  gcc_assert (GET_MODE (operands[1]) != TFmode);
 
   if (fisttp)
       output_asm_insn ("fisttp%z0\t%0", operands);
@@ -9276,7 +9292,7 @@ output_387_ffreep (rtx *operands ATTRIBUTE_UNUSED, int opno)
     {
       static char retval[] = ".word\t0xc_df";
       int regno = REGNO (operands[opno]);
-      
+
       gcc_assert (FP_REGNO_P (regno));
 
       retval[9] = '0' + (regno - FIRST_STACK_REG);
@@ -9666,7 +9682,7 @@ ix86_expand_vector_move (enum machine_mode mode, rtx operands[])
        movlpd mem, reg      (gas syntax)
      else
        movsd mem, reg
+
    Code generation for unaligned packed loads of single precision data
    (x86_sse_unaligned_move_optimal overrides x86_sse_partial_reg_dependency):
      if (x86_sse_unaligned_move_optimal)
@@ -9855,7 +9871,7 @@ ix86_expand_push (enum machine_mode mode, rtx x)
 
 /* Helper function of ix86_fixup_binary_operands to canonicalize
    operand order.  Returns true if the operands should be swapped.  */
-   
+
 static bool
 ix86_swap_binary_operands_p (enum rtx_code code, enum machine_mode mode,
                             rtx operands[])
@@ -10250,7 +10266,7 @@ ix86_expand_convert_sign_didf_sse (rtx target, rtx input)
 {
   REAL_VALUE_TYPE TWO32r;
   rtx fp_lo, fp_hi, x;
-  
+
   fp_lo = gen_reg_rtx (DFmode);
   fp_hi = gen_reg_rtx (DFmode);
 
@@ -10665,8 +10681,14 @@ ix86_fp_compare_mode (enum rtx_code code ATTRIBUTE_UNUSED)
 enum machine_mode
 ix86_cc_mode (enum rtx_code code, rtx op0, rtx op1)
 {
-  if (SCALAR_FLOAT_MODE_P (GET_MODE (op0)))
-    return ix86_fp_compare_mode (code);
+  enum machine_mode mode = GET_MODE (op0);
+
+  if (SCALAR_FLOAT_MODE_P (mode))
+    {
+      gcc_assert (!DECIMAL_FLOAT_MODE_P (mode));
+      return ix86_fp_compare_mode (code);
+    }
+
   switch (code)
     {
       /* Only zero flag is needed.  */
@@ -11251,8 +11273,11 @@ ix86_expand_compare (enum rtx_code code, rtx *second_test, rtx *bypass_test)
       ix86_compare_emitted = NULL_RTX;
     }
   else if (SCALAR_FLOAT_MODE_P (GET_MODE (op0)))
-    ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
-                                 second_test, bypass_test);
+    {
+      gcc_assert (!DECIMAL_FLOAT_MODE_P (GET_MODE (op0)));
+      ret = ix86_expand_fp_compare (code, op0, op1, NULL_RTX,
+                                   second_test, bypass_test);
+    }
   else
     ret = ix86_expand_int_compare (code, op0, op1);
 
@@ -11613,16 +11638,20 @@ ix86_expand_carry_flag_compare (enum rtx_code code, rtx op0, rtx op1, rtx *pop)
   enum machine_mode mode =
     GET_MODE (op0) != VOIDmode ? GET_MODE (op0) : GET_MODE (op1);
 
-  /* Do not handle DImode compares that go through special path.  Also we can't
-     deal with FP compares yet.  This is possible to add.  */
+  /* Do not handle DImode compares that go through special path.
+     Also we can't deal with FP compares yet.  This is possible to add.  */
   if (mode == (TARGET_64BIT ? TImode : DImode))
     return false;
-  if (FLOAT_MODE_P (mode))
+
+  if (SCALAR_FLOAT_MODE_P (mode))
     {
       rtx second_test = NULL, bypass_test = NULL;
       rtx compare_op, compare_seq;
 
-      /* Shortcut:  following common codes never translate into carry flag compares.  */
+      gcc_assert (!DECIMAL_FLOAT_MODE_P (mode));
+
+      /* Shortcut:  following common codes never translate
+        into carry flag compares.  */
       if (code == EQ || code == NE || code == UNEQ || code == LTGT
          || code == ORDERED || code == UNORDERED)
        return false;
@@ -11911,11 +11940,16 @@ ix86_expand_int_movcc (rtx operands[])
 
       if (diff < 0)
        {
+         enum machine_mode cmp_mode = GET_MODE (ix86_compare_op0);
+
          HOST_WIDE_INT tmp;
          tmp = ct, ct = cf, cf = tmp;
          diff = -diff;
-         if (FLOAT_MODE_P (GET_MODE (ix86_compare_op0)))
+
+         if (SCALAR_FLOAT_MODE_P (cmp_mode))
            {
+             gcc_assert (!DECIMAL_FLOAT_MODE_P (cmp_mode));
+
              /* We may be reversing unordered compare to normal compare, that
                 is not valid in general (we may convert non-trapping condition
                 to trapping one), however on i386 we currently emit all
@@ -12064,14 +12098,21 @@ ix86_expand_int_movcc (rtx operands[])
        {
          if (cf == 0)
            {
+             enum machine_mode cmp_mode = GET_MODE (ix86_compare_op0);
+
              cf = ct;
              ct = 0;
-             if (FLOAT_MODE_P (GET_MODE (ix86_compare_op0)))
-               /* We may be reversing unordered compare to normal compare,
-                  that is not valid in general (we may convert non-trapping
-                  condition to trapping one), however on i386 we currently
-                  emit all comparisons unordered.  */
-               code = reverse_condition_maybe_unordered (code);
+
+             if (SCALAR_FLOAT_MODE_P (cmp_mode))
+               {
+                 gcc_assert (!DECIMAL_FLOAT_MODE_P (cmp_mode));
+
+                 /* We may be reversing unordered compare to normal compare,
+                    that is not valid in general (we may convert non-trapping
+                    condition to trapping one), however on i386 we currently
+                    emit all comparisons unordered.  */
+                 code = reverse_condition_maybe_unordered (code);
+               }
              else
                {
                  code = reverse_condition (code);
@@ -12669,11 +12710,11 @@ ix86_expand_sse_unpack (rtx operands[2], bool unsigned_p, bool high_p)
     case V4SImode:
       if (high_p)
         unpack = gen_vec_interleave_highv4si;
-      else 
+      else
         unpack = gen_vec_interleave_lowv4si;
       break;
     default:
-      gcc_unreachable (); 
+      gcc_unreachable ();
     }
 
   dest = gen_lowpart (imode, operands[0]);
@@ -13527,8 +13568,8 @@ scale_counter (rtx countreg, int scale)
   return sc;
 }
 
-/* Return mode for the memcpy/memset loop counter.  Preffer SImode over DImode
-   for constant loop counts.  */
+/* Return mode for the memcpy/memset loop counter.  Prefer SImode over
+   DImode for constant loop counts.  */
 
 static enum machine_mode
 counter_mode (rtx count_exp)
@@ -13549,7 +13590,7 @@ counter_mode (rtx count_exp)
 
    The size is rounded down to whole number of chunk size moved at once.
    SRCMEM and DESTMEM provide MEMrtx to feed proper aliasing info.  */
-  
+
 
 static void
 expand_set_or_movmem_via_loop (rtx destmem, rtx srcmem,
@@ -13593,7 +13634,7 @@ expand_set_or_movmem_via_loop (rtx destmem, rtx srcmem,
       srcmem = change_address (srcmem, mode, y_addr);
 
       /* When unrolling for chips that reorder memory reads and writes,
-        we can save registers by using single temporary.  
+        we can save registers by using single temporary.
         Also using 4 temporaries is overkill in 32bit mode.  */
       if (!TARGET_64BIT && 0)
        {
@@ -13677,7 +13718,7 @@ expand_set_or_movmem_via_loop (rtx destmem, rtx srcmem,
   emit_label (out_label);
 }
 
-/* Output "rep; mov" instruction.  
+/* Output "rep; mov" instruction.
    Arguments have same meaning as for previous function */
 static void
 expand_movmem_via_rep_mov (rtx destmem, rtx srcmem,
@@ -13717,7 +13758,7 @@ expand_movmem_via_rep_mov (rtx destmem, rtx srcmem,
                          destexp, srcexp));
 }
 
-/* Output "rep; stos" instruction.  
+/* Output "rep; stos" instruction.
    Arguments have same meaning as for previous function */
 static void
 expand_setmem_via_rep_stos (rtx destmem, rtx destptr, rtx value,
@@ -14165,7 +14206,7 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size, bool memset,
   /* When asked to inline the call anyway, try to pick meaningful choice.
      We look for maximal size of block that is faster to copy by hand and
      take blocks of at most of that size guessing that average size will
-     be roughly half of the block.  
+     be roughly half of the block.
 
      If this turns out to be bad, we might simply specify the preferred
      choice in ix86_costs.  */
@@ -14275,7 +14316,7 @@ smallest_pow2_greater_than (int val)
 
    4) Epilogue: code copying tail of the block that is too small to be
       handled by main body (or up to size guarded by prologue guard).  */
-   
+
 int
 ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
                    rtx expected_align_exp, rtx expected_size_exp)
@@ -14467,7 +14508,7 @@ ix86_expand_movmem (rtx dst, rtx src, rtx count_exp, rtx align_exp,
         while we want to copy only COUNT_EXP & SIZE_NEEDED bytes.
         Epilogue code will actually copy COUNT_EXP & EPILOGUE_SIZE_NEEDED
         bytes. Compensate if needed.  */
-        
+
       if (size_needed < epilogue_size_needed)
        {
          tmp =
@@ -14663,7 +14704,7 @@ ix86_expand_setmem (rtx dst, rtx count_exp, rtx val_exp, rtx align_exp,
        mode = DImode;
       count_exp = force_reg (mode, count_exp);
     }
-  /* Do the cheap promotion to allow better CSE across the 
+  /* Do the cheap promotion to allow better CSE across the
      main loop and epilogue (ie one load of the big constant in the
      front of all code.  */
   if (CONST_INT_P (val_exp))
@@ -16448,7 +16489,7 @@ static const struct builtin_description bdesc_2arg[] =
     BUILTIN_DESC_SWAP_OPERANDS },
   { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpngess", IX86_BUILTIN_CMPNGESS, UNGT,
     BUILTIN_DESC_SWAP_OPERANDS },
-  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, UNORDERED, 0 },
+  { MASK_SSE, CODE_FOR_sse_vmmaskcmpv4sf3, "__builtin_ia32_cmpordss", IX86_BUILTIN_CMPORDSS, ORDERED, 0 },
 
   { MASK_SSE, CODE_FOR_sminv4sf3, "__builtin_ia32_minps", IX86_BUILTIN_MINPS, 0, 0 },
   { MASK_SSE, CODE_FOR_smaxv4sf3, "__builtin_ia32_maxps", IX86_BUILTIN_MAXPS, 0, 0 },
@@ -17397,11 +17438,11 @@ ix86_init_mmx_sse_builtins (void)
               IX86_BUILTIN_PALIGNR);
 
   /* AMDFAM10 SSE4A New built-ins  */
-  def_builtin (MASK_SSE4A, "__builtin_ia32_movntsd", 
+  def_builtin (MASK_SSE4A, "__builtin_ia32_movntsd",
                void_ftype_pdouble_v2df, IX86_BUILTIN_MOVNTSD);
-  def_builtin (MASK_SSE4A, "__builtin_ia32_movntss", 
+  def_builtin (MASK_SSE4A, "__builtin_ia32_movntss",
                void_ftype_pfloat_v4sf, IX86_BUILTIN_MOVNTSS);
-  def_builtin (MASK_SSE4A, "__builtin_ia32_extrqi", 
+  def_builtin (MASK_SSE4A, "__builtin_ia32_extrqi",
                v2di_ftype_v2di_unsigned_unsigned, IX86_BUILTIN_EXTRQI);
   def_builtin (MASK_SSE4A, "__builtin_ia32_extrq",
                v2di_ftype_v2di_v16qi,  IX86_BUILTIN_EXTRQ);
@@ -17863,7 +17904,7 @@ ix86_expand_vec_set_builtin (tree exp)
   enum machine_mode tmode, mode1;
   tree arg0, arg1, arg2;
   int elt;
-  rtx op0, op1;
+  rtx op0, op1, target;
 
   arg0 = CALL_EXPR_ARG (exp, 0);
   arg1 = CALL_EXPR_ARG (exp, 1);
@@ -17883,9 +17924,13 @@ ix86_expand_vec_set_builtin (tree exp)
   op0 = force_reg (tmode, op0);
   op1 = force_reg (mode1, op1);
 
-  ix86_expand_vector_set (true, op0, op1, elt);
+  /* OP0 is the source of these builtin functions and shouldn't be
+     modified.  Create a copy, use it and return it as target.  */
+  target = gen_reg_rtx (tmode);
+  emit_move_insn (target, op0);
+  ix86_expand_vector_set (true, target, op1, elt);
 
-  return op0;
+  return target;
 }
 
 /* Expand an expression EXP that calls a built-in function,
@@ -18630,7 +18675,7 @@ ix86_builtin_conversion (enum tree_code code, tree type)
 {
   if (TREE_CODE (type) != VECTOR_TYPE)
     return NULL_TREE;
-  
+
   switch (code)
     {
     case FLOAT_EXPR:
@@ -18845,7 +18890,7 @@ ix86_preferred_output_reload_class (rtx x, enum reg_class class)
   if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode))
     return MAYBE_SSE_CLASS_P (class) ? SSE_REGS : NO_REGS;
 
-  if (TARGET_80387 && SCALAR_FLOAT_MODE_P (mode))
+  if (X87_FLOAT_MODE_P (mode))
     {
       if (class == FP_TOP_SSE_REGS)
        return FP_TOP_REG;
@@ -19330,11 +19375,23 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total)
       return false;
 
     case MULT:
-      if (FLOAT_MODE_P (mode))
+      if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
+       {
+         /* ??? SSE scalar cost should be used here.  */
+         *total = ix86_cost->fmul;
+         return false;
+       }
+      else if (X87_FLOAT_MODE_P (mode))
        {
          *total = ix86_cost->fmul;
          return false;
        }
+      else if (FLOAT_MODE_P (mode))
+       {
+         /* ??? SSE vector cost should be used here.  */
+         *total = ix86_cost->fmul;
+         return false;
+       }
       else
        {
          rtx op0 = XEXP (x, 0);
@@ -19384,16 +19441,20 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total)
     case UDIV:
     case MOD:
     case UMOD:
-      if (FLOAT_MODE_P (mode))
+      if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
+       /* ??? SSE cost should be used here.  */
+       *total = ix86_cost->fdiv;
+      else if (X87_FLOAT_MODE_P (mode))
+       *total = ix86_cost->fdiv;
+      else if (FLOAT_MODE_P (mode))
+       /* ??? SSE vector cost should be used here.  */
        *total = ix86_cost->fdiv;
       else
        *total = ix86_cost->divide[MODE_INDEX (mode)];
       return false;
 
     case PLUS:
-      if (FLOAT_MODE_P (mode))
-       *total = ix86_cost->fadd;
-      else if (GET_MODE_CLASS (mode) == MODE_INT
+      if (GET_MODE_CLASS (mode) == MODE_INT
               && GET_MODE_BITSIZE (mode) <= GET_MODE_BITSIZE (Pmode))
        {
          if (GET_CODE (XEXP (x, 0)) == PLUS
@@ -19436,8 +19497,20 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total)
       /* FALLTHRU */
 
     case MINUS:
-      if (FLOAT_MODE_P (mode))
+      if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
+       {
+         /* ??? SSE cost should be used here.  */
+         *total = ix86_cost->fadd;
+         return false;
+       }
+      else if (X87_FLOAT_MODE_P (mode))
+       {
+         *total = ix86_cost->fadd;
+         return false;
+       }
+      else if (FLOAT_MODE_P (mode))
        {
+         /* ??? SSE vector cost should be used here.  */
          *total = ix86_cost->fadd;
          return false;
        }
@@ -19458,11 +19531,23 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total)
       /* FALLTHRU */
 
     case NEG:
-      if (FLOAT_MODE_P (mode))
+      if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
+       {
+         /* ??? SSE cost should be used here.  */
+         *total = ix86_cost->fchs;
+         return false;
+       }
+      else if (X87_FLOAT_MODE_P (mode))
        {
          *total = ix86_cost->fchs;
          return false;
        }
+      else if (FLOAT_MODE_P (mode))
+       {
+         /* ??? SSE vector cost should be used here.  */
+         *total = ix86_cost->fchs;
+         return false;
+       }
       /* FALLTHRU */
 
     case NOT:
@@ -19488,19 +19573,29 @@ ix86_rtx_costs (rtx x, int code, int outer_code, int *total)
       return false;
 
     case FLOAT_EXTEND:
-      if (!TARGET_SSE_MATH
-         || mode == XFmode
-         || (mode == DFmode && !TARGET_SSE2))
+      if (!(SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH))
        *total = 0;
       return false;
 
     case ABS:
-      if (FLOAT_MODE_P (mode))
+      if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
+       /* ??? SSE cost should be used here.  */
+       *total = ix86_cost->fabs;
+      else if (X87_FLOAT_MODE_P (mode))
+       *total = ix86_cost->fabs;
+      else if (FLOAT_MODE_P (mode))
+       /* ??? SSE vector cost should be used here.  */
        *total = ix86_cost->fabs;
       return false;
 
     case SQRT:
-      if (FLOAT_MODE_P (mode))
+      if (SSE_FLOAT_MODE_P (mode) && TARGET_SSE_MATH)
+       /* ??? SSE cost should be used here.  */
+       *total = ix86_cost->fsqrt;
+      else if (X87_FLOAT_MODE_P (mode))
+       *total = ix86_cost->fsqrt;
+      else if (FLOAT_MODE_P (mode))
+       /* ??? SSE vector cost should be used here.  */
        *total = ix86_cost->fsqrt;
       return false;
 
@@ -21052,7 +21147,7 @@ ix86_md_asm_clobbers (tree outputs ATTRIBUTE_UNUSED,
   return clobbers;
 }
 
-/* Implementes target vector targetm.asm.encode_section_info.  This
+/* Implements target vector targetm.asm.encode_section_info.  This
    is not used by netware.  */
 
 static void ATTRIBUTE_UNUSED
@@ -21082,16 +21177,36 @@ ix86_reverse_condition (enum rtx_code code, enum machine_mode mode)
 const char *
 output_387_reg_move (rtx insn, rtx *operands)
 {
-  if (REG_P (operands[1])
-      && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+  if (REG_P (operands[0]))
+    {
+      if (REG_P (operands[1])
+         && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+       {
+         if (REGNO (operands[0]) == FIRST_STACK_REG)
+           return output_387_ffreep (operands, 0);
+         return "fstp\t%y0";
+       }
+      if (STACK_TOP_P (operands[0]))
+       return "fld%z1\t%y1";
+      return "fst\t%y0";
+    }
+  else if (MEM_P (operands[0]))
     {
-      if (REGNO (operands[0]) == FIRST_STACK_REG)
-       return output_387_ffreep (operands, 0);
-      return "fstp\t%y0";
+      gcc_assert (REG_P (operands[1]));
+      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+       return "fstp%z0\t%y0";
+      else
+       {
+         /* There is no non-popping store to memory for XFmode.
+            So if we need one, follow the store with a load.  */
+         if (GET_MODE (operands[0]) == XFmode)
+           return "fstp%z0\t%y0\n\tfld%z0\t%y0";
+         else
+           return "fst%z0\t%y0";
+       }
     }
-  if (STACK_TOP_P (operands[0]))
-    return "fld%z1\t%y1";
-  return "fst\t%y0";
+  else
+    gcc_unreachable();
 }
 
 /* Output code to perform a conditional jump to LABEL, if C2 flag in