OSDN Git Service

* optabs.h (enum optab_index): Add new OTI_scalb.
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.md
index 92fcde9..920b9dd 100644 (file)
@@ -27,9 +27,6 @@
 ;;
 ;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
 ;;
-;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register
-;; constraint letters.
-;;
 ;; The special asm out single letter directives following a '%' are:
 ;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of
 ;;     operands[1].
 ;; SSE asm suffix for floating point modes
 (define_mode_attr ssemodefsuffix [(SF "s") (DF "d")])
 
+;; SSE vector mode corresponding to a scalar mode
+(define_mode_attr ssevecmode
+  [(QI "V16QI") (HI "V8HI") (SI "V4SI") (DI "V2DI") (SF "V4SF") (DF "V2DF")])
 \f
 ;; Scheduling descriptions
 
                 (match_operand:DI 1 "const0_operand" "n,n")))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCNOmode)"
   "@
-   test{q}\t{%0, %0|%0, %0}
+   test{q}\t%0, %0
    cmp{q}\t{%1, %0|%0, %1}"
   [(set_attr "type" "test,icmp")
    (set_attr "length_immediate" "0,1")
                 (match_operand:SI 1 "const0_operand" "n,n")))]
   "ix86_match_ccmode (insn, CCNOmode)"
   "@
-   test{l}\t{%0, %0|%0, %0}
+   test{l}\t%0, %0
    cmp{l}\t{%1, %0|%0, %1}"
   [(set_attr "type" "test,icmp")
    (set_attr "length_immediate" "0,1")
                 (match_operand:HI 1 "const0_operand" "n,n")))]
   "ix86_match_ccmode (insn, CCNOmode)"
   "@
-   test{w}\t{%0, %0|%0, %0}
+   test{w}\t%0, %0
    cmp{w}\t{%1, %0|%0, %1}"
   [(set_attr "type" "test,icmp")
    (set_attr "length_immediate" "0,1")
                 (match_operand:QI 1 "const0_operand" "n,n")))]
   "ix86_match_ccmode (insn, CCNOmode)"
   "@
-   test{b}\t{%0, %0|%0, %0}
+   test{b}\t%0, %0
    cmp{b}\t{$0, %0|%0, 0}"
   [(set_attr "type" "test,icmp")
    (set_attr "length_immediate" "0,1")
        (match_operand:SI 1 "const0_operand" "i"))
    (clobber (reg:CC FLAGS_REG))]
   "reload_completed && (!TARGET_USE_MOV0 || optimize_size)"
-  "xor{l}\t{%0, %0|%0, %0}"
+  "xor{l}\t%0, %0"
   [(set_attr "type" "alu1")
    (set_attr "mode" "SI")
    (set_attr "length_immediate" "0")])
 
 (define_insn "*movsi_1"
   [(set (match_operand:SI 0 "nonimmediate_operand"
-                       "=r  ,m  ,*y,*y,?rm,?*y,*x,*x,?r,m ,?*Y,*x")
+                       "=r  ,m  ,*y,*y,?rm,?*y,*x,*x,?r ,m ,?*Yi,*x")
        (match_operand:SI 1 "general_operand"
-                       "rinm,rin,C ,*y,*y ,rm ,C ,*x,*Y,*x,r  ,m "))]
+                       "rinm,rin,C ,*y,*y ,rm ,C ,*x,*Yi,*x,r   ,m "))]
   "!(MEM_P (operands[0]) && MEM_P (operands[1]))"
 {
   switch (get_attr_type (insn))
    (clobber (reg:CC FLAGS_REG))]
   "reload_completed
    && ((!TARGET_USE_MOV0 && !TARGET_PARTIAL_REG_STALL) || optimize_size)"
-  "xor{w}\t{%0, %0|%0, %0}"
+  "xor{w}\t%0, %0"
   [(set_attr "type" "alu1")
    (set_attr "mode" "HI")
    (set_attr "length_immediate" "0")])
        (match_operand:QI 1 "const0_operand" "i"))
    (clobber (reg:CC FLAGS_REG))]
   "reload_completed && (!TARGET_USE_MOV0 || optimize_size)"
-  "xor{b}\t{%0, %0|%0, %0}"
+  "xor{b}\t%0, %0"
   [(set_attr "type" "alu1")
    (set_attr "mode" "QI")
    (set_attr "length_immediate" "0")])
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_64BIT && (!TARGET_USE_MOV0 || optimize_size)
    && reload_completed"
-  "xor{l}\t{%k0, %k0|%k0, %k0}"
+  "xor{l}\t%k0, %k0";
   [(set_attr "type" "alu1")
    (set_attr "mode" "SI")
    (set_attr "length_immediate" "0")])
 
 (define_insn "*movdi_2"
   [(set (match_operand:DI 0 "nonimmediate_operand"
-                               "=r  ,o  ,*y,m*y,*y,*Y,m ,*Y,*Y,*x,m ,*x,*x")
+                       "=r  ,o  ,*y,m*y,*y,*Y2,m  ,*Y2,*Y2,*x,m ,*x,*x")
        (match_operand:DI 1 "general_operand"
-                               "riFo,riF,C ,*y ,m ,C ,*Y,*Y,m ,C ,*x,*x,m "))]
+                       "riFo,riF,C ,*y ,m ,C  ,*Y2,*Y2,m  ,C ,*x,*x,m "))]
   "!TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
   "@
    #
 
 (define_insn "*movdi_1_rex64"
   [(set (match_operand:DI 0 "nonimmediate_operand"
-               "=r,r  ,r,m ,!m,*y,*y,?rm,?*y,*x,*x,?rm,?*x,?*x,?*y")
+         "=r,r  ,r,m ,!m,*y,*y,?r ,m ,?*Ym,*y,*x,*x,?r ,m,?*Yi,*x,?*x,?*Ym")
        (match_operand:DI 1 "general_operand"
-               "Z ,rem,i,re,n ,C ,*y,*y ,rm ,C ,*x,*x ,rm ,*y ,*x"))]
+         "Z ,rem,i,re,n ,C ,*y,*Ym,*y,r   ,m ,C ,*x,*Yi,*x,r  ,m ,*Ym,*x"))]
   "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))"
 {
   switch (get_attr_type (insn))
     {
     case TYPE_SSECVT:
-      if (which_alternative == 13)
+      if (SSE_REG_P (operands[0]))
        return "movq2dq\t{%1, %0|%0, %1}";
       else
        return "movdq2q\t{%1, %0|%0, %1}";
+
     case TYPE_SSEMOV:
       if (get_attr_mode (insn) == MODE_TI)
-         return "movdqa\t{%1, %0|%0, %1}";
+       return "movdqa\t{%1, %0|%0, %1}";
       /* FALLTHRU */
+
     case TYPE_MMXMOV:
-      /* Moves from and into integer register is done using movd opcode with
-        REX prefix.  */
+      /* Moves from and into integer register is done using movd
+        opcode with REX prefix.  */
       if (GENERAL_REG_P (operands[0]) || GENERAL_REG_P (operands[1]))
-         return "movd\t{%1, %0|%0, %1}";
+       return "movd\t{%1, %0|%0, %1}";
       return "movq\t{%1, %0|%0, %1}";
+
     case TYPE_SSELOG1:
     case TYPE_MMXADD:
       return "pxor\t%0, %0";
+
     case TYPE_MULTI:
       return "#";
+
     case TYPE_LEA:
       return "lea{q}\t{%a1, %0|%0, %a1}";
+
     default:
       gcc_assert (!flag_pic || LEGITIMATE_PIC_OPERAND_P (operands[1]));
       if (get_attr_mode (insn) == MODE_SI)
   [(set (attr "type")
      (cond [(eq_attr "alternative" "5")
              (const_string "mmxadd")
-           (eq_attr "alternative" "6,7,8")
+           (eq_attr "alternative" "6,7,8,9,10")
              (const_string "mmxmov")
-           (eq_attr "alternative" "9")
+           (eq_attr "alternative" "11")
              (const_string "sselog1")
-           (eq_attr "alternative" "10,11,12")
+           (eq_attr "alternative" "12,13,14,15,16")
              (const_string "ssemov")
-           (eq_attr "alternative" "13,14")
+           (eq_attr "alternative" "17,18")
              (const_string "ssecvt")
            (eq_attr "alternative" "4")
              (const_string "multi")
              (const_string "lea")
           ]
           (const_string "imov")))
-   (set_attr "modrm" "*,0,0,*,*,*,*,*,*,*,*,*,*,*,*")
-   (set_attr "length_immediate" "*,4,8,*,*,*,*,*,*,*,*,*,*,*,*")
-   (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,DI,TI,TI,DI,DI,DI,DI")])
+   (set_attr "modrm" "*,0,0,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")
+   (set_attr "length_immediate" "*,4,8,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*,*")
+   (set_attr "mode" "SI,DI,DI,DI,SI,DI,DI,DI,DI,DI,DI,TI,TI,DI,DI,DI,DI,DI,DI")])
 
 ;; Stores and loads of ax to arbitrary constant address.
 ;; We fake an second form of instruction to force reload to load address
    (set_attr "mode" "SF,SI,SF")])
 
 (define_insn "*pushsf_rex64"
-  [(set (match_operand:SF 0 "push_operand" "=X,X,X")
+  [(set (match_operand:SF 0 "push_operand" "=<,<,<")
        (match_operand:SF 1 "nonmemory_no_elim_operand" "f,rF,x"))]
   "TARGET_64BIT"
 {
 
 (define_insn "*movsf_1"
   [(set (match_operand:SF 0 "nonimmediate_operand"
-         "=f,m   ,f,r  ,m    ,x,x,x ,m   ,!*y,!rm,!*y")
+         "=f,m,f,r  ,m ,x,x,x ,m,*y,m ,*y,Yi,r ,*Ym,r  ")
        (match_operand:SF 1 "general_operand"
-         "fm,f,G   ,rmF,Fr,C   ,x   ,xm,x,rm ,*y ,*y"))]
+         "fm,f,G,rmF,Fr,C,x,xm,x,m ,*y,*y,r ,Yi,r  ,*Ym"))]
   "!(MEM_P (operands[0]) && MEM_P (operands[1]))
    && (reload_in_progress || reload_completed
        || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
        return "movaps\t{%1, %0|%0, %1}";
       else
        return "movss\t{%1, %0|%0, %1}";
-    case 7:
-    case 8:
+    case 7: case 8:
       return "movss\t{%1, %0|%0, %1}";
 
-    case 9:
-    case 10:
+    case 9: case 10:
+    case 12: case 13: case 14: case 15:
       return "movd\t{%1, %0|%0, %1}";
 
     case 11:
       gcc_unreachable ();
     }
 }
-  [(set_attr "type" "fmov,fmov,fmov,imov,imov,sselog1,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov")
+  [(set_attr "type" "fmov,fmov,fmov,imov,imov,sselog1,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov,ssemov,ssemov,mmxmov,mmxmov")
    (set (attr "mode")
         (cond [(eq_attr "alternative" "3,4,9,10")
                 (const_string "SI")
 
 (define_insn "*pushdf_nointeger"
   [(set (match_operand:DF 0 "push_operand" "=<,<,<,<")
-       (match_operand:DF 1 "general_no_elim_operand" "f,Fo,*r,Y"))]
+       (match_operand:DF 1 "general_no_elim_operand" "f,Fo,*r,Y2"))]
   "!TARGET_64BIT && !TARGET_INTEGER_DFMODE_MOVES"
 {
   /* This insn should be already split before reg-stack.  */
 
 (define_insn "*pushdf_integer"
   [(set (match_operand:DF 0 "push_operand" "=<,<,<")
-       (match_operand:DF 1 "general_no_elim_operand" "f,rFo,Y"))]
+       (match_operand:DF 1 "general_no_elim_operand" "f,rFo,Y2"))]
   "TARGET_64BIT || TARGET_INTEGER_DFMODE_MOVES"
 {
   /* This insn should be already split before reg-stack.  */
 
 (define_insn "*movdf_nointeger"
   [(set (match_operand:DF 0 "nonimmediate_operand"
-                       "=f,m,f,*r  ,o  ,Y*x,Y*x,Y*x ,m  ")
+                       "=f,m,f,*r  ,o  ,Y2*x,Y2*x,Y2*x ,m  ")
        (match_operand:DF 1 "general_operand"
-                       "fm,f,G,*roF,F*r,C  ,Y*x,mY*x,Y*x"))]
+                       "fm,f,G,*roF,F*r,C   ,Y2*x,mY2*x,Y2*x"))]
   "!(MEM_P (operands[0]) && MEM_P (operands[1]))
    && ((optimize_size || !TARGET_INTEGER_DFMODE_MOVES) && !TARGET_64BIT)
    && (reload_in_progress || reload_completed
              ]
              (const_string "DF")))])
 
+(define_insn "*movdf_integer_rex64"
+  [(set (match_operand:DF 0 "nonimmediate_operand"
+               "=f,m,f,r  ,m ,Y2*x,Y2*x,Y2*x,m   ,Yi,r ")
+       (match_operand:DF 1 "general_operand"
+               "fm,f,G,rmF,Fr,C   ,Y2*x,m   ,Y2*x,r ,Yi"))]
+  "TARGET_64BIT && !(MEM_P (operands[0]) && MEM_P (operands[1]))
+   && (reload_in_progress || reload_completed
+       || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
+       || (!(TARGET_SSE2 && TARGET_SSE_MATH) && optimize_size
+          && standard_80387_constant_p (operands[1]))
+       || GET_CODE (operands[1]) != CONST_DOUBLE
+       || memory_operand (operands[0], DFmode))"
+{
+  switch (which_alternative)
+    {
+    case 0:
+      return output_387_reg_move (insn, operands);
+
+    case 1:
+      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
+        return "fstp%z0\t%y0";
+      else
+        return "fst%z0\t%y0";
+
+    case 2:
+      return standard_80387_constant_opcode (operands[1]);
+
+    case 3:
+    case 4:
+      return "#";
+
+    case 5:
+      switch (get_attr_mode (insn))
+       {
+       case MODE_V4SF:
+         return "xorps\t%0, %0";
+       case MODE_V2DF:
+         return "xorpd\t%0, %0";
+       case MODE_TI:
+         return "pxor\t%0, %0";
+       default:
+         gcc_unreachable ();
+       }
+    case 6:
+    case 7:
+    case 8:
+      switch (get_attr_mode (insn))
+       {
+       case MODE_V4SF:
+         return "movaps\t{%1, %0|%0, %1}";
+       case MODE_V2DF:
+         return "movapd\t{%1, %0|%0, %1}";
+       case MODE_TI:
+         return "movdqa\t{%1, %0|%0, %1}";
+       case MODE_DI:
+         return "movq\t{%1, %0|%0, %1}";
+       case MODE_DF:
+         return "movsd\t{%1, %0|%0, %1}";
+       case MODE_V1DF:
+         return "movlpd\t{%1, %0|%0, %1}";
+       case MODE_V2SF:
+         return "movlps\t{%1, %0|%0, %1}";
+       default:
+         gcc_unreachable ();
+       }
+
+    case 9:
+    case 10:
+      return "movd\t{%1, %0|%0, %1}";
+
+    default:
+      gcc_unreachable();
+    }
+}
+  [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov,ssemov,ssemov")
+   (set (attr "mode")
+        (cond [(eq_attr "alternative" "0,1,2")
+                (const_string "DF")
+              (eq_attr "alternative" "3,4,9,10")
+                (const_string "DI")
+
+              /* For SSE1, we have many fewer alternatives.  */
+              (eq (symbol_ref "TARGET_SSE2") (const_int 0))
+                (cond [(eq_attr "alternative" "5,6")
+                         (const_string "V4SF")
+                      ]
+                  (const_string "V2SF"))
+
+              /* xorps is one byte shorter.  */
+              (eq_attr "alternative" "5")
+                (cond [(ne (symbol_ref "optimize_size")
+                           (const_int 0))
+                         (const_string "V4SF")
+                       (ne (symbol_ref "TARGET_SSE_LOAD0_BY_PXOR")
+                           (const_int 0))
+                         (const_string "TI")
+                      ]
+                      (const_string "V2DF"))
+
+              /* For architectures resolving dependencies on
+                 whole SSE registers use APD move to break dependency
+                 chains, otherwise use short move to avoid extra work.
+
+                 movaps encodes one byte shorter.  */
+              (eq_attr "alternative" "6")
+                (cond
+                  [(ne (symbol_ref "optimize_size")
+                       (const_int 0))
+                     (const_string "V4SF")
+                   (ne (symbol_ref "TARGET_SSE_PARTIAL_REG_DEPENDENCY")
+                       (const_int 0))
+                     (const_string "V2DF")
+                  ]
+                  (const_string "DF"))
+              /* For architectures resolving dependencies on register
+                 parts we may avoid extra work to zero out upper part
+                 of register.  */
+              (eq_attr "alternative" "7")
+                (if_then_else
+                  (ne (symbol_ref "TARGET_SSE_SPLIT_REGS")
+                      (const_int 0))
+                  (const_string "V1DF")
+                  (const_string "DF"))
+             ]
+             (const_string "DF")))])
+
 (define_insn "*movdf_integer"
   [(set (match_operand:DF 0 "nonimmediate_operand"
-               "=f,m,f,r  ,o ,Y*x,Y*x,Y*x,m  ")
+               "=f,m,f,r  ,o ,Y2*x,Y2*x,Y2*x,m   ")
        (match_operand:DF 1 "general_operand"
-               "fm,f,G,roF,Fr,C  ,Y*x,m  ,Y*x"))]
+               "fm,f,G,roF,Fr,C   ,Y2*x,m   ,Y2*x"))]
   "!(MEM_P (operands[0]) && MEM_P (operands[1]))
-   && ((!optimize_size && TARGET_INTEGER_DFMODE_MOVES) || TARGET_64BIT)
+   && !optimize_size && TARGET_INTEGER_DFMODE_MOVES
    && (reload_in_progress || reload_completed
        || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
        || (!(TARGET_SSE2 && TARGET_SSE_MATH) && optimize_size
   [(set (match_operand:DI 0 "register_operand" "=r")
      (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm")))]
   ""
-  "if (!TARGET_64BIT)
-     {
-       emit_insn (gen_zero_extendsidi2_32 (operands[0], operands[1]));
-       DONE;
-     }
-  ")
+{
+  if (!TARGET_64BIT)
+    {
+      emit_insn (gen_zero_extendsidi2_32 (operands[0], operands[1]));
+      DONE;
+    }
+})
 
 (define_insn "zero_extendsidi2_32"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o,?*y,?*Y")
-       (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "0,rm,r,rm,rm")))
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?o,?*Ym,*y,?*Yi,*Y2")
+       (zero_extend:DI
+        (match_operand:SI 1 "nonimmediate_operand" "0,rm,r ,r   ,m ,r   ,m")))
    (clobber (reg:CC FLAGS_REG))]
   "!TARGET_64BIT"
   "@
    #
    #
    movd\t{%1, %0|%0, %1}
+   movd\t{%1, %0|%0, %1}
+   movd\t{%1, %0|%0, %1}
    movd\t{%1, %0|%0, %1}"
-  [(set_attr "mode" "SI,SI,SI,DI,TI")
-   (set_attr "type" "multi,multi,multi,mmxmov,ssemov")])
+  [(set_attr "mode" "SI,SI,SI,DI,DI,TI,TI")
+   (set_attr "type" "multi,multi,multi,mmxmov,mmxmov,ssemov,ssemov")])
 
 (define_insn "zero_extendsidi2_rex64"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,?*y,?*Y")
-     (zero_extend:DI (match_operand:SI 1 "nonimmediate_operand" "rm,0,rm,rm")))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o,?*Ym,*y,?*Yi,*Y2")
+     (zero_extend:DI
+       (match_operand:SI 1 "nonimmediate_operand"  "rm,0,r   ,m ,r   ,m")))]
   "TARGET_64BIT"
   "@
    mov\t{%k1, %k0|%k0, %k1}
    #
    movd\t{%1, %0|%0, %1}
+   movd\t{%1, %0|%0, %1}
+   movd\t{%1, %0|%0, %1}
    movd\t{%1, %0|%0, %1}"
-  [(set_attr "type" "imovx,imov,mmxmov,ssemov")
-   (set_attr "mode" "SI,DI,SI,SI")])
+  [(set_attr "type" "imovx,imov,mmxmov,mmxmov,ssemov,ssemov")
+   (set_attr "mode" "SI,DI,DI,DI,TI,TI")])
 
 (define_split
   [(set (match_operand:DI 0 "memory_operand" "")
 })
 
 (define_insn "*extendsfdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,Y")
-        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f,mY")))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,x")
+        (float_extend:DF
+         (match_operand:SF 1 "nonimmediate_operand" "fm,f,xm")))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387"
 {
   switch (which_alternative)
    (set_attr "mode" "SF,XF,DF")])
 
 (define_insn "*extendsfdf2_sse"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=Y")
-        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "mY")))]
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=x")
+        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "xm")))]
   "TARGET_SSE2 && TARGET_SSE_MATH"
   "cvtss2sd\t{%1, %0|%0, %1}"
   [(set_attr "type" "ssecvt")
   "")
 
 (define_insn "*truncdfsf_fast_mixed"
-  [(set (match_operand:SF 0 "nonimmediate_operand"   "=m,f,Y")
+  [(set (match_operand:SF 0 "nonimmediate_operand"   "=m,f,x")
         (float_truncate:SF
-          (match_operand:DF 1 "nonimmediate_operand" "f ,f,Ym")))]
+          (match_operand:DF 1 "nonimmediate_operand" "f ,f,xm")))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387 && flag_unsafe_math_optimizations"
 {
   switch (which_alternative)
 ;; Yes, this one doesn't depend on flag_unsafe_math_optimizations,
 ;; because nothing we do here is unsafe.
 (define_insn "*truncdfsf_fast_sse"
-  [(set (match_operand:SF 0 "nonimmediate_operand"   "=Y")
+  [(set (match_operand:SF 0 "nonimmediate_operand"   "=x")
         (float_truncate:SF
-          (match_operand:DF 1 "nonimmediate_operand" "Ym")))]
+          (match_operand:DF 1 "nonimmediate_operand" "xm")))]
   "TARGET_SSE2 && TARGET_SSE_MATH"
   "cvtsd2ss\t{%1, %0|%0, %1}"
   [(set_attr "type" "ssecvt")
    (set_attr "mode" "SF")])
 
 (define_insn "*truncdfsf_mixed"
-  [(set (match_operand:SF 0 "nonimmediate_operand"   "=m,?fx*r,Y")
+  [(set (match_operand:SF 0 "nonimmediate_operand"   "=m,?fx*r,Y2")
        (float_truncate:SF
-         (match_operand:DF 1 "nonimmediate_operand" "f ,f    ,Ym")))
+         (match_operand:DF 1 "nonimmediate_operand" "f ,f    ,Y2m")))
    (clobber (match_operand:SF 2 "memory_operand"     "=X,m    ,X"))]
   "TARGET_MIX_SSE_I387"
 {
 })
 
 (define_insn "*truncxfdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r,?Y")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r,?Y2*x")
        (float_truncate:DF
         (match_operand:XF 1 "register_operand" "f,f,f,f")))
    (clobber (match_operand:DF 2 "memory_operand" "=X,m,m,m"))]
    }
 })
 
+;; Unsigned conversion to SImode.
+
+(define_expand "fixuns_trunc<mode>si2"
+  [(parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (unsigned_fix:SI
+           (match_operand:SSEMODEF 1 "nonimmediate_operand" "")))
+     (use (match_dup 2))
+     (clobber (match_scratch:<ssevecmode> 3 ""))
+     (clobber (match_scratch:<ssevecmode> 4 ""))])]
+  "!TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH && !optimize_size"
+{
+  enum machine_mode mode = <MODE>mode;
+  enum machine_mode vecmode = <ssevecmode>mode;
+  REAL_VALUE_TYPE TWO31r;
+  rtx two31;
+
+  real_ldexp (&TWO31r, &dconst1, 31);
+  two31 = const_double_from_real_value (TWO31r, mode);
+  two31 = ix86_build_const_vector (mode, true, two31);
+  operands[2] = force_reg (vecmode, two31);
+})
+
+(define_insn_and_split "*fixuns_trunc<mode>_1"
+  [(set (match_operand:SI 0 "register_operand" "=&x,&x")
+       (unsigned_fix:SI
+         (match_operand:SSEMODEF 3 "nonimmediate_operand" "xm,xm")))
+   (use (match_operand:<ssevecmode> 4  "nonimmediate_operand" "m,x"))
+   (clobber (match_scratch:<ssevecmode> 1 "=x,&x"))
+   (clobber (match_scratch:<ssevecmode> 2 "=x,x"))]
+  "!TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH && !optimize_size"
+  "#"
+  "&& reload_completed"
+  [(const_int 0)]
+{
+  ix86_split_convert_uns_si_sse (operands);
+  DONE;
+})
+
+;; Unsigned conversion to HImode.
+;; Without these patterns, we'll try the unsigned SI conversion which
+;; is complex for SSE, rather than the signed SI conversion, which isn't.
+
+(define_expand "fixuns_truncsfhi2"
+  [(set (match_dup 2)
+       (fix:SI (match_operand:SF 1 "nonimmediate_operand" "")))
+   (set (match_operand:HI 0 "nonimmediate_operand" "")
+       (subreg:HI (match_dup 2) 0))]
+  "TARGET_SSE_MATH"
+  "operands[2] = gen_reg_rtx (SImode);")
+
+(define_expand "fixuns_truncdfhi2"
+  [(set (match_dup 2)
+       (fix:SI (match_operand:DF 1 "nonimmediate_operand" "")))
+   (set (match_operand:HI 0 "nonimmediate_operand" "")
+       (subreg:HI (match_dup 2) 0))]
+  "TARGET_SSE_MATH && TARGET_SSE2"
+  "operands[2] = gen_reg_rtx (SImode);")
+
 ;; When SSE is available, it is always faster to use it!
 (define_insn "fix_truncsfdi_sse"
   [(set (match_operand:DI 0 "register_operand" "=r,r")
 
 (define_insn "fix_truncdfdi_sse"
   [(set (match_operand:DI 0 "register_operand" "=r,r")
-       (fix:DI (match_operand:DF 1 "nonimmediate_operand" "Y,Ym")))]
+       (fix:DI (match_operand:DF 1 "nonimmediate_operand" "x,xm")))]
   "TARGET_64BIT && TARGET_SSE2 && (!TARGET_FISTTP || TARGET_SSE_MATH)"
   "cvttsd2si{q}\t{%1, %0|%0, %1}"
   [(set_attr "type" "sseicvt")
 
 (define_insn "fix_truncdfsi_sse"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
-       (fix:SI (match_operand:DF 1 "nonimmediate_operand" "Y,Ym")))]
+       (fix:SI (match_operand:DF 1 "nonimmediate_operand" "x,xm")))]
   "TARGET_SSE2 && (!TARGET_FISTTP || TARGET_SSE_MATH)"
   "cvttsd2si\t{%1, %0|%0, %1}"
   [(set_attr "type" "sseicvt")
   "")
 
 (define_insn "*floatsidf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y")
+  [(set (match_operand:DF 0 "register_operand" "=f,?f,x,x")
        (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
    (set_attr "fp_int_src" "true")])
 
 (define_insn "*floatsidf2_sse"
-  [(set (match_operand:DF 0 "register_operand" "=Y,Y")
+  [(set (match_operand:DF 0 "register_operand" "=x,x")
        (float:DF (match_operand:SI 1 "nonimmediate_operand" "r,mr")))]
   "TARGET_SSE2 && TARGET_SSE_MATH"
   "cvtsi2sd\t{%1, %0|%0, %1}"
 (define_expand "floatdidf2"
   [(set (match_operand:DF 0 "register_operand" "")
        (float:DF (match_operand:DI 1 "nonimmediate_operand" "")))]
-  "TARGET_80387 || (TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH)"
-  "")
+  "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)"
+{
+  if (!TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH)
+    {
+      ix86_expand_convert_sign_didf_sse (operands[0], operands[1]);
+      DONE;
+    }
+})
 
 (define_insn "*floatdidf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y")
+  [(set (match_operand:DF 0 "register_operand" "=f,?f,x,x")
        (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_64BIT && TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
    (set_attr "fp_int_src" "true")])
 
 (define_insn "*floatdidf2_sse"
-  [(set (match_operand:DF 0 "register_operand" "=Y,Y")
+  [(set (match_operand:DF 0 "register_operand" "=x,x")
        (float:DF (match_operand:DI 1 "nonimmediate_operand" "r,mr")))]
   "TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH"
   "cvtsi2sd{q}\t{%1, %0|%0, %1}"
 
 (define_expand "floatunssisf2"
   [(use (match_operand:SF 0 "register_operand" ""))
-   (use (match_operand:SI 1 "register_operand" ""))]
-  "!TARGET_64BIT && TARGET_SSE_MATH"
-  "x86_emit_floatuns (operands); DONE;")
+   (use (match_operand:SI 1 "nonimmediate_operand" ""))]
+  "!TARGET_64BIT"
+{
+  if (TARGET_SSE_MATH && TARGET_SSE2)
+    ix86_expand_convert_uns_sisf_sse (operands[0], operands[1]);
+  else
+    x86_emit_floatuns (operands);
+  DONE;
+})
+
+(define_expand "floatunssidf2"
+  [(use (match_operand:DF 0 "register_operand" ""))
+   (use (match_operand:SI 1 "nonimmediate_operand" ""))]
+  "!TARGET_64BIT && TARGET_SSE_MATH && TARGET_SSE2"
+  "ix86_expand_convert_uns_sidf_sse (operands[0], operands[1]); DONE;")
 
 (define_expand "floatunsdisf2"
   [(use (match_operand:SF 0 "register_operand" ""))
-   (use (match_operand:DI 1 "register_operand" ""))]
+   (use (match_operand:DI 1 "nonimmediate_operand" ""))]
   "TARGET_64BIT && TARGET_SSE_MATH"
   "x86_emit_floatuns (operands); DONE;")
 
 (define_expand "floatunsdidf2"
   [(use (match_operand:DF 0 "register_operand" ""))
-   (use (match_operand:DI 1 "register_operand" ""))]
-  "TARGET_64BIT && TARGET_SSE2 && TARGET_SSE_MATH"
-  "x86_emit_floatuns (operands); DONE;")
+   (use (match_operand:DI 1 "nonimmediate_operand" ""))]
+  "TARGET_SSE_MATH && TARGET_SSE2
+   && (TARGET_64BIT || TARGET_KEEPS_VECTOR_ALIGNED_STACK)"
+{
+  if (TARGET_64BIT)
+    x86_emit_floatuns (operands);
+  else
+    ix86_expand_convert_uns_didf_sse (operands[0], operands[1]);
+  DONE;
+})
 \f
 ;; SSE extract/set expanders
 
   "ix86_expand_fp_absneg_operator (ABS, DFmode, operands); DONE;")
 
 (define_insn "*absnegdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand"    "=Y,Y,f,rm")
+  [(set (match_operand:DF 0 "nonimmediate_operand"    "=x,x,f,rm")
        (match_operator:DF 3 "absneg_operator"
-         [(match_operand:DF 1 "nonimmediate_operand" "0 ,Y,0,0")]))
-   (use (match_operand:V2DF 2 "nonimmediate_operand"  "Ym,0,X,X"))
+         [(match_operand:DF 1 "nonimmediate_operand" "0 ,x,0,0")]))
+   (use (match_operand:V2DF 2 "nonimmediate_operand"  "xm,0,X,X"))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387
    && ix86_unary_operator_ok (GET_CODE (operands[3]), DFmode, operands)"
   "#")
 
 (define_insn "*absnegdf2_sse"
-  [(set (match_operand:DF 0 "nonimmediate_operand"    "=Y,Y,rm")
+  [(set (match_operand:DF 0 "nonimmediate_operand"    "=x,x,rm")
        (match_operator:DF 3 "absneg_operator"
-         [(match_operand:DF 1 "nonimmediate_operand" "0 ,Y,0 ")]))
-   (use (match_operand:V2DF 2 "nonimmediate_operand"  "Ym,0,X "))
+         [(match_operand:DF 1 "nonimmediate_operand" "0 ,x,0 ")]))
+   (use (match_operand:V2DF 2 "nonimmediate_operand"  "xm,0,X "))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_SSE2 && TARGET_SSE_MATH
    && ix86_unary_operator_ok (GET_CODE (operands[3]), DFmode, operands)"
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
       gcc_assert (rtx_equal_p (operands[0], operands[1]));
-      return "add{q}\t{%0, %0|%0, %0}";
+      return "add{q}\t%0, %0";
 
     case TYPE_LEA:
       gcc_assert (CONST_INT_P (operands[2]));
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{q}\t{%0, %0|%0, %0}";
+      return "add{q}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{q}\t{%0, %0|%0, %0}";
+      return "add{q}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
       gcc_assert (rtx_equal_p (operands[0], operands[1]));
-      return "add{l}\t{%0, %0|%0, %0}";
+      return "add{l}\t%0, %0";
 
     case TYPE_LEA:
       return "#";
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{l}\t{%k0, %k0|%k0, %k0}";
+      return "add{l}\t%k0, %k0";
 
     case TYPE_LEA:
       return "#";
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{l}\t{%0, %0|%0, %0}";
+      return "add{l}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{l}\t{%0, %0|%0, %0}";
+      return "add{l}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{l}\t{%k0, %k0|%k0, %k0}";
+      return "add{l}\t%k0, %k0";
 
     default:
       if (REG_P (operands[2]))
       return "#";
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{w}\t{%0, %0|%0, %0}";
+      return "add{w}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{w}\t{%0, %0|%0, %0}";
+      return "add{w}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{w}\t{%0, %0|%0, %0}";
+      return "add{w}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{w}\t{%0, %0|%0, %0}";
+      return "add{w}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
       if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1]))
-        return "add{l}\t{%k0, %k0|%k0, %k0}";
+        return "add{l}\t%k0, %k0";
       else
-        return "add{b}\t{%0, %0|%0, %0}";
+        return "add{b}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
       if (REG_P (operands[1]) && !ANY_QI_REG_P (operands[1]))
-        return "add{l}\t{%k0, %k0|%k0, %k0}";
+        return "add{l}\t%k0, %k0";
       else
-        return "add{b}\t{%0, %0|%0, %0}";
+        return "add{b}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{b}\t{%0, %0|%0, %0}";
+      return "add{b}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
     {
     case TYPE_ALU:
       gcc_assert (operands[2] == const1_rtx);
-      return "add{b}\t{%0, %0|%0, %0}";
+      return "add{b}\t%0, %0";
 
     default:
       if (REG_P (operands[2]))
   [(set_attr "type" "rotate")
    (set_attr "mode" "HI")])
 
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+       (rotate:HI (match_dup 0) (const_int 8)))
+  (clobber (reg:CC FLAGS_REG))]
+ "reload_completed"
+ [(parallel [(set (strict_low_part (match_dup 0))
+                 (bswap:HI (match_dup 0)))
+            (clobber (reg:CC FLAGS_REG))])]
+ "")
+
 (define_expand "rotlqi3"
   [(set (match_operand:QI 0 "nonimmediate_operand" "")
        (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "")
        (const_string "2")
        (const_string "*")))])
 
-(define_insn "*rotrhi3"
+(define_insn "*rotrhi3_1"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
        (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
                     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   [(set_attr "type" "rotate")
    (set_attr "mode" "HI")])
 
+(define_split
+ [(set (match_operand:HI 0 "register_operand" "")
+       (rotatert:HI (match_dup 0) (const_int 8)))
+  (clobber (reg:CC FLAGS_REG))]
+ "reload_completed"
+ [(parallel [(set (strict_low_part (match_dup 0))
+                 (bswap:HI (match_dup 0)))
+            (clobber (reg:CC FLAGS_REG))])]
+ "")
+
 (define_expand "rotrqi3"
   [(set (match_operand:QI 0 "nonimmediate_operand" "")
        (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "")
    (set_attr "mode" "SF")])
 
 (define_insn "*sse_setccdf"
-  [(set (match_operand:DF 0 "register_operand" "=Y")
+  [(set (match_operand:DF 0 "register_operand" "=x")
        (match_operator:DF 1 "sse_comparison_operator"
          [(match_operand:DF 2 "register_operand" "0")
-          (match_operand:DF 3 "nonimmediate_operand" "Ym")]))]
+          (match_operand:DF 3 "nonimmediate_operand" "xm")]))]
   "TARGET_SSE2"
   "cmp%D1sd\t{%3, %0|%0, %3}"
   [(set_attr "type" "ssecmp")
    (set_attr "type" "bitmanip")
    (set_attr "mode" "SI")])
 
-(define_insn "bswapsi2"
+(define_expand "bswapsi2"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (bswap:SI (match_operand:SI 1 "register_operand" "")))]
+  ""
+{
+  if (!TARGET_BSWAP)
+    {
+      rtx x = operands[0];
+
+      emit_move_insn (x, operands[1]);
+      emit_insn (gen_bswaphi_lowpart (gen_lowpart (HImode, x)));
+      emit_insn (gen_rotlsi3 (x, x, GEN_INT (16)));
+      emit_insn (gen_bswaphi_lowpart (gen_lowpart (HImode, x)));
+      DONE;
+    }
+})
+
+(define_insn "*bswapsi_1"
   [(set (match_operand:SI 0 "register_operand" "=r")
-       (bswap:SI (match_operand:SI 1 "register_operand" "0")))
-   (clobber (reg:CC FLAGS_REG))]
+       (bswap:SI (match_operand:SI 1 "register_operand" "0")))]
   "TARGET_BSWAP"
-  "bswap\t%k0"
+  "bswap\t%0"
   [(set_attr "prefix_0f" "1")
    (set_attr "length" "2")])
 
+(define_insn "*bswaphi_lowpart_1"
+  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+Q,r"))
+       (bswap:HI (match_dup 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_USE_XCHGB || optimize_size"
+  "@
+    xchg{b}\t{%h0, %b0|%b0, %h0}
+    rol{w}\t{$8, %0|%0, 8}"
+  [(set_attr "length" "2,4")
+   (set_attr "mode" "QI,HI")])
+
+(define_insn "bswaphi_lowpart"
+  [(set (strict_low_part (match_operand:HI 0 "register_operand" "+r"))
+       (bswap:HI (match_dup 0)))
+   (clobber (reg:CC FLAGS_REG))]
+  ""
+  "rol{w}\t{$8, %0|%0, 8}"
+  [(set_attr "length" "4")
+   (set_attr "mode" "HI")])
+
 (define_insn "bswapdi2"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (bswap:DI (match_operand:DI 1 "register_operand" "0")))
-   (clobber (reg:CC FLAGS_REG))]
-  "TARGET_64BIT && TARGET_BSWAP"
+       (bswap:DI (match_operand:DI 1 "register_operand" "0")))]
+  "TARGET_64BIT"
   "bswap\t%0"
   [(set_attr "prefix_0f" "1")
    (set_attr "length" "3")])
   [(set_attr "prefix_rep" "1")
    (set_attr "type" "bitmanip")
    (set_attr "mode" "HI")])
+
+(define_expand "paritydi2"
+  [(set (match_operand:DI 0 "register_operand" "")
+       (parity:DI (match_operand:DI 1 "nonimmediate_operand" "")))]
+  "! TARGET_POPCNT"
+{
+  rtx scratch = gen_reg_rtx (QImode);
+  rtx cond;
+
+  emit_insn (gen_paritydi2_cmp (NULL_RTX, NULL_RTX,
+                               NULL_RTX, operands[1]));
+
+  cond = gen_rtx_fmt_ee (ORDERED, QImode,
+                        gen_rtx_REG (CCmode, FLAGS_REG),
+                        const0_rtx);
+  emit_insn (gen_rtx_SET (VOIDmode, scratch, cond));
+
+  if (TARGET_64BIT)
+    emit_insn (gen_zero_extendqidi2 (operands[0], scratch));
+  else
+    {
+      rtx tmp = gen_reg_rtx (SImode);
+
+      emit_insn (gen_zero_extendqisi2 (tmp, scratch));
+      emit_insn (gen_zero_extendsidi2 (operands[0], tmp));
+    }
+  DONE;
+})
+
+(define_insn_and_split "paritydi2_cmp"
+  [(set (reg:CC FLAGS_REG)
+       (parity:CC (match_operand:DI 3 "nonimmediate_operand" "0,m")))
+   (clobber (match_scratch:DI 0 "=r,X"))
+   (clobber (match_scratch:SI 1 "=r,r"))
+   (clobber (match_scratch:HI 2 "=Q,Q"))]
+  "! TARGET_POPCNT"
+  "#"
+  "&& reload_completed"
+  [(parallel
+     [(set (match_dup 1)
+          (xor:SI (match_dup 1) (match_dup 4)))
+      (clobber (reg:CC FLAGS_REG))])
+   (parallel
+     [(set (reg:CC FLAGS_REG)
+          (parity:CC (match_dup 1)))
+      (clobber (match_dup 1))
+      (clobber (match_dup 2))])]
+{
+  operands[4] = gen_lowpart (SImode, operands[3]);
+
+  if (MEM_P (operands[3]))
+    emit_move_insn (operands[1], gen_highpart (SImode, operands[3]));
+  else if (! TARGET_64BIT)
+    operands[1] = gen_highpart (SImode, operands[3]);
+  else
+    {
+      emit_move_insn (operands[1], gen_lowpart (SImode, operands[3]));
+      emit_insn (gen_lshrdi3 (operands[3], operands[3], GEN_INT (32)));
+    }
+})
+
+(define_expand "paritysi2"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (parity:SI (match_operand:SI 1 "nonimmediate_operand" "")))]
+  "! TARGET_POPCNT"
+{
+  rtx scratch = gen_reg_rtx (QImode);
+  rtx cond;
+
+  emit_insn (gen_paritysi2_cmp (NULL_RTX, NULL_RTX, operands[1]));
+
+  cond = gen_rtx_fmt_ee (ORDERED, QImode,
+                        gen_rtx_REG (CCmode, FLAGS_REG),
+                        const0_rtx);
+  emit_insn (gen_rtx_SET (VOIDmode, scratch, cond));
+
+  emit_insn (gen_zero_extendqisi2 (operands[0], scratch));
+  DONE;
+})
+
+(define_insn_and_split "paritysi2_cmp"
+  [(set (reg:CC FLAGS_REG)
+       (parity:CC (match_operand:SI 2 "nonimmediate_operand" "0,m")))
+   (clobber (match_scratch:SI 0 "=r,X"))
+   (clobber (match_scratch:HI 1 "=Q,Q"))]
+  "! TARGET_POPCNT"
+  "#"
+  "&& reload_completed"
+  [(parallel
+     [(set (match_dup 1)
+          (xor:HI (match_dup 1) (match_dup 3)))
+      (clobber (reg:CC FLAGS_REG))])
+   (parallel
+     [(set (reg:CC FLAGS_REG)
+          (parity:CC (match_dup 1)))
+      (clobber (match_dup 1))])]
+{
+  operands[3] = gen_lowpart (HImode, operands[2]);
+
+  if (MEM_P (operands[2]))
+    emit_move_insn (operands[1], gen_highpart (HImode, operands[2]));
+  else
+    {
+      emit_move_insn (operands[1], gen_lowpart (HImode, operands[2]));
+      emit_insn (gen_lshrsi3 (operands[2], operands[2], GEN_INT (16)));
+    }
+})
+
+(define_insn "*parityhi2_cmp"
+  [(set (reg:CC FLAGS_REG)
+       (parity:CC (match_operand:HI 1 "register_operand" "0")))
+   (clobber (match_scratch:HI 0 "=Q"))]
+  "! TARGET_POPCNT"
+  "xor{b}\t{%h0, %b0|%b0, %h0}"
+  [(set_attr "length" "2")
+   (set_attr "mode" "HI")])
+
+(define_insn "*parityqi2_cmp"
+  [(set (reg:CC FLAGS_REG)
+       (parity:CC (match_operand:QI 0 "register_operand" "q")))]
+  "! TARGET_POPCNT"
+  "test{b}\t%0, %0"
+  [(set_attr "length" "2")
+   (set_attr "mode" "QI")])
 \f
 ;; Thread-local storage patterns for ELF.
 ;;
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*fop_df_comm_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f,Y")
+  [(set (match_operand:DF 0 "register_operand" "=f,x")
        (match_operator:DF 3 "binary_fp_operator"
-                       [(match_operand:DF 1 "nonimmediate_operand" "%0,0")
-                        (match_operand:DF 2 "nonimmediate_operand" "fm,Ym")]))]
+         [(match_operand:DF 1 "nonimmediate_operand" "%0,0")
+          (match_operand:DF 2 "nonimmediate_operand" "fm,xm")]))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387
    && COMMUTATIVE_ARITH_P (operands[3])
    && !(MEM_P (operands[1]) && MEM_P (operands[2]))"
    (set_attr "mode" "DF")])
 
 (define_insn "*fop_df_comm_sse"
-  [(set (match_operand:DF 0 "register_operand" "=Y")
+  [(set (match_operand:DF 0 "register_operand" "=x")
        (match_operator:DF 3 "binary_fp_operator"
-                       [(match_operand:DF 1 "nonimmediate_operand" "%0")
-                        (match_operand:DF 2 "nonimmediate_operand" "Ym")]))]
+         [(match_operand:DF 1 "nonimmediate_operand" "%0")
+          (match_operand:DF 2 "nonimmediate_operand" "xm")]))]
   "TARGET_SSE2 && TARGET_SSE_MATH
    && COMMUTATIVE_ARITH_P (operands[3])
    && !(MEM_P (operands[1]) && MEM_P (operands[2]))"
    (set_attr "mode" "DF")])
 
 (define_insn "*fop_df_1_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f,f,Y")
+  [(set (match_operand:DF 0 "register_operand" "=f,f,x")
        (match_operator:DF 3 "binary_fp_operator"
-                       [(match_operand:DF 1 "nonimmediate_operand" "0,fm,0")
-                        (match_operand:DF 2 "nonimmediate_operand" "fm,0,Ym")]))]
+         [(match_operand:DF 1 "nonimmediate_operand" "0,fm,0")
+          (match_operand:DF 2 "nonimmediate_operand" "fm,0,xm")]))]
   "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387
    && !COMMUTATIVE_ARITH_P (operands[3])
    && !(MEM_P (operands[1]) && MEM_P (operands[2]))"
    (set_attr "mode" "DF")])
 
 (define_insn "*fop_df_1_sse"
-  [(set (match_operand:DF 0 "register_operand" "=Y")
+  [(set (match_operand:DF 0 "register_operand" "=x")
        (match_operator:DF 3 "binary_fp_operator"
-                       [(match_operand:DF 1 "register_operand" "0")
-                        (match_operand:DF 2 "nonimmediate_operand" "Ym")]))]
+         [(match_operand:DF 1 "register_operand" "0")
+          (match_operand:DF 2 "nonimmediate_operand" "xm")]))]
   "TARGET_SSE2 && TARGET_SSE_MATH
    && !COMMUTATIVE_ARITH_P (operands[3])"
   "* return output_387_binary_op (insn, operands);"
                               (match_dup 2)))
    (set (match_dup 4) (unspec:XF [(match_dup 3)] UNSPEC_FRNDINT))
    (set (match_dup 5) (minus:XF (match_dup 3) (match_dup 4)))
+   (set (match_dup 9) (float_extend:XF (match_dup 13)))
    (set (match_dup 6) (unspec:XF [(match_dup 5)] UNSPEC_F2XM1))
    (parallel [(set (match_dup 7)
                   (unspec:XF [(match_dup 6) (match_dup 4)]
                              UNSPEC_FSCALE_FRACT))
-                  (set (match_dup 8)
+             (set (match_dup 8)
                   (unspec:XF [(match_dup 6) (match_dup 4)]
                              UNSPEC_FSCALE_EXP))])
    (parallel [(set (match_dup 10)
              (set (match_dup 11)
                   (unspec:XF [(match_dup 9) (match_dup 8)]
                              UNSPEC_FSCALE_EXP))])
-   (set (match_dup 12) (minus:XF (match_dup 10) (match_dup 9)))
+   (set (match_dup 12) (minus:XF (match_dup 10)
+                                (float_extend:XF (match_dup 13))))
    (set (match_operand:XF 0 "register_operand" "")
        (plus:XF (match_dup 12) (match_dup 7)))]
   "TARGET_USE_FANCY_MATH_387
 
   for (i = 2; i < 13; i++)
     operands[i] = gen_reg_rtx (XFmode);
+
+  operands[13]
+    = validize_mem (force_const_mem (SFmode, CONST1_RTX (SFmode))); /* fld1 */
+
   emit_move_insn (operands[2], standard_80387_constant_rtx (5)); /* fldl2e */
-  emit_move_insn (operands[9], CONST1_RTX (XFmode));  /* fld1 */
 })
 
 (define_expand "expm1<mode>2"
   emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
   DONE;
 })
+
+(define_expand "scalbxf3"
+  [(parallel [(set (match_operand:XF 0 " register_operand" "")
+                  (unspec:XF [(match_operand:XF 1 "register_operand" "")
+                              (match_operand:XF 2 "register_operand" "")]
+                             UNSPEC_FSCALE_FRACT))
+             (set (match_dup 3)
+                  (unspec:XF [(match_dup 1) (match_dup 2)]
+                             UNSPEC_FSCALE_EXP))])]
+  "TARGET_USE_FANCY_MATH_387
+   && flag_unsafe_math_optimizations && !optimize_size"
+{
+  operands[3] = gen_reg_rtx (XFmode);
+})
+
+(define_expand "scalb<mode>3"
+  [(use (match_operand:X87MODEF12 0 "register_operand" ""))
+   (use (match_operand:X87MODEF12 1 "general_operand" ""))
+   (use (match_operand:X87MODEF12 2 "register_operand" ""))]
+ "TARGET_USE_FANCY_MATH_387
+   && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
+       || TARGET_MIX_SSE_I387)
+   && flag_unsafe_math_optimizations && !optimize_size"
+{
+  rtx op0 = gen_reg_rtx (XFmode);
+  rtx op1 = gen_reg_rtx (XFmode);
+  rtx op2 = gen_reg_rtx (XFmode);
+
+  emit_insn (gen_extend<mode>xf2 (op1, operands[1]));
+  emit_insn (gen_extend<mode>xf2 (op2, operands[2]));
+  emit_insn (gen_scalbxf3 (op0, op1, op2));
+  emit_insn (gen_truncxf<mode>2_i387_noop (operands[0], op0));
+  DONE;
+})
 \f
 
 (define_insn "frndintxf2"