OSDN Git Service

2005-03-07 David Billinghurst <David.Billinghurst@riotinto.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.c
index d9dcca5..bc680c8 100644 (file)
@@ -571,7 +571,11 @@ const int x86_sse_typeless_stores = m_ATHLON_K8;
 const int x86_sse_load0_by_pxor = m_PPRO | m_PENT4 | m_NOCONA;
 const int x86_use_ffreep = m_ATHLON_K8;
 const int x86_rep_movl_optimal = m_386 | m_PENT | m_PPRO | m_K6;
-const int x86_inter_unit_moves = ~(m_ATHLON_K8);
+
+/* ??? Allowing interunit moves makes it all too easy for the compiler to put
+   integer data in xmm registers.  Which results in pretty abysmal code.  */
+const int x86_inter_unit_moves = 0 /* ~(m_ATHLON_K8) */;
+
 const int x86_ext_80387_constants = m_K6 | m_ATHLON | m_PENT4 | m_NOCONA | m_PPRO;
 /* Some CPU cores are not able to predict more than 4 branch instructions in
    the 16 byte window.  */
@@ -1557,9 +1561,9 @@ override_options (void)
        error ("bad value (%s) for -mfpmath= switch", ix86_fpmath_string);
     }
 
-  /* If fpmath doesn't include 387, disable use of x87 intrinsics.  */
-  if (! (ix86_fpmath & FPMATH_387))
-    target_flags |= MASK_NO_FANCY_MATH_387;
+  /* If the i387 is disabled, then do not return values in it. */
+  if (!TARGET_80387)
+    target_flags &= ~MASK_FLOAT_RETURNS;
 
   if ((x86_accumulate_outgoing_args & TUNEMASK)
       && !(target_flags_explicit & MASK_ACCUMULATE_OUTGOING_ARGS)
@@ -1674,6 +1678,13 @@ ix86_function_ok_for_sibcall (tree decl, tree exp)
        }
     }
 
+#if TARGET_DLLIMPORT_DECL_ATTRIBUTES
+  /* Dllimport'd functions are also called indirectly.  */
+  if (decl && lookup_attribute ("dllimport", DECL_ATTRIBUTES (decl))
+      && ix86_function_regparm (TREE_TYPE (decl), NULL) >= 3)
+    return false;
+#endif
+
   /* Otherwise okay.  That also includes certain types of indirect calls.  */
   return true;
 }
@@ -7703,6 +7714,8 @@ ix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[])
          else
            emit_insn (gen_rtx_CLOBBER (VOIDmode, op0));
 
+         if (mode != V4SFmode)
+           op0 = gen_lowpart (V4SFmode, op0);
          m = adjust_address (op1, V2SFmode, 0);
          emit_insn (gen_sse_loadlps (op0, op0, m));
          m = adjust_address (op1, V2SFmode, 8);
@@ -7752,6 +7765,24 @@ ix86_expand_vector_move_misalign (enum machine_mode mode, rtx operands[])
     gcc_unreachable ();
 }
 
+/* Expand a push in MODE.  This is some mode for which we do not support
+   proper push instructions, at least from the registers that we expect
+   the value to live in.  */
+
+void
+ix86_expand_push (enum machine_mode mode, rtx x)
+{
+  rtx tmp;
+
+  tmp = expand_simple_binop (Pmode, PLUS, stack_pointer_rtx,
+                            GEN_INT (-GET_MODE_SIZE (mode)),
+                            stack_pointer_rtx, 1, OPTAB_DIRECT);
+  if (tmp != stack_pointer_rtx)
+    emit_move_insn (stack_pointer_rtx, tmp);
+
+  tmp = gen_rtx_MEM (mode, stack_pointer_rtx);
+  emit_move_insn (tmp, x);
+}
 
 /* Fix up OPERANDS to satisfy ix86_binary_operator_ok.  Return the
    destination to use for the operation.  If different from the true
@@ -7976,6 +8007,56 @@ ix86_unary_operator_ok (enum rtx_code code ATTRIBUTE_UNUSED,
   return TRUE;
 }
 
+/* A subroutine of ix86_expand_fp_absneg_operator and copysign expanders.
+   Create a mask for the sign bit in MODE for an SSE register.  If VECT is
+   true, then replicate the mask for all elements of the vector register.
+   If INVERT is true, then create a mask excluding the sign bit.  */
+
+rtx
+ix86_build_signbit_mask (enum machine_mode mode, bool vect, bool invert)
+{
+  enum machine_mode vec_mode;
+  HOST_WIDE_INT hi, lo;
+  int shift = 63;
+  rtvec v;
+  rtx mask;
+
+  /* Find the sign bit, sign extended to 2*HWI.  */
+  if (mode == SFmode)
+    lo = 0x80000000, hi = lo < 0;
+  else if (HOST_BITS_PER_WIDE_INT >= 64)
+    lo = (HOST_WIDE_INT)1 << shift, hi = -1;
+  else
+    lo = 0, hi = (HOST_WIDE_INT)1 << (shift - HOST_BITS_PER_WIDE_INT);
+
+  if (invert)
+    lo = ~lo, hi = ~hi;
+
+  /* Force this value into the low part of a fp vector constant.  */
+  mask = immed_double_const (lo, hi, mode == SFmode ? SImode : DImode);
+  mask = gen_lowpart (mode, mask);
+
+  if (mode == SFmode)
+    {
+      if (vect)
+       v = gen_rtvec (4, mask, mask, mask, mask);
+      else
+       v = gen_rtvec (4, mask, CONST0_RTX (SFmode),
+                      CONST0_RTX (SFmode), CONST0_RTX (SFmode));
+      vec_mode = V4SFmode;
+    }
+  else
+    {
+      if (vect)
+       v = gen_rtvec (2, mask, mask);
+      else
+       v = gen_rtvec (2, mask, CONST0_RTX (DFmode));
+      vec_mode = V2DFmode;
+    }
+
+  return force_reg (vec_mode, gen_rtx_CONST_VECTOR (vec_mode, v));
+}
+
 /* Generate code for floating point ABS or NEG.  */
 
 void
@@ -7987,79 +8068,19 @@ ix86_expand_fp_absneg_operator (enum rtx_code code, enum machine_mode mode,
   bool use_sse = false;
   bool vector_mode = VECTOR_MODE_P (mode);
   enum machine_mode elt_mode = mode;
-  enum machine_mode vec_mode = VOIDmode;
 
   if (vector_mode)
     {
       elt_mode = GET_MODE_INNER (mode);
-      vec_mode = mode;
       use_sse = true;
     }
-  if (TARGET_SSE_MATH)
-    {
-      if (mode == SFmode)
-       {
-         use_sse = true;
-         vec_mode = V4SFmode;
-       }
-      else if (mode == DFmode && TARGET_SSE2)
-       {
-         use_sse = true;
-         vec_mode = V2DFmode;
-       }
-    }
+  else if (TARGET_SSE_MATH)
+    use_sse = SSE_FLOAT_MODE_P (mode);
 
   /* NEG and ABS performed with SSE use bitwise mask operations.
      Create the appropriate mask now.  */
   if (use_sse)
-    {
-      HOST_WIDE_INT hi, lo;
-      int shift = 63;
-      rtvec v;
-
-      /* Find the sign bit, sign extended to 2*HWI.  */
-      if (elt_mode == SFmode)
-        lo = 0x80000000, hi = lo < 0;
-      else if (HOST_BITS_PER_WIDE_INT >= 64)
-        lo = (HOST_WIDE_INT)1 << shift, hi = -1;
-      else
-        lo = 0, hi = (HOST_WIDE_INT)1 << (shift - HOST_BITS_PER_WIDE_INT);
-
-      /* If we're looking for the absolute value, then we want
-        the compliment.  */
-      if (code == ABS)
-        lo = ~lo, hi = ~hi;
-
-      /* Force this value into the low part of a fp vector constant.  */
-      mask = immed_double_const (lo, hi, mode == SFmode ? SImode : DImode);
-      mask = gen_lowpart (mode, mask);
-
-      switch (mode)
-       {
-       case SFmode:
-         v = gen_rtvec (4, mask, CONST0_RTX (SFmode),
-                        CONST0_RTX (SFmode), CONST0_RTX (SFmode));
-         break;
-
-       case DFmode:
-         v = gen_rtvec (2, mask, CONST0_RTX (DFmode));
-         break;
-
-       case V4SFmode:
-         v = gen_rtvec (4, mask, mask, mask, mask);
-         break;
-
-       case V4DFmode:
-         v = gen_rtvec (2, mask, mask);
-         break;
-
-       default:
-         gcc_unreachable ();
-       }
-
-      mask = gen_rtx_CONST_VECTOR (vec_mode, v);
-      mask = force_reg (vec_mode, mask);
-    }
+    mask = ix86_build_signbit_mask (elt_mode, vector_mode, code == ABS);
   else
     {
       /* When not using SSE, we don't use the mask, but prefer to keep the
@@ -8103,6 +8124,160 @@ ix86_expand_fp_absneg_operator (enum rtx_code code, enum machine_mode mode,
     emit_move_insn (operands[0], dst);
 }
 
+/* Expand a copysign operation.  Special case operand 0 being a constant.  */
+
+void
+ix86_expand_copysign (rtx operands[])
+{
+  enum machine_mode mode, vmode;
+  rtx dest, op0, op1, mask, nmask;
+
+  dest = operands[0];
+  op0 = operands[1];
+  op1 = operands[2];
+
+  mode = GET_MODE (dest);
+  vmode = mode == SFmode ? V4SFmode : V2DFmode;
+
+  if (GET_CODE (op0) == CONST_DOUBLE)
+    {
+      rtvec v;
+
+      if (real_isneg (CONST_DOUBLE_REAL_VALUE (op0)))
+       op0 = simplify_unary_operation (ABS, mode, op0, mode);
+
+      if (op0 == CONST0_RTX (mode))
+       op0 = CONST0_RTX (vmode);
+      else
+        {
+         if (mode == SFmode)
+           v = gen_rtvec (4, op0, CONST0_RTX (SFmode),
+                           CONST0_RTX (SFmode), CONST0_RTX (SFmode));
+         else
+           v = gen_rtvec (2, op0, CONST0_RTX (DFmode));
+          op0 = force_reg (vmode, gen_rtx_CONST_VECTOR (vmode, v));
+       }
+
+      mask = ix86_build_signbit_mask (mode, 0, 0);
+
+      if (mode == SFmode)
+       emit_insn (gen_copysignsf3_const (dest, op0, op1, mask));
+      else
+       emit_insn (gen_copysigndf3_const (dest, op0, op1, mask));
+    }
+  else
+    {
+      nmask = ix86_build_signbit_mask (mode, 0, 1);
+      mask = ix86_build_signbit_mask (mode, 0, 0);
+
+      if (mode == SFmode)
+       emit_insn (gen_copysignsf3_var (dest, NULL, op0, op1, nmask, mask));
+      else
+       emit_insn (gen_copysigndf3_var (dest, NULL, op0, op1, nmask, mask));
+    }
+}
+
+/* Deconstruct a copysign operation into bit masks.  Operand 0 is known to
+   be a constant, and so has already been expanded into a vector constant.  */
+
+void
+ix86_split_copysign_const (rtx operands[])
+{
+  enum machine_mode mode, vmode;
+  rtx dest, op0, op1, mask, x;
+
+  dest = operands[0];
+  op0 = operands[1];
+  op1 = operands[2];
+  mask = operands[3];
+
+  mode = GET_MODE (dest);
+  vmode = GET_MODE (mask);
+
+  dest = simplify_gen_subreg (vmode, dest, mode, 0);
+  x = gen_rtx_AND (vmode, dest, mask);
+  emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+
+  if (op0 != CONST0_RTX (vmode))
+    {
+      x = gen_rtx_IOR (vmode, dest, op0);
+      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+    }
+}
+
+/* Deconstruct a copysign operation into bit masks.  Operand 0 is variable,
+   so we have to do two masks.  */
+
+void
+ix86_split_copysign_var (rtx operands[])
+{
+  enum machine_mode mode, vmode;
+  rtx dest, scratch, op0, op1, mask, nmask, x;
+
+  dest = operands[0];
+  scratch = operands[1];
+  op0 = operands[2];
+  op1 = operands[3];
+  nmask = operands[4];
+  mask = operands[5];
+
+  mode = GET_MODE (dest);
+  vmode = GET_MODE (mask);
+
+  if (rtx_equal_p (op0, op1))
+    {
+      /* Shouldn't happen often (it's useless, obviously), but when it does
+        we'd generate incorrect code if we continue below.  */
+      emit_move_insn (dest, op0);
+      return;
+    }
+
+  if (REG_P (mask) && REGNO (dest) == REGNO (mask))    /* alternative 0 */
+    {
+      gcc_assert (REGNO (op1) == REGNO (scratch));
+
+      x = gen_rtx_AND (vmode, scratch, mask);
+      emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
+
+      dest = mask;
+      op0 = simplify_gen_subreg (vmode, op0, mode, 0);
+      x = gen_rtx_NOT (vmode, dest);
+      x = gen_rtx_AND (vmode, x, op0);
+      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+    }
+  else
+    {
+      if (REGNO (op1) == REGNO (scratch))              /* alternative 1,3 */
+       {
+         x = gen_rtx_AND (vmode, scratch, mask);
+       }
+      else                                             /* alternative 2,4 */
+       {
+          gcc_assert (REGNO (mask) == REGNO (scratch));
+          op1 = simplify_gen_subreg (vmode, op1, mode, 0);
+         x = gen_rtx_AND (vmode, scratch, op1);
+       }
+      emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
+
+      if (REGNO (op0) == REGNO (dest))                 /* alternative 1,2 */
+       {
+         dest = simplify_gen_subreg (vmode, op0, mode, 0);
+         x = gen_rtx_AND (vmode, dest, nmask);
+       }
+      else                                             /* alternative 3,4 */
+       {
+          gcc_assert (REGNO (nmask) == REGNO (dest));
+         dest = nmask;
+         op0 = simplify_gen_subreg (vmode, op0, mode, 0);
+         x = gen_rtx_AND (vmode, dest, op0);
+       }
+      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+    }
+
+  x = gen_rtx_IOR (vmode, dest, scratch);
+  emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+}
+
 /* Return TRUE or FALSE depending on whether the first SET in INSN
    has source and destination with matching CC modes, and that the
    CC mode is at least as constrained as REQ_MODE.  */
@@ -8311,7 +8486,7 @@ ix86_prepare_fp_compare_args (enum rtx_code code, rtx *pop0, rtx *pop1)
   enum machine_mode fpcmp_mode = ix86_fp_compare_mode (code);
   rtx op0 = *pop0, op1 = *pop1;
   enum machine_mode op_mode = GET_MODE (op0);
-  int is_sse = SSE_REG_P (op0) || SSE_REG_P (op1);
+  int is_sse = TARGET_SSE_MATH && SSE_FLOAT_MODE_P (op_mode);
 
   /* All of the unordered compare instructions only work on registers.
      The same is true of the fcomi compare instructions.  The same is
@@ -9743,118 +9918,100 @@ ix86_expand_int_movcc (rtx operands[])
 int
 ix86_expand_fp_movcc (rtx operands[])
 {
-  enum rtx_code code;
-  rtx tmp;
-  rtx compare_op, second_test, bypass_test;
-
-  /* For SF/DFmode conditional moves based on comparisons
-     in same mode, we may want to use SSE min/max instructions.  */
-  if (((TARGET_SSE_MATH && GET_MODE (operands[0]) == SFmode)
-       || (TARGET_SSE2 && TARGET_SSE_MATH && GET_MODE (operands[0]) == DFmode))
-      && GET_MODE (ix86_compare_op0) == GET_MODE (operands[0])
-      /* The SSE comparisons does not support the LTGT/UNEQ pair.  */
-      && (!TARGET_IEEE_FP
-         || (GET_CODE (operands[1]) != LTGT && GET_CODE (operands[1]) != UNEQ))
-      /* We may be called from the post-reload splitter.  */
-      && (!REG_P (operands[0])
-         || SSE_REG_P (operands[0])
-         || REGNO (operands[0]) >= FIRST_PSEUDO_REGISTER))
-    {
-      rtx op0 = ix86_compare_op0, op1 = ix86_compare_op1;
-      code = GET_CODE (operands[1]);
-
-      /* See if we have (cross) match between comparison operands and
-         conditional move operands.  */
-      if (rtx_equal_p (operands[2], op1))
+  enum machine_mode mode = GET_MODE (operands[0]);
+  enum rtx_code code = GET_CODE (operands[1]);
+  rtx tmp, compare_op, second_test, bypass_test;
+
+  if (TARGET_SSE_MATH && SSE_FLOAT_MODE_P (mode))
+    {
+      rtx cmp_op0, cmp_op1, if_true, if_false;
+      rtx clob;
+      enum machine_mode vmode, cmode;
+      bool is_minmax = false;
+
+      cmp_op0 = ix86_compare_op0;
+      cmp_op1 = ix86_compare_op1;
+      if_true = operands[2];
+      if_false = operands[3];
+
+      /* Since we've no cmove for sse registers, don't force bad register
+        allocation just to gain access to it.  Deny movcc when the
+        comparison mode doesn't match the move mode.  */
+      cmode = GET_MODE (cmp_op0);
+      if (cmode == VOIDmode)
+       cmode = GET_MODE (cmp_op1);
+      if (cmode != mode)
+       return 0;
+
+      /* We have no LTGT as an operator.  We could implement it with
+        NE & ORDERED, but this requires an extra temporary.  It's
+        not clear that it's worth it.  */
+      if (code == LTGT || code == UNEQ)
+       return 0;
+
+      /* Massage condition to satisfy sse_comparison_operator.  Try
+        to canonicalize the destination operand to be first in the
+        comparison - this helps reload to avoid extra moves.  */
+      if (!sse_comparison_operator (operands[1], VOIDmode)
+         || (COMMUTATIVE_P (operands[1])
+             && rtx_equal_p (operands[0], cmp_op1)))
        {
-         rtx tmp = op0;
-         op0 = op1;
-         op1 = tmp;
-         code = reverse_condition_maybe_unordered (code);
+         tmp = cmp_op0;
+         cmp_op0 = cmp_op1;
+         cmp_op1 = tmp;
+         code = swap_condition (code);
        }
-      if (rtx_equal_p (operands[2], op0) && rtx_equal_p (operands[3], op1))
+
+      /* Detect conditional moves that exactly match min/max operational
+        semantics.  Note that this is IEEE safe, as long as we don't
+        interchange the operands.  Which is why we keep this in the form
+        if an IF_THEN_ELSE instead of reducing to SMIN/SMAX.  */
+      if ((code == LT || code == UNGE) && REG_P (cmp_op0) && REG_P (cmp_op1))
        {
-         /* Check for min operation.  */
-         if (code == LT || code == UNLE)
-           {
-              if (code == UNLE)
-               {
-                 rtx tmp = op0;
-                 op0 = op1;
-                 op1 = tmp;
-               }
-              operands[0] = force_reg (GET_MODE (operands[0]), operands[0]);
-              if (memory_operand (op0, VOIDmode))
-                op0 = force_reg (GET_MODE (operands[0]), op0);
-              if (GET_MODE (operands[0]) == SFmode)
-                emit_insn (gen_minsf3 (operands[0], op0, op1));
-              else
-                emit_insn (gen_mindf3 (operands[0], op0, op1));
-              return 1;
-           }
-         /* Check for max operation.  */
-         if (code == GT || code == UNGE)
+         if (((cmp_op0 == if_true && cmp_op1 == if_false)
+             || (cmp_op0 == if_false && cmp_op1 == if_true)))
            {
-              if (code == UNGE)
+             is_minmax = true;
+             if (code == UNGE)
                {
-                 rtx tmp = op0;
-                 op0 = op1;
-                 op1 = tmp;
+                 code = LT;
+                 tmp = if_true;
+                 if_true = if_false;
+                 if_false = tmp;
                }
-              operands[0] = force_reg (GET_MODE (operands[0]), operands[0]);
-              if (memory_operand (op0, VOIDmode))
-                op0 = force_reg (GET_MODE (operands[0]), op0);
-              if (GET_MODE (operands[0]) == SFmode)
-                emit_insn (gen_maxsf3 (operands[0], op0, op1));
-              else
-                emit_insn (gen_maxdf3 (operands[0], op0, op1));
-              return 1;
            }
        }
-      /* Manage condition to be sse_comparison_operator.  In case we are
-        in non-ieee mode, try to canonicalize the destination operand
-        to be first in the comparison - this helps reload to avoid extra
-        moves.  */
-      if (!sse_comparison_operator (operands[1], VOIDmode)
-         || (rtx_equal_p (operands[0], ix86_compare_op1) && !TARGET_IEEE_FP))
-       {
-         rtx tmp = ix86_compare_op0;
-         ix86_compare_op0 = ix86_compare_op1;
-         ix86_compare_op1 = tmp;
-         operands[1] = gen_rtx_fmt_ee (swap_condition (GET_CODE (operands[1])),
-                                       VOIDmode, ix86_compare_op0,
-                                       ix86_compare_op1);
-       }
-      /* Similarly try to manage result to be first operand of conditional
-        move. We also don't support the NE comparison on SSE, so try to
-        avoid it.  */
-      if ((rtx_equal_p (operands[0], operands[3])
-          && (!TARGET_IEEE_FP || GET_CODE (operands[1]) != EQ))
-         || (GET_CODE (operands[1]) == NE && TARGET_IEEE_FP))
-       {
-         rtx tmp = operands[2];
-         operands[2] = operands[3];
-         operands[3] = tmp;
-         operands[1] = gen_rtx_fmt_ee (reverse_condition_maybe_unordered
-                                         (GET_CODE (operands[1])),
-                                       VOIDmode, ix86_compare_op0,
-                                       ix86_compare_op1);
-       }
-      if (GET_MODE (operands[0]) == SFmode)
-       emit_insn (gen_sse_movsfcc (operands[0], operands[1],
-                                   operands[2], operands[3],
-                                   ix86_compare_op0, ix86_compare_op1));
+
+      if (mode == SFmode)
+       vmode = V4SFmode;
+      else if (mode == DFmode)
+       vmode = V2DFmode;
       else
-       emit_insn (gen_sse_movdfcc (operands[0], operands[1],
-                                   operands[2], operands[3],
-                                   ix86_compare_op0, ix86_compare_op1));
+       gcc_unreachable ();
+
+      cmp_op0 = force_reg (mode, cmp_op0);
+      if (!nonimmediate_operand (cmp_op1, mode))
+       cmp_op1 = force_reg (mode, cmp_op1);
+
+      tmp = gen_rtx_fmt_ee (code, mode, cmp_op0, cmp_op1);
+      gcc_assert (sse_comparison_operator (tmp, VOIDmode));
+
+      tmp = gen_rtx_IF_THEN_ELSE (mode, tmp, if_true, if_false);
+      tmp = gen_rtx_SET (VOIDmode, operands[0], tmp);
+
+      if (!is_minmax)
+       {
+         clob = gen_rtx_CLOBBER (VOIDmode, gen_rtx_SCRATCH (vmode));
+         tmp = gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, tmp, clob));
+       }
+
+      emit_insn (tmp);
       return 1;
     }
 
   /* The floating point conditional move instructions don't directly
      support conditions resulting from a signed integer comparison.  */
 
-  code = GET_CODE (operands[1]);
   compare_op = ix86_expand_compare (code, &second_test, &bypass_test);
 
   /* The floating point conditional move instructions don't directly
@@ -9873,38 +10030,126 @@ ix86_expand_fp_movcc (rtx operands[])
     }
   if (bypass_test && reg_overlap_mentioned_p (operands[0], operands[3]))
     {
-      tmp = gen_reg_rtx (GET_MODE (operands[0]));
+      tmp = gen_reg_rtx (mode);
       emit_move_insn (tmp, operands[3]);
       operands[3] = tmp;
     }
   if (second_test && reg_overlap_mentioned_p (operands[0], operands[2]))
     {
-      tmp = gen_reg_rtx (GET_MODE (operands[0]));
+      tmp = gen_reg_rtx (mode);
       emit_move_insn (tmp, operands[2]);
       operands[2] = tmp;
     }
 
   emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                         gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
-                               compare_op,
-                               operands[2],
-                               operands[3])));
+                         gen_rtx_IF_THEN_ELSE (mode, compare_op,
+                                               operands[2], operands[3])));
   if (bypass_test)
     emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                           gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
-                                 bypass_test,
-                                 operands[3],
-                                 operands[0])));
+                           gen_rtx_IF_THEN_ELSE (mode, bypass_test,
+                                                 operands[3], operands[0])));
   if (second_test)
     emit_insn (gen_rtx_SET (VOIDmode, operands[0],
-                           gen_rtx_IF_THEN_ELSE (GET_MODE (operands[0]),
-                                 second_test,
-                                 operands[2],
-                                 operands[0])));
+                           gen_rtx_IF_THEN_ELSE (mode, second_test,
+                                                 operands[2], operands[0])));
 
   return 1;
 }
 
+void
+ix86_split_sse_movcc (rtx operands[])
+{
+  rtx dest, scratch, cmp, op_true, op_false, x;
+  enum machine_mode mode, vmode;
+
+  /* Note that the operator CMP has been set up with matching constraints
+     such that dest is valid for the comparison.  Unless one of the true
+     or false operands are zero, the true operand has already been placed
+     in SCRATCH.  */
+  dest = operands[0];
+  scratch = operands[1];
+  op_true = operands[2];
+  op_false = operands[3];
+  cmp = operands[4];
+
+  mode = GET_MODE (dest);
+  vmode = GET_MODE (scratch);
+
+  /* We need to make sure that the TRUE and FALSE operands are out of the
+     way of the destination.  Marking the destination earlyclobber doesn't
+     work, since we want matching constraints for the actual comparison, so
+     at some point we always wind up having to do a copy ourselves here.
+     We very much prefer the TRUE value to be in SCRATCH.  If it turns out
+     that FALSE overlaps DEST, then we invert the comparison so that we
+     still only have to do one move.  */
+  if (rtx_equal_p (op_false, dest))
+    {
+      enum rtx_code code;
+
+      if (rtx_equal_p (op_true, dest))
+       {
+         /* ??? Really ought not happen.  It means some optimizer managed
+            to prove the operands were identical, but failed to fold the
+            conditional move to a straight move.  Do so here, because 
+            otherwise we'll generate incorrect code.  And since they're
+            both already in the destination register, nothing to do.  */
+         return;
+       }
+
+      x = gen_rtx_REG (mode, REGNO (scratch));
+      emit_move_insn (x, op_false);
+      op_false = op_true;
+      op_true = x;
+
+      code = GET_CODE (cmp);
+      code = reverse_condition_maybe_unordered (code);
+      cmp = gen_rtx_fmt_ee (code, mode, XEXP (cmp, 0), XEXP (cmp, 1));
+    }
+  else if (op_true == CONST0_RTX (mode))
+    ;
+  else if (op_false == CONST0_RTX (mode) && !rtx_equal_p (op_true, dest))
+    ;
+  else
+    {
+      x = gen_rtx_REG (mode, REGNO (scratch));
+      emit_move_insn (x, op_true);
+      op_true = x;
+    }
+
+  emit_insn (gen_rtx_SET (VOIDmode, dest, cmp));
+  dest = simplify_gen_subreg (vmode, dest, mode, 0);
+
+  if (op_false == CONST0_RTX (mode))
+    {
+      op_true = simplify_gen_subreg (vmode, op_true, mode, 0);
+      x = gen_rtx_AND (vmode, dest, op_true);
+      emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+    }
+  else
+    {
+      op_false = simplify_gen_subreg (vmode, op_false, mode, 0);
+
+      if (op_true == CONST0_RTX (mode))
+       {
+         x = gen_rtx_NOT (vmode, dest);
+         x = gen_rtx_AND (vmode, x, op_false);
+         emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+       }
+      else
+       {
+         x = gen_rtx_AND (vmode, scratch, dest);
+         emit_insn (gen_rtx_SET (VOIDmode, scratch, x));
+
+         x = gen_rtx_NOT (vmode, dest);
+         x = gen_rtx_AND (vmode, x, op_false);
+         emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+
+         x = gen_rtx_IOR (vmode, dest, scratch);
+         emit_insn (gen_rtx_SET (VOIDmode, dest, x));
+       }
+    }
+}
+
 /* Expand conditional increment or decrement using adb/sbb instructions.
    The default case using setcc followed by the conditional move can be
    done by generic code.  */
@@ -12265,9 +12510,6 @@ enum ix86_builtins
 
   IX86_BUILTIN_LOADDQU,
   IX86_BUILTIN_STOREDQU,
-  IX86_BUILTIN_MOVQ,
-  IX86_BUILTIN_LOADD,
-  IX86_BUILTIN_STORED,
 
   IX86_BUILTIN_PACKSSWB,
   IX86_BUILTIN_PACKSSDW,
@@ -12498,8 +12740,6 @@ enum ix86_builtins
   IX86_BUILTIN_MASKMOVDQU,
   IX86_BUILTIN_MOVMSKPD,
   IX86_BUILTIN_PMOVMSKB128,
-  IX86_BUILTIN_MOVQ2DQ,
-  IX86_BUILTIN_MOVDQ2Q,
 
   IX86_BUILTIN_PACKSSWB128,
   IX86_BUILTIN_PACKSSDW128,
@@ -12607,7 +12847,9 @@ enum ix86_builtins
   IX86_BUILTIN_VEC_EXT_V2DF,
   IX86_BUILTIN_VEC_EXT_V2DI,
   IX86_BUILTIN_VEC_EXT_V4SF,
+  IX86_BUILTIN_VEC_EXT_V4SI,
   IX86_BUILTIN_VEC_EXT_V8HI,
+  IX86_BUILTIN_VEC_EXT_V2SI,
   IX86_BUILTIN_VEC_EXT_V4HI,
   IX86_BUILTIN_VEC_SET_V8HI,
   IX86_BUILTIN_VEC_SET_V4HI,
@@ -13154,8 +13396,6 @@ ix86_init_mmx_sse_builtins (void)
     = build_function_type_list (V2SI_type_node,
                                V2SF_type_node, V2SF_type_node, NULL_TREE);
   tree pint_type_node    = build_pointer_type (integer_type_node);
-  tree pcint_type_node = build_pointer_type (
-                            build_type_variant (integer_type_node, 1, 0));
   tree pdouble_type_node = build_pointer_type (double_type_node);
   tree pcdouble_type_node = build_pointer_type (
                                build_type_variant (double_type_node, 1, 0));
@@ -13168,12 +13408,6 @@ ix86_init_mmx_sse_builtins (void)
                                intTI_type_node, intTI_type_node, NULL_TREE);
   tree void_ftype_pcvoid
     = build_function_type_list (void_type_node, const_ptr_type_node, NULL_TREE);
-  tree v2di_ftype_di
-    = build_function_type_list (V2DI_type_node,
-                               long_long_unsigned_type_node, NULL_TREE);
-  tree di_ftype_v2di
-    = build_function_type_list (long_long_unsigned_type_node,
-                               V2DI_type_node, NULL_TREE);
   tree v4sf_ftype_v4si
     = build_function_type_list (V4SF_type_node, V4SI_type_node, NULL_TREE);
   tree v4si_ftype_v4sf
@@ -13285,13 +13519,6 @@ ix86_init_mmx_sse_builtins (void)
   tree void_ftype_pchar_v16qi
     = build_function_type_list (void_type_node,
                                pchar_type_node, V16QI_type_node, NULL_TREE);
-  tree v4si_ftype_pcint
-    = build_function_type_list (V4SI_type_node, pcint_type_node, NULL_TREE);
-  tree void_ftype_pcint_v4si
-    = build_function_type_list (void_type_node,
-                               pcint_type_node, V4SI_type_node, NULL_TREE);
-  tree v2di_ftype_v2di
-    = build_function_type_list (V2DI_type_node, V2DI_type_node, NULL_TREE);
 
   tree float80_type;
   tree float128_type;
@@ -13479,8 +13706,6 @@ ix86_init_mmx_sse_builtins (void)
 
   /* SSE2 */
   def_builtin (MASK_SSE2, "__builtin_ia32_maskmovdqu", void_ftype_v16qi_v16qi_pchar, IX86_BUILTIN_MASKMOVDQU);
-  def_builtin (MASK_SSE2, "__builtin_ia32_movq2dq", v2di_ftype_di, IX86_BUILTIN_MOVQ2DQ);
-  def_builtin (MASK_SSE2, "__builtin_ia32_movdq2q", di_ftype_v2di, IX86_BUILTIN_MOVDQ2Q);
 
   def_builtin (MASK_SSE2, "__builtin_ia32_loadupd", v2df_ftype_pcdouble, IX86_BUILTIN_LOADUPD);
   def_builtin (MASK_SSE2, "__builtin_ia32_storeupd", void_ftype_pdouble_v2df, IX86_BUILTIN_STOREUPD);
@@ -13534,10 +13759,7 @@ ix86_init_mmx_sse_builtins (void)
   def_builtin (MASK_SSE2, "__builtin_ia32_mfence", void_ftype_void, IX86_BUILTIN_MFENCE);
 
   def_builtin (MASK_SSE2, "__builtin_ia32_loaddqu", v16qi_ftype_pcchar, IX86_BUILTIN_LOADDQU);
-  def_builtin (MASK_SSE2, "__builtin_ia32_loadd", v4si_ftype_pcint, IX86_BUILTIN_LOADD);
   def_builtin (MASK_SSE2, "__builtin_ia32_storedqu", void_ftype_pchar_v16qi, IX86_BUILTIN_STOREDQU);
-  def_builtin (MASK_SSE2, "__builtin_ia32_stored", void_ftype_pcint_v4si, IX86_BUILTIN_STORED);
-  def_builtin (MASK_SSE2, "__builtin_ia32_movq", v2di_ftype_v2di, IX86_BUILTIN_MOVQ);
 
   def_builtin (MASK_SSE2, "__builtin_ia32_pmuludq", di_ftype_v2si_v2si, IX86_BUILTIN_PMULUDQ);
   def_builtin (MASK_SSE2, "__builtin_ia32_pmuludq128", v2di_ftype_v4si_v4si, IX86_BUILTIN_PMULUDQ128);
@@ -13622,6 +13844,11 @@ ix86_init_mmx_sse_builtins (void)
   def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v4sf",
               ftype, IX86_BUILTIN_VEC_EXT_V4SF);
 
+  ftype = build_function_type_list (intSI_type_node, V4SI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v4si",
+              ftype, IX86_BUILTIN_VEC_EXT_V4SI);
+
   ftype = build_function_type_list (intHI_type_node, V8HI_type_node,
                                    integer_type_node, NULL_TREE);
   def_builtin (MASK_SSE, "__builtin_ia32_vec_ext_v8hi",
@@ -13632,6 +13859,11 @@ ix86_init_mmx_sse_builtins (void)
   def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_vec_ext_v4hi",
               ftype, IX86_BUILTIN_VEC_EXT_V4HI);
 
+  ftype = build_function_type_list (intSI_type_node, V2SI_type_node,
+                                   integer_type_node, NULL_TREE);
+  def_builtin (MASK_MMX, "__builtin_ia32_vec_ext_v2si",
+              ftype, IX86_BUILTIN_VEC_EXT_V2SI);
+
   /* Access to the vec_set patterns.  */
   ftype = build_function_type_list (V8HI_type_node, V8HI_type_node,
                                    intHI_type_node,
@@ -14399,13 +14631,8 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
 
     case IX86_BUILTIN_LOADDQU:
       return ix86_expand_unop_builtin (CODE_FOR_sse2_movdqu, arglist, target, 1);
-    case IX86_BUILTIN_LOADD:
-      return ix86_expand_unop_builtin (CODE_FOR_sse2_loadd, arglist, target, 1);
-
     case IX86_BUILTIN_STOREDQU:
       return ix86_expand_store_builtin (CODE_FOR_sse2_movdqu, arglist);
-    case IX86_BUILTIN_STORED:
-      return ix86_expand_store_builtin (CODE_FOR_sse2_stored, arglist);
 
     case IX86_BUILTIN_MONITOR:
       arg0 = TREE_VALUE (arglist);
@@ -14447,7 +14674,9 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
     case IX86_BUILTIN_VEC_EXT_V2DF:
     case IX86_BUILTIN_VEC_EXT_V2DI:
     case IX86_BUILTIN_VEC_EXT_V4SF:
+    case IX86_BUILTIN_VEC_EXT_V4SI:
     case IX86_BUILTIN_VEC_EXT_V8HI:
+    case IX86_BUILTIN_VEC_EXT_V2SI:
     case IX86_BUILTIN_VEC_EXT_V4HI:
       return ix86_expand_vec_ext_builtin (arglist, target);
 
@@ -14480,8 +14709,7 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
     if (d->code == fcode)
       return ix86_expand_sse_comi (d, arglist, target);
 
-  /* @@@ Should really do something sensible here.  */
-  return 0;
+  gcc_unreachable ();
 }
 
 /* Store OPERAND to the memory after reload is completed.  This means
@@ -14593,34 +14821,65 @@ ix86_free_from_memory (enum machine_mode mode)
 enum reg_class
 ix86_preferred_reload_class (rtx x, enum reg_class class)
 {
-  if (GET_CODE (x) == CONST_VECTOR && x != CONST0_RTX (GET_MODE (x)))
+  /* We're only allowed to return a subclass of CLASS.  Many of the 
+     following checks fail for NO_REGS, so eliminate that early.  */
+  if (class == NO_REGS)
     return NO_REGS;
+
+  /* All classes can load zeros.  */
+  if (x == CONST0_RTX (GET_MODE (x)))
+    return class;
+
+  /* Floating-point constants need more complex checks.  */
   if (GET_CODE (x) == CONST_DOUBLE && GET_MODE (x) != VOIDmode)
     {
-      /* SSE can't load any constant directly yet.  */
-      if (SSE_CLASS_P (class))
-       return NO_REGS;
-      /* Floats can load 0 and 1.  */
-      if (MAYBE_FLOAT_CLASS_P (class) && standard_80387_constant_p (x))
-       {
-         /* Limit class to non-SSE.  Use GENERAL_REGS if possible.  */
-         if (MAYBE_SSE_CLASS_P (class))
-           return (reg_class_subset_p (class, GENERAL_REGS)
-                   ? GENERAL_REGS : FLOAT_REGS);
-         else
-           return class;
-       }
       /* General regs can load everything.  */
       if (reg_class_subset_p (class, GENERAL_REGS))
-       return GENERAL_REGS;
-      /* In case we haven't resolved FLOAT or SSE yet, give up.  */
-      if (MAYBE_FLOAT_CLASS_P (class) || MAYBE_SSE_CLASS_P (class))
-       return NO_REGS;
+        return class;
+
+      /* Floats can load 0 and 1 plus some others.  Note that we eliminated
+        zero above.  We only want to wind up preferring 80387 registers if
+        we plan on doing computation with them.  */
+      if (TARGET_80387
+         && (TARGET_MIX_SSE_I387 
+             || !(TARGET_SSE_MATH && SSE_FLOAT_MODE_P (GET_MODE (x))))
+         && standard_80387_constant_p (x))
+       {
+         /* Limit class to non-sse.  */
+         if (class == FLOAT_SSE_REGS)
+           return FLOAT_REGS;
+         if (class == FP_TOP_SSE_REGS)
+           return FP_TOP_REG;
+         if (class == FP_SECOND_SSE_REGS)
+           return FP_SECOND_REG;
+         if (class == FLOAT_INT_REGS || class == FLOAT_REGS)
+           return class;
+       }
+
+      return NO_REGS;
     }
   if (MAYBE_MMX_CLASS_P (class) && CONSTANT_P (x))
     return NO_REGS;
-  if (GET_MODE (x) == QImode && ! reg_class_subset_p (class, Q_REGS))
-    return Q_REGS;
+  if (MAYBE_SSE_CLASS_P (class) && CONSTANT_P (x))
+    return NO_REGS;
+
+  /* Generally when we see PLUS here, it's the function invariant
+     (plus soft-fp const_int).  Which can only be computed into general
+     regs.  */
+  if (GET_CODE (x) == PLUS)
+    return reg_class_subset_p (class, GENERAL_REGS) ? class : NO_REGS;
+
+  /* QImode constants are easy to load, but non-constant QImode data
+     must go into Q_REGS.  */
+  if (GET_MODE (x) == QImode && !CONSTANT_P (x))
+    {
+      if (reg_class_subset_p (class, Q_REGS))
+       return class;
+      if (reg_class_subset_p (Q_REGS, class))
+       return Q_REGS;
+      return NO_REGS;
+    }
+
   return class;
 }
 
@@ -14634,6 +14893,7 @@ ix86_preferred_reload_class (rtx x, enum reg_class class)
 
    When STRICT is false, we are being called from REGISTER_MOVE_COST, so do not
    enforce these sanity checks.  */
+
 int
 ix86_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
                              enum machine_mode mode, int strict)
@@ -14647,21 +14907,50 @@ ix86_secondary_memory_needed (enum reg_class class1, enum reg_class class2,
     {
       if (strict)
        abort ();
-      else
-       return 1;
+      return true;
+    }
+
+  if (FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class2))
+    return true;
+
+  /* ??? This is a lie.  We do have moves between mmx/general, and for
+     mmx/sse2.  But by saying we need secondary memory we discourage the
+     register allocator from using the mmx registers unless needed.  */
+  if (MMX_CLASS_P (class1) != MMX_CLASS_P (class2))
+    return true;
+
+  if (SSE_CLASS_P (class1) != SSE_CLASS_P (class2))
+    {
+      /* SSE1 doesn't have any direct moves from other classes.  */
+      if (!TARGET_SSE2)
+       return true;
+
+      /* If the target says that inter-unit moves are more expensive 
+        than moving through memory, then don't generate them.  */
+      if (!TARGET_INTER_UNIT_MOVES && !optimize_size)
+       return true;
+
+      /* Between SSE and general, we have moves no larger than word size.  */
+      if (GET_MODE_SIZE (mode) > UNITS_PER_WORD)
+       return true;
+
+      /* ??? For the cost of one register reformat penalty, we could use
+        the same instructions to move SFmode and DFmode data, but the 
+        relevant move patterns don't support those alternatives.  */
+      if (mode == SFmode || mode == DFmode)
+       return true;
     }
-  return (FLOAT_CLASS_P (class1) != FLOAT_CLASS_P (class2)
-         || ((SSE_CLASS_P (class1) != SSE_CLASS_P (class2)
-              || MMX_CLASS_P (class1) != MMX_CLASS_P (class2))
-             && ((mode != SImode && (mode != DImode || !TARGET_64BIT))
-                 || (!TARGET_INTER_UNIT_MOVES && !optimize_size))));
+
+  return false;
 }
+
 /* Return the cost of moving data from a register in class CLASS1 to
    one in class CLASS2.
 
    It is not required that the cost always equal 2 when FROM is the same as TO;
    on some machines it is expensive to move between registers if they are not
    general registers.  */
+
 int
 ix86_register_move_cost (enum machine_mode mode, enum reg_class class1,
                         enum reg_class class2)
@@ -14708,7 +14997,8 @@ ix86_register_move_cost (enum machine_mode mode, enum reg_class class1,
 }
 
 /* Return 1 if hard register REGNO can hold a value of machine-mode MODE.  */
-int
+
+bool
 ix86_hard_regno_mode_ok (int regno, enum machine_mode mode)
 {
   /* Flags and only flags can only hold CCmode values.  */
@@ -14749,6 +15039,67 @@ ix86_hard_regno_mode_ok (int regno, enum machine_mode mode)
   return reload_in_progress || reload_completed || !TARGET_PARTIAL_REG_STALL;
 }
 
+/* A subroutine of ix86_modes_tieable_p.  Return true if MODE is a 
+   tieable integer mode.  */
+
+static bool
+ix86_tieable_integer_mode_p (enum machine_mode mode)
+{
+  switch (mode)
+    {
+    case HImode:
+    case SImode:
+      return true;
+
+    case QImode:
+      return TARGET_64BIT || !TARGET_PARTIAL_REG_STALL;
+
+    case DImode:
+      return TARGET_64BIT;
+
+    default:
+      return false;
+    }
+}
+
+/* Return true if MODE1 is accessible in a register that can hold MODE2
+   without copying.  That is, all register classes that can hold MODE2
+   can also hold MODE1.  */
+
+bool
+ix86_modes_tieable_p (enum machine_mode mode1, enum machine_mode mode2)
+{
+  if (mode1 == mode2)
+    return true;
+
+  if (ix86_tieable_integer_mode_p (mode1)
+      && ix86_tieable_integer_mode_p (mode2))
+    return true;
+
+  /* MODE2 being XFmode implies fp stack or general regs, which means we
+     can tie any smaller floating point modes to it.  Note that we do not
+     tie this with TFmode.  */
+  if (mode2 == XFmode)
+    return mode1 == SFmode || mode1 == DFmode;
+
+  /* MODE2 being DFmode implies fp stack, general or sse regs, which means
+     that we can tie it with SFmode.  */
+  if (mode2 == DFmode)
+    return mode1 == SFmode;
+
+  /* If MODE2 is only appropriate for an SSE register, then tie with 
+     any other mode acceptable to SSE registers.  */
+  if (SSE_REG_MODE_P (mode2))
+    return ix86_hard_regno_mode_ok (FIRST_SSE_REG, mode1);
+
+  /* If MODE2 is appropriate for an MMX (or SSE) register, then tie
+     with any other mode acceptable to MMX registers.  */
+  if (MMX_REG_MODE_P (mode2))
+    return ix86_hard_regno_mode_ok (FIRST_MMX_REG, mode1);
+
+  return false;
+}
+
 /* Return the cost of moving data of mode M between a
    register and memory.  A value of 2 is the default; this cost is
    relative to those in `REGISTER_MOVE_COST'.
@@ -16009,7 +16360,7 @@ ix86_expand_vector_init_one_var (bool mmx_ok, enum machine_mode mode,
 
       x = gen_reg_rtx (wmode);
       emit_move_insn (x, gen_lowpart (wmode, const_vec));
-      ix86_expand_vector_set (mmx_ok, target, var, one_var >> 1);
+      ix86_expand_vector_set (mmx_ok, x, var, one_var >> 1);
 
       emit_move_insn (target, gen_lowpart (mode, x));
       return true;
@@ -16144,7 +16495,7 @@ ix86_expand_vector_init_general (bool mmx_ok, enum machine_mode mode,
        {
          rtx tmp = gen_reg_rtx (V4SImode);
          vals = gen_rtx_PARALLEL (V4SImode, gen_rtvec_v (4, words));
-         ix86_expand_vector_init_general (false, V4SImode, target, vals);
+         ix86_expand_vector_init_general (false, V4SImode, tmp, vals);
          emit_move_insn (target, gen_lowpart (mode, tmp));
        }
       else
@@ -16218,9 +16569,18 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
     {
     case V2SFmode:
     case V2SImode:
-      if (!mmx_ok)
-       break;
-      /* FALLTHRU */
+      if (mmx_ok)
+       {
+         tmp = gen_reg_rtx (GET_MODE_INNER (mode));
+         ix86_expand_vector_extract (true, tmp, target, 1 - elt);
+         if (elt == 0)
+           tmp = gen_rtx_VEC_CONCAT (mode, tmp, val);
+         else
+           tmp = gen_rtx_VEC_CONCAT (mode, val, tmp);
+         emit_insn (gen_rtx_SET (VOIDmode, target, tmp));
+         return;
+       }
+      break;
 
     case V2DFmode:
     case V2DImode:
@@ -16263,7 +16623,7 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
          /* op0 = A B X D  */
          emit_insn (gen_sse_shufps_1 (target, target, tmp,
                                       GEN_INT (1), GEN_INT (0),
-                                      GEN_INT (2), GEN_INT (3)));
+                                      GEN_INT (2+4), GEN_INT (3+4)));
          return;
 
        case 2:
@@ -16271,7 +16631,7 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
          ix86_expand_vector_set (false, target, val, 0);
          emit_insn (gen_sse_shufps_1 (target, target, tmp,
                                       GEN_INT (0), GEN_INT (1),
-                                      GEN_INT (0), GEN_INT (3)));
+                                      GEN_INT (0+4), GEN_INT (3+4)));
          return;
 
        case 3:
@@ -16279,7 +16639,7 @@ ix86_expand_vector_set (bool mmx_ok, rtx target, rtx val, int elt)
          ix86_expand_vector_set (false, target, val, 0);
          emit_insn (gen_sse_shufps_1 (target, target, tmp,
                                       GEN_INT (0), GEN_INT (1),
-                                      GEN_INT (2), GEN_INT (0)));
+                                      GEN_INT (2+4), GEN_INT (0+4)));
          return;
 
        default:
@@ -16389,7 +16749,7 @@ ix86_expand_vector_extract (bool mmx_ok, rtx target, rtx vec, int elt)
          tmp = gen_reg_rtx (mode);
          emit_insn (gen_sse_shufps_1 (tmp, vec, vec,
                                       GEN_INT (elt), GEN_INT (elt),
-                                      GEN_INT (elt), GEN_INT (elt)));
+                                      GEN_INT (elt+4), GEN_INT (elt+4)));
          break;
 
        case 2:
@@ -16402,6 +16762,7 @@ ix86_expand_vector_extract (bool mmx_ok, rtx target, rtx vec, int elt)
        }
       vec = tmp;
       use_vec_extr = true;
+      elt = 0;
       break;
 
     case V4SImode:
@@ -16431,6 +16792,7 @@ ix86_expand_vector_extract (bool mmx_ok, rtx target, rtx vec, int elt)
            }
          vec = tmp;
          use_vec_extr = true;
+         elt = 0;
        }
       else
        {