OSDN Git Service

2006-10-21 H.J. Lu <hongjiu.lu@intel.com>
[pf3gnuchains/gcc-fork.git] / gcc / config / i386 / i386.md
index d533408..10b5eb8 100644 (file)
@@ -1,6 +1,6 @@
 ;; GCC machine description for IA-32 and x86-64.
 ;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000,
-;; 2001, 2002, 2003, 2004, 2005
+;; 2001, 2002, 2003, 2004, 2005, 2006
 ;; Free Software Foundation, Inc.
 ;; Mostly by William Schelter.
 ;; x86_64 support added by Jan Hubicka
    (UNSPEC_STACK_ALLOC         11)
    (UNSPEC_SET_GOT             12)
    (UNSPEC_SSE_PROLOGUE_SAVE   13)
+   (UNSPEC_REG_SAVE            14)
+   (UNSPEC_DEF_CFA             15)
 
    ; TLS support
-   (UNSPEC_TP                  15)
-   (UNSPEC_TLS_GD              16)
-   (UNSPEC_TLS_LD_BASE         17)
+   (UNSPEC_TP                  16)
+   (UNSPEC_TLS_GD              17)
+   (UNSPEC_TLS_LD_BASE         18)
+   (UNSPEC_TLSDESC             19)
 
    ; Other random patterns
    (UNSPEC_SCAS                        20)
@@ -81,6 +84,7 @@
    (UNSPEC_FLDCW               25)
    (UNSPEC_REP                 26)
    (UNSPEC_EH_RETURN           27)
+   (UNSPEC_LD_MPIC             28)     ; load_macho_picbase
 
    ; For SSE/MMX support:
    (UNSPEC_FIX_NOTRUNC         30)
    (UNSPEC_MFENCE              44)
    (UNSPEC_LFENCE              45)
    (UNSPEC_PSADBW              46)
-   (UNSPEC_LDQQU               47)
+   (UNSPEC_LDDQU               47)
 
    ; Generic math support
    (UNSPEC_COPYSIGN            50)
 \f
 ;; Processor type.  This attribute must exactly match the processor_type
 ;; enumeration in i386.h.
-(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6,athlon,pentium4,k8,nocona"
+(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6,athlon,pentium4,k8,nocona,generic32,generic64"
   (const (symbol_ref "ix86_tune")))
 
 ;; A basic instruction type.  Refinements due to arguments to be
              (not (match_operand 0 "memory_operand" "")))
           (const_int 0)
         (and (eq_attr "type" "imov")
-             (and (match_operand 0 "register_operand" "")
-                  (match_operand 1 "immediate_operand" "")))
+             (ior (and (match_operand 0 "register_operand" "")
+                       (match_operand 1 "immediate_operand" ""))
+                  (ior (and (match_operand 0 "ax_reg_operand" "")
+                            (match_operand 1 "memory_displacement_only_operand" ""))
+                       (and (match_operand 0 "memory_displacement_only_operand" "")
+                            (match_operand 1 "ax_reg_operand" "")))))
           (const_int 0)
         (and (eq_attr "type" "call")
              (match_operand 0 "constant_call_address_operand" ""))
 (include "athlon.md")
 
 \f
-;; Operand and operator predicates
+;; Operand and operator predicates and constraints
 
 (include "predicates.md")
+(include "constraints.md")
 
 \f
 ;; Compare instructions.
 
 (define_insn "*cmpfp_i_mixed"
   [(set (reg:CCFP FLAGS_REG)
-       (compare:CCFP (match_operand 0 "register_operand" "f#x,x#f")
-                     (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))]
+       (compare:CCFP (match_operand 0 "register_operand" "f,x")
+                     (match_operand 1 "nonimmediate_operand" "f,xm")))]
   "TARGET_MIX_SSE_I387
    && SSE_FLOAT_MODE_P (GET_MODE (operands[0]))
    && GET_MODE (operands[0]) == GET_MODE (operands[1])"
 
 (define_insn "*cmpfp_iu_mixed"
   [(set (reg:CCFPU FLAGS_REG)
-       (compare:CCFPU (match_operand 0 "register_operand" "f#x,x#f")
-                      (match_operand 1 "nonimmediate_operand" "f#x,xm#f")))]
+       (compare:CCFPU (match_operand 0 "register_operand" "f,x")
+                      (match_operand 1 "nonimmediate_operand" "f,xm")))]
   "TARGET_MIX_SSE_I387
    && SSE_FLOAT_MODE_P (GET_MODE (operands[0]))
    && GET_MODE (operands[0]) == GET_MODE (operands[1])"
 }
   [(set (attr "type")
      (cond [(eq_attr "alternative" "2")
-             (const_string "mmx")
+             (const_string "mmxadd")
            (eq_attr "alternative" "3,4,5")
              (const_string "mmxmov")
            (eq_attr "alternative" "6")
              (const_string "sselog1")
            (eq_attr "alternative" "7,8,9,10,11")
              (const_string "ssemov")
-           (and (ne (symbol_ref "flag_pic") (const_int 0))
-                (match_operand:SI 1 "symbolic_operand" ""))
+           (match_operand:DI 1 "pic_32bit_operand" "")
              (const_string "lea")
           ]
           (const_string "imov")))
   "ix86_expand_move (HImode, operands); DONE;")
 
 (define_insn "*pushhi2"
-  [(set (match_operand:HI 0 "push_operand" "=<,<")
-       (match_operand:HI 1 "general_no_elim_operand" "n,r*m"))]
+  [(set (match_operand:HI 0 "push_operand" "=X")
+       (match_operand:HI 1 "nonmemory_no_elim_operand" "rn"))]
   "!TARGET_64BIT"
-  "@
-   push{w}\t{|WORD PTR }%1
-   push{w}\t%1"
+  "push{l}\t%k1"
   [(set_attr "type" "push")
-   (set_attr "mode" "HI")])
+   (set_attr "mode" "SI")])
 
 ;; For 64BIT abi we always round up to 8 bytes.
 (define_insn "*pushhi2_rex64"
   "TARGET_64BIT"
   "push{q}\t%q1"
   [(set_attr "type" "push")
-   (set_attr "mode" "QI")])
+   (set_attr "mode" "DI")])
 
 (define_insn "*movhi_1"
   [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,m")
   "ix86_expand_move (QImode, operands); DONE;")
 
 ;; emit_push_insn when it calls move_by_pieces requires an insn to
-;; "push a byte".  But actually we use pushw, which has the effect
-;; of rounding the amount pushed up to a halfword.
+;; "push a byte".  But actually we use pushl, which has the effect
+;; of rounding the amount pushed up to a word.
 
 (define_insn "*pushqi2"
-  [(set (match_operand:QI 0 "push_operand" "=X,X")
-       (match_operand:QI 1 "nonmemory_no_elim_operand" "n,r"))]
+  [(set (match_operand:QI 0 "push_operand" "=X")
+       (match_operand:QI 1 "nonmemory_no_elim_operand" "rn"))]
   "!TARGET_64BIT"
-  "@
-   push{w}\t{|word ptr }%1
-   push{w}\t%w1"
+  "push{l}\t%k1"
   [(set_attr "type" "push")
-   (set_attr "mode" "HI")])
+   (set_attr "mode" "SI")])
 
 ;; For 64BIT abi we always round up to 8 bytes.
 (define_insn "*pushqi2_rex64"
   "TARGET_64BIT"
   "push{q}\t%q1"
   [(set_attr "type" "push")
-   (set_attr "mode" "QI")])
+   (set_attr "mode" "DI")])
 
 ;; Situation is quite tricky about when to choose full sized (SImode) move
 ;; over QImode moves.  For Q_REG -> Q_REG move we use full size only for
 ;; partial register stall can be caused there.  Then we use movzx.
 (define_insn "*movqi_1"
   [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q ,q ,r,r ,?r,m")
-       (match_operand:QI 1 "general_operand"      " q,qn,qm,q,rn,,qn"))]
+       (match_operand:QI 1 "general_operand"      " q,qn,qm,q,rn,qm,qn"))]
   "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
 {
   switch (get_attr_type (insn))
     }
 }
   [(set (attr "type")
-     (cond [(eq_attr "alternative" "5")
+     (cond [(and (eq_attr "alternative" "5")
+                (not (match_operand:QI 1 "aligned_operand" "")))
              (const_string "imovx")
            (ne (symbol_ref "optimize_size") (const_int 0))
              (const_string "imov")
                      (eq (symbol_ref "TARGET_QIMODE_MATH")
                          (const_int 0))))
              (const_string "imov")
-           (eq_attr "alternative" "3")
+           (eq_attr "alternative" "3,5")
              (const_string "imovx")
            (and (ne (symbol_ref "TARGET_MOVX")
                     (const_int 0))
               (const_string "SI")
             (and (eq_attr "type" "imov")
                  (and (eq_attr "alternative" "0,1")
-                      (ne (symbol_ref "TARGET_PARTIAL_REG_DEPENDENCY")
-                          (const_int 0))))
+                      (and (ne (symbol_ref "TARGET_PARTIAL_REG_DEPENDENCY")
+                               (const_int 0))
+                           (and (eq (symbol_ref "optimize_size")
+                                    (const_int 0))
+                                (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
+                                    (const_int 0))))))
               (const_string "SI")
             ;; Avoid partial register stalls when not using QImode arithmetic
             (and (eq_attr "type" "imov")
 (define_split
   [(set (match_operand:DI 0 "push_operand" "")
         (match_operand:DI 1 "immediate_operand" ""))]
-  "TARGET_64BIT && (flag_peephole2 ? flow2_completed : reload_completed)
+  "TARGET_64BIT && ((optimize > 0 && flag_peephole2)
+                   ? flow2_completed : reload_completed)
    && !symbolic_operand (operands[1], DImode)
    && !x86_64_immediate_operand (operands[1], DImode)"
   [(set (match_dup 0) (match_dup 1))
 }
   [(set (attr "type")
      (cond [(eq_attr "alternative" "5")
-             (const_string "mmx")
+             (const_string "mmxadd")
            (eq_attr "alternative" "6,7,8")
              (const_string "mmxmov")
            (eq_attr "alternative" "9")
              (const_string "ssecvt")
            (eq_attr "alternative" "4")
              (const_string "multi")
-           (and (ne (symbol_ref "flag_pic") (const_int 0))
-                (match_operand:DI 1 "symbolic_operand" ""))
+           (match_operand:DI 1 "pic_32bit_operand" "")
              (const_string "lea")
           ]
           (const_string "imov")))
 (define_split
   [(set (match_operand:DI 0 "memory_operand" "")
         (match_operand:DI 1 "immediate_operand" ""))]
-  "TARGET_64BIT && (flag_peephole2 ? flow2_completed : reload_completed)
+  "TARGET_64BIT && ((optimize > 0 && flag_peephole2)
+                   ? flow2_completed : reload_completed)
    && !symbolic_operand (operands[1], DImode)
    && !x86_64_immediate_operand (operands[1], DImode)"
   [(set (match_dup 2) (match_dup 3))
       gcc_unreachable ();
     }
 }
-  [(set_attr "type" "ssemov,ssemov,ssemov")
+  [(set_attr "type" "sselog1,ssemov,ssemov")
    (set (attr "mode")
-        (cond [(eq (symbol_ref "TARGET_SSE2") (const_int 0))
+       (cond [(ior (eq (symbol_ref "TARGET_SSE2") (const_int 0))
+                   (ne (symbol_ref "optimize_size") (const_int 0)))
                 (const_string "V4SF")
-
-              (eq_attr "alternative" "0,1")
-                (if_then_else
-                  (ne (symbol_ref "optimize_size")
-                      (const_int 0))
-                  (const_string "V4SF")
-                  (const_string "TI"))
-              (eq_attr "alternative" "2")
-                (if_then_else
-                  (ne (symbol_ref "optimize_size")
-                      (const_int 0))
-                  (const_string "V4SF")
-                  (const_string "TI"))]
-              (const_string "TI")))])
+              (and (eq_attr "alternative" "2")
+                   (ne (symbol_ref "TARGET_SSE_TYPELESS_STORES")
+                       (const_int 0)))
+                (const_string "V4SF")]
+             (const_string "TI")))])
 
 (define_insn "*movti_rex64"
   [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o,x,x,xm")
       gcc_unreachable ();
     }
 }
-  [(set_attr "type" "*,*,ssemov,ssemov,ssemov")
+  [(set_attr "type" "*,*,sselog1,ssemov,ssemov")
    (set (attr "mode")
         (cond [(eq_attr "alternative" "2,3")
                 (if_then_else
 
 (define_insn "*pushsf"
   [(set (match_operand:SF 0 "push_operand" "=<,<,<")
-       (match_operand:SF 1 "general_no_elim_operand" "f#rx,rFm#fx,x#rf"))]
+       (match_operand:SF 1 "general_no_elim_operand" "f,rFm,x"))]
   "!TARGET_64BIT"
 {
   /* Anything else should be already split before reg-stack.  */
 
 (define_insn "*pushsf_rex64"
   [(set (match_operand:SF 0 "push_operand" "=X,X,X")
-       (match_operand:SF 1 "nonmemory_no_elim_operand" "f#rx,rF#fx,x#rf"))]
+       (match_operand:SF 1 "nonmemory_no_elim_operand" "f,rF,x"))]
   "TARGET_64BIT"
 {
   /* Anything else should be already split before reg-stack.  */
        (match_operand:SF 1 "memory_operand" ""))]
   "reload_completed
    && GET_CODE (operands[1]) == MEM
-   && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
-   && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0))"
+   && constant_pool_reference_p (operands[1])"
   [(set (match_dup 0)
        (match_dup 1))]
-  "operands[1] = get_pool_constant (XEXP (operands[1], 0));")
+  "operands[1] = avoid_constant_pool_reference (operands[1]);")
 
 
 ;; %%% Kill this when call knows how to work this out.
 
 (define_insn "*movsf_1"
   [(set (match_operand:SF 0 "nonimmediate_operand"
-         "=f#xr,m   ,f#xr,r#xf  ,m    ,x#rf,x#rf,x#rf ,m   ,!*y,!rm,!*y")
+         "=f,m   ,f,r  ,m    ,x,x,x ,m   ,!*y,!rm,!*y")
        (match_operand:SF 1 "general_operand"
-         "fm#rx,f#rx,G   ,rmF#fx,Fr#fx,C   ,x   ,xm#rf,x#rf,rm ,*y ,*y"))]
+         "fm,f,G   ,rmF,Fr,C   ,x   ,xm,x,rm ,*y ,*y"))]
   "!(MEM_P (operands[0]) && MEM_P (operands[1]))
    && (reload_in_progress || reload_completed
        || (ix86_cmodel == CM_MEDIUM || ix86_cmodel == CM_LARGE)
       gcc_unreachable ();
     }
 }
-  [(set_attr "type" "fmov,fmov,fmov,imov,imov,ssemov,ssemov,ssemov,ssemov,mmxmov,mmxmov,mmxmov")
+  [(set_attr "type" "fmov,fmov,fmov,imov,imov,sselog1,ssemov,ssemov,ssemov,mmxmov,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#Y,Fo#fY,*r#fY,Y#f"))]
+       (match_operand:DF 1 "general_no_elim_operand" "f,Fo,*r,Y"))]
   "!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#rY,rFo#fY,Y#rf"))]
+       (match_operand:DF 1 "general_no_elim_operand" "f,rFo,Y"))]
   "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#Y,m  ,f#Y,*r  ,o  ,Y*x#f,Y*x#f,Y*x#f  ,m    ")
+                       "=f,m,f,*r  ,o  ,Y*x,Y*x,Y*x ,m  ")
        (match_operand:DF 1 "general_operand"
-                       "fm#Y,f#Y,G  ,*roF,F*r,C    ,Y*x#f,HmY*x#f,Y*x#f"))]
+                       "fm,f,G,*roF,F*r,C  ,Y*x,mY*x,Y*x"))]
   "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
    && ((optimize_size || !TARGET_INTEGER_DFMODE_MOVES) && !TARGET_64BIT)
    && (reload_in_progress || reload_completed
       gcc_unreachable ();
     }
 }
-  [(set_attr "type" "fmov,fmov,fmov,multi,multi,ssemov,ssemov,ssemov,ssemov")
+  [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov")
    (set (attr "mode")
         (cond [(eq_attr "alternative" "0,1,2")
                 (const_string "DF")
 
 (define_insn "*movdf_integer"
   [(set (match_operand:DF 0 "nonimmediate_operand"
-               "=f#Yr,m   ,f#Yr,r#Yf  ,o    ,Y*x#rf,Y*x#rf,Y*x#rf,m")
+               "=f,m,f,r  ,o ,Y*x,Y*x,Y*x,m  ")
        (match_operand:DF 1 "general_operand"
-               "fm#Yr,f#Yr,G   ,roF#Yf,Fr#Yf,C     ,Y*x#rf,m     ,Y*x#rf"))]
+               "fm,f,G,roF,Fr,C  ,Y*x,m  ,Y*x"))]
   "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
    && ((!optimize_size && TARGET_INTEGER_DFMODE_MOVES) || TARGET_64BIT)
    && (reload_in_progress || reload_completed
       gcc_unreachable();
     }
 }
-  [(set_attr "type" "fmov,fmov,fmov,multi,multi,ssemov,ssemov,ssemov,ssemov")
+  [(set_attr "type" "fmov,fmov,fmov,multi,multi,sselog1,ssemov,ssemov,ssemov")
    (set (attr "mode")
         (cond [(eq_attr "alternative" "0,1,2")
                 (const_string "DF")
 
 (define_insn "*pushxf_integer"
   [(set (match_operand:XF 0 "push_operand" "=<,<")
-       (match_operand:XF 1 "general_no_elim_operand" "f#r,ro#f"))]
+       (match_operand:XF 1 "general_no_elim_operand" "f,ro"))]
   "!optimize_size"
 {
   /* This insn should be already split before reg-stack.  */
    (set_attr "mode" "XF,XF,XF,SI,SI")])
 
 (define_insn "*movxf_integer"
-  [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o")
-       (match_operand:XF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))]
+  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,r,o")
+       (match_operand:XF 1 "general_operand" "fm,f,G,roF,Fr"))]
   "!optimize_size
    && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
    && (reload_in_progress || reload_completed
    && GET_CODE (operands[1]) == MEM
    && (GET_MODE (operands[0]) == XFmode
        || GET_MODE (operands[0]) == SFmode || GET_MODE (operands[0]) == DFmode)
-   && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF
-   && CONSTANT_POOL_ADDRESS_P (XEXP (operands[1], 0))"
+   && constant_pool_reference_p (operands[1])"
   [(set (match_dup 0) (match_dup 1))]
 {
-  rtx c = get_pool_constant (XEXP (operands[1], 0));
+  rtx c = avoid_constant_pool_reference (operands[1]);
   rtx r = operands[0];
 
   if (GET_CODE (r) == SUBREG)
       gcc_unreachable ();
     }
 }
-  [(set_attr "type" "*,*,ssemov,ssemov,ssemov")
+  [(set_attr "type" "*,*,sselog1,ssemov,ssemov")
    (set (attr "mode")
         (cond [(eq_attr "alternative" "2,3")
                 (if_then_else
   [(set_attr "type" "imovx,alu1")
    (set_attr "mode" "HI")])
 
-(define_insn "*zero_extendqihi2_movzbw"
+; zero extend to SImode here to avoid partial register stalls
+(define_insn "*zero_extendqihi2_movzbl"
   [(set (match_operand:HI 0 "register_operand" "=r")
      (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
   "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) && reload_completed"
-  "movz{bw|x}\t{%1, %0|%0, %1}"
+  "movz{bl|x}\t{%1, %k0|%k0, %k1}"
   [(set_attr "type" "imovx")
-   (set_attr "mode" "HI")])
+   (set_attr "mode" "SI")])
 
 ;; For the movzbw case strip only the clobber
 (define_split
   /* ??? Needed for compress_float_constant since all fp constants
      are LEGITIMATE_CONSTANT_P.  */
   if (GET_CODE (operands[1]) == CONST_DOUBLE)
-    operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
-  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
-    operands[1] = force_reg (SFmode, operands[1]);
+    {
+      if ((!TARGET_SSE2 || TARGET_MIX_SSE_I387)
+         && standard_80387_constant_p (operands[1]) > 0)
+       {
+         operands[1] = simplify_const_unary_operation
+           (FLOAT_EXTEND, DFmode, operands[1], SFmode);
+         emit_move_insn_1 (operands[0], operands[1]);
+         DONE;
+       }
+      operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
+    }
 })
 
 (define_insn "*extendsfdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=f#Y,m#fY,Y#f")
-        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm#Y,f#Y,mY#f")))]
-  "TARGET_SSE2 && TARGET_MIX_SSE_I387
-   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,Y")
+        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f,mY")))]
+  "TARGET_SSE2 && TARGET_MIX_SSE_I387"
 {
   switch (which_alternative)
     {
 (define_insn "*extendsfdf2_sse"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=Y")
         (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "mY")))]
-  "TARGET_SSE2 && TARGET_SSE_MATH
-   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+  "TARGET_SSE2 && TARGET_SSE_MATH"
   "cvtss2sd\t{%1, %0|%0, %1}"
   [(set_attr "type" "ssecvt")
    (set_attr "mode" "DF")])
 (define_insn "*extendsfdf2_i387"
   [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m")
         (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
-  "TARGET_80387
-   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+  "TARGET_80387"
 {
   switch (which_alternative)
     {
   /* ??? Needed for compress_float_constant since all fp constants
      are LEGITIMATE_CONSTANT_P.  */
   if (GET_CODE (operands[1]) == CONST_DOUBLE)
-    operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
-  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
-    operands[1] = force_reg (SFmode, operands[1]);
+    {
+      if (standard_80387_constant_p (operands[1]) > 0)
+       {
+         operands[1] = simplify_const_unary_operation
+           (FLOAT_EXTEND, XFmode, operands[1], SFmode);
+         emit_move_insn_1 (operands[0], operands[1]);
+         DONE;
+       }
+      operands[1] = validize_mem (force_const_mem (SFmode, operands[1]));
+    }
 })
 
 (define_insn "*extendsfxf2_i387"
   [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
         (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
-  "TARGET_80387
-   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+  "TARGET_80387"
 {
   switch (which_alternative)
     {
   /* ??? Needed for compress_float_constant since all fp constants
      are LEGITIMATE_CONSTANT_P.  */
   if (GET_CODE (operands[1]) == CONST_DOUBLE)
-    operands[1] = validize_mem (force_const_mem (DFmode, operands[1]));
-  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
-    operands[1] = force_reg (DFmode, operands[1]);
+    {
+      if (standard_80387_constant_p (operands[1]) > 0)
+       {
+         operands[1] = simplify_const_unary_operation
+           (FLOAT_EXTEND, XFmode, operands[1], DFmode);
+         emit_move_insn_1 (operands[0], operands[1]);
+         DONE;
+       }
+      operands[1] = validize_mem (force_const_mem (DFmode, operands[1]));
+    }
 })
 
 (define_insn "*extenddfxf2_i387"
   [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
         (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
-  "TARGET_80387
-   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
+  "TARGET_80387"
 {
   switch (which_alternative)
     {
          (match_operand:DF 1 "nonimmediate_operand" "")))]
   "TARGET_80387 || (TARGET_SSE2 && TARGET_SSE_MATH)"
 {
-  if (MEM_P (operands[0]) && MEM_P (operands[1]))
-    operands[1] = force_reg (DFmode, operands[1]);
-
   if (TARGET_SSE2 && TARGET_SSE_MATH && !TARGET_MIX_SSE_I387)
     ;
   else if (flag_unsafe_math_optimizations)
 })
 
 (define_insn "*truncxfsf2_mixed"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#rx,?r#fx,?x#rf")
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f,?r,?x")
        (float_truncate:SF
         (match_operand:XF 1 "register_operand" "f,f,f,f")))
    (clobber (match_operand:SF 2 "memory_operand" "=X,m,m,m"))]
    (set_attr "mode" "SF")])
 
 (define_insn "*truncxfsf2_i387"
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f#r,?r#f")
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,?f,?r")
        (float_truncate:SF
         (match_operand:XF 1 "register_operand" "f,f,f")))
    (clobber (match_operand:SF 2 "memory_operand" "=X,m,m"))]
 })
 
 (define_insn "*truncxfdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f#rY,?r#fY,?Y#rf")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r,?Y")
        (float_truncate:DF
         (match_operand:XF 1 "register_operand" "f,f,f,f")))
    (clobber (match_operand:DF 2 "memory_operand" "=X,m,m,m"))]
    (set_attr "mode" "DF")])
 
 (define_insn "*truncxfdf2_i387"
-  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f#r,?r#f")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,?f,?r")
        (float_truncate:DF
         (match_operand:XF 1 "register_operand" "f,f,f")))
    (clobber (match_operand:DF 2 "memory_operand" "=X,m,m"))]
   [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
                   (fix:SI (match_operand:SSEMODEF 1 "register_operand" "")))
              (clobber (reg:CC FLAGS_REG))])]
-  "TARGET_80387 || (SSE_FLOAT_MODE_P (<MODE>mode))"
+  "TARGET_80387 || SSE_FLOAT_MODE_P (<MODE>mode)"
 {
   if (TARGET_FISTTP
       && !(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH))
    (set_attr "mode" "DF")
    (set_attr "athlon_decode" "double,vector")])
 
+;; Shorten x87->SSE reload sequences of fix_trunc?f?i_sse patterns.
+(define_peephole2
+  [(set (match_operand:DF 0 "register_operand" "")
+       (match_operand:DF 1 "memory_operand" ""))
+   (set (match_operand:SSEMODEI24 2 "register_operand" "")
+       (fix:SSEMODEI24 (match_dup 0)))]
+  "!TARGET_K8
+   && peep2_reg_dead_p (2, operands[0])"
+  [(set (match_dup 2) (fix:SSEMODEI24 (match_dup 1)))]
+  "")
+
+(define_peephole2
+  [(set (match_operand:SF 0 "register_operand" "")
+       (match_operand:SF 1 "memory_operand" ""))
+   (set (match_operand:SSEMODEI24 2 "register_operand" "")
+       (fix:SSEMODEI24 (match_dup 0)))]
+  "!TARGET_K8
+   && peep2_reg_dead_p (2, operands[0])"
+  [(set (match_dup 2) (fix:SSEMODEI24 (match_dup 1)))]
+  "")
+
 ;; Avoid vector decoded forms of the instruction.
 (define_peephole2
   [(match_scratch:DF 2 "Y")
    (set (match_operand:SSEMODEI24 0 "register_operand" "")
        (fix:SSEMODEI24 (match_operand:DF 1 "memory_operand" "")))]
-  "TARGET_K8 && !optimize_size"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size"
   [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (fix:SSEMODEI24 (match_dup 2)))]
   "")
   [(match_scratch:SF 2 "x")
    (set (match_operand:SSEMODEI24 0 "register_operand" "")
        (fix:SSEMODEI24 (match_operand:SF 1 "memory_operand" "")))]
-  "TARGET_K8 && !optimize_size"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size"
   [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (fix:SSEMODEI24 (match_dup 2)))]
   "")
 (define_insn_and_split "fix_trunc<mode>_fisttp_i387_1"
   [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "=m,?r")
        (fix:X87MODEI (match_operand 1 "register_operand" "f,f")))]
-  "TARGET_80387 && TARGET_FISTTP
+  "TARGET_FISTTP
    && FLOAT_MODE_P (GET_MODE (operands[1]))
    && !((SSE_FLOAT_MODE_P (GET_MODE (operands[1]))
         && (TARGET_64BIT || <MODE>mode != DImode))
   [(set (match_operand:X87MODEI 0 "memory_operand" "=m")
        (fix:X87MODEI (match_operand 1 "register_operand" "f")))
    (clobber (match_scratch:XF 2 "=&1f"))]
-  "TARGET_80387 && TARGET_FISTTP
+  "TARGET_FISTTP
    && FLOAT_MODE_P (GET_MODE (operands[1]))
    && !((SSE_FLOAT_MODE_P (GET_MODE (operands[1]))
         && (TARGET_64BIT || <MODE>mode != DImode))
        (fix:X87MODEI (match_operand 1 "register_operand" "f,f")))
    (clobber (match_operand:X87MODEI 2 "memory_operand" "=m,m"))
    (clobber (match_scratch:XF 3 "=&1f,&1f"))]
-  "TARGET_80387 && TARGET_FISTTP
+  "TARGET_FISTTP
    && FLOAT_MODE_P (GET_MODE (operands[1]))
    && !((SSE_FLOAT_MODE_P (GET_MODE (operands[1]))
        && (TARGET_64BIT || <MODE>mode != DImode))
   "")
 
 (define_insn "*floatsisf2_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,?f#x,x#f,x#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,?f,x,x")
        (float:SF (match_operand:SI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_MIX_SSE_I387"
   "@
   "")
 
 (define_insn "*floatdisf2_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,?f#x,x#f,x#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,?f,x,x")
        (float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_64BIT && TARGET_MIX_SSE_I387"
   "@
   "")
 
 (define_insn "*floatsidf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,?f#Y,Y#f,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y")
        (float:DF (match_operand:SI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
   "")
 
 (define_insn "*floatdidf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,?f#Y,Y#f,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,?f,Y,Y")
        (float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r,r,mr")))]
   "TARGET_64BIT && TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
                    (match_dup 2))))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCmode)
    && ix86_binary_operator_ok (MINUS, SImode, operands)"
-  "sub{q}\t{%2, %0|%0, %2}"
+  "sub{l}\t{%2, %1|%1, %2}"
   [(set_attr "type" "alu")
    (set_attr "mode" "DI")])
 
                   (match_operand:SI 2 "const_int_operand" ""))
                 (const_int 0)))]
   "ix86_match_ccmode (insn, CCNOmode)
+   && INTVAL (operands[1]) > 0
+   && INTVAL (operands[2]) >= 0
+   && INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
    && (GET_MODE (operands[0]) == SImode
        || (TARGET_64BIT && GET_MODE (operands[0]) == DImode)
        || GET_MODE (operands[0]) == HImode
                 (const_int 0)))]
   "TARGET_64BIT
    && ix86_match_ccmode (insn, CCNOmode)
-   /* The code below cannot deal with constants outside HOST_WIDE_INT.  */
-   && INTVAL (operands[1]) + INTVAL (operands[2]) < HOST_BITS_PER_WIDE_INT
+   && INTVAL (operands[1]) > 0
+   && INTVAL (operands[2]) >= 0
    /* Ensure that resulting mask is zero or sign extended operand.  */
    && (INTVAL (operands[1]) + INTVAL (operands[2]) <= 32
        || (INTVAL (operands[1]) + INTVAL (operands[2]) == 64
       val = gen_lowpart (QImode, val);
     }
 
-  mask  = ((HOST_WIDE_INT)1 << (pos + len)) - 1;
-  mask &= ~(((HOST_WIDE_INT)1 << pos) - 1);
+  if (len == HOST_BITS_PER_WIDE_INT)
+    mask = -1;
+  else
+    mask = ((HOST_WIDE_INT)1 << len) - 1;
+  mask <<= pos;
 
   operands[2] = gen_rtx_AND (mode, val, gen_int_mode (mask, mode));
 })
   "ix86_expand_fp_absneg_operator (ABS, SFmode, operands); DONE;")
 
 (define_insn "*absnegsf2_mixed"
-  [(set (match_operand:SF 0 "nonimmediate_operand"    "=x#f,x#f,f#x,rm")
+  [(set (match_operand:SF 0 "nonimmediate_operand"    "=x  ,x,f,rm")
        (match_operator:SF 3 "absneg_operator"
-         [(match_operand:SF 1 "nonimmediate_operand" "0   ,x#f,0  ,0")]))
-   (use (match_operand:V4SF 2 "nonimmediate_operand"  "xm  ,0  ,X  ,X"))
+         [(match_operand:SF 1 "nonimmediate_operand" "0   ,x,0,0 ")]))
+   (use (match_operand:V4SF 2 "nonimmediate_operand"  "xm  ,0,X,X "))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_SSE_MATH && TARGET_MIX_SSE_I387
    && ix86_unary_operator_ok (GET_CODE (operands[3]), SFmode, operands)"
   "ix86_expand_fp_absneg_operator (ABS, DFmode, operands); DONE;")
 
 (define_insn "*absnegdf2_mixed"
-  [(set (match_operand:DF 0 "nonimmediate_operand"    "=Y#f,Y#f,f#Y,rm")
+  [(set (match_operand:DF 0 "nonimmediate_operand"    "=Y,Y,f,rm")
        (match_operator:DF 3 "absneg_operator"
-         [(match_operand:DF 1 "nonimmediate_operand" "0   ,Y#f,0  ,0")]))
-   (use (match_operand:V2DF 2 "nonimmediate_operand"  "Ym  ,0  ,X  ,X"))
+         [(match_operand:DF 1 "nonimmediate_operand" "0 ,Y,0,0")]))
+   (use (match_operand:V2DF 2 "nonimmediate_operand"  "Ym,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")
        (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 ,Y,0 ")]))
+   (use (match_operand:V2DF 2 "nonimmediate_operand"  "Ym,0,X "))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_SSE2 && TARGET_SSE_MATH
    && ix86_unary_operator_ok (GET_CODE (operands[3]), DFmode, operands)"
 
 (define_expand "absxf2"
   [(set (match_operand:XF 0 "nonimmediate_operand" "")
-       (neg:XF (match_operand:XF 1 "nonimmediate_operand" "")))]
+       (abs:XF (match_operand:XF 1 "nonimmediate_operand" "")))]
   "TARGET_80387"
   "ix86_expand_fp_absneg_operator (ABS, XFmode, operands); DONE;")
 
 (define_insn "*negsf2_1"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (neg:SF (match_operand:SF 1 "register_operand" "0")))]
-  "TARGET_80387 && reload_completed"
+  "TARGET_80387 && (reload_completed || !TARGET_SSE_MATH)"
   "fchs"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "SF")])
 (define_insn "*negdf2_1"
   [(set (match_operand:DF 0 "register_operand" "=f")
        (neg:DF (match_operand:DF 1 "register_operand" "0")))]
-  "TARGET_80387 && reload_completed"
+  "TARGET_80387 && (reload_completed || !(TARGET_SSE2 && TARGET_SSE_MATH))"
   "fchs"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "DF")])
 (define_insn "*negxf2_1"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (neg:XF (match_operand:XF 1 "register_operand" "0")))]
-  "TARGET_80387 && reload_completed"
+  "TARGET_80387"
   "fchs"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "XF")])
 (define_insn "*abssf2_1"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (abs:SF (match_operand:SF 1 "register_operand" "0")))]
-  "TARGET_80387 && reload_completed"
+  "TARGET_80387 && (reload_completed || !TARGET_SSE_MATH)"
   "fabs"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "SF")])
 (define_insn "*absdf2_1"
   [(set (match_operand:DF 0 "register_operand" "=f")
        (abs:DF (match_operand:DF 1 "register_operand" "0")))]
-  "TARGET_80387 && reload_completed"
+  "TARGET_80387 && (reload_completed || !(TARGET_SSE2 && TARGET_SSE_MATH))"
   "fabs"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "DF")])
 (define_insn "*absxf2_1"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (abs:XF (match_operand:XF 1 "register_operand" "0")))]
-  "TARGET_80387 && reload_completed"
+  "TARGET_80387"
   "fabs"
   [(set_attr "type" "fsgn")
    (set_attr "mode" "DF")])
    (set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (ashift:DI (match_dup 1) (match_dup 2)))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFT, DImode, operands)"
+   && ix86_binary_operator_ok (ASHIFT, DImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))"
+{
+  switch (get_attr_type (insn))
+    {
+    case TYPE_ALU:
+      gcc_assert (operands[2] == const1_rtx);
+      return "add{q}\t{%0, %0|%0, %0}";
+
+    default:
+      if (REG_P (operands[2]))
+       return "sal{q}\t{%b2, %0|%0, %b2}";
+      else if (operands[2] == const1_rtx
+              && (TARGET_SHIFT1 || optimize_size))
+       return "sal{q}\t%0";
+      else
+       return "sal{q}\t{%2, %0|%0, %2}";
+    }
+}
+  [(set (attr "type")
+     (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+                         (const_int 0))
+                     (match_operand 0 "register_operand" ""))
+                (match_operand 2 "const1_operand" ""))
+             (const_string "alu")
+          ]
+          (const_string "ishift")))
+   (set_attr "mode" "DI")])
+
+(define_insn "*ashldi3_cconly_rex64"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "0")
+                    (match_operand:QI 2 "immediate_operand" "e"))
+         (const_int 0)))
+   (clobber (match_scratch:DI 0 "=r"))]
+  "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFT, DImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || TARGET_DOUBLE_WITH_ADD)))"
 {
   switch (get_attr_type (insn))
     {
        (ashift:DI (match_operand:DI 1 "nonmemory_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))
    (clobber (reg:CC FLAGS_REG))]
-  "!TARGET_64BIT && (flag_peephole2 ? flow2_completed : reload_completed)"
+  "!TARGET_64BIT && ((optimize > 0 && flag_peephole2)
+                    ? flow2_completed : reload_completed)"
   [(const_int 0)]
   "ix86_split_ashl (operands, NULL_RTX, DImode); DONE;")
 
   [(const_int 0)]
 {
   rtx pat, clob;
-  emit_move_insn (operands[1], operands[0]);
+  emit_move_insn (operands[0], operands[1]);
   pat = gen_rtx_SET (VOIDmode, operands[0],
                     gen_rtx_ASHIFT (GET_MODE (operands[0]),
                                     operands[0], operands[2]));
    (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
        (ashift:SI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFT, SImode, operands)"
+   && ix86_binary_operator_ok (ASHIFT, SImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))"
+{
+  switch (get_attr_type (insn))
+    {
+    case TYPE_ALU:
+      gcc_assert (operands[2] == const1_rtx);
+      return "add{l}\t{%0, %0|%0, %0}";
+
+    default:
+      if (REG_P (operands[2]))
+       return "sal{l}\t{%b2, %0|%0, %b2}";
+      else if (operands[2] == const1_rtx
+              && (TARGET_SHIFT1 || optimize_size))
+       return "sal{l}\t%0";
+      else
+       return "sal{l}\t{%2, %0|%0, %2}";
+    }
+}
+  [(set (attr "type")
+     (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+                         (const_int 0))
+                     (match_operand 0 "register_operand" ""))
+                (match_operand 2 "const1_operand" ""))
+             (const_string "alu")
+          ]
+          (const_string "ishift")))
+   (set_attr "mode" "SI")])
+
+(define_insn "*ashlsi3_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+                    (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:SI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFT, SImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || TARGET_DOUBLE_WITH_ADD)))"
 {
   switch (get_attr_type (insn))
     {
    (set (match_operand:DI 0 "register_operand" "=r")
        (zero_extend:DI (ashift:SI (match_dup 1) (match_dup 2))))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFT, SImode, operands)"
+   && ix86_binary_operator_ok (ASHIFT, SImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || TARGET_DOUBLE_WITH_ADD)))"
 {
   switch (get_attr_type (insn))
     {
    (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
        (ashift:HI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFT, HImode, operands)"
+   && ix86_binary_operator_ok (ASHIFT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))"
+{
+  switch (get_attr_type (insn))
+    {
+    case TYPE_ALU:
+      gcc_assert (operands[2] == const1_rtx);
+      return "add{w}\t{%0, %0|%0, %0}";
+
+    default:
+      if (REG_P (operands[2]))
+       return "sal{w}\t{%b2, %0|%0, %b2}";
+      else if (operands[2] == const1_rtx
+              && (TARGET_SHIFT1 || optimize_size))
+       return "sal{w}\t%0";
+      else
+       return "sal{w}\t{%2, %0|%0, %2}";
+    }
+}
+  [(set (attr "type")
+     (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+                         (const_int 0))
+                     (match_operand 0 "register_operand" ""))
+                (match_operand 2 "const1_operand" ""))
+             (const_string "alu")
+          ]
+          (const_string "ishift")))
+   (set_attr "mode" "HI")])
+
+(define_insn "*ashlhi3_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+                    (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:HI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || TARGET_DOUBLE_WITH_ADD)))"
 {
   switch (get_attr_type (insn))
     {
    (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
        (ashift:QI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFT, QImode, operands)"
+   && ix86_binary_operator_ok (ASHIFT, QImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || (TARGET_DOUBLE_WITH_ADD && REG_P (operands[0])))))"
+{
+  switch (get_attr_type (insn))
+    {
+    case TYPE_ALU:
+      gcc_assert (operands[2] == const1_rtx);
+      return "add{b}\t{%0, %0|%0, %0}";
+
+    default:
+      if (REG_P (operands[2]))
+       return "sal{b}\t{%b2, %0|%0, %b2}";
+      else if (operands[2] == const1_rtx
+              && (TARGET_SHIFT1 || optimize_size))
+       return "sal{b}\t%0";
+      else
+       return "sal{b}\t{%2, %0|%0, %2}";
+    }
+}
+  [(set (attr "type")
+     (cond [(and (and (ne (symbol_ref "TARGET_DOUBLE_WITH_ADD")
+                         (const_int 0))
+                     (match_operand 0 "register_operand" ""))
+                (match_operand 2 "const1_operand" ""))
+             (const_string "alu")
+          ]
+          (const_string "ishift")))
+   (set_attr "mode" "QI")])
+
+(define_insn "*ashlqi3_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
+                    (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=q"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFT, QImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL
+       || (operands[2] == const1_rtx
+          && (TARGET_SHIFT1
+              || TARGET_DOUBLE_WITH_ADD)))"
 {
   switch (get_attr_type (insn))
     {
        (const_string "2")
        (const_string "*")))])
 
+(define_insn "*ashrdi3_one_bit_cconly_rex64"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" ""))
+         (const_int 0)))
+   (clobber (match_scratch:DI 0 "=r"))]
+  "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)"
+  "sar{q}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
 ;; This pattern can't accept a variable shift count, since shifts by
 ;; zero don't affect the flags.  We assume that shifts by constant
 ;; zero are optimized away.
    (set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (ashiftrt:DI (match_dup 1) (match_dup 2)))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)"
+   && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "sar{q}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "DI")])
+
+(define_insn "*ashrdi3_cconly_rex64"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const_int_operand" "n"))
+         (const_int 0)))
+   (clobber (match_scratch:DI 0 "=r"))]
+  "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFTRT, DImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "sar{q}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "DI")])
        (ashiftrt:DI (match_operand:DI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))
    (clobber (reg:CC FLAGS_REG))]
-  "!TARGET_64BIT && (flag_peephole2 ? flow2_completed : reload_completed)"
+  "!TARGET_64BIT && ((optimize > 0 && flag_peephole2)
+                    ? flow2_completed : reload_completed)"
   [(const_int 0)]
   "ix86_split_ashr (operands, NULL_RTX, DImode); DONE;")
 
        (const_string "2")
        (const_string "*")))])
 
-(define_insn "*ashrsi3_one_bit_cmp_zext"
+(define_insn "*ashrsi3_one_bit_cconly"
   [(set (reg FLAGS_REG)
        (compare
-         (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+         (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" ""))
+         (const_int 0)))
+   (clobber (match_scratch:SI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)"
+  "sar{l}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
+(define_insn "*ashrsi3_one_bit_cmp_zext"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
                       (match_operand:QI 2 "const1_operand" ""))
          (const_int 0)))
    (set (match_operand:DI 0 "register_operand" "=r")
    (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
        (ashiftrt:SI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)"
+   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "sar{l}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "SI")])
+
+(define_insn "*ashrsi3_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:SI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "sar{l}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "SI")])
    (set (match_operand:DI 0 "register_operand" "=r")
        (zero_extend:DI (ashiftrt:SI (match_dup 1) (match_dup 2))))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)"
+   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "sar{l}\t{%2, %k0|%k0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "SI")])
        (const_string "2")
        (const_string "*")))])
 
+(define_insn "*ashrhi3_one_bit_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" ""))
+         (const_int 0)))
+   (clobber (match_scratch:HI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)"
+  "sar{w}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
 ;; This pattern can't accept a variable shift count, since shifts by
 ;; zero don't affect the flags.  We assume that shifts by constant
 ;; zero are optimized away.
    (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
        (ashiftrt:HI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)"
+   && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "sar{w}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "HI")])
+
+(define_insn "*ashrhi3_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:HI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "sar{w}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "HI")])
        (const_string "2")
        (const_string "*")))])
 
+(define_insn "*ashrqi3_one_bit_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=q"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)"
+  "sar{b}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
 ;; This pattern can't accept a variable shift count, since shifts by
 ;; zero don't affect the flags.  We assume that shifts by constant
 ;; zero are optimized away.
    (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
        (ashiftrt:QI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)"
+   && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "sar{b}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "QI")])
+
+(define_insn "*ashrqi3_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=q"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "sar{b}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "QI")])
+
 \f
 ;; Logical shift instructions
 
        (const_string "2")
        (const_string "*")))])
 
+(define_insn "*lshrdi3_cconly_one_bit_rex64"
+  [(set (reg FLAGS_REG)
+       (compare
+         (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" ""))
+         (const_int 0)))
+   (clobber (match_scratch:DI 0 "=r"))]
+  "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
+  "shr{q}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
 ;; This pattern can't accept a variable shift count, since shifts by
 ;; zero don't affect the flags.  We assume that shifts by constant
 ;; zero are optimized away.
    (set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (lshiftrt:DI (match_dup 1) (match_dup 2)))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "shr{q}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "DI")])
+
+(define_insn "*lshrdi3_cconly_rex64"
+  [(set (reg FLAGS_REG)
+       (compare
+         (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const_int_operand" "e"))
+         (const_int 0)))
+   (clobber (match_scratch:DI 0 "=r"))]
+  "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "shr{q}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "DI")])
        (lshiftrt:DI (match_operand:DI 1 "register_operand" "")
                     (match_operand:QI 2 "nonmemory_operand" "")))
    (clobber (reg:CC FLAGS_REG))]
-  "!TARGET_64BIT && (flag_peephole2 ? flow2_completed : reload_completed)"
+  "!TARGET_64BIT && ((optimize > 0 && flag_peephole2)
+                    ? flow2_completed : reload_completed)"
   [(const_int 0)]
   "ix86_split_lshr (operands, NULL_RTX, DImode); DONE;")
 
        (const_string "2")
        (const_string "*")))])
 
+(define_insn "*lshrsi3_one_bit_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" ""))
+         (const_int 0)))
+   (clobber (match_scratch:SI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
+  "shr{l}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
 (define_insn "*lshrsi3_cmp_one_bit_zext"
   [(set (reg FLAGS_REG)
        (compare
    (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
        (lshiftrt:SI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "shr{l}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "SI")])
+
+(define_insn "*lshrsi3_cconly"
+  [(set (reg FLAGS_REG)
+      (compare
+       (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
+                    (match_operand:QI 2 "const_1_to_31_operand" "I"))
+        (const_int 0)))
+   (clobber (match_scratch:SI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "shr{l}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "SI")])
    (set (match_operand:DI 0 "register_operand" "=r")
        (lshiftrt:DI (zero_extend:DI (match_dup 1)) (match_dup 2)))]
   "TARGET_64BIT && ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "shr{l}\t{%2, %k0|%k0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "SI")])
        (const_string "2")
        (const_string "*")))])
 
+(define_insn "*lshrhi3_one_bit_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" ""))
+         (const_int 0)))
+   (clobber (match_scratch:HI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
+  "shr{w}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
 ;; This pattern can't accept a variable shift count, since shifts by
 ;; zero don't affect the flags.  We assume that shifts by constant
 ;; zero are optimized away.
    (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
        (lshiftrt:HI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "shr{w}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "HI")])
+
+(define_insn "*lshrhi3_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:HI 0 "=r"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "shr{w}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "HI")])
        (const_string "2")
        (const_string "*")))])
 
+(define_insn "*lshrqi2_one_bit_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const1_operand" ""))
+         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=q"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && (TARGET_SHIFT1 || optimize_size)
+   && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)"
+  "shr{b}\t%0"
+  [(set_attr "type" "ishift")
+   (set_attr "length" "2")])
+
 ;; This pattern can't accept a variable shift count, since shifts by
 ;; zero don't affect the flags.  We assume that shifts by constant
 ;; zero are optimized away.
    (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
        (lshiftrt:QI (match_dup 1) (match_dup 2)))]
   "ix86_match_ccmode (insn, CCGOCmode)
-   && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)"
+   && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
+  "shr{b}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "ishift")
+   (set_attr "mode" "QI")])
+
+(define_insn "*lshrqi2_cconly"
+  [(set (reg FLAGS_REG)
+       (compare
+         (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
+                      (match_operand:QI 2 "const_1_to_31_operand" "I"))
+         (const_int 0)))
+   (clobber (match_scratch:QI 0 "=q"))]
+  "ix86_match_ccmode (insn, CCGOCmode)
+   && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)
+   && (optimize_size
+       || !TARGET_PARTIAL_FLAG_REG_STALL)"
   "shr{b}\t{%2, %0|%0, %2}"
   [(set_attr "type" "ishift")
    (set_attr "mode" "QI")])
 ;; Rotate instructions
 
 (define_expand "rotldi3"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "")
+  [(set (match_operand:DI 0 "shiftdi_operand" "")
+       (rotate:DI (match_operand:DI 1 "shiftdi_operand" "")
                   (match_operand:QI 2 "nonmemory_operand" "")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_64BIT"
-  "ix86_expand_binary_operator (ROTATE, DImode, operands); DONE;")
+ ""
+{
+  if (TARGET_64BIT)
+    {
+      ix86_expand_binary_operator (ROTATE, DImode, operands);
+      DONE;
+    }
+  if (!const_1_to_31_operand (operands[2], VOIDmode))
+    FAIL;
+  emit_insn (gen_ix86_rotldi3 (operands[0], operands[1], operands[2]));
+  DONE;
+})
 
+;; Implement rotation using two double-precision shift instructions
+;; and a scratch register.   
+(define_insn_and_split "ix86_rotldi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+       (rotate:DI (match_operand:DI 1 "register_operand" "0")
+                  (match_operand:QI 2 "const_1_to_31_operand" "I")))
+  (clobber (reg:CC FLAGS_REG))
+  (clobber (match_scratch:SI 3 "=&r"))]
+ "!TARGET_64BIT"
+ "" 
+ "&& reload_completed"
+ [(set (match_dup 3) (match_dup 4))
+  (parallel
+   [(set (match_dup 4)
+         (ior:SI (ashift:SI (match_dup 4) (match_dup 2))
+                 (lshiftrt:SI (match_dup 5)
+                              (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])
+  (parallel
+   [(set (match_dup 5)
+         (ior:SI (ashift:SI (match_dup 5) (match_dup 2))
+                 (lshiftrt:SI (match_dup 3)
+                              (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])]
+ "split_di (operands, 1, operands + 4, operands + 5);")
 (define_insn "*rotlsi3_1_one_bit_rex64"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (rotate:DI (match_operand:DI 1 "nonimmediate_operand" "0")
    (set_attr "mode" "QI")])
 
 (define_expand "rotrdi3"
-  [(set (match_operand:DI 0 "nonimmediate_operand" "")
-       (rotatert:DI (match_operand:DI 1 "nonimmediate_operand" "")
-                    (match_operand:QI 2 "nonmemory_operand" "")))
+  [(set (match_operand:DI 0 "shiftdi_operand" "")
+       (rotate:DI (match_operand:DI 1 "shiftdi_operand" "")
+                  (match_operand:QI 2 "nonmemory_operand" "")))
    (clobber (reg:CC FLAGS_REG))]
-  "TARGET_64BIT"
-  "ix86_expand_binary_operator (ROTATERT, DImode, operands); DONE;")
+ ""
+{
+  if (TARGET_64BIT)
+    {
+      ix86_expand_binary_operator (ROTATERT, DImode, operands);
+      DONE;
+    }
+  if (!const_1_to_31_operand (operands[2], VOIDmode))
+    FAIL;
+  emit_insn (gen_ix86_rotrdi3 (operands[0], operands[1], operands[2]));
+  DONE;
+})
+  
+;; Implement rotation using two double-precision shift instructions
+;; and a scratch register.   
+(define_insn_and_split "ix86_rotrdi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+       (rotatert:DI (match_operand:DI 1 "register_operand" "0")
+                    (match_operand:QI 2 "const_1_to_31_operand" "I")))
+  (clobber (reg:CC FLAGS_REG))
+  (clobber (match_scratch:SI 3 "=&r"))]
+ "!TARGET_64BIT"
+ ""
+ "&& reload_completed"
+ [(set (match_dup 3) (match_dup 4))
+  (parallel
+   [(set (match_dup 4)
+         (ior:SI (ashiftrt:SI (match_dup 4) (match_dup 2))
+                 (ashift:SI (match_dup 5)
+                            (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])
+  (parallel
+   [(set (match_dup 5)
+         (ior:SI (ashiftrt:SI (match_dup 5) (match_dup 2))
+                 (ashift:SI (match_dup 3)
+                            (minus:QI (const_int 32) (match_dup 2)))))
+    (clobber (reg:CC FLAGS_REG))])]
+ "split_di (operands, 1, operands + 4, operands + 5);")
 
 (define_insn "*rotrdi3_1_one_bit_rex64"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
 (define_expand "extv"
   [(set (match_operand:SI 0 "register_operand" "")
        (sign_extract:SI (match_operand:SI 1 "register_operand" "")
-                        (match_operand:SI 2 "immediate_operand" "")
-                        (match_operand:SI 3 "immediate_operand" "")))]
+                        (match_operand:SI 2 "const8_operand" "")
+                        (match_operand:SI 3 "const8_operand" "")))]
   ""
 {
   /* Handle extractions from %ah et al.  */
 (define_expand "extzv"
   [(set (match_operand:SI 0 "register_operand" "")
        (zero_extract:SI (match_operand 1 "ext_register_operand" "")
-                        (match_operand:SI 2 "immediate_operand" "")
-                        (match_operand:SI 3 "immediate_operand" "")))]
+                        (match_operand:SI 2 "const8_operand" "")
+                        (match_operand:SI 3 "const8_operand" "")))]
   ""
 {
   /* Handle extractions from %ah et al.  */
 
 (define_expand "insv"
   [(set (zero_extract (match_operand 0 "ext_register_operand" "")
-                     (match_operand 1 "immediate_operand" "")
-                     (match_operand 2 "immediate_operand" ""))
+                     (match_operand 1 "const8_operand" "")
+                     (match_operand 2 "const8_operand" ""))
         (match_operand 3 "register_operand" ""))]
   ""
 {
-  /* Handle extractions from %ah et al.  */
+  /* Handle insertions to %ah et al.  */
   if (INTVAL (operands[1]) != 8 || INTVAL (operands[2]) != 8)
     FAIL;
 
 (define_insn "*fp_jcc_1_mixed"
   [(set (pc)
        (if_then_else (match_operator 0 "comparison_operator"
-                       [(match_operand 1 "register_operand" "f#x,x#f")
-                        (match_operand 2 "nonimmediate_operand" "f#x,xm#f")])
+                       [(match_operand 1 "register_operand" "f,x")
+                        (match_operand 2 "nonimmediate_operand" "f,xm")])
          (label_ref (match_operand 3 "" ""))
          (pc)))
    (clobber (reg:CCFP FPSR_REG))
 (define_insn "*fp_jcc_2_mixed"
   [(set (pc)
        (if_then_else (match_operator 0 "comparison_operator"
-                       [(match_operand 1 "register_operand" "f#x,x#f")
-                        (match_operand 2 "nonimmediate_operand" "f#x,xm#f")])
+                       [(match_operand 1 "register_operand" "f,x")
+                        (match_operand 2 "nonimmediate_operand" "f,xm")])
          (pc)
          (label_ref (match_operand 3 "" ""))))
    (clobber (reg:CCFP FPSR_REG))
 #else
   /* It is tempting to use ASM_OUTPUT_ALIGN here, but we don't want to do that.
      The align insn is used to avoid 3 jump instructions in the row to improve
-     branch prediction and the benefits hardly outweight the cost of extra 8
+     branch prediction and the benefits hardly outweigh the cost of extra 8
      nops on the average inserted by full alignment pseudo operation.  */
 #endif
   return "";
        (unspec:SI [(const_int 0)] UNSPEC_SET_GOT))
    (clobber (reg:CC FLAGS_REG))]
   "!TARGET_64BIT"
-  { return output_set_got (operands[0]); }
+  { return output_set_got (operands[0], NULL_RTX); }
+  [(set_attr "type" "multi")
+   (set_attr "length" "12")])
+
+(define_insn "set_got_labelled"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (unspec:SI [(label_ref (match_operand 1 "" ""))]
+        UNSPEC_SET_GOT))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT"
+  { return output_set_got (operands[0], operands[1]); }
   [(set_attr "type" "multi")
    (set_attr "length" "12")])
 
       operands[2] = gen_reg_rtx (Pmode);
       emit_insn (gen_set_got (operands[2]));
     }
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_32
+                 (operands[0], operands[1], operands[2]));
+       DONE;
+    }
   operands[3] = ix86_tls_get_addr ();
 })
 
 (define_insn "*tls_global_dynamic_64"
   [(set (match_operand:DI 0 "register_operand" "=a")
-       (call (mem:QI (match_operand:DI 2 "call_insn_operand" ""))
-                     (match_operand:DI 3 "" "")))
+       (call:DI (mem:QI (match_operand:DI 2 "call_insn_operand" ""))
+                (match_operand:DI 3 "" "")))
    (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")]
              UNSPEC_TLS_GD)]
   "TARGET_64BIT"
 
 (define_expand "tls_global_dynamic_64"
   [(parallel [(set (match_operand:DI 0 "register_operand" "")
-                  (call (mem:QI (match_dup 2)) (const_int 0)))
+                  (call:DI (mem:QI (match_dup 2)) (const_int 0)))
              (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")]
                         UNSPEC_TLS_GD)])]
   ""
 {
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_64
+                 (operands[0], operands[1]));
+       DONE;
+    }
   operands[2] = ix86_tls_get_addr ();
 })
 
       operands[1] = gen_reg_rtx (Pmode);
       emit_insn (gen_set_got (operands[1]));
     }
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_32
+                 (operands[0], ix86_tls_module_base (), operands[1]));
+       DONE;
+    }
   operands[2] = ix86_tls_get_addr ();
 })
 
 (define_insn "*tls_local_dynamic_base_64"
   [(set (match_operand:DI 0 "register_operand" "=a")
-       (call (mem:QI (match_operand:DI 1 "call_insn_operand" ""))
-                     (match_operand:DI 2 "" "")))
+       (call:DI (mem:QI (match_operand:DI 1 "call_insn_operand" ""))
+                (match_operand:DI 2 "" "")))
    (unspec:DI [(const_int 0)] UNSPEC_TLS_LD_BASE)]
   "TARGET_64BIT"
   "lea{q}\t{%&@TLSLD(%%rip), %%rdi|%%rdi, %&@TLSLD[%%rip]}\;call\t%P1"
 
 (define_expand "tls_local_dynamic_base_64"
   [(parallel [(set (match_operand:DI 0 "register_operand" "")
-                  (call (mem:QI (match_dup 1)) (const_int 0)))
+                  (call:DI (mem:QI (match_dup 1)) (const_int 0)))
              (unspec:DI [(const_int 0)] UNSPEC_TLS_LD_BASE)])]
   ""
 {
+  if (TARGET_GNU2_TLS)
+    {
+       emit_insn (gen_tls_dynamic_gnu2_64
+                 (operands[0], ix86_tls_module_base ()));
+       DONE;
+    }
   operands[1] = ix86_tls_get_addr ();
 })
 
    (set_attr "length" "7")
    (set_attr "memory" "load")
    (set_attr "imm_disp" "false")])
+
+;; GNU2 TLS patterns can be split.
+
+(define_expand "tls_dynamic_gnu2_32"
+  [(set (match_dup 3)
+       (plus:SI (match_operand:SI 2 "register_operand" "")
+                (const:SI
+                 (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "")]
+                            UNSPEC_TLSDESC))))
+   (parallel
+    [(set (match_operand:SI 0 "register_operand" "")
+         (unspec:SI [(match_dup 1) (match_dup 3)
+                     (match_dup 2) (reg:SI SP_REG)]
+                     UNSPEC_TLSDESC))
+     (clobber (reg:CC FLAGS_REG))])]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+{
+  operands[3] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  ix86_tls_descriptor_calls_expanded_in_cfun = true;
+})
+
+(define_insn "*tls_dynamic_lea_32"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (plus:SI (match_operand:SI 1 "register_operand" "b")
+                (const:SI
+                 (unspec:SI [(match_operand:SI 2 "tls_symbolic_operand" "")]
+                             UNSPEC_TLSDESC))))]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+  "lea{l}\t{%a2@TLSDESC(%1), %0|%0, %a2@TLSDESC[%1]}"
+  [(set_attr "type" "lea")
+   (set_attr "mode" "SI")
+   (set_attr "length" "6")
+   (set_attr "length_address" "4")])
+
+(define_insn "*tls_dynamic_call_32"
+  [(set (match_operand:SI 0 "register_operand" "=a")
+       (unspec:SI [(match_operand:SI 1 "tls_symbolic_operand" "")
+                   (match_operand:SI 2 "register_operand" "0")
+                   ;; we have to make sure %ebx still points to the GOT
+                   (match_operand:SI 3 "register_operand" "b")
+                   (reg:SI SP_REG)]
+                  UNSPEC_TLSDESC))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+  "call\t{*%a1@TLSCALL(%2)|[DWORD PTR [%2+%a1@TLSCALL]]}"
+  [(set_attr "type" "call")
+   (set_attr "length" "2")
+   (set_attr "length_address" "0")])
+
+(define_insn_and_split "*tls_dynamic_gnu2_combine_32"
+  [(set (match_operand:SI 0 "register_operand" "=&a")
+       (plus:SI
+        (unspec:SI [(match_operand:SI 3 "tls_modbase_operand" "")
+                    (match_operand:SI 4 "" "")
+                    (match_operand:SI 2 "register_operand" "b")
+                    (reg:SI SP_REG)]
+                   UNSPEC_TLSDESC)
+        (const:SI (unspec:SI
+                   [(match_operand:SI 1 "tls_symbolic_operand" "")]
+                   UNSPEC_DTPOFF))))
+   (clobber (reg:CC FLAGS_REG))]
+  "!TARGET_64BIT && TARGET_GNU2_TLS"
+  "#"
+  ""
+  [(set (match_dup 0) (match_dup 5))]
+{
+  operands[5] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  emit_insn (gen_tls_dynamic_gnu2_32 (operands[5], operands[1], operands[2]));
+})
+
+(define_expand "tls_dynamic_gnu2_64"
+  [(set (match_dup 2)
+       (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")]
+                  UNSPEC_TLSDESC))
+   (parallel
+    [(set (match_operand:DI 0 "register_operand" "")
+         (unspec:DI [(match_dup 1) (match_dup 2) (reg:DI SP_REG)]
+                    UNSPEC_TLSDESC))
+     (clobber (reg:CC FLAGS_REG))])]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+{
+  operands[2] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  ix86_tls_descriptor_calls_expanded_in_cfun = true;
+})
+
+(define_insn "*tls_dynamic_lea_64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")]
+                  UNSPEC_TLSDESC))]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+  "lea{q}\t{%a1@TLSDESC(%%rip), %0|%0, %a1@TLSDESC[%%rip]}"
+  [(set_attr "type" "lea")
+   (set_attr "mode" "DI")
+   (set_attr "length" "7")
+   (set_attr "length_address" "4")])
+
+(define_insn "*tls_dynamic_call_64"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (unspec:DI [(match_operand:DI 1 "tls_symbolic_operand" "")
+                   (match_operand:DI 2 "register_operand" "0")
+                   (reg:DI SP_REG)]
+                  UNSPEC_TLSDESC))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+  "call\t{*%a1@TLSCALL(%2)|[QWORD PTR [%2+%a1@TLSCALL]]}"
+  [(set_attr "type" "call")
+   (set_attr "length" "2")
+   (set_attr "length_address" "0")])
+
+(define_insn_and_split "*tls_dynamic_gnu2_combine_64"
+  [(set (match_operand:DI 0 "register_operand" "=&a")
+       (plus:DI
+        (unspec:DI [(match_operand:DI 2 "tls_modbase_operand" "")
+                    (match_operand:DI 3 "" "")
+                    (reg:DI SP_REG)]
+                   UNSPEC_TLSDESC)
+        (const:DI (unspec:DI
+                   [(match_operand:DI 1 "tls_symbolic_operand" "")]
+                   UNSPEC_DTPOFF))))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT && TARGET_GNU2_TLS"
+  "#"
+  ""
+  [(set (match_dup 0) (match_dup 4))]
+{
+  operands[4] = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
+  emit_insn (gen_tls_dynamic_gnu2_64 (operands[4], operands[1]));
+})
+
+;;
 \f
 ;; These patterns match the binary 387 instructions for addM3, subM3,
 ;; mulM3 and divM3.  There are three patterns for each of DFmode and
 ;; so use special patterns for add and mull.
 
 (define_insn "*fop_sf_comm_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,x#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,x")
        (match_operator:SF 3 "binary_fp_operator"
                        [(match_operand:SF 1 "nonimmediate_operand" "%0,0")
-                        (match_operand:SF 2 "nonimmediate_operand" "fm#x,xm#f")]))]
+                        (match_operand:SF 2 "nonimmediate_operand" "fm,xm")]))]
   "TARGET_MIX_SSE_I387
    && COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
   [(set (match_operand:SF 0 "register_operand" "=f,f,x")
        (match_operator:SF 3 "binary_fp_operator"
                        [(match_operand:SF 1 "nonimmediate_operand" "0,fm,0")
-                        (match_operand:SF 2 "nonimmediate_operand" "fm,0,xm#f")]))]
+                        (match_operand:SF 2 "nonimmediate_operand" "fm,0,xm")]))]
   "TARGET_MIX_SSE_I387
    && !COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*fop_df_comm_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,Y")
        (match_operator:DF 3 "binary_fp_operator"
                        [(match_operand:DF 1 "nonimmediate_operand" "%0,0")
-                        (match_operand:DF 2 "nonimmediate_operand" "fm#Y,Ym#f")]))]
+                        (match_operand:DF 2 "nonimmediate_operand" "fm,Ym")]))]
   "TARGET_SSE2 && TARGET_MIX_SSE_I387
    && COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
   "* return output_387_binary_op (insn, operands);"
   [(set (attr "type") 
        (if_then_else (eq_attr "alternative" "1")
-          (if_then_else (match_operand:SF 3 "mult_operator" "") 
+          (if_then_else (match_operand:DF 3 "mult_operator" "") 
              (const_string "ssemul")
              (const_string "sseadd"))
-          (if_then_else (match_operand:SF 3 "mult_operator" "") 
+          (if_then_else (match_operand:DF 3 "mult_operator" "") 
              (const_string "fmul")
              (const_string "fop"))))
    (set_attr "mode" "DF")])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
   "* return output_387_binary_op (insn, operands);"
   [(set (attr "type") 
-        (if_then_else (match_operand:SF 3 "mult_operator" "") 
+        (if_then_else (match_operand:DF 3 "mult_operator" "") 
           (const_string "ssemul")
           (const_string "sseadd")))
    (set_attr "mode" "DF")])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
   "* return output_387_binary_op (insn, operands);"
   [(set (attr "type") 
-       (if_then_else (match_operand:SF 3 "mult_operator" "") 
+       (if_then_else (match_operand:DF 3 "mult_operator" "") 
           (const_string "fmul")
           (const_string "fop")))
    (set_attr "mode" "DF")])
 
 (define_insn "*fop_df_1_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,f#Y,Y#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,f,Y")
        (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#f")]))]
+                        (match_operand:DF 2 "nonimmediate_operand" "fm,0,Ym")]))]
   "TARGET_SSE2 && TARGET_SSE_MATH && TARGET_MIX_SSE_I387
    && !COMMUTATIVE_ARITH_P (operands[3])
    && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
   "* return output_387_binary_op (insn, operands);"
   [(set (attr "type") 
         (cond [(and (eq_attr "alternative" "2")
-                   (match_operand:SF 3 "mult_operator" ""))
+                   (match_operand:DF 3 "mult_operator" ""))
                  (const_string "ssemul")
               (and (eq_attr "alternative" "2")
-                   (match_operand:SF 3 "div_operator" ""))
+                   (match_operand:DF 3 "div_operator" ""))
                  (const_string "ssediv")
               (eq_attr "alternative" "2")
                  (const_string "sseadd")
   "* return output_387_binary_op (insn, operands);"
   [(set_attr "mode" "DF")
    (set (attr "type") 
-        (cond [(match_operand:SF 3 "mult_operator" "")
+        (cond [(match_operand:DF 3 "mult_operator" "")
                  (const_string "ssemul")
-              (match_operand:SF 3 "div_operator" "")
+              (match_operand:DF 3 "div_operator" "")
                  (const_string "ssediv")
               ]
               (const_string "sseadd")))])
 })
 
 (define_insn "*sqrtsf2_mixed"
-  [(set (match_operand:SF 0 "register_operand" "=f#x,x#f")
-       (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "0#x,xm#f")))]
+  [(set (match_operand:SF 0 "register_operand" "=f,x")
+       (sqrt:SF (match_operand:SF 1 "nonimmediate_operand" "0,xm")))]
   "TARGET_USE_FANCY_MATH_387 && TARGET_MIX_SSE_I387"
   "@
    fsqrt
 })
 
 (define_insn "*sqrtdf2_mixed"
-  [(set (match_operand:DF 0 "register_operand" "=f#Y,Y#f")
-       (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "0#Y,Ym#f")))]
+  [(set (match_operand:DF 0 "register_operand" "=f,Y")
+       (sqrt:DF (match_operand:DF 1 "nonimmediate_operand" "0,Ym")))]
   "TARGET_USE_FANCY_MATH_387 && TARGET_SSE2 && TARGET_MIX_SSE_I387"
   "@
    fsqrt
 (define_insn "sqrtxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (sqrt:XF (match_operand:XF 1 "register_operand" "0")))]
-  "TARGET_USE_FANCY_MATH_387 
-   && (TARGET_IEEE_FP || flag_unsafe_math_optimizations) "
+  "TARGET_USE_FANCY_MATH_387"
   "fsqrt"
   [(set_attr "type" "fpspc")
    (set_attr "mode" "XF")
   DONE;
 })
 
+(define_insn_and_split "*fistdi2_1"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r")
+       (unspec:DI [(match_operand:XF 1 "register_operand" "f,f")]
+        UNSPEC_FIST))]
+  "TARGET_USE_FANCY_MATH_387
+   && flag_unsafe_math_optimizations
+   && !(reload_completed || reload_in_progress)"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  if (memory_operand (operands[0], VOIDmode))
+    emit_insn (gen_fistdi2 (operands[0], operands[1]));
+  else
+    {
+      operands[2] = assign_386_stack_local (DImode, SLOT_TEMP);
+      emit_insn (gen_fistdi2_with_temp (operands[0], operands[1],
+                                        operands[2]));
+    }
+  DONE;
+}
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "DI")])
+
 (define_insn "fistdi2"
   [(set (match_operand:DI 0 "memory_operand" "=m")
        (unspec:DI [(match_operand:XF 1 "register_operand" "f")]
              (clobber (match_dup 3))])]
   "")
 
+(define_insn_and_split "*fist<mode>2_1"
+  [(set (match_operand:X87MODEI12 0 "register_operand" "=r")
+       (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")]
+        UNSPEC_FIST))]
+  "TARGET_USE_FANCY_MATH_387
+   && flag_unsafe_math_optimizations
+   && !(reload_completed || reload_in_progress)"
+  "#"
+  "&& 1"
+  [(const_int 0)]
+{
+  operands[2] = assign_386_stack_local (<MODE>mode, SLOT_TEMP);
+  emit_insn (gen_fist<mode>2_with_temp (operands[0], operands[1],
+                                       operands[2]));
+  DONE;
+}
+  [(set_attr "type" "fpspc")
+   (set_attr "mode" "<MODE>")])
+
 (define_insn "fist<mode>2"
   [(set (match_operand:X87MODEI12 0 "memory_operand" "=m")
        (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")]
    (set_attr "mode" "<MODE>")])
 
 (define_insn "fist<mode>2_with_temp"
-  [(set (match_operand:X87MODEI12 0 "nonimmediate_operand" "=m,?r")
-       (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f,f")]
+  [(set (match_operand:X87MODEI12 0 "register_operand" "=r")
+       (unspec:X87MODEI12 [(match_operand:XF 1 "register_operand" "f")]
         UNSPEC_FIST))
-   (clobber (match_operand:X87MODEI12 2 "memory_operand" "=m,m"))]
+   (clobber (match_operand:X87MODEI12 2 "memory_operand" "=m"))]
   "TARGET_USE_FANCY_MATH_387
    && flag_unsafe_math_optimizations"
   "#"
   "")
 
 (define_expand "lrint<mode>2"
-  [(use (match_operand:X87MODEI 0 "nonimmediate_operand" ""))
-   (use (match_operand:XF 1 "register_operand" ""))]
+  [(set (match_operand:X87MODEI 0 "nonimmediate_operand" "")
+       (unspec:X87MODEI [(match_operand:XF 1 "register_operand" "")]
+        UNSPEC_FIST))]
   "TARGET_USE_FANCY_MATH_387
    && (!TARGET_SSE_MATH || TARGET_MIX_SSE_I387)
    && flag_unsafe_math_optimizations"
-{
-  if (memory_operand (operands[0], VOIDmode))
-    emit_insn (gen_fist<mode>2 (operands[0], operands[1]));
-  else
-    {
-      rtx op = assign_386_stack_local (<MODE>mode, SLOT_TEMP);
-      emit_insn (gen_fist<mode>2_with_temp (operands[0], operands[1],
-                                           op));
-    }
-  DONE;
-})
+  "")
 
 ;; Rounding mode control word calculation could clobber FLAGS_REG.
 (define_insn_and_split "frndintxf2_floor"
   "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
 
 (define_insn "*movsfcc_1_387"
-  [(set (match_operand:SF 0 "register_operand" "=f#r,f#r,r#f,r#f")
+  [(set (match_operand:SF 0 "register_operand" "=f,f,r,r")
        (if_then_else:SF (match_operator 1 "fcmov_comparison_operator" 
                                [(reg FLAGS_REG) (const_int 0)])
-                     (match_operand:SF 2 "nonimmediate_operand" "f#r,0,rm#f,0")
-                     (match_operand:SF 3 "nonimmediate_operand" "0,f#r,0,rm#f")))]
+                     (match_operand:SF 2 "nonimmediate_operand" "f,0,rm,0")
+                     (match_operand:SF 3 "nonimmediate_operand" "0,f,0,rm")))]
   "TARGET_80387 && TARGET_CMOVE
    && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
   "@
   "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")
 
 (define_insn "*movdfcc_1"
-  [(set (match_operand:DF 0 "register_operand" "=f#r,f#r,&r#f,&r#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,f,&r,&r")
        (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" 
                                [(reg FLAGS_REG) (const_int 0)])
-                     (match_operand:DF 2 "nonimmediate_operand" "f#r,0,rm#f,0")
-                     (match_operand:DF 3 "nonimmediate_operand" "0,f#r,0,rm#f")))]
+                     (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0")
+                     (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))]
   "!TARGET_64BIT && TARGET_80387 && TARGET_CMOVE
    && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
   "@
    (set_attr "mode" "DF")])
 
 (define_insn "*movdfcc_1_rex64"
-  [(set (match_operand:DF 0 "register_operand" "=f#r,f#r,r#f,r#f")
+  [(set (match_operand:DF 0 "register_operand" "=f,f,r,r")
        (if_then_else:DF (match_operator 1 "fcmov_comparison_operator" 
                                [(reg FLAGS_REG) (const_int 0)])
-                     (match_operand:DF 2 "nonimmediate_operand" "f#r,0#r,rm#f,0#f")
-                     (match_operand:DF 3 "nonimmediate_operand" "0#r,f#r,0#f,rm#f")))]
+                     (match_operand:DF 2 "nonimmediate_operand" "f,0,rm,0")
+                     (match_operand:DF 3 "nonimmediate_operand" "0,f,0,rm")))]
   "TARGET_64BIT && TARGET_80387 && TARGET_CMOVE
    && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
   "@
   [(set_attr "type" "sseadd")
    (set_attr "mode" "DF")])
 
+;; Make two stack loads independent:
+;;   fld aa              fld aa
+;;   fld %st(0)     ->   fld bb
+;;   fmul bb             fmul %st(1), %st
+;;
+;; Actually we only match the last two instructions for simplicity.
+(define_peephole2
+  [(set (match_operand 0 "fp_register_operand" "")
+       (match_operand 1 "fp_register_operand" ""))
+   (set (match_dup 0)
+       (match_operator 2 "binary_fp_operator"
+          [(match_dup 0)
+           (match_operand 3 "memory_operand" "")]))]
+  "REGNO (operands[0]) != REGNO (operands[1])"
+  [(set (match_dup 0) (match_dup 3))
+   (set (match_dup 0) (match_dup 4))]
+
+  ;; The % modifier is not operational anymore in peephole2's, so we have to
+  ;; swap the operands manually in the case of addition and multiplication.
+  "if (COMMUTATIVE_ARITH_P (operands[2]))
+     operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[2]), GET_MODE (operands[2]),
+                                operands[0], operands[1]);
+   else
+     operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[2]), GET_MODE (operands[2]),
+                                operands[1], operands[0]);")
+
 ;; Conditional addition patterns
 (define_expand "addqicc"
   [(match_operand:QI 0 "register_operand" "")
   [(label_ref (match_operand 0 "" ""))]
   "!TARGET_64BIT && flag_pic"
 {
-  emit_insn (gen_set_got (pic_offset_table_rtx));
+  if (TARGET_MACHO)
+    {
+      rtx xops[3];
+      rtx picreg = gen_rtx_REG (Pmode, PIC_OFFSET_TABLE_REGNUM);
+      rtx label_rtx = gen_label_rtx ();
+      emit_insn (gen_set_got_labelled (pic_offset_table_rtx, label_rtx));
+      xops[0] = xops[1] = picreg;
+      xops[2] = gen_rtx_CONST (SImode,
+                 gen_rtx_MINUS (SImode,
+                   gen_rtx_LABEL_REF (SImode, label_rtx),
+                   gen_rtx_SYMBOL_REF (SImode, GOT_SYMBOL_NAME)));
+      ix86_expand_binary_operator (MINUS, SImode, xops);
+    }
+  else
+    emit_insn (gen_set_got (pic_offset_table_rtx));
   DONE;
 })
 \f
   "! TARGET_PARTIAL_REG_STALL && reload_completed
    && ((GET_MODE (operands[0]) == HImode 
        && ((!optimize_size && !TARGET_FAST_PREFIX)
+            /* ??? next two lines just !satisfies_constraint_K (...) */
            || GET_CODE (operands[2]) != CONST_INT
-           || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')))
+           || satisfies_constraint_K (operands[2])))
        || (GET_MODE (operands[0]) == QImode 
           && (TARGET_PROMOTE_QImode || optimize_size)))"
   [(parallel [(set (match_dup 0)
   [(set (match_operand:SI 0 "push_operand" "")
        (match_operand:SI 1 "memory_operand" ""))
    (match_scratch:SI 2 "r")]
-  "! optimize_size && ! TARGET_PUSH_MEMORY"
+  "!optimize_size && !TARGET_PUSH_MEMORY
+   && !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
   [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (match_dup 2))]
   "")
   [(set (match_operand:DI 0 "push_operand" "")
        (match_operand:DI 1 "memory_operand" ""))
    (match_scratch:DI 2 "r")]
-  "! optimize_size && ! TARGET_PUSH_MEMORY"
+  "!optimize_size && !TARGET_PUSH_MEMORY
+   && !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
   [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (match_dup 2))]
   "")
   [(set (match_operand:SF 0 "push_operand" "")
        (match_operand:SF 1 "memory_operand" ""))
    (match_scratch:SF 2 "r")]
-  "! optimize_size && ! TARGET_PUSH_MEMORY"
+  "!optimize_size && !TARGET_PUSH_MEMORY
+   && !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
   [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (match_dup 2))]
   "")
   [(set (match_operand:HI 0 "push_operand" "")
        (match_operand:HI 1 "memory_operand" ""))
    (match_scratch:HI 2 "r")]
-  "! optimize_size && ! TARGET_PUSH_MEMORY"
+  "!optimize_size && !TARGET_PUSH_MEMORY
+   && !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
   [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (match_dup 2))]
   "")
   [(set (match_operand:QI 0 "push_operand" "")
        (match_operand:QI 1 "memory_operand" ""))
    (match_scratch:QI 2 "q")]
-  "! optimize_size && ! TARGET_PUSH_MEMORY"
+  "!optimize_size && !TARGET_PUSH_MEMORY
+   && !RTX_FRAME_RELATED_P (peep2_next_insn (0))"
   [(set (match_dup 2) (match_dup 1))
    (set (match_dup 0) (match_dup 2))]
   "")
           (const_int 0)]))]
   "ix86_match_ccmode (insn, CCNOmode)
    && (true_regnum (operands[2]) != 0
-       || (GET_CODE (operands[3]) == CONST_INT
-          && CONST_OK_FOR_LETTER_P (INTVAL (operands[3]), 'K')))
+       || satisfies_constraint_K (operands[3]))
    && peep2_reg_dead_p (1, operands[2])"
   [(parallel
      [(set (match_dup 0)
                   (mult:DI (match_operand:DI 1 "memory_operand" "")
                            (match_operand:DI 2 "immediate_operand" "")))
              (clobber (reg:CC FLAGS_REG))])]
-  "TARGET_K8 && !optimize_size
-   && (GET_CODE (operands[2]) != CONST_INT
-       || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size
+   && !satisfies_constraint_K (operands[2])"
   [(set (match_dup 3) (match_dup 1))
    (parallel [(set (match_dup 0) (mult:DI (match_dup 3) (match_dup 2)))
              (clobber (reg:CC FLAGS_REG))])]
                   (mult:SI (match_operand:SI 1 "memory_operand" "")
                            (match_operand:SI 2 "immediate_operand" "")))
              (clobber (reg:CC FLAGS_REG))])]
-  "TARGET_K8 && !optimize_size
-   && (GET_CODE (operands[2]) != CONST_INT
-       || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size
+   && !satisfies_constraint_K (operands[2])"
   [(set (match_dup 3) (match_dup 1))
    (parallel [(set (match_dup 0) (mult:SI (match_dup 3) (match_dup 2)))
              (clobber (reg:CC FLAGS_REG))])]
                     (mult:SI (match_operand:SI 1 "memory_operand" "")
                              (match_operand:SI 2 "immediate_operand" ""))))
              (clobber (reg:CC FLAGS_REG))])]
-  "TARGET_K8 && !optimize_size
-   && (GET_CODE (operands[2]) != CONST_INT
-       || !CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K'))"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size
+   && !satisfies_constraint_K (operands[2])"
   [(set (match_dup 3) (match_dup 1))
    (parallel [(set (match_dup 0) (zero_extend:DI (mult:SI (match_dup 3) (match_dup 2))))
              (clobber (reg:CC FLAGS_REG))])]
                            (match_operand:DI 2 "const_int_operand" "")))
              (clobber (reg:CC FLAGS_REG))])
    (match_scratch:DI 3 "r")]
-  "TARGET_K8 && !optimize_size
-   && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size
+   && satisfies_constraint_K (operands[2])"
   [(set (match_dup 3) (match_dup 2))
    (parallel [(set (match_dup 0) (mult:DI (match_dup 0) (match_dup 3)))
              (clobber (reg:CC FLAGS_REG))])]
                            (match_operand:SI 2 "const_int_operand" "")))
              (clobber (reg:CC FLAGS_REG))])
    (match_scratch:SI 3 "r")]
-  "TARGET_K8 && !optimize_size
-   && CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size
+   && satisfies_constraint_K (operands[2])"
   [(set (match_dup 3) (match_dup 2))
    (parallel [(set (match_dup 0) (mult:SI (match_dup 0) (match_dup 3)))
              (clobber (reg:CC FLAGS_REG))])]
                            (match_operand:HI 2 "immediate_operand" "")))
              (clobber (reg:CC FLAGS_REG))])
    (match_scratch:HI 3 "r")]
-  "TARGET_K8 && !optimize_size"
+  "(TARGET_K8 || TARGET_GENERIC64) && !optimize_size"
   [(set (match_dup 3) (match_dup 2))
    (parallel [(set (match_dup 0) (mult:HI (match_dup 0) (match_dup 3)))
              (clobber (reg:CC FLAGS_REG))])]
   if (!rtx_equal_p (operands[0], operands[1]))
     emit_move_insn (operands[0], operands[1]);
 })
+
+;; After splitting up read-modify operations, array accesses with memory
+;; operands might end up in form:
+;;  sall    $2, %eax
+;;  movl    4(%esp), %edx
+;;  addl    %edx, %eax
+;; instead of pre-splitting:
+;;  sall    $2, %eax
+;;  addl    4(%esp), %eax
+;; Turn it into:
+;;  movl    4(%esp), %edx
+;;  leal    (%edx,%eax,4), %eax
+
+(define_peephole2
+  [(parallel [(set (match_operand 0 "register_operand" "")
+                  (ashift (match_operand 1 "register_operand" "")
+                          (match_operand 2 "const_int_operand" "")))
+              (clobber (reg:CC FLAGS_REG))])
+   (set (match_operand 3 "register_operand")
+        (match_operand 4 "x86_64_general_operand" ""))
+   (parallel [(set (match_operand 5 "register_operand" "")
+                  (plus (match_operand 6 "register_operand" "")
+                        (match_operand 7 "register_operand" "")))
+                  (clobber (reg:CC FLAGS_REG))])]
+  "INTVAL (operands[2]) >= 0 && INTVAL (operands[2]) <= 3
+   /* Validate MODE for lea.  */
+   && ((!TARGET_PARTIAL_REG_STALL
+       && (GET_MODE (operands[0]) == QImode
+           || GET_MODE (operands[0]) == HImode))
+       || GET_MODE (operands[0]) == SImode 
+       || (TARGET_64BIT && GET_MODE (operands[0]) == DImode))
+   /* We reorder load and the shift.  */
+   && !rtx_equal_p (operands[1], operands[3])
+   && !reg_overlap_mentioned_p (operands[0], operands[4])
+   /* Last PLUS must consist of operand 0 and 3.  */
+   && !rtx_equal_p (operands[0], operands[3])
+   && (rtx_equal_p (operands[3], operands[6])
+       || rtx_equal_p (operands[3], operands[7]))
+   && (rtx_equal_p (operands[0], operands[6])
+       || rtx_equal_p (operands[0], operands[7]))
+   /* The intermediate operand 0 must die or be same as output.  */
+   && (rtx_equal_p (operands[0], operands[5])
+       || peep2_reg_dead_p (3, operands[0]))"
+  [(set (match_dup 3) (match_dup 4))
+   (set (match_dup 0) (match_dup 1))]
+{
+  enum machine_mode mode = GET_MODE (operands[5]) == DImode ? DImode : SImode;
+  int scale = 1 << INTVAL (operands[2]);
+  rtx index = gen_lowpart (Pmode, operands[1]);
+  rtx base = gen_lowpart (Pmode, operands[3]);
+  rtx dest = gen_lowpart (mode, operands[5]);
+
+  operands[1] = gen_rtx_PLUS (Pmode, base,
+                             gen_rtx_MULT (Pmode, index, GEN_INT (scale)));
+  if (mode != Pmode)
+    operands[1] = gen_rtx_SUBREG (mode, operands[1], 0);
+  operands[0] = dest;
+})
 \f
 ;; Call-value patterns last so that the wildcard operand does not
 ;; disrupt insn-recog's switch tables.
 (define_insn "trap"
   [(trap_if (const_int 1) (const_int 6))]
   ""
-  ".word\t0x0b0f"
+  { return ASM_SHORT "0x0b0f"; }
   [(set_attr "length" "2")])
 
 (define_expand "sse_prologue_save"
    (set (match_scratch:DI 2 "=&r") (const_int 0))
    (clobber (reg:CC FLAGS_REG))]
   "TARGET_64BIT"
-  "mov{q}\t{%%fs:%P1, %2|%2, QWORD PTR %%fs:%P1}\;mov{q}\t{%2, %0|%0, %2}\;xor{l}\t%k2, %k2"
+  {
+     /* The kernel uses a different segment register for performance reasons; a
+        system call would not have to trash the userspace segment register,
+        which would be expensive */
+     if (ix86_cmodel != CM_KERNEL)
+        return "mov{q}\t{%%fs:%P1, %2|%2, QWORD PTR %%fs:%P1}\;mov{q}\t{%2, %0|%0, %2}\;xor{l}\t%k2, %k2";
+     else
+        return "mov{q}\t{%%gs:%P1, %2|%2, QWORD PTR %%gs:%P1}\;mov{q}\t{%2, %0|%0, %2}\;xor{l}\t%k2, %k2";
+  }
   [(set_attr "type" "multi")])
 
 (define_expand "stack_protect_test"
                    UNSPEC_SP_TLS_TEST))
    (clobber (match_scratch:DI 3 "=r"))]
   "TARGET_64BIT"
-  "mov{q}\t{%1, %3|%3, %1}\;xor{q}\t{%%fs:%P2, %3|%3, QWORD PTR %%fs:%P2}"
+  {
+     /* The kernel uses a different segment register for performance reasons; a
+        system call would not have to trash the userspace segment register,
+        which would be expensive */
+     if (ix86_cmodel != CM_KERNEL)
+        return "mov{q}\t{%1, %3|%3, %1}\;xor{q}\t{%%fs:%P2, %3|%3, QWORD PTR %%fs:%P2}";
+     else
+        return "mov{q}\t{%1, %3|%3, %1}\;xor{q}\t{%%gs:%P2, %3|%3, QWORD PTR %%gs:%P2}";
+  }
   [(set_attr "type" "multi")])
 
 (include "sse.md")