OSDN Git Service

(fp, integer): Added function units for pentium.
authorcoxs <coxs@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Feb 1996 22:46:21 +0000 (22:46 +0000)
committercoxs <coxs@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 9 Feb 1996 22:46:21 +0000 (22:46 +0000)
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@11190 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/config/i386/i386.md

index 9df676e..c0a5d01 100644 (file)
@@ -17,8 +17,7 @@
 ;; You should have received a copy of the GNU General Public License
 ;; along with GNU CC; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
-
+;; Boston, MA 02111-1307, USA. */
 
 ;; The original PO technology requires these to be ordered by speed,
 ;; so that assigner will pick the fastest.
 ;; 2  This is a `cos' operation.  The mode of the UNSPEC is MODE_FLOAT.
 ;;    operand 0 is the argument for `cos'.
 \f
+;; This shadows the processor_type enumeration, so changes must be made
+;; to i386.h at the same time.
+
+(define_attr "type" "integer,fld,fpop,fpdiv"
+  (const_string "integer"))
+
+;; Functional units
+
+;; Floating point
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "fpop") (eq_attr "cpu" "!pentium"))
+ 5 5)
+
+(define_function_unit "fp" 1 0
+ (and (eq_attr "type" "fpop") (eq_attr "cpu" "pentium")) 
+ 3 0)
+
+(define_function_unit "fp" 1 0
+ (eq_attr "type" "fpdiv") 
+ 10 10)
+
+(define_function_unit "fp" 1 0
+ (eq_attr "type" "fld") 
+ 1 0)
+
+(define_function_unit "integer" 1 0
+  (and (eq_attr "type" "integer") (eq_attr "cpu" "!i386"))
+ 2 0)
+
+\f
 ;; "movl MEM,REG / testl REG,REG" is faster on a 486 than "cmpl $0,MEM".
 ;; But restricting MEM here would mean that gcc could not remove a redundant
 ;; test in cases like "incl MEM / je TARGET".
 ;; enumeration in rs6000.h.
 
 (define_attr "cpu" "i386,i486,pentium"
-  (const (symbol_ref "ix86_cpu_attr")))
+  (const (symbol_ref "ix86_cpu")))
 
 (define_insn "tstsi_1"
   [(set (cc0)
   return output_fp_cc0_set (insn);
 }")
 
-;; Don't generate tstdf if generating IEEE code, since the `ftst' opcode
+;; Don't generate tstxf if generating IEEE code, since the `ftst' opcode
 ;; isn't IEEE compliant.
 
 (define_expand "tstxf"
 (define_insn ""
   [(set (cc0)
        (match_operator 2 "VOIDmode_compare_op"
-                       [(match_operand:XF 0 "nonimmediate_operand" "f")
-                        (match_operand:XF 1 "nonimmediate_operand" "f")]))
+                       [(match_operand:XF 0 "register_operand" "f")
+                        (match_operand:XF 1 "register_operand" "f")]))
    (clobber (match_scratch:HI 3 "=a"))]
   "TARGET_80387
    && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
 
 (define_insn ""
   [(set (cc0)
+       (match_operator 2 "VOIDmode_compare_op"
+                       [(float_extend:DF
+                         (match_operand:SF 0 "register_operand" "f"))
+                        (match_operand:DF 1 "nonimmediate_operand" "fm")]))
+   (clobber (match_scratch:HI 3 "=a"))]
+  "TARGET_80387"
+  "* return output_float_compare (insn, operands);")
+
+(define_insn ""
+  [(set (cc0)
        (compare:CCFPEQ (match_operand:DF 0 "register_operand" "f")
                        (match_operand:DF 1 "register_operand" "f")))
    (clobber (match_scratch:HI 2 "=a"))]
   i386_compare_gen = gen_cmpxf_cc;
   i386_compare_gen_eq = gen_cmpxf_ccfpeq;
   i386_compare_op0 = operands[0];
-  i386_compare_op1 = operands[1];
+  i386_compare_op1 = (immediate_operand (operands[1], XFmode))
+                       ? copy_to_mode_reg (XFmode, operands[1]) : operands[1];
   DONE;
 }")
 
 (define_expand "cmpdf"
   [(set (cc0)
        (compare (match_operand:DF 0 "register_operand" "")
-                (match_operand:DF 1 "nonimmediate_operand" "")))]
+                (match_operand:DF 1 "general_operand" "")))]
   "TARGET_80387"
   "
 {
   i386_compare_gen = gen_cmpdf_cc;
   i386_compare_gen_eq = gen_cmpdf_ccfpeq;
   i386_compare_op0 = operands[0];
-  i386_compare_op1 = operands[1];
+  i386_compare_op1 = (immediate_operand (operands[1], DFmode))
+                       ? copy_to_mode_reg (DFmode, operands[1]) : operands[1];
   DONE;
 }")
 
 (define_expand "cmpsf"
   [(set (cc0)
        (compare (match_operand:SF 0 "register_operand" "")
-                (match_operand:SF 1 "nonimmediate_operand" "")))]
+                (match_operand:SF 1 "general_operand" "")))]
   "TARGET_80387"
   "
 {
   i386_compare_gen = gen_cmpsf_cc;
   i386_compare_gen_eq = gen_cmpsf_ccfpeq;
   i386_compare_op0 = operands[0];
-  i386_compare_op1 = operands[1];
+  i386_compare_op1 = (immediate_operand (operands[1], SFmode))
+                       ? copy_to_mode_reg (SFmode, operands[1]) : operands[1];
   DONE;
 }")
 
 (define_insn ""
   [(set (cc0)
        (and:SI (match_operand:SI 0 "general_operand" "%ro")
-               (match_operand:SI 1 "general_operand" "ri")))]
+               (match_operand:SI 1 "nonmemory_operand" "ri")))]
   ""
   "*
 {
 (define_insn ""
   [(set (cc0)
        (and:HI (match_operand:HI 0 "general_operand" "%ro")
-               (match_operand:HI 1 "general_operand" "ri")))]
+               (match_operand:HI 1 "nonmemory_operand" "ri")))]
   ""
   "*
 {
 
 (define_insn ""
   [(set (cc0)
-       (and:QI (match_operand:QI 0 "general_operand" "%qm")
-               (match_operand:QI 1 "general_operand" "qi")))]
+       (and:QI (match_operand:QI 0 "nonimmediate_operand" "%qm")
+               (match_operand:QI 1 "nonmemory_operand" "qi")))]
   ""
   "*
 {
 
 (define_insn ""
   [(set (match_operand:SI 0 "push_operand" "=<")
-       (match_operand:SI 1 "general_operand" "ri"))]
+       (match_operand:SI 1 "nonmemory_operand" "ri"))]
   "!TARGET_PUSH_MEMORY && !TARGET_MOVE"
   "push%L0 %1")
 
 
 (define_insn ""
   [(set (match_operand:HI 0 "push_operand" "=<")
-       (match_operand:HI 1 "general_operand" "ri"))]
+       (match_operand:HI 1 "nonmemory_operand" "ri"))]
   "!TARGET_PUSH_MEMORY && !TARGET_MOVE"
   "push%W0 %1")
 
 ;; the amount pushed up to a halfword.
 (define_insn ""
   [(set (match_operand:QI 0 "push_operand" "=<")
-       (match_operand:QI 1 "immediate_operand" "n"))]
+       (match_operand:QI 1 "const_int_operand" "n"))]
   ""
   "* return AS1 (push%W0,%1);")
 
 (define_insn ""
   [(set (match_operand:QI 0 "push_operand" "=<")
-       (match_operand:QI 1 "nonimmediate_operand" "q"))]
+       (match_operand:QI 1 "register_operand" "q"))]
   "!TARGET_MOVE"
   "*
 {
 }")
 
 (define_insn ""
-  [(set (match_operand:QI 0 "general_operand" "=q,*r,qm")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,*r,qm")
        (match_operand:QI 1 "general_operand" "*g,q,qn"))]
   "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
   "*
 }")
 
 (define_insn ""
-  [(set (strict_low_part (match_operand:QI 0 "general_operand" "+qm,q"))
+  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
        (match_operand:QI 1 "general_operand" "*qn,m"))]
   "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
   "*
       DONE;
     }
 
-  /* If we are loading a floating point constant that isn't 0 or 1 into a register,
-     indicate we need the pic register loaded.  This could be optimized into stores
-     of constants if the target eventually moves to memory, but better safe than
-     sorry.  */
-  if (flag_pic
+  /* If we are loading a floating point constant that isn't 0 or 1
+into a register, indicate we need the pic register loaded.  This could
+be optimized into stores of constants if the target eventually moves
+to memory, but better safe than sorry.  */
+  if ((reload_in_progress | reload_completed) == 0
       && GET_CODE (operands[0]) != MEM
       && GET_CODE (operands[1]) == CONST_DOUBLE
       && !standard_80387_constant_p (operands[1]))
     {
-      current_function_uses_pic_offset_table = 1;
+      rtx insn, note, fp_const;
+
+      fp_const = force_const_mem (SFmode, operands[1]);
+      if (flag_pic)
+       current_function_uses_pic_offset_table = 1;
+
+      insn = emit_insn (gen_rtx (SET, SFmode, operands[0], fp_const));
+      note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+
+      if (note)
+       XEXP (note, 0) = operands[1];
+      else
+       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, operands[1], REG_NOTES (insn));
     }
 }")
 
 
 ;; For the purposes of regclass, prefer FLOAT_REGS.
 (define_insn "movsf_normal"
-  [(set (match_operand:SF 0 "general_operand" "=*rfm,*rf,f,!*rm")
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=*rfm,*rf,f,!*rm")
        (match_operand:SF 1 "general_operand" "*rf,*rfm,fG,fF"))]
   "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
   "*
   /* Handle all SFmode moves not involving the 387 */
 
   return singlemove_string (operands);
-}")
+}"
+  [(set_attr "type" "fld")])
+
 
 (define_insn "swapsf"
   [(set (match_operand:SF 0 "register_operand" "f")
      indicate we need the pic register loaded.  This could be optimized into stores
      of constants if the target eventually moves to memory, but better safe than
      sorry.  */
-  if (flag_pic
+  if ((reload_in_progress | reload_completed) == 0
       && GET_CODE (operands[0]) != MEM
       && GET_CODE (operands[1]) == CONST_DOUBLE
       && !standard_80387_constant_p (operands[1]))
     {
-      current_function_uses_pic_offset_table = 1;
+      rtx insn, note, fp_const;
+
+      fp_const = force_const_mem (DFmode, operands[1]);
+      if (flag_pic)
+       current_function_uses_pic_offset_table = 1;
+
+      insn = emit_insn (gen_rtx (SET, DFmode, operands[0], fp_const));
+      note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+
+      if (note)
+       XEXP (note, 0) = operands[1];
+      else
+       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, operands[1], REG_NOTES (insn));
     }
 }")
 
 
 ;; For the purposes of regclass, prefer FLOAT_REGS.
 (define_insn "movdf_normal"
-  [(set (match_operand:DF 0 "general_operand" "=f,fm,!*rf,!*rm")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,fm,!*rf,!*rm")
        (match_operand:DF 1 "general_operand" "fmG,f,*rfm,*rfF"))]
   "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
   "*
   /* Handle all DFmode moves not involving the 387 */
 
   return output_move_double (operands);
-}")
+}"
+[(set_attr "type" "fld")])
+
+
 
 (define_insn "swapdf"
   [(set (match_operand:DF 0 "register_operand" "f")
       DONE;
     }
 
-  /* If we are loading a floating point constant that isn't 0 or 1 into a register,
-     indicate we need the pic register loaded.  This could be optimized into stores
-     of constants if the target eventually moves to memory, but better safe than
-     sorry.  */
-  if (flag_pic
+  /* If we are loading a floating point constant that isn't 0 or 1
+into a register, indicate we need the pic register loaded.  This could
+be optimized into stores of constants if the target eventually moves
+to memory, but better safe than sorry.  */
+  if ((reload_in_progress | reload_completed) == 0
       && GET_CODE (operands[0]) != MEM
       && GET_CODE (operands[1]) == CONST_DOUBLE
       && !standard_80387_constant_p (operands[1]))
     {
-      current_function_uses_pic_offset_table = 1;
+      rtx insn, note, fp_const;
+
+      fp_const = force_const_mem (XFmode, operands[1]);
+      if (flag_pic)
+       current_function_uses_pic_offset_table = 1;
+
+      insn = emit_insn (gen_rtx (SET, XFmode, operands[0], fp_const));
+      note = find_reg_note (insn, REG_EQUAL, NULL_RTX);
+
+      if (note)
+       XEXP (note, 0) = operands[1];
+      else
+       REG_NOTES (insn) = gen_rtx (EXPR_LIST, REG_EQUAL, operands[1], REG_NOTES (insn));
     }
 }")
 
   "* return output_move_memory (operands, insn, GET_MODE_SIZE (XFmode), 2, 4);")
 
 (define_insn "movxf_normal"
-  [(set (match_operand:XF 0 "general_operand" "=f,fm,!*rf,!*rm")
+  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,fm,!*rf,!*rm")
        (match_operand:XF 1 "general_operand" "fmG,f,*rfm,*rfF"))]
   "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
   "*
   return output_move_double (operands);
 }")
 
-(define_insn "swapxf"
+(define_insn "swapxf" 
   [(set (match_operand:XF 0 "register_operand" "f")
        (match_operand:XF 1 "register_operand" "f"))
    (set (match_dup 1)
 ;; See comments by `andsi' for when andl is faster than movzx.
 
 (define_insn "zero_extendhisi2"
-  [(set (match_operand:SI 0 "general_operand" "=r")
-       (zero_extend:SI
-        (match_operand:HI 1 "nonimmediate_operand" "rm")))]
+  [(set (match_operand:SI 0 "register_operand" "=r,&r,?r")
+       (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm,rm")))]
   ""
   "*
-{
-  if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
+  {
+  rtx xops[2];
+
+  if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0) 
       && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
     {
-      rtx xops[2];
       xops[0] = operands[0];
       xops[1] = GEN_INT (0xffff);
       output_asm_insn (AS2 (and%L0,%1,%k0), xops);
       RET;
     }
+  if (TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1]))
+    {
+      output_asm_insn (AS2 (xor%L0,%0,%0),operands);
+      output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
+      RET;
+    }
+
+  if (TARGET_ZERO_EXTEND_WITH_AND)
+    {
+      xops[0] = operands[0];
+      xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xffff);
+      output_asm_insn (AS2 (mov%W0,%1,%w0),operands);
+      output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+      RET;
+    }
 
 #ifdef INTEL_SYNTAX
   return AS2 (movzx,%1,%0);
 #endif
 }")
 
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+       (const_int 0))
+  (set (strict_low_part (match_dup 2))
+       (match_dup 1))]
+ "operands[2] = gen_rtx (REG, HImode, REGNO (operands[0]));")
+
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (zero_extend:SI (match_operand:HI 1 "memory_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (match_dup 2))
+       (match_dup 1))
+  (set (match_dup 0)
+       (and:SI (match_dup 0)
+              (const_int 65535)))]
+  "operands[2] = gen_rtx (REG, HImode, REGNO (operands[0]));")
+
 (define_insn "zero_extendqihi2"
-  [(set (match_operand:HI 0 "general_operand" "=r")
-       (zero_extend:HI
-        (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+  [(set (match_operand:HI 0 "register_operand" "=q,&q,?r")
+       (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
   ""
   "*
-{
+  {
+  rtx xops[2];
+
   if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
-      && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
+      && REG_P (operands[1]) 
+      && REGNO (operands[0]) == REGNO (operands[1]))
     {
-      rtx xops[2];
       xops[0] = operands[0];
       xops[1] = GEN_INT (0xff);
       output_asm_insn (AS2 (and%L0,%1,%k0), xops);
       RET;
     }
-
+  if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
+    {
+      if(!reg_overlap_mentioned_p(operands[0],operands[1]))
+       {
+         output_asm_insn (AS2 (xor%L0,%k0,%k0), operands);
+         output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
+       }
+      else
+       {
+         xops[0] = operands[0];
+         xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xff);
+         output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
+         output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+       }
+      RET;
+    }
+  
 #ifdef INTEL_SYNTAX
   return AS2 (movzx,%1,%0);
 #else
 #endif
 }")
 
+(define_split
+  [(set (match_operand:HI 0 "register_operand" "")
+       (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+  && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+       (const_int 0))
+  (set (strict_low_part (match_dup 2))
+       (match_dup 1))]
+ "operands[2] = gen_rtx (REG, QImode, REGNO (operands[0]));")
+
+
+(define_split
+  [(set (match_operand:HI 0 "register_operand" "")
+       (zero_extend:HI (match_operand:QI 1 "memory_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+  && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (match_dup 2))
+       (match_dup 1))
+  (set (match_dup 0)
+       (and:HI (match_dup 0)
+              (const_int 255)))]
+ "operands[2] = gen_rtx (REG, QImode, REGNO (operands[0]));")
+
+(define_split
+  [(set (match_operand:HI 0 "register_operand" "")
+       (zero_extend:HI (match_operand:QI 1 "register_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && REGNO (operands[0]) != REGNO (operands[1])"
+ [(set (match_dup 0)
+       (match_dup 2))
+  (set (match_dup 0)
+       (and:HI (match_dup 0)
+              (const_int 255)))]
+ "operands[2] = gen_rtx (REG, HImode, REGNO (operands[1]));")
+
 (define_insn "zero_extendqisi2"
-  [(set (match_operand:SI 0 "general_operand" "=r")
-       (zero_extend:SI
-        (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+  [(set (match_operand:SI 0 "register_operand" "=q,&q,?r")
+       (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm,qm")))]
   ""
   "*
-{
+  {
+  rtx xops[2];
+
   if ((TARGET_ZERO_EXTEND_WITH_AND || REGNO (operands[0]) == 0)
-      && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1]))
+      && REG_P (operands[1]) 
+      && REGNO (operands[0]) == REGNO (operands[1]))
     {
-      rtx xops[2];
       xops[0] = operands[0];
       xops[1] = GEN_INT (0xff);
       output_asm_insn (AS2 (and%L0,%1,%k0), xops);
       RET;
     }
+  if (TARGET_ZERO_EXTEND_WITH_AND && QI_REG_P (operands[0]))
+    {
+      if(!reg_overlap_mentioned_p (operands[0], operands[1]))
+       {
+         output_asm_insn (AS2 (xor%L0,%0,%0),operands);
+         output_asm_insn (AS2 (mov%B0,%1,%b0),operands);
+       }
+      else
+       {
+         xops[0] = operands[0];
+         xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xff);
+         output_asm_insn (AS2 (mov%B0,%1,%b0), operands);
+         output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+       }
+      RET;
+    }
+
+  if (TARGET_ZERO_EXTEND_WITH_AND && GET_CODE (operands[1]) == REG)
+    {
+      xops[0] = operands[0];
+      xops[1] = gen_rtx (CONST_INT, VOIDmode, 0xff);
+      operands[1] = gen_rtx (REG, SImode, REGNO (operands[1]));
+      output_asm_insn (AS2 (mov%L0,%1,%0), operands);
+      output_asm_insn (AS2 (and%L0,%1,%k0), xops);
+      RET;
+    }
 
 #ifdef INTEL_SYNTAX
   return AS2 (movzx,%1,%0);
 #endif
 }")
 
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+  && !reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (match_dup 0)
+       (const_int 0))
+  (set (strict_low_part (match_dup 2))
+       (match_dup 1))]
+ "operands[2] = gen_rtx (REG, QImode, REGNO (operands[0]));")
+
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (zero_extend:SI (match_operand:QI 1 "memory_operand" "")))]
+ "reload_completed && QI_REG_P (operands[0]) && TARGET_ZERO_EXTEND_WITH_AND
+  && reg_overlap_mentioned_p (operands[0], operands[1])"
+ [(set (strict_low_part (match_dup 2))
+       (match_dup 1))
+  (set (match_dup 0)
+       (and:SI (match_dup 0)
+              (const_int 255)))]
+ "operands[2] = gen_rtx (REG, QImode, REGNO (operands[0]));")
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (zero_extend:SI (match_operand:QI 1 "register_operand" "")))]
+ "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && REGNO (operands[0]) != REGNO (operands[1])"
+ [(set (match_dup 0)
+       (match_dup 2))
+  (set (match_dup 0)
+       (and:SI (match_dup 0)
+              (const_int 255)))]
+ "operands[2] = gen_rtx (REG, SImode, REGNO (operands[1]));")
+
 (define_insn "zero_extendsidi2"
-  [(set (match_operand:DI 0 "register_operand" "=r")
-       (zero_extend:DI
-        (match_operand:SI 1 "register_operand" "0")))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?m")
+       (zero_extend:DI (match_operand:SI 1 "register_operand" "0,rm,r")))]
   ""
   "*
-{
-  operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
-  return AS2 (xor%L0,%0,%0);
+  {
+  rtx high[2], low[2], xops[4];
+
+  if (REG_P (operands[0]) && REG_P (operands[1])
+      && REGNO (operands[0]) == REGNO (operands[1]))
+    {
+      operands[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
+      return AS2 (xor%L0,%0,%0);
+    }
+
+  split_di (operands, 1, low, high);
+  xops[0] = low[0];
+  xops[1] = operands[1];
+  xops[2] = high[0];
+  xops[3] = const0_rtx;
+
+  output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+  if (GET_CODE (low[0]) == MEM)
+    output_asm_insn (AS2 (mov%L2,%3,%2), xops);
+  else
+    output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+
+  RET;
 }")
 \f
 ;;- sign extension instructions
 
 (define_insn "extendsidi2"
   [(set (match_operand:DI 0 "register_operand" "=r")
-       (sign_extend:DI
-        (match_operand:SI 1 "register_operand" "0")))]
+       (sign_extend:DI (match_operand:SI 1 "register_operand" "0")))]
   ""
   "*
 {
 ;; We use what the Unix assembler expects.
 
 (define_insn "extendhisi2"
-  [(set (match_operand:SI 0 "general_operand" "=r")
-       (sign_extend:SI
-        (match_operand:HI 1 "nonimmediate_operand" "rm")))]
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
   ""
   "*
 {
 }")
 
 (define_insn "extendqihi2"
-  [(set (match_operand:HI 0 "general_operand" "=r")
-       (sign_extend:HI
-        (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
   ""
   "*
 {
 }")
 
 (define_insn "extendqisi2"
-  [(set (match_operand:SI 0 "general_operand" "=r")
-       (sign_extend:SI
-        (match_operand:QI 1 "nonimmediate_operand" "qm")))]
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
   ""
   "*
 {
   return AS2 (movs%B0%L0,%1,%0);
 #endif
 }")
+
+\f
+;; Truncation of long long -> 32 bit
+
+(define_expand "truncdisi2"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+       (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
+  ""
+  "
+{
+  /* Don't generate memory->memory moves, go through a register */
+  if (TARGET_MOVE
+      && (reload_in_progress | reload_completed) == 0
+      && GET_CODE (operands[0]) == MEM
+      && GET_CODE (operands[1]) == MEM)
+    {
+      rtx target = gen_reg_rtx (SImode);
+      emit_insn (gen_truncdisi2 (target, operands[1]));
+      emit_move_insn (operands[0], target);
+      DONE;
+    }
+}")
+
+(define_insn ""
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+       (truncate:SI (match_operand:DI 1 "nonimmediate_operand" "ro,r")))]
+  "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+  "*
+{
+  rtx low[2], high[2], xops[2];
+
+  split_di (&operands[1], 1, low, high);
+  xops[0] = operands[0];
+  xops[1] = low[0];
+  if (!rtx_equal_p (xops[0], xops[1]))
+    output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+  RET;
+}")
+
+(define_insn ""
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
+       (truncate:SI (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
+                                 (const_int 32))))]
+  "(!TARGET_MOVE || GET_CODE (operands[0]) != MEM) || (GET_CODE (operands[1]) != MEM)"
+  "*
+{
+  rtx low[2], high[2], xops[2];
+
+  split_di (&operands[1], 1, low, high);
+  xops[0] = operands[0];
+  xops[1] = high[0];
+  if (!rtx_equal_p (xops[0], xops[1]))
+    output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+  RET;
+}")
+
+
 \f
 ;; Conversions between float and double.
 
 (define_insn "extendsfdf2"
-  [(set (match_operand:DF 0 "general_operand" "=fm,f")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=fm,f")
        (float_extend:DF
-        (match_operand:SF 1 "general_operand" "f,fm")))]
+        (match_operand:SF 1 "nonimmediate_operand" "f,fm")))]
   "TARGET_80387"
   "*
 {
 }")
 
 (define_insn "extenddfxf2"
-  [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r")
+  [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f,f,!*r")
        (float_extend:XF
-        (match_operand:DF 1 "general_operand" "f,fm,!*r,f")))]
+        (match_operand:DF 1 "nonimmediate_operand" "f,fm,!*r,f")))]
   "TARGET_80387"
   "*
 {
 }")
 
 (define_insn "extendsfxf2"
-  [(set (match_operand:XF 0 "general_operand" "=fm,f,f,!*r")
+  [(set (match_operand:XF 0 "nonimmediate_operand" "=fm,f,f,!*r")
        (float_extend:XF
-        (match_operand:SF 1 "general_operand" "f,fm,!*r,f")))]
+        (match_operand:SF 1 "nonimmediate_operand" "f,fm,!*r,f")))]
   "TARGET_80387"
   "*
 {
 }")
 
 (define_insn "truncxfsf2"
-  [(set (match_operand:SF 0 "general_operand" "=m,!*r")
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,!*r")
        (float_truncate:SF
         (match_operand:XF 1 "register_operand" "f,f")))]
   "TARGET_80387"
 }")
 
 (define_insn "truncxfdf2"
-  [(set (match_operand:DF 0 "general_operand" "=m,!*r")
+  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,!*r")
        (float_truncate:DF
         (match_operand:XF 1 "register_operand" "f,f")))]
   "TARGET_80387"
 ;; These match a signed conversion of either DFmode or SFmode to DImode.
 
 (define_insn ""
-  [(set (match_operand:DI 0 "general_operand" "=rm")
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (fix:DI (fix:XF (match_operand:XF 1 "register_operand" "f"))))
    (clobber (match_dup 1))
    (clobber (match_operand:SI 2 "memory_operand" "m"))
   "* return output_fix_trunc (insn, operands);")
 
 (define_insn ""
-  [(set (match_operand:DI 0 "general_operand" "=rm")
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (fix:DI (fix:DF (match_operand:DF 1 "register_operand" "f"))))
    (clobber (match_dup 1))
    (clobber (match_operand:SI 2 "memory_operand" "m"))
   "* return output_fix_trunc (insn, operands);")
 
 (define_insn ""
-  [(set (match_operand:DI 0 "general_operand" "=rm")
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=rm")
        (fix:DI (fix:SF (match_operand:SF 1 "register_operand" "f"))))
    (clobber (match_dup 1))
    (clobber (match_operand:SI 2 "memory_operand" "m"))
 }")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=rm")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
        (fix:SI (fix:XF (match_operand:XF 1 "register_operand" "f"))))
    (clobber (match_operand:SI 2 "memory_operand" "m"))
    (clobber (match_operand:SI 3 "memory_operand" "m"))
   "* return output_fix_trunc (insn, operands);")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=rm")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
        (fix:SI (fix:DF (match_operand:DF 1 "register_operand" "f"))))
    (clobber (match_operand:SI 2 "memory_operand" "m"))
    (clobber (match_operand:SI 3 "memory_operand" "m"))
   "* return output_fix_trunc (insn, operands);")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=rm")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
        (fix:SI (fix:SF (match_operand:SF 1 "register_operand" "f"))))
    (clobber (match_operand:SI 2 "memory_operand" "m"))
    (clobber (match_operand:SI 3 "memory_operand" "m"))
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f")
-       (float:XF (match_operand:DI 1 "general_operand" "rm")))]
+       (float:XF (match_operand:DI 1 "nonimmediate_operand" "rm")))]
   "TARGET_80387"
   "*
 {
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f,f")
-       (float:XF (match_operand:SI 1 "general_operand" "m,!*r")))]
+       (float:XF (match_operand:SI 1 "nonimmediate_operand" "m,!*r")))]
   "TARGET_80387"
   "*
 {
 \f
 ;;- add instructions
 
+(define_insn "addsidi3_1"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,&r,r,o,o")
+       (plus:DI (match_operand:DI 1 "general_operand" "0,0,0,o,riF,riF,o")
+                (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,roi,roi,ri,ri"))))
+   (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,&r"))]
+  ""
+  "*
+{
+  rtx low[3], high[3], xops[7], temp;
+
+  CC_STATUS_INIT;
+
+  split_di (operands, 2, low, high);
+  high[2] = const0_rtx;
+  low[2]  = operands[2];
+
+  if (!rtx_equal_p (operands[0], operands[1]))
+    {
+      xops[0] = high[0];
+      xops[1] = low[0];
+      xops[2] = high[1];
+      xops[3] = low[1];
+
+      if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+       {
+         output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+         output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+       }
+      else
+       {
+         xops[4] = high[2];
+         xops[5] = low[2];
+         xops[6] = operands[3];
+         output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+         output_asm_insn (AS2 (add%L6,%5,%6), xops);
+         output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+         output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+         output_asm_insn (AS2 (adc%L6,%4,%6), xops);
+         output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+         RET;
+       }
+    }
+
+  output_asm_insn (AS2 (add%L0,%2,%0), low);
+  output_asm_insn (AS2 (adc%L0,%2,%0), high);
+  RET;
+}")
+
+(define_insn "addsidi3_2"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=&r,r,o,&r,r,o,o")
+       (plus:DI (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,ri,o,ri,ri,ri"))
+                (match_operand:DI 1 "general_operand" "0,0,0,roiF,roiF,riF,o")))
+   (clobber (match_scratch:SI 3 "=X,X,X,X,X,X,&r"))]
+  ""
+  "*
+{
+  rtx low[3], high[3], xops[7], temp;
+
+  CC_STATUS_INIT;
+
+  split_di (operands, 2, low, high);
+  high[2] = const0_rtx;
+  low[2]  = operands[2];
+
+  if (!rtx_equal_p (operands[0], operands[1]))
+    {
+      xops[0] = high[0];
+      xops[1] = low[0];
+      xops[2] = high[1];
+      xops[3] = low[1];
+
+      if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+       {
+         output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+         output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+       }
+      else
+       {
+         xops[4] = high[2];
+         xops[5] = low[2];
+         xops[6] = operands[3];
+         output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+         output_asm_insn (AS2 (add%L6,%5,%6), xops);
+         output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+         output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+         output_asm_insn (AS2 (adc%L6,%4,%6), xops);
+         output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+         RET;
+       }
+    }
+
+  output_asm_insn (AS2 (add%L0,%2,%0), low);
+  output_asm_insn (AS2 (adc%L0,%2,%0), high);
+  RET;
+}")
+
 (define_insn "adddi3"
   [(set (match_operand:DI 0 "general_operand" "=&r,ro,o,&r,ro,o,&r,o,o,o")
        (plus:DI (match_operand:DI 1 "general_operand" "%0,0,0,o,riF,o,or,riF,riF,o")
 ;; On a 486, it is faster to do movl/addl than to do a single leal if
 ;; operands[1] and operands[2] are both registers.
 
-(define_insn "addsi3"
-  [(set (match_operand:SI 0 "general_operand" "=?r,rm,r")
-       (plus:SI (match_operand:SI 1 "general_operand" "%r,0,0")
-                (match_operand:SI 2 "general_operand" "ri,ri,rm")))]
+(define_expand "addsi3"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+       (plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+                (match_operand:SI 2 "general_operand" "")))]
   ""
+  "IX86_EXPAND_BINARY_OPERATOR (PLUS, SImode, operands);")
+
+(define_insn ""
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm,r")
+       (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,r")
+                (match_operand:SI 2 "general_operand" "rmi,ri,ri")))]
+  "ix86_binary_operator_ok (PLUS, SImode, operands)"
   "*
 {
-  if (REG_P (operands[0]) && REGNO (operands[0]) != REGNO (operands[1]))
+  if (REG_P (operands[0]) && REG_P (operands[1])
+      && (REG_P (operands[2]) || GET_CODE (operands[2]) == CONST_INT)
+      && REGNO (operands[0]) != REGNO (operands[1]))
     {
       if (REG_P (operands[2]) && REGNO (operands[0]) == REGNO (operands[2]))
        return AS2 (add%L0,%1,%0);
          operands[1] = SET_SRC (PATTERN (insn));
          return AS2 (lea%L0,%a1,%0);
        }
-
-      output_asm_insn (AS2 (mov%L0,%1,%0), operands);
     }
 
+  if (!rtx_equal_p (operands[0], operands[1]))
+    output_asm_insn (AS2 (mov%L0,%1,%0), operands);
+
   if (operands[2] == const1_rtx)
     return AS1 (inc%L0,%0);
 
   return AS2 (add%L0,%2,%0);
 }")
 
+;; addsi3 is faster, so put this after.
+
+(define_insn "movsi_lea"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+        (match_operand:QI 1 "address_operand" "p"))]
+  ""
+  "*
+{
+  /* Adding a constant to a register is faster with an add.  */
+  /* ??? can this ever happen? */
+  if (GET_CODE (operands[1]) == PLUS
+      && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
+      && rtx_equal_p (operands[0], XEXP (operands[1], 0)))
+    {
+      operands[1] = XEXP (operands[1], 1);
+
+      if (operands[1] == const1_rtx)
+        return AS1 (inc%L0,%0);
+
+      if (operands[1] == constm1_rtx)
+        return AS1 (dec%L0,%0);
+
+      return AS2 (add%L0,%1,%0);
+    }
+
+  CC_STATUS_INIT;
+  return AS2 (lea%L0,%a1,%0);
+}")
+
 ;; ??? `lea' here, for three operand add?  If leaw is used, only %bx,
 ;; %si and %di can appear in SET_SRC, and output_asm_insn might not be
 ;; able to handle the operand.  But leal always works?
 
-(define_insn "addhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm,r")
-       (plus:HI (match_operand:HI 1 "general_operand" "%0,0")
-                (match_operand:HI 2 "general_operand" "ri,rm")))]
+(define_expand "addhi3"
+  [(set (match_operand:HI 0 "general_operand" "")
+       (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
+                (match_operand:HI 2 "general_operand" "")))]
   ""
+  "IX86_EXPAND_BINARY_OPERATOR (PLUS, HImode, operands);")
+
+(define_insn ""
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+       (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+                (match_operand:HI 2 "general_operand" "ri,rm")))]
+  "ix86_binary_operator_ok (PLUS, HImode, operands)"
   "*
 {
   /* ??? what about offsettable memory references? */
   return AS2 (add%W0,%2,%0);
 }")
 
-(define_insn "addqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm,q")
-       (plus:QI (match_operand:QI 1 "general_operand" "%0,0")
-                (match_operand:QI 2 "general_operand" "qn,qmn")))]
+(define_expand "addqi3"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (plus:QI (match_operand:QI 1 "general_operand" "")
+                (match_operand:QI 2 "general_operand" "")))]
   ""
+  "IX86_EXPAND_BINARY_OPERATOR (PLUS, QImode, operands);")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+       (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
+                (match_operand:QI 2 "general_operand" "qn,qmn")))]
+  "ix86_binary_operator_ok (PLUS, QImode, operands)"
   "*
 {
   if (operands[2] == const1_rtx)
 ;
 ;(define_insn ""
 ;  [(set (match_operand:SI 0 "push_operand" "=<")
-;      (plus:SI (match_operand:SI 1 "general_operand" "%r")
-;               (match_operand:SI 2 "general_operand" "ri")))]
+;      (plus:SI (match_operand:SI 1 "register_operand" "%r")
+;               (match_operand:SI 2 "nonmemory_operand" "ri")))]
 ;  ""
 ;  "*
 ;{
 ;  RET;
 ;}")
 
-;; addsi3 is faster, so put this after.
-
-(define_insn "movsi_lea"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-        (match_operand:QI 1 "address_operand" "p"))]
-  ""
-  "*
-{
-  CC_STATUS_INIT;
-  /* Adding a constant to a register is faster with an add.  */
-  /* ??? can this ever happen? */
-  if (GET_CODE (operands[1]) == PLUS
-      && GET_CODE (XEXP (operands[1], 1)) == CONST_INT
-      && rtx_equal_p (operands[0], XEXP (operands[1], 0)))
-    {
-      operands[1] = XEXP (operands[1], 1);
-
-      if (operands[1] == const1_rtx)
-        return AS1 (inc%L0,%0);
-
-      if (operands[1] == constm1_rtx)
-        return AS1 (dec%L0,%0);
-
-      return AS2 (add%L0,%1,%0);
-    }
-  return AS2 (lea%L0,%a1,%0);
-}")
-
 ;; The patterns that match these are at the end of this file.
 
 (define_expand "addxf3"
   [(set (match_operand:XF 0 "register_operand" "")
-       (plus:XF (match_operand:XF 1 "nonimmediate_operand" "")
-                (match_operand:XF 2 "nonimmediate_operand" "")))]
+       (plus:XF (match_operand:XF 1 "register_operand" "")
+                (match_operand:XF 2 "register_operand" "")))]
   "TARGET_80387"
   "")
 
 \f
 ;;- subtract instructions
 
+(define_insn "subsidi3"
+  [(set (match_operand:DI 0 "general_operand" "=&r,ro,&r,o,o")
+       (minus:DI (match_operand:DI 1 "general_operand" "0,0,roiF,riF,o")
+                 (zero_extend:DI (match_operand:SI 2 "general_operand" "o,ri,roi,ri,ri"))))
+   (clobber (match_scratch:SI 3 "=X,X,X,X,&r"))]
+  ""
+  "*
+{
+  rtx low[3], high[3], xops[7];
+
+  CC_STATUS_INIT;
+
+  split_di (operands, 2, low, high);
+  high[2] = const0_rtx;
+  low[2]  = operands[2];
+
+  if (!rtx_equal_p (operands[0], operands[1]))
+    {
+      xops[0] = high[0];
+      xops[1] = low[0];
+      xops[2] = high[1];
+      xops[3] = low[1];
+
+      if (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
+       {
+         output_asm_insn (AS2 (mov%L1,%3,%1), xops);
+         output_asm_insn (AS2 (mov%L0,%2,%0), xops);
+       }
+      else
+       {
+         xops[4] = high[2];
+         xops[5] = low[2];
+         xops[6] = operands[3];
+         output_asm_insn (AS2 (mov%L6,%3,%6), xops);
+         output_asm_insn (AS2 (sub%L6,%5,%6), xops);
+         output_asm_insn (AS2 (mov%L1,%6,%1), xops);
+         output_asm_insn (AS2 (mov%L6,%2,%6), xops);
+         output_asm_insn (AS2 (sbb%L6,%4,%6), xops);
+         output_asm_insn (AS2 (mov%L0,%6,%0), xops);
+         RET;
+       }
+    }
+
+  output_asm_insn (AS2 (sub%L0,%2,%0), low);
+  output_asm_insn (AS2 (sbb%L0,%2,%0), high);
+  RET;
+}")
+
 (define_insn "subdi3"
   [(set (match_operand:DI 0 "general_operand" "=&r,ro,&r,o,o")
        (minus:DI (match_operand:DI 1 "general_operand" "0,0,roiF,riF,o")
   RET;
 }")
 
-(define_insn "subsi3"
-  [(set (match_operand:SI 0 "general_operand" "=rm,r")
-       (minus:SI (match_operand:SI 1 "general_operand" "0,0")
-                 (match_operand:SI 2 "general_operand" "ri,rm")))]
+(define_expand "subsi3"
+  [(set (match_operand:SI 0 "nonimmediate_operand" "")
+       (minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
+                 (match_operand:SI 2 "general_operand" "")))]
   ""
+  "IX86_EXPAND_BINARY_OPERATOR (MINUS, SImode, operands);")
+
+(define_insn ""
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+       (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
+                 (match_operand:SI 2 "general_operand" "ri,rm")))]
+  "ix86_binary_operator_ok (MINUS, SImode, operands)"
   "* return AS2 (sub%L0,%2,%0);")
 
-(define_insn "subhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm,r")
-       (minus:HI (match_operand:HI 1 "general_operand" "0,0")
-                 (match_operand:HI 2 "general_operand" "ri,rm")))]
+(define_insn ""
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+       (minus:SI (match_operand:SI 1 "general_operand" "ri,rm")
+                 (match_operand:SI 2 "nonimmediate_operand" "0,0")))]
+  "ix86_binary_operator_ok (MINUS, SImode, operands)"
+  "* return AS2 (sub%L0,%2,%0);")
+
+(define_expand "subhi3"
+  [(set (match_operand:HI 0 "general_operand" "")
+       (minus:HI (match_operand:HI 1 "nonimmediate_operand" "")
+                 (match_operand:HI 2 "general_operand" "")))]
   ""
+  "IX86_EXPAND_BINARY_OPERATOR (MINUS, HImode, operands);")
+
+(define_insn ""
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+       (minus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
+                 (match_operand:HI 2 "general_operand" "ri,rm")))]
+  "ix86_binary_operator_ok (MINUS, HImode, operands)"
   "* return AS2 (sub%W0,%2,%0);")
 
-(define_insn "subqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm,q")
-       (minus:QI (match_operand:QI 1 "general_operand" "0,0")
-                 (match_operand:QI 2 "general_operand" "qn,qmn")))]
+(define_insn ""
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+       (minus:HI (match_operand:HI 1 "general_operand" "ri,rm")
+                 (match_operand:HI 2 "nonimmediate_operand" "0,0")))]
+  "ix86_binary_operator_ok (MINUS, HImode, operands)"
+  "* return AS2 (sub%W0,%2,%0);")
+
+(define_expand "subqi3"
+  [(set (match_operand:QI 0 "general_operand" "")
+       (minus:QI (match_operand:QI 1 "general_operand" "")
+                 (match_operand:QI 2 "general_operand" "")))]
   ""
+  "IX86_EXPAND_BINARY_OPERATOR (MINUS, QImode, operands);")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+       (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
+                 (match_operand:QI 2 "general_operand" "qn,qmn")))]
+  "ix86_binary_operator_ok (MINUS, QImode, operands)"
+  "* return AS2 (sub%B0,%2,%0);")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+       (minus:QI (match_operand:QI 1 "general_operand" "qn,qmn")
+                 (match_operand:QI 2 "nonimmediate_operand" "0,0")))]
+  "ix86_binary_operator_ok (MINUS, QImode, operands)"
   "* return AS2 (sub%B0,%2,%0);")
 
 ;; The patterns that match these are at the end of this file.
 
 (define_expand "subxf3"
   [(set (match_operand:XF 0 "register_operand" "")
-       (minus:XF (match_operand:XF 1 "nonimmediate_operand" "")
-                 (match_operand:XF 2 "nonimmediate_operand" "")))]
+       (minus:XF (match_operand:XF 1 "register_operand" "")
+                 (match_operand:XF 2 "register_operand" "")))]
   "TARGET_80387"
   "")
 
 ;;- multiply instructions
 
 ;(define_insn "mulqi3"
-;  [(set (match_operand:QI 0 "general_operand" "=a")
-;      (mult:QI (match_operand:QI 1 "general_operand" "%0")
-;               (match_operand:QI 2 "general_operand" "qm")))]
+;  [(set (match_operand:QI 0 "register_operand" "=a")
+;      (mult:QI (match_operand:QI 1 "register_operand" "%0")
+;               (match_operand:QI 2 "nonimmediate_operand" "qm")))]
 ;  ""
 ;  "imul%B0 %2,%0")
 
-(define_insn ""
-  [(set (match_operand:HI 0 "general_operand" "=r")
-       (mult:HI (match_operand:HI 1 "general_operand" "%0")
-                (match_operand:HI 2 "general_operand" "r")))]
-  "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80"
-  "* return AS2 (imul%W0,%2,%0);")
-
 (define_insn "mulhi3"
-  [(set (match_operand:HI 0 "general_operand" "=r,r")
-       (mult:HI (match_operand:HI 1 "general_operand" "%0,rm")
+  [(set (match_operand:HI 0 "register_operand" "=r,r")
+       (mult:HI (match_operand:HI 1 "nonimmediate_operand" "%0,rm")
                 (match_operand:HI 2 "general_operand" "g,i")))]
   ""
   "*
   return AS3 (imul%W0,%2,%1,%0);
 }")
 
-(define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=r")
-       (mult:SI (match_operand:SI 1 "general_operand" "%0")
-                (match_operand:SI 2 "general_operand" "r")))]
-  "GET_CODE (operands[2]) == CONST_INT && INTVAL (operands[2]) == 0x80"
-  "* return AS2 (imul%L0,%2,%0);")
-
 (define_insn "mulsi3"
-  [(set (match_operand:SI 0 "general_operand" "=r,r")
-       (mult:SI (match_operand:SI 1 "general_operand" "%0,rm")
+  [(set (match_operand:SI 0 "register_operand" "=r,r")
+       (mult:SI (match_operand:SI 1 "nonimmediate_operand" "%0,rm")
                 (match_operand:SI 2 "general_operand" "g,i")))]
   ""
   "*
 }")
 
 (define_insn "umulqihi3"
-  [(set (match_operand:HI 0 "general_operand" "=a")
-       (mult:HI (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0"))
+  [(set (match_operand:HI 0 "register_operand" "=a")
+       (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand" "%0"))
                 (zero_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
   ""
   "mul%B0 %2")
 
 (define_insn "mulqihi3"
-  [(set (match_operand:HI 0 "general_operand" "=a")
-       (mult:HI (sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "%0"))
+  [(set (match_operand:HI 0 "register_operand" "=a")
+       (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
                 (sign_extend:HI (match_operand:QI 2 "nonimmediate_operand" "qm"))))]
   ""
   "imul%B0 %2")
 
 (define_expand "mulxf3"
   [(set (match_operand:XF 0 "register_operand" "")
-       (mult:XF (match_operand:XF 1 "nonimmediate_operand" "")
-                (match_operand:XF 2 "nonimmediate_operand" "")))]
+       (mult:XF (match_operand:XF 1 "register_operand" "")
+                (match_operand:XF 2 "register_operand" "")))]
   "TARGET_80387"
   "")
 
 (define_expand "muldf3"
   [(set (match_operand:DF 0 "register_operand" "")
-       (mult:DF (match_operand:DF 1 "nonimmediate_operand" "")
+       (mult:DF (match_operand:DF 1 "register_operand" "")
                 (match_operand:DF 2 "nonimmediate_operand" "")))]
   "TARGET_80387"
   "")
 
 (define_expand "mulsf3"
   [(set (match_operand:SF 0 "register_operand" "")
-       (mult:SF (match_operand:SF 1 "nonimmediate_operand" "")
+       (mult:SF (match_operand:SF 1 "register_operand" "")
                 (match_operand:SF 2 "nonimmediate_operand" "")))]
   "TARGET_80387"
   "")
 ;;- divide instructions
 
 (define_insn "divqi3"
-  [(set (match_operand:QI 0 "general_operand" "=a")
-       (div:QI (match_operand:HI 1 "general_operand" "0")
-               (match_operand:QI 2 "general_operand" "qm")))]
+  [(set (match_operand:QI 0 "register_operand" "=a")
+       (div:QI (match_operand:HI 1 "register_operand" "0")
+               (match_operand:QI 2 "nonimmediate_operand" "qm")))]
   ""
   "idiv%B0 %2")
 
 (define_insn "udivqi3"
-  [(set (match_operand:QI 0 "general_operand" "=a")
-       (udiv:QI (match_operand:HI 1 "general_operand" "0")
-                (match_operand:QI 2 "general_operand" "qm")))]
+  [(set (match_operand:QI 0 "register_operand" "=a")
+       (udiv:QI (match_operand:HI 1 "register_operand" "0")
+                (match_operand:QI 2 "nonimmediate_operand" "qm")))]
   ""
   "div%B0 %2")
 
 
 (define_expand "divxf3"
   [(set (match_operand:XF 0 "register_operand" "")
-       (div:XF (match_operand:XF 1 "nonimmediate_operand" "")
-               (match_operand:XF 2 "nonimmediate_operand" "")))]
-  "TARGET_80387"
-  "")
-
-(define_expand "divdf3"
-  [(set (match_operand:DF 0 "register_operand" "")
-       (div:DF (match_operand:DF 1 "nonimmediate_operand" "")
-               (match_operand:DF 2 "nonimmediate_operand" "")))]
+       (div:XF (match_operand:XF 1 "register_operand" "")
+               (match_operand:XF 2 "register_operand" "")))]
   "TARGET_80387"
   "")
 
 (define_expand "divsf3"
   [(set (match_operand:SF 0 "register_operand" "")
-       (div:SF (match_operand:SF 1 "nonimmediate_operand" "")
+       (div:SF (match_operand:SF 1 "register_operand" "")
                (match_operand:SF 2 "nonimmediate_operand" "")))]
   "TARGET_80387"
   "")
 (define_insn "divmodsi4"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (div:SI (match_operand:SI 1 "register_operand" "0")
-               (match_operand:SI 2 "general_operand" "rm")))
+               (match_operand:SI 2 "nonimmediate_operand" "rm")))
    (set (match_operand:SI 3 "register_operand" "=&d")
        (mod:SI (match_dup 1) (match_dup 2)))]
   ""
 (define_insn "divmodhi4"
   [(set (match_operand:HI 0 "register_operand" "=a")
        (div:HI (match_operand:HI 1 "register_operand" "0")
-               (match_operand:HI 2 "general_operand" "rm")))
+               (match_operand:HI 2 "nonimmediate_operand" "rm")))
    (set (match_operand:HI 3 "register_operand" "=&d")
        (mod:HI (match_dup 1) (match_dup 2)))]
   ""
 (define_insn "udivmodsi4"
   [(set (match_operand:SI 0 "register_operand" "=a")
        (udiv:SI (match_operand:SI 1 "register_operand" "0")
-                (match_operand:SI 2 "general_operand" "rm")))
+                (match_operand:SI 2 "nonimmediate_operand" "rm")))
    (set (match_operand:SI 3 "register_operand" "=&d")
        (umod:SI (match_dup 1) (match_dup 2)))]
   ""
 (define_insn "udivmodhi4"
   [(set (match_operand:HI 0 "register_operand" "=a")
        (udiv:HI (match_operand:HI 1 "register_operand" "0")
-                (match_operand:HI 2 "general_operand" "rm")))
+                (match_operand:HI 2 "nonimmediate_operand" "rm")))
    (set (match_operand:HI 3 "register_operand" "=&d")
        (umod:HI (match_dup 1) (match_dup 2)))]
   ""
 (define_insn ""
   [(set (match_operand:SI 0 "register_operand" "=a")
        (udiv:DI (match_operand:DI 1 "register_operand" "a")
-                (match_operand:SI 2 "general_operand" "rm")))
+                (match_operand:SI 2 "nonimmediate_operand" "rm")))
    (set (match_operand:SI 3 "register_operand" "=d")
        (umod:SI (match_dup 1) (match_dup 2)))]
   ""
 
 ;; ??? What if we only change one byte of an offsettable memory reference?
 (define_insn "andsi3"
-  [(set (match_operand:SI 0 "general_operand" "=r,r,rm,r")
-       (and:SI (match_operand:SI 1 "general_operand" "%rm,qm,0,0")
-               (match_operand:SI 2 "general_operand" "L,K,ri,rm")))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+       (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
+               (match_operand:SI 2 "general_operand" "ri,rm")))]
   ""
   "*
 {
+  if (!rtx_equal_p (operands[0], operands[1])
+      && rtx_equal_p (operands[0], operands[2]))
+    {
+      rtx tmp;
+      tmp = operands[1];
+      operands[1] = operands[2];
+      operands[2] = tmp;
+    }
   if (GET_CODE (operands[2]) == CONST_INT
       && ! (GET_CODE (operands[0]) == MEM && MEM_VOLATILE_P (operands[0])))
     {
 }")
 
 (define_insn "andhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm,r")
-       (and:HI (match_operand:HI 1 "general_operand" "%0,0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+       (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
                (match_operand:HI 2 "general_operand" "ri,rm")))]
   ""
   "*
 }")
 
 (define_insn "andqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm,q")
-       (and:QI (match_operand:QI 1 "general_operand" "%0,0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+       (and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
                (match_operand:QI 2 "general_operand" "qn,qmn")))]
   ""
   "* return AS2 (and%B0,%2,%0);")
   "and%W0 %1,%0")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=q")
+  [(set (match_operand:SI 0 "register_operand" "=q")
        (and:SI
         (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm"))
-               (match_operand:SI 2 "general_operand" "0")))]
+               (match_operand:SI 2 "register_operand" "0")))]
   "GET_CODE (operands[2]) == CONST_INT
    && (unsigned int) INTVAL (operands[2]) < (1 << GET_MODE_BITSIZE (QImode))"
   "and%L0 %1,%0")
 
 ;; ??? What if we only change one byte of an offsettable memory reference?
 (define_insn "iorsi3"
-  [(set (match_operand:SI 0 "general_operand" "=rm,r")
-       (ior:SI (match_operand:SI 1 "general_operand" "%0,0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+       (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "ri,rm")))]
   ""
   "*
 }")
 
 (define_insn "iorhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm,r")
-       (ior:HI (match_operand:HI 1 "general_operand" "%0,0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+       (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
                (match_operand:HI 2 "general_operand" "ri,rm")))]
   ""
   "*
 }")
 
 (define_insn "iorqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm,q")
-       (ior:QI (match_operand:QI 1 "general_operand" "%0,0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+       (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
                (match_operand:QI 2 "general_operand" "qn,qmn")))]
   ""
   "* return AS2 (or%B0,%2,%0);")
 
 ;; ??? What if we only change one byte of an offsettable memory reference?
 (define_insn "xorsi3"
-  [(set (match_operand:SI 0 "general_operand" "=rm,r")
-       (xor:SI (match_operand:SI 1 "general_operand" "%0,0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
+       (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
                (match_operand:SI 2 "general_operand" "ri,rm")))]
   ""
   "*
 }")
 
 (define_insn "xorhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm,r")
-       (xor:HI (match_operand:HI 1 "general_operand" "%0,0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
+       (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
                (match_operand:HI 2 "general_operand" "ri,rm")))]
   ""
   "*
 }")
 
 (define_insn "xorqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm,q")
-       (xor:QI (match_operand:QI 1 "general_operand" "%0,0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
+       (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
                (match_operand:QI 2 "general_operand" "qn,qm")))]
   ""
   "* return AS2 (xor%B0,%2,%0);")
 }")
 
 (define_insn "negsi2"
-  [(set (match_operand:SI 0 "general_operand" "=rm")
-       (neg:SI (match_operand:SI 1 "general_operand" "0")))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+       (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
   ""
   "neg%L0 %0")
 
 (define_insn "neghi2"
-  [(set (match_operand:HI 0 "general_operand" "=rm")
-       (neg:HI (match_operand:HI 1 "general_operand" "0")))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+       (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
   ""
   "neg%W0 %0")
 
 (define_insn "negqi2"
-  [(set (match_operand:QI 0 "general_operand" "=qm")
-       (neg:QI (match_operand:QI 1 "general_operand" "0")))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+       (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
   ""
   "neg%B0 %0")
 
 (define_insn "negsf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
-       (neg:SF (match_operand:SF 1 "general_operand" "0")))]
+       (neg:SF (match_operand:SF 1 "register_operand" "0")))]
   "TARGET_80387"
   "fchs")
 
 (define_insn "negdf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
-       (neg:DF (match_operand:DF 1 "general_operand" "0")))]
+       (neg:DF (match_operand:DF 1 "register_operand" "0")))]
   "TARGET_80387"
   "fchs")
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f")
-       (neg:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))]
+       (neg:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
   "TARGET_80387"
   "fchs")
 
 (define_insn "negxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
-       (neg:XF (match_operand:XF 1 "general_operand" "0")))]
+       (neg:XF (match_operand:XF 1 "register_operand" "0")))]
   "TARGET_80387"
   "fchs")
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f")
-       (neg:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))]
+       (neg:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
   "TARGET_80387"
   "fchs")
 \f
 
 (define_insn "abssf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
-       (abs:SF (match_operand:SF 1 "general_operand" "0")))]
+       (abs:SF (match_operand:SF 1 "register_operand" "0")))]
   "TARGET_80387"
-  "fabs")
+  "fabs"
+  [(set_attr "type" "fpop")])
 
 (define_insn "absdf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
-       (abs:DF (match_operand:DF 1 "general_operand" "0")))]
+       (abs:DF (match_operand:DF 1 "register_operand" "0")))]
   "TARGET_80387"
-  "fabs")
+  "fabs"
+  [(set_attr "type" "fpop")])
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f")
-       (abs:DF (float_extend:DF (match_operand:SF 1 "general_operand" "0"))))]
+       (abs:DF (float_extend:DF (match_operand:SF 1 "register_operand" "0"))))]
   "TARGET_80387"
-  "fabs")
+  "fabs"
+  [(set_attr "type" "fpop")])
 
 (define_insn "absxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
-       (abs:XF (match_operand:XF 1 "general_operand" "0")))]
+       (abs:XF (match_operand:XF 1 "register_operand" "0")))]
   "TARGET_80387"
-  "fabs")
+  "fabs"
+  [(set_attr "type" "fpop")])
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f")
-       (abs:XF (float_extend:XF (match_operand:DF 1 "general_operand" "0"))))]
+       (abs:XF (float_extend:XF (match_operand:DF 1 "register_operand" "0"))))]
   "TARGET_80387"
-  "fabs")
+  "fabs"
+  [(set_attr "type" "fpop")])
 
 (define_insn "sqrtsf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
-       (sqrt:SF (match_operand:SF 1 "general_operand" "0")))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
-   && (TARGET_IEEE_FP || flag_fast_math) "
+       (sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
   "fsqrt")
 
 (define_insn "sqrtdf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
-       (sqrt:DF (match_operand:DF 1 "general_operand" "0")))]
+       (sqrt:DF (match_operand:DF 1 "register_operand" "0")))]
   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
    && (TARGET_IEEE_FP || flag_fast_math) "
   "fsqrt")
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f")
        (sqrt:DF (float_extend:DF
-                 (match_operand:SF 1 "general_operand" "0"))))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+                 (match_operand:SF 1 "register_operand" "0"))))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
   "fsqrt")
 
 (define_insn "sqrtxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
-       (sqrt:XF (match_operand:XF 1 "general_operand" "0")))]
+       (sqrt:XF (match_operand:XF 1 "register_operand" "0")))]
   "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
    && (TARGET_IEEE_FP || flag_fast_math) "
   "fsqrt")
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f")
        (sqrt:XF (float_extend:XF
-                 (match_operand:DF 1 "general_operand" "0"))))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+                 (match_operand:DF 1 "register_operand" "0"))))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
   "fsqrt")
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f")
        (sqrt:XF (float_extend:XF
-                 (match_operand:SF 1 "general_operand" "0"))))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+                 (match_operand:SF 1 "register_operand" "0"))))]
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
   "fsqrt")
 
 (define_insn "sindf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
        (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 1))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fsin")
 
 (define_insn "sinsf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 1))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fsin")
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f")
        (unspec:DF [(float_extend:DF
                     (match_operand:SF 1 "register_operand" "0"))] 1))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fsin")
 
 (define_insn "sinxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 1))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fsin")
 
 (define_insn "cosdf2"
   [(set (match_operand:DF 0 "register_operand" "=f")
        (unspec:DF [(match_operand:DF 1 "register_operand" "0")] 2))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fcos")
 
 (define_insn "cossf2"
   [(set (match_operand:SF 0 "register_operand" "=f")
        (unspec:SF [(match_operand:SF 1 "register_operand" "0")] 2))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fcos")
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f")
        (unspec:DF [(float_extend:DF
                     (match_operand:SF 1 "register_operand" "0"))] 2))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fcos")
 
 (define_insn "cosxf2"
   [(set (match_operand:XF 0 "register_operand" "=f")
        (unspec:XF [(match_operand:XF 1 "register_operand" "0")] 2))]
-  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
-   && (TARGET_IEEE_FP || flag_fast_math) "
+  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 && flag_fast_math"
   "fcos")
 \f
 ;;- one complement instructions
 
 (define_insn "one_cmplsi2"
-  [(set (match_operand:SI 0 "general_operand" "=rm")
-       (not:SI (match_operand:SI 1 "general_operand" "0")))]
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+       (not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
   ""
   "not%L0 %0")
 
 (define_insn "one_cmplhi2"
-  [(set (match_operand:HI 0 "general_operand" "=rm")
-       (not:HI (match_operand:HI 1 "general_operand" "0")))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+       (not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
   ""
   "not%W0 %0")
 
 (define_insn "one_cmplqi2"
-  [(set (match_operand:QI 0 "general_operand" "=qm")
-       (not:QI (match_operand:QI 1 "general_operand" "0")))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+       (not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
   ""
   "not%B0 %0")
 \f
 ;; is smaller - use leal for now unless the shift count is 1.
 
 (define_insn "ashlsi3"
-  [(set (match_operand:SI 0 "general_operand" "=r,rm")
-       (ashift:SI (match_operand:SI 1 "general_operand" "r,0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
+       (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "r,0")
                   (match_operand:SI 2 "nonmemory_operand" "M,cI")))]
   ""
   "*
 }")
 
 (define_insn "ashlhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm")
-       (ashift:HI (match_operand:HI 1 "general_operand" "0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+       (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
                   (match_operand:HI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "ashlqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm")
-       (ashift:QI (match_operand:QI 1 "general_operand" "0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+       (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
                   (match_operand:QI 2 "nonmemory_operand" "cI")))]
   ""
   "*
   DONE;
 }")
 
+(define_insn "ashldi3_32"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
+       (ashift:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
+                  (const_int 32)))]
+  ""
+  "*
+{
+  rtx low[2], high[2], xops[4];
+
+  split_di (operands, 2, low, high);
+  xops[0] = high[0];
+  xops[1] = low[1];
+  xops[2] = low[0];
+  xops[3] = const0_rtx;
+  if (!rtx_equal_p (xops[0], xops[1]))
+    output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+  if (GET_CODE (low[0]) == MEM)
+    output_asm_insn (AS2 (mov%L2,%3,%2), xops);
+  else
+    output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+
+  RET;
+}")
+
 (define_insn "ashrdi3_const_int"
   [(set (match_operand:DI 0 "register_operand" "=&r")
        (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
 }")
 
 (define_insn "ashrsi3"
-  [(set (match_operand:SI 0 "general_operand" "=rm")
-       (ashiftrt:SI (match_operand:SI 1 "general_operand" "0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+       (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
                     (match_operand:SI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "ashrhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm")
-       (ashiftrt:HI (match_operand:HI 1 "general_operand" "0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+       (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
                     (match_operand:HI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "ashrqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm")
-       (ashiftrt:QI (match_operand:QI 1 "general_operand" "0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+       (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
                     (match_operand:QI 2 "nonmemory_operand" "cI")))]
   ""
   "*
   DONE;
 }")
 
+(define_insn "lshrdi3_32"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,m")
+       (lshiftrt:DI (match_operand:DI 1 "nonimmediate_operand" "ro,r")
+                    (const_int 32)))]
+  ""
+  "*
+{
+  rtx low[2], high[2], xops[4];
+
+  split_di (operands, 2, low, high);
+  xops[0] = low[0];
+  xops[1] = high[1];
+  xops[2] = high[0];
+  xops[3] = const0_rtx;
+  if (!rtx_equal_p (xops[0], xops[1]))
+    output_asm_insn (AS2 (mov%L0,%1,%0), xops);
+
+  if (GET_CODE (low[0]) == MEM)
+    output_asm_insn (AS2 (mov%L2,%3,%2), xops);
+  else
+    output_asm_insn (AS2 (xor%L2,%2,%2), xops);
+
+  RET;
+}")
+
 (define_insn "lshrdi3_const_int"
   [(set (match_operand:DI 0 "register_operand" "=&r")
        (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
 }")
 
 (define_insn "lshrsi3"
-  [(set (match_operand:SI 0 "general_operand" "=rm")
-       (lshiftrt:SI (match_operand:SI 1 "general_operand" "0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+       (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
                     (match_operand:SI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "lshrhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm")
-       (lshiftrt:HI (match_operand:HI 1 "general_operand" "0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+       (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
                     (match_operand:HI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "lshrqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm")
-       (lshiftrt:QI (match_operand:QI 1 "general_operand" "0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+       (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
                     (match_operand:QI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 ;;- rotate instructions
 
 (define_insn "rotlsi3"
-  [(set (match_operand:SI 0 "general_operand" "=rm")
-       (rotate:SI (match_operand:SI 1 "general_operand" "0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+       (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0")
                   (match_operand:SI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "rotlhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm")
-       (rotate:HI (match_operand:HI 1 "general_operand" "0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+       (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0")
                   (match_operand:HI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "rotlqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm")
-       (rotate:QI (match_operand:QI 1 "general_operand" "0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+       (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0")
                   (match_operand:QI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "rotrsi3"
-  [(set (match_operand:SI 0 "general_operand" "=rm")
-       (rotatert:SI (match_operand:SI 1 "general_operand" "0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+       (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0")
                     (match_operand:SI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "rotrhi3"
-  [(set (match_operand:HI 0 "general_operand" "=rm")
-       (rotatert:HI (match_operand:HI 1 "general_operand" "0")
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
+       (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0")
                     (match_operand:HI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 }")
 
 (define_insn "rotrqi3"
-  [(set (match_operand:QI 0 "general_operand" "=qm")
-       (rotatert:QI (match_operand:QI 1 "general_operand" "0")
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
+       (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0")
                     (match_operand:QI 2 "nonmemory_operand" "cI")))]
   ""
   "*
 ;; %ah, %bh, %ch, %dh.
 (define_insn "insv"
   [(set (zero_extract:SI (match_operand:SI 0 "register_operand" "+&r")
-                        (match_operand:SI 1 "general_operand" "i")
-                        (match_operand:SI 2 "general_operand" "i"))
-       (match_operand:SI 3 "general_operand" "ri"))]
+                        (match_operand:SI 1 "immediate_operand" "i")
+                        (match_operand:SI 2 "immediate_operand" "i"))
+       (match_operand:SI 3 "nonmemory_operand" "ri"))]
   ""
   "*
 {
   [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "")
                         (match_operand:SI 1 "immediate_operand" "")
                         (match_operand:SI 2 "immediate_operand" ""))
-       (match_operand:QI 3 "general_operand" "ri"))]
+       (match_operand:QI 3 "nonmemory_operand" "ri"))]
   ""
   "
 {
 
 ;; General bit set and clear.
 (define_insn ""
-  [(set (zero_extract:SI (match_operand:SI 0 "general_operand" "+rm")
+  [(set (zero_extract:SI (match_operand:SI 0 "nonimmediate_operand" "+rm")
                         (const_int 1)
-                        (match_operand:SI 2 "general_operand" "r"))
+                        (match_operand:SI 2 "register_operand" "r"))
        (match_operand:SI 3 "const_int_operand" "n"))]
   "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
   "*
 ;; Bit complement.  See comments on previous pattern.
 ;; ??? Is this really worthwhile?
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=rm")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
        (xor:SI (ashift:SI (const_int 1)
-                          (match_operand:SI 1 "general_operand" "r"))
-               (match_operand:SI 2 "general_operand" "0")))]
+                          (match_operand:SI 1 "register_operand" "r"))
+               (match_operand:SI 2 "nonimmediate_operand" "0")))]
   "TARGET_USE_BIT_TEST && GET_CODE (operands[1]) != CONST_INT"
   "*
 {
 }")
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=rm")
-       (xor:SI (match_operand:SI 1 "general_operand" "0")
+  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
+       (xor:SI (match_operand:SI 1 "nonimmediate_operand" "0")
                (ashift:SI (const_int 1)
-                          (match_operand:SI 2 "general_operand" "r"))))]
+                          (match_operand:SI 2 "register_operand" "r"))))]
   "TARGET_USE_BIT_TEST && GET_CODE (operands[2]) != CONST_INT"
   "*
 {
 (define_insn ""
   [(set (cc0) (zero_extract (match_operand:SI 0 "register_operand" "r")
                            (const_int 1)
-                           (match_operand:SI 1 "general_operand" "r")))]
+                           (match_operand:SI 1 "register_operand" "r")))]
   "GET_CODE (operands[1]) != CONST_INT"
   "*
 {
 ;; The CPU may access unspecified bytes around the actual target byte.
 
 (define_insn ""
-  [(set (cc0) (zero_extract (match_operand:QI 0 "general_operand" "rm")
+  [(set (cc0) (zero_extract (match_operand:QI 0 "nonimmediate_operand" "rm")
                            (match_operand:SI 1 "const_int_operand" "n")
                            (match_operand:SI 2 "const_int_operand" "n")))]
   "GET_CODE (operands[0]) != MEM || ! MEM_VOLATILE_P (operands[0])"
   if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jnc %l0\";
   else
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4000);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (jne,%l0);
+    }
+
     return \"je %l0\";
 }")
 
   if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jc %l0\";
   else
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4000);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (je,%l0);
+    }
+
     return \"jne %l0\";
 }")
 
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (je,%l0);
 
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (je,%l0);
+    }
   OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR);
 }")
 
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (je,%l0);
 
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (jne,%l0);
+    }
   OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
 }")
 
 {
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (je,%l0);
-
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (je,%l0);
+    }
   OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
 }")
 
 {
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (jb,%l0);
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (jne,%l0);
+    }
 
   OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR);
 }")
   if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jc %l0\";
   else
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4000);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (je,%l0);
+    }
     return \"jne %l0\";
 }")
 
   if (cc_prev_status.flags & CC_Z_IN_NOT_C)
     return \"jnc %l0\";
   else
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4000);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (jne,%l0);
+    }
     return \"je %l0\";
 }")
 
 {
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (jne,%l0);
-
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (jne,%l0);
+    }
   OUTPUT_JUMP (\"jle %l0\", \"jbe %l0\", NULL_PTR);
 }")
 
 {
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (jne,%l0);
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (je,%l0);
+    }
 
   OUTPUT_JUMP (\"jge %l0\", \"jae %l0\", \"jns %l0\");
 }")
 {
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (jne,%l0);
-
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (jne,%l0);
+    }
   OUTPUT_JUMP (\"jl %l0\", \"jb %l0\", \"js %l0\");
 }")
 
   if (TARGET_IEEE_FP && (cc_prev_status.flags & CC_IN_80387))
     return AS1 (jae,%l0);
 
+  if (cc_prev_status.flags & CC_TEST_AX)
+    {
+      operands[1] = gen_rtx (REG, SImode, 0);
+      operands[2] = GEN_INT (0x4100);
+      output_asm_insn (AS2 (testl,%2,%1), operands);
+      return AS1 (je,%l0);
+    }
   OUTPUT_JUMP (\"jg %l0\", \"ja %l0\", NULL_PTR);
 }")
 
   "jmp %l0")
 
 (define_insn "indirect_jump"
-  [(set (pc) (match_operand:SI 0 "general_operand" "rm"))]
+  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
   ""
   "*
 {
 (define_insn ""
   [(set (pc)
        (if_then_else (match_operator 0 "arithmetic_comparison_operator"
-                                     [(plus:SI (match_operand:SI 1 "general_operand" "+r,m")
+                                     [(plus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m")
                                                (match_operand:SI 2 "general_operand" "rmi,ri"))
                                       (const_int 0)])
                      (label_ref (match_operand 3 "" ""))
 (define_insn ""
   [(set (pc)
        (if_then_else (match_operator 0 "arithmetic_comparison_operator"
-                                     [(minus:SI (match_operand:SI 1 "general_operand" "+r,m")
+                                     [(minus:SI (match_operand:SI 1 "nonimmediate_operand" "+r,m")
                                                 (match_operand:SI 2 "general_operand" "rmi,ri"))
                                       (const_int 0)])
                      (label_ref (match_operand 3 "" ""))
 }")
 
 (define_insn "tablejump"
-  [(set (pc) (match_operand:SI 0 "general_operand" "rm"))
+  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
   "*
 ;; code to handle zero-length compares.
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=&r")
+  [(set (match_operand:SI 0 "register_operand" "=&r")
        (compare:SI (mem:BLK (match_operand:SI 1 "address_operand" "S"))
                    (mem:BLK (match_operand:SI 2 "address_operand" "D"))))
    (use (match_operand:SI 3 "register_operand" "c"))
   ""
   "*
 {
-  rtx xops[4], label;
+  rtx xops[2], label;
 
   label = gen_label_rtx ();
 
   output_asm_insn (\"je %l0\", &label);
 
   xops[0] = operands[0];
-  xops[1] = gen_rtx (MEM, QImode,
-                    gen_rtx (PLUS, SImode, operands[1], constm1_rtx));
-  xops[2] = gen_rtx (MEM, QImode,
-                    gen_rtx (PLUS, SImode, operands[2], constm1_rtx));
-  xops[3] = operands[3];
-
-  output_asm_insn (AS2 (movz%B1%L0,%1,%0), xops);
-  output_asm_insn (AS2 (movz%B2%L3,%2,%3), xops);
-
-  output_asm_insn (AS2 (sub%L0,%3,%0), xops);
+  xops[1] = const1_rtx;
+  output_asm_insn (AS2 (sbb%L0,%0,%0), xops);
+  if (QI_REG_P (xops[0]))
+     output_asm_insn (AS2 (or%B0,%1,%b0), xops);
+  else
+     output_asm_insn (AS2 (or%L0,%1,%0), xops);
+       
   ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\", CODE_LABEL_NUMBER (label));
   RET;
 }")
   return \"repz\;cmps%B2\";
 }")
 
+\f
 (define_expand "ffssi2"
   [(set (match_dup 2)
        (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" ""))
 ;; x86 implementations do this.
 
 (define_insn ""
-  [(set (match_operand:SI 0 "general_operand" "=&r")
-       (plus:SI (ffs:SI (match_operand:SI 1 "general_operand" "rm"))
+  [(set (match_operand:SI 0 "register_operand" "=&r")
+       (plus:SI (ffs:SI (match_operand:SI 1 "nonimmediate_operand" "rm"))
                 (const_int -1)))]
   ""
   "*
   "operands[2] = gen_reg_rtx (HImode);")
 
 (define_insn ""
-  [(set (match_operand:HI 0 "general_operand" "=&r")
-       (plus:HI (ffs:HI (match_operand:SI 1 "general_operand" "rm"))
+  [(set (match_operand:HI 0 "register_operand" "=&r")
+       (plus:HI (ffs:HI (match_operand:SI 1 "nonimmediate_operand" "rm"))
                 (const_int -1)))]
   ""
   "*
                        [(match_operand:DF 1 "nonimmediate_operand" "0,fm")
                         (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f")
        (match_operator:DF 3 "binary_387_op"
-          [(float:DF (match_operand:SI 1 "general_operand" "rm"))
-           (match_operand:DF 2 "general_operand" "0")]))]
+          [(float:DF (match_operand:SI 1 "nonimmediate_operand" "rm"))
+           (match_operand:DF 2 "register_operand" "0")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_387_op"
-                       [(match_operand:XF 1 "nonimmediate_operand" "0,f")
-                        (match_operand:XF 2 "nonimmediate_operand" "f,0")]))]
+                       [(match_operand:XF 1 "register_operand" "0,f")
+                        (match_operand:XF 2 "register_operand" "f,0")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f")
        (match_operator:XF 3 "binary_387_op"
-          [(float:XF (match_operand:SI 1 "general_operand" "rm"))
-           (match_operand:XF 2 "general_operand" "0")]))]
+          [(float:XF (match_operand:SI 1 "nonimmediate_operand" "rm"))
+           (match_operand:XF 2 "register_operand" "0")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_387_op"
-          [(float_extend:XF (match_operand:SF 1 "general_operand" "fm,0"))
-           (match_operand:XF 2 "general_operand" "0,f")]))]
+          [(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
+           (match_operand:XF 2 "register_operand" "0,f")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f")
        (match_operator:XF 3 "binary_387_op"
-         [(match_operand:XF 1 "general_operand" "0")
-          (float:XF (match_operand:SI 2 "general_operand" "rm"))]))]
+         [(match_operand:XF 1 "register_operand" "0")
+          (float:XF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:XF 0 "register_operand" "=f,f")
        (match_operator:XF 3 "binary_387_op"
-         [(match_operand:XF 1 "general_operand" "0,f")
+         [(match_operand:XF 1 "register_operand" "0,f")
           (float_extend:XF
-           (match_operand:SF 2 "general_operand" "fm,0"))]))]
+           (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f,f")
        (match_operator:DF 3 "binary_387_op"
-          [(float_extend:DF (match_operand:SF 1 "general_operand" "fm,0"))
-           (match_operand:DF 2 "general_operand" "0,f")]))]
+          [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
+           (match_operand:DF 2 "register_operand" "0,f")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f")
        (match_operator:DF 3 "binary_387_op"
-         [(match_operand:DF 1 "general_operand" "0")
-          (float:DF (match_operand:SI 2 "general_operand" "rm"))]))]
+         [(match_operand:DF 1 "register_operand" "0")
+          (float:DF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:DF 0 "register_operand" "=f,f")
        (match_operator:DF 3 "binary_387_op"
-         [(match_operand:DF 1 "general_operand" "0,f")
+         [(match_operand:DF 1 "register_operand" "0,f")
           (float_extend:DF
-           (match_operand:SF 2 "general_operand" "fm,0"))]))]
+           (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:SF 0 "register_operand" "=f,f")
                        [(match_operand:SF 1 "nonimmediate_operand" "0,fm")
                         (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:SF 0 "register_operand" "=f")
        (match_operator:SF 3 "binary_387_op"
-         [(float:SF (match_operand:SI 1 "general_operand" "rm"))
-          (match_operand:SF 2 "general_operand" "0")]))]
+         [(float:SF (match_operand:SI 1 "nonimmediate_operand" "rm"))
+          (match_operand:SF 2 "register_operand" "0")]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 
 (define_insn ""
   [(set (match_operand:SF 0 "register_operand" "=f")
        (match_operator:SF 3 "binary_387_op"
-         [(match_operand:SF 1 "general_operand" "0")
-          (float:SF (match_operand:SI 2 "general_operand" "rm"))]))]
+         [(match_operand:SF 1 "register_operand" "0")
+          (float:SF (match_operand:SI 2 "nonimmediate_operand" "rm"))]))]
   "TARGET_80387"
-  "* return output_387_binary_op (insn, operands);")
+  "* return output_387_binary_op (insn, operands);"
+  [(set (attr "type") 
+        (cond [(match_operand:DF 3 "is_mul" "") 
+                 (const_string "fpop")
+               (match_operand:DF 3 "is_div" "") 
+                 (const_string "fpdiv")
+              ]
+               (const_string "fpop")
+        )
+  )])
 \f
 (define_expand "strlensi"
   [(parallel [(set (match_dup 4)
   return \"repnz\;scas%B2\";
 }")
 
+(define_insn "strlensi_unroll"
+  [(set (match_operand:SI 0 "register_operand" "=&r,&r")
+       (unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "r,r"))
+                   (match_operand:SI 2 "immediate_operand" "i,i")] 0))
+   (clobber (match_scratch:SI 3 "=&q,&r"))]
+  "optimize > 1"
+  "* return output_strlen_unroll (operands);")
+
 ;; the only difference between the following patterns is the register preference
 ;; on a pentium using a q-register saves one clock cycle per 4 characters