;; GCC machine description for IA-32.
;; Copyright (C) 1988, 1994, 1995, 1996, 1997, 1998, 1999, 2000
;; Free Software Foundation, Inc.
;; Mostly by William Schelter.
;;
;; This file is part of GNU CC.
;;
;; GNU CC is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation; either version 2, or (at your option)
;; any later version.
;;
;; GNU CC is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
;; GNU General Public License for more details.
;;
;; 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. */
;;
;; The original PO technology requires these to be ordered by speed,
;; so that assigner will pick the fastest.
;;
;; See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;
;; Macro #define NOTICE_UPDATE_CC in file i386.h handles condition code
;; updates for most instructions.
;;
;; Macro REG_CLASS_FROM_LETTER in file i386.h defines the register
;; constraint letters.
;;
;; The special asm out single letter directives following a '%' are:
;; 'z' mov%z1 would be movl, movw, or movb depending on the mode of
;;     operands[1].
;; 'L' Print the opcode suffix for a 32-bit integer opcode.
;; 'W' Print the opcode suffix for a 16-bit integer opcode.
;; 'B' Print the opcode suffix for an 8-bit integer opcode.
;; 'Q' Print the opcode suffix for a 64-bit float opcode.
;; 'S' Print the opcode suffix for a 32-bit float opcode.
;; 'T' Print the opcode suffix for an 80-bit extended real XFmode float opcode.
;; 'J' Print the appropriate jump operand.
;;
;; 'b' Print the QImode name of the register for the indicated operand.
;;     %b0 would print %al if operands[0] is reg 0.
;; 'w' Likewise, print the HImode name of the register.
;; 'k' Likewise, print the SImode name of the register.
;; 'h' Print the QImode name for a "high" register, either ah, bh, ch or dh.
;; 'y' Print "st(0)" instead of "st" as a register.
;;
;; UNSPEC usage:
;; 0  This is a `scas' operation.  The mode of the UNSPEC is always SImode.
;;    operand 0 is the memory address to scan.
;;    operand 1 is a register containing the value to scan for.  The mode
;;       of the scas opcode will be the same as the mode of this operand.
;;    operand 2 is the known alignment of operand 0.
;; 1  This is a `sin' operation.  The mode of the UNSPEC is MODE_FLOAT.
;;    operand 0 is the argument for `sin'.
;; 2  This is a `cos' operation.  The mode of the UNSPEC is MODE_FLOAT.
;;    operand 0 is the argument for `cos'.
;; 3  This is part of a `stack probe' operation.  The mode of the UNSPEC is 
;;    always SImode.  operand 0 is the size of the stack allocation.
;; 4  This is the source of a fake SET of the frame pointer which is used to
;;    prevent insns referencing it being scheduled across the initial
;;    decrement of the stack pointer.
;; 5  This is a `bsf' operation.
;; 6  This is the @GOT offset of a PIC address.
;; 7  This is the @GOTOFF offset of a PIC address.
;; 8  This is a reference to a symbol's @PLT address.
;; 9  This is an `fnstsw' operation.
;; 10 This is a `sahf' operation.
;; 11 This is a `fstcw' operation
;;
;; Insns whose names begin with "x86_" are emitted by gen_FOO calls
;; from i386.c.


;; Processor type.  This attribute must exactly match the processor_type
;; enumeration in i386.h.
(define_attr "cpu" "i386,i486,pentium,pentiumpro,k6,athlon"
  (const (symbol_ref "ix86_cpu")))

;; A basic instruction type.  Refinements due to arguments to be
;; provided in other attributes.
(define_attr "type"
  "other,multi,alu1,negnot,alu,icmp,test,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch,str,cld"
  (const_string "other"))

;; Main data type used by the insn
(define_attr "mode" "unknown,none,QI,HI,SI,DI,unknownfp,SF,DF,XF"
  (const_string "unknown"))

;; Set for i387 operations.
(define_attr "i387" ""
  (if_then_else (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch")
    (const_int 1)
    (const_int 0)))

;; The (bounding maximum) length of an instruction immediate.
(define_attr "length_immediate" ""
  (cond [(eq_attr "type" "incdec,setcc,icmov,ibr,str,cld,lea,other,multi,idiv")
	   (const_int 0)
	 (eq_attr "i387" "1")
	   (const_int 0)
	 (eq_attr "type" "alu1,negnot,alu,icmp,imovx,ishift,imul,push,pop")
	   (symbol_ref "ix86_attr_length_immediate_default(insn,1)")
	 (eq_attr "type" "imov,test")
	   (symbol_ref "ix86_attr_length_immediate_default(insn,0)")
	 (eq_attr "type" "call")
	   (if_then_else (match_operand 0 "constant_call_address_operand" "")
	     (const_int 4)
	     (const_int 0))
	 (eq_attr "type" "callv")
	   (if_then_else (match_operand 1 "constant_call_address_operand" "")
	     (const_int 4)
	     (const_int 0))
	 (eq_attr "type" "ibr")
	   (if_then_else (and (ge (minus (match_dup 0) (pc))
				  (const_int -128))
			      (lt (minus (match_dup 0) (pc))
				  (const_int 124)))
	     (const_int 1)
	     (const_int 4))
	 ]
	 (symbol_ref "/* Update immediate_length and other attributes! */ abort(),1")))

;; The (bounding maximum) length of an instruction address.
(define_attr "length_address" ""
  (cond [(eq_attr "type" "str,cld,other,multi,fxch")
	   (const_int 0)
	 (and (eq_attr "type" "call")
	      (match_operand 1 "constant_call_address_operand" ""))
	     (const_int 0)
	 (and (eq_attr "type" "callv")
	      (match_operand 1 "constant_call_address_operand" ""))
	     (const_int 0)
	 ]
	 (symbol_ref "ix86_attr_length_address_default (insn)")))

;; Set when length prefix is used.
(define_attr "prefix_data16" ""
  (if_then_else (eq_attr "mode" "HI")
    (const_int 1)
    (const_int 0)))

;; Set when string REP prefix is used.
(define_attr "prefix_rep" "" (const_int 0))

;; Set when 0f opcode prefix is used.
(define_attr "prefix_0f" ""
  (if_then_else (eq_attr "type" "imovx,setcc,icmov")
    (const_int 1)
    (const_int 0)))

;; Set when modrm byte is used.
(define_attr "modrm" ""
  (cond [(eq_attr "type" "str,cld")
	   (const_int 0)
	 (eq_attr "i387" "1")
	   (const_int 0)
         (and (eq_attr "type" "incdec")
	      (ior (match_operand:SI 1 "register_operand" "")
		   (match_operand:HI 1 "register_operand" "")))
	   (const_int 0)
	 (and (eq_attr "type" "push")
	      (not (match_operand 1 "memory_operand" "")))
	   (const_int 0)
	 (and (eq_attr "type" "pop")
	      (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" "")))
	   (const_int 0)
	 ]
	 (const_int 1)))

;; The (bounding maximum) length of an instruction in bytes.
(define_attr "length" ""
  (cond [(eq_attr "type" "other,multi")
	   (const_int 16)
	 ]
	 (plus (plus (attr "modrm")
		     (plus (attr "prefix_0f")
			   (plus (attr "i387")
				 (const_int 1))))
	       (plus (attr "prefix_rep")
		     (plus (attr "prefix_data16")
			   (plus (attr "length_immediate")
				 (attr "length_address")))))))

;; The `memory' attribute is `none' if no memory is referenced, `load' or
;; `store' if there is a simple memory reference therein, or `unknown'
;; if the instruction is complex.

(define_attr "memory" "none,load,store,both,unknown"
  (cond [(eq_attr "type" "other,multi,str")
	   (const_string "unknown")
	 (eq_attr "type" "lea,fcmov,fpspc,cld")
	   (const_string "none")
	 (eq_attr "type" "push")
	   (if_then_else (match_operand 1 "memory_operand" "")
	     (const_string "both")
	     (const_string "store"))
	 (eq_attr "type" "pop,setcc")
	   (if_then_else (match_operand 0 "memory_operand" "")
	     (const_string "both")
	     (const_string "load"))
	 (eq_attr "type" "icmp,test")
	   (if_then_else (ior (match_operand 0 "memory_operand" "")
			      (match_operand 1 "memory_operand" ""))
	     (const_string "load")
	     (const_string "none"))
	 (eq_attr "type" "ibr")
	   (if_then_else (match_operand 0 "memory_operand" "")
	     (const_string "load")
	     (const_string "none"))
	 (eq_attr "type" "call")
	   (if_then_else (match_operand 0 "constant_call_address_operand" "")
	     (const_string "none")
	     (const_string "load"))
	 (eq_attr "type" "callv")
	   (if_then_else (match_operand 1 "constant_call_address_operand" "")
	     (const_string "none")
	     (const_string "load"))
	 (and (eq_attr "type" "alu1,negnot")
	      (match_operand 1 "memory_operand" ""))
	   (const_string "both")
	 (and (match_operand 0 "memory_operand" "")
	      (match_operand 1 "memory_operand" ""))
	   (const_string "both")
	 (match_operand 0 "memory_operand" "")
	   (const_string "store")
	 (match_operand 1 "memory_operand" "")
	   (const_string "load")
	 (and (eq_attr "type" "!icmp,test,alu1,negnot,fop1,fsgn,imov,imovx,fmov,fcmp")
	      (match_operand 2 "memory_operand" ""))
	   (const_string "load")
	 (and (eq_attr "type" "icmov")
	      (match_operand 3 "memory_operand" ""))
	   (const_string "load")
	]
	(const_string "none")))

;; Indicates if an instruction has both an immediate and a displacement.

(define_attr "imm_disp" "false,true,unknown"
  (cond [(eq_attr "type" "other,multi")
	   (const_string "unknown")
	 (and (eq_attr "type" "icmp,test,imov")
	      (and (match_operand 0 "memory_displacement_operand" "")
		   (match_operand 1 "immediate_operand" "")))
	   (const_string "true")
	 (and (eq_attr "type" "alu,ishift,imul,idiv")
	      (and (match_operand 0 "memory_displacement_operand" "")
		   (match_operand 2 "immediate_operand" "")))
	   (const_string "true")
	]
	(const_string "false")))

;; Indicates if an FP operation has an integer source.

(define_attr "fp_int_src" "false,true"
  (const_string "false"))

;; Describe a user's asm statement.
(define_asm_attributes
  [(set_attr "length" "128")
   (set_attr "type" "multi")])

;; Pentium Scheduling
;;
;; The Pentium is an in-order core with two integer pipelines.

;; True for insns that behave like prefixed insns on the Pentium.
(define_attr "pent_prefix" "false,true"
  (if_then_else (ior (eq_attr "prefix_0f" "1")
  		     (ior (eq_attr "prefix_data16" "1")
			  (eq_attr "prefix_rep" "1")))
    (const_string "true")
    (const_string "false")))

;; Categorize how an instruction slots.

;; The non-MMX Pentium slots an instruction with prefixes on U pipe only,
;; while MMX Pentium can slot it on either U or V.  Model non-MMX Pentium
;; rules, because it results in noticeably better code on non-MMX Pentium
;; and doesn't hurt much on MMX.  (Prefixed instructions are not very
;; common, so the scheduler usualy has a non-prefixed insn to pair).

(define_attr "pent_pair" "uv,pu,pv,np"
  (cond [(eq_attr "imm_disp" "true")
	   (const_string "np")
	 (ior (eq_attr "type" "alu1,alu,imov,icmp,test,lea,incdec")
	      (and (eq_attr "type" "pop,push")
		   (eq_attr "memory" "!both")))
	   (if_then_else (eq_attr "pent_prefix" "true")
	     (const_string "pu")
	     (const_string "uv"))
	 (eq_attr "type" "ibr")
	   (const_string "pv")
	 (and (eq_attr "type" "ishift")
	      (match_operand 2 "const_int_operand" ""))
	   (const_string "pu")
	 (and (eq_attr "type" "call")
	      (match_operand 0 "constant_call_address_operand" ""))
	   (const_string "pv")
	 (and (eq_attr "type" "callv")
	      (match_operand 1 "constant_call_address_operand" ""))
	   (const_string "pv")
	]
	(const_string "np")))

;; Rough readiness numbers.  Fine tuning happens in i386.c.
;;
;; u	describes pipe U
;; v	describes pipe V
;; uv	describes either pipe U or V for those that can issue to either
;; np	describes not paring
;; fpu	describes fpu
;; fpm	describes fp insns of different types are not pipelined.
;;
;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real.

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "imul"))
  11 11)

(define_function_unit "pent_mul" 1 1
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "imul"))
  11 11)

;; Rep movs takes minimally 12 cycles.
(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "str"))
  12 12)

; ??? IDIV for SI takes 46 cycles, for HI 30, for QI 22
(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "idiv"))
  46 46)

; Fp reg-reg moves takes 1 cycle. Loads takes 1 cycle for SF/DF mode,
; 3 cycles for XFmode.  Stores takes 2 cycles for SF/DF and 3 for XF.
; fldz and fld1 takes 2 cycles.  Only reg-reg moves are pairable.
; The integer <-> fp conversion is not modeled correctly. Fild behaves
; like normal fp operation and fist takes 6 cycles.

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "fmov")
	    (ior (and (eq_attr "memory" "store")
		      (match_operand:XF 0 "memory_operand" ""))
		 (and (eq_attr "memory" "load")
		      (match_operand:XF 1 "memory_operand" "")))))
  3 3)

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "fmov")
	    (ior (and (eq_attr "memory" "store")
		      (match_operand:XF 0 "memory_operand" ""))
		 (and (eq_attr "memory" "load")
		      (match_operand:XF 1 "memory_operand" "")))))
  3 3)

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "fmov")
            (ior (match_operand 1 "immediate_operand" "")
	         (eq_attr "memory" "store"))))
  2 2)

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "fmov")
            (ior (match_operand 1 "immediate_operand" "")
	         (eq_attr "memory" "store"))))
  2 2)

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "cld"))
  2 2)

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "fmov")
	    (eq_attr "memory" "none,load")))
  1 1)

; Read/Modify/Write instructions usually take 3 cycles.
(define_function_unit "pent_u" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,alu1,ishift")
	    (and (eq_attr "pent_pair" "pu")
		 (eq_attr "memory" "both"))))
  3 3)

(define_function_unit "pent_uv" 2 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,alu1,ishift")
	    (and (eq_attr "pent_pair" "!np")
		 (eq_attr "memory" "both"))))
  3 3)

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,alu1,negnot,ishift")
	    (and (eq_attr "pent_pair" "np")
		 (eq_attr "memory" "both"))))
  3 3)

; Read/Modify or Modify/Write instructions usually take 2 cycles.
(define_function_unit "pent_u" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,ishift")
	    (and (eq_attr "pent_pair" "pu")
		 (eq_attr "memory" "load,store"))))
  2 2)

(define_function_unit "pent_uv" 2 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,ishift")
	    (and (eq_attr "pent_pair" "!np")
		 (eq_attr "memory" "load,store"))))
  2 2)

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,ishift")
	    (and (eq_attr "pent_pair" "np")
		 (eq_attr "memory" "load,store"))))
  2 2)

; Insns w/o memory operands and move instructions usually take one cycle.
(define_function_unit "pent_u" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "pent_pair" "pu"))
  1 1)

(define_function_unit "pent_v" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "pent_pair" "pv"))
  1 1)

(define_function_unit "pent_uv" 2 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "pent_pair" "!np"))
  1 1)

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "pent_pair" "np"))
  1 1)

; Pairable insns only conflict with other non-pairable insns.
(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,alu1,ishift")
	    (and (eq_attr "pent_pair" "!np")
		 (eq_attr "memory" "both"))))
  3 3
  [(eq_attr "pent_pair" "np")])

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (and (eq_attr "type" "alu,alu1,ishift")
	    (and (eq_attr "pent_pair" "!np")
		 (eq_attr "memory" "load,store"))))
  2 2
  [(eq_attr "pent_pair" "np")])

(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "pent_pair" "!np"))
  1 1
  [(eq_attr "pent_pair" "np")])

; Floating point instructions usually blocks cycle longer when combined with
; integer instructions, because of the inpaired fxch instruction.
(define_function_unit "pent_np" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp"))
  2 2
  [(eq_attr "type" "!fmov,fop,fop1,fsgn,fmul,fpspc,fcmov,fcmp")])

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fcmp,fxch,fsgn"))
  1 1)

; Addition takes 3 cycles; assume other random cruft does as well.
; ??? Trivial fp operations such as fabs or fchs takes only one cycle.
(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fop,fop1"))
  3 1)

; Multiplication takes 3 cycles and is only half pipelined.
(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fmul"))
  3 1)

(define_function_unit "pent_mul" 1 1
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fmul"))
  2 2)

; ??? This is correct only for fdiv and sqrt -- sin/cos take 65-100 cycles. 
; They can overlap with integer insns.  Only the last two cycles can overlap
; with other fp insns.  Only fsin/fcos can overlap with multiplies.
; Only last two cycles of fsin/fcos can overlap with other instructions.
(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fdiv"))
  39 37)

(define_function_unit "pent_mul" 1 1
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fdiv"))
  39 39)

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fpspc"))
  70 68)

(define_function_unit "pent_mul" 1 1
  (and (eq_attr "cpu" "pentium")
       (eq_attr "type" "fpspc"))
  70 70)

;; Pentium Pro/PII Scheduling
;;
;; The PPro has an out-of-order core, but the instruction decoders are
;; naturally in-order and asymmetric.  We get best performance by scheduling
;; for the decoders, for in doing so we give the oo execution unit the 
;; most choices.

;; Categorize how many uops an ia32 instruction evaluates to:
;;   one --  an instruction with 1 uop can be decoded by any of the
;;           three decoders.
;;   few --  an instruction with 1 to 4 uops can be decoded only by 
;;	     decoder 0.
;;   many -- a complex instruction may take an unspecified number of
;;	     cycles to decode in decoder 0.

(define_attr "ppro_uops" "one,few,many"
  (cond [(eq_attr "type" "other,multi,call,callv,fpspc,str")
	   (const_string "many")
	 (eq_attr "type" "icmov,fcmov,str,cld")
	   (const_string "few")
	 (eq_attr "type" "imov")
	   (if_then_else (eq_attr "memory" "store,both")
	     (const_string "few")
	     (const_string "one"))
	 (eq_attr "memory" "!none")
	   (const_string "few")
	]
	(const_string "one")))

;; Rough readiness numbers.  Fine tuning happens in i386.c.
;;
;; p0	describes port 0.
;; p01	describes ports 0 and 1 as a pair; alu insns can issue to either.
;; p2	describes port 2 for loads.
;; p34	describes ports 3 and 4 for stores.
;; fpu	describes the fpu accessed via port 0. 
;;	??? It is less than clear if there are separate fadd and fmul units
;;	that could operate in parallel.
;;
;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real.

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "ishift,lea,ibr,cld"))
  1 1)

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "imul"))
  4 1)

;; ??? Does the divider lock out the pipe while it works,
;; or is there a disconnected unit?
(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "idiv"))
  17 17)

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fop,fop1,fsgn"))
  3 1)

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fcmov"))
  2 1)

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fcmp"))
  1 1)

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fmov"))
  1 1)

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fmul"))
  5 1)

(define_function_unit "ppro_p0" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fdiv,fpspc"))
  56 1)

(define_function_unit "ppro_p01" 2 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "!imov,fmov"))
  1 1)

(define_function_unit "ppro_p01" 2 0
  (and (and (eq_attr "cpu" "pentiumpro")
            (eq_attr "type" "imov,fmov"))
       (eq_attr "memory" "none"))
  1 1)

(define_function_unit "ppro_p2" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (ior (eq_attr "type" "pop")
	    (eq_attr "memory" "load,both")))
  3 1)

(define_function_unit "ppro_p34" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (ior (eq_attr "type" "push")
	    (eq_attr "memory" "store,both")))
  1 1)

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fop,fop1,fsgn,fmov,fcmp,fcmov"))
  1 1)

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fmul"))
  5 2)

(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "fdiv,fpspc"))
  56 56)

;; imul uses the fpu.  ??? does it have the same throughput as fmul?
(define_function_unit "fpu" 1 0
  (and (eq_attr "cpu" "pentiumpro")
       (eq_attr "type" "imul"))
  4 1)

;; AMD K6/K6-2 Scheduling
;;
;; The K6 has similar architecture to PPro.  Important difference is, that
;; there are only two decoders and they seems to be much slower than execution
;; units.  So we have to pay much more attention to proper decoding for
;; schedulers.  We share most of scheduler code for PPro in i386.c
;;
;; The fp unit is not pipelined and do one operation per two cycles including
;; the FXCH.
;;
;; alu	  describes both ALU units (ALU-X and ALU-Y).
;; alux   describes X alu unit
;; fpu    describes FPU unit
;; load   describes load unit.
;; branch describes branch unit.
;; store  decsribes store unit.  This unit is not modelled completely and only
;;        used to model lea operation.  Otherwise it lie outside of the critical
;;        path.
;;
;; ??? fxch isn't handled; not an issue until sched3 after reg-stack is real.

;; The decoder specification is in the PPro section above!

;; Shift instructions and certain arithmetic are issued only to X pipe.
(define_function_unit "k6_alux" 1 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "ishift,alu1,negnot,cld"))
  1 1)

;; The QI mode arithmetic is issued to X pipe only.
(define_function_unit "k6_alux" 1 0
  (and (eq_attr "cpu" "k6")
       (and (eq_attr "type" "alu,alu1,negnot,icmp,test,imovx,incdec")
	    (match_operand:QI 0 "general_operand" "")))
  1 1)

(define_function_unit "k6_alu" 2 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "ishift,alu1,negnot,alu,icmp,test,imovx,incdec,setcc,lea"))
  1 1)

(define_function_unit "k6_alu" 2 0
  (and (eq_attr "cpu" "k6")
       (and (eq_attr "type" "imov")
       	    (eq_attr "memory" "none")))
  1 1)

(define_function_unit "k6_branch" 1 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "call,callv,ibr"))
  1 1)

;; Load unit have two cycle latency, but we take care for it in adjust_cost
(define_function_unit "k6_load" 1 0
  (and (eq_attr "cpu" "k6")
       (ior (eq_attr "type" "pop")
	    (eq_attr "memory" "load,both")))
  1 1)

(define_function_unit "k6_load" 1 0
  (and (eq_attr "cpu" "k6")
       (and (eq_attr "type" "str")
	    (eq_attr "memory" "load,both")))
  10 10)

;; Lea have two instructions, so latency is probably 2
(define_function_unit "k6_store" 1 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "lea"))
  2 1)

(define_function_unit "k6_store" 1 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "str"))
  10 10)

(define_function_unit "k6_store" 1 0
  (and (eq_attr "cpu" "k6")
       (ior (eq_attr "type" "push")
	    (eq_attr "memory" "store,both")))
  1 1)

(define_function_unit "k6_fpu" 1 1
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "fop,fop1,fmov,fcmp"))
  2 2)

(define_function_unit "k6_fpu" 1 1
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "fmul"))
  2 2)

;; ??? Guess
(define_function_unit "k6_fpu" 1 1
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "fdiv,fpspc"))
  56 56)

(define_function_unit "k6_alu" 2 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "imul"))
  2 2)

(define_function_unit "k6_alux" 1 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "imul"))
  2 2)

;; ??? Guess
(define_function_unit "k6_alu" 2 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "idiv"))
  17 17)

(define_function_unit "k6_alux" 1 0
  (and (eq_attr "cpu" "k6")
       (eq_attr "type" "idiv"))
  17 17)

;; AMD Athlon Scheduling
;;
;; The Athlon does contain three pipelined FP units, three integer units and
;; three address generation units. 
;;
;; The predecode logic is determining boundaries of instructions in the 64
;; byte cache line. So the cache line straddling problem of K6 might be issue
;; here as well, but it is not noted in the documentation.
;;
;; Three DirectPath instructions decoders and only one VectorPath decoder
;; is available. They can decode three DirectPath instructions or one VectorPath
;; instruction per cycle.
;; Decoded macro instructions are then passed to 72 entry instruction control
;; unit, that passes
;; it to the specialized integer (18 entry) and fp (36 entry) schedulers.
;;
;; The load/store queue unit is not attached to the schedulers but
;; communicates with all the execution units seperately instead.

(define_attr "athlon_decode" "direct,vector"
  (cond [(eq_attr "type" "call,imul,idiv,other,multi,fcmov,fpspc,str,pop,cld,fcmov")
	   (const_string "vector")
         (and (eq_attr "type" "push")
              (match_operand 1 "memory_operand" ""))
	   (const_string "vector")
         (and (eq_attr "type" "fmov")
              (ior (match_operand:XF 0 "memory_operand" "")
                   (match_operand:XF 1 "memory_operand" "")))
	   (const_string "vector")]
	(const_string "direct")))

(define_function_unit "athlon_vectordec" 1 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "athlon_decode" "vector"))
  1 1)

(define_function_unit "athlon_directdec" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "athlon_decode" "direct"))
  1 1)

(define_function_unit "athlon_vectordec" 1 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "athlon_decode" "direct"))
  1 1 [(eq_attr "athlon_decode" "vector")])

(define_function_unit "athlon_ieu" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "alu1,negnot,alu,icmp,test,imov,imovx,lea,incdec,ishift,ibr,call,callv,icmov,cld,pop,setcc,push,pop"))
  1 1)

(define_function_unit "athlon_ieu" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "str"))
  15 15)

(define_function_unit "athlon_ieu" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "imul"))
  5 0)

(define_function_unit "athlon_ieu" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "idiv"))
  42 0)

(define_function_unit "athlon_muldiv" 1 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "imul"))
  5 0)

(define_function_unit "athlon_muldiv" 1 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "idiv"))
  42 42)

(define_attr "athlon_fpunits" "none,store,mul,add,muladd,any"
  (cond [(eq_attr "type" "fop,fop1,fcmp")
	   (const_string "add")
         (eq_attr "type" "fmul,fdiv,fpspc,fsgn,fcmov")
	   (const_string "mul")
	 (and (eq_attr "type" "fmov") (eq_attr "memory" "store,both"))
	   (const_string "store")
	 (and (eq_attr "type" "fmov") (eq_attr "memory" "load"))
	   (const_string "any")
         (and (eq_attr "type" "fmov")
              (ior (match_operand:SI 1 "register_operand" "")
                   (match_operand 1 "immediate_operand" "")))
	   (const_string "store")
         (eq_attr "type" "fmov")
	   (const_string "muladd")]
	(const_string "none")))

;; We use latencies 1 for definitions.  This is OK to model colisions
;; in execution units.  The real latencies are modeled in the "fp" pipeline.

;; fsin, fcos: 96-192
;; fsincos: 107-211
;; fsqrt: 19 for SFmode, 27 for DFmode, 35 for XFmode.
(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "fpspc"))
  100 1)

;; 16 cycles for SFmode, 20 for DFmode and 24 for XFmode.
(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "fdiv"))
  24 1)

(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "fop,fop1,fmul"))
  4 1)

;; XFmode loads are slow.
;; XFmode store is slow too (8 cycles), but we don't need to model it, because
;; there are no dependent instructions.

(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (and (eq_attr "type" "fmov")
	    (match_operand:XF 1 "memory_operand" "")))
  10 1)

(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "fmov,fsgn"))
  2 1)

;; fcmp and ftst instructions
(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (and (eq_attr "type" "fcmp")
	    (eq_attr "athlon_decode" "direct")))
  3 1)

;; fcmpi instructions.
(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (and (eq_attr "type" "fcmp")
	    (eq_attr "athlon_decode" "vector")))
  3 1)

(define_function_unit "athlon_fp" 3 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "type" "fcmov"))
  7 1)

(define_function_unit "athlon_fp_mul" 1 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "athlon_fpunits" "mul"))
  1 1)

(define_function_unit "athlon_fp_add" 1 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "athlon_fpunits" "add"))
  1 1)

(define_function_unit "athlon_fp_muladd" 2 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "athlon_fpunits" "muladd,mul,add"))
  1 1)

(define_function_unit "athlon_fp_store" 1 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "athlon_fpunits" "store"))
  1 1)

;; We don't need to model the Adress Generation Unit, since we don't model
;; the re-order buffer yet and thus we never schedule more than three operations
;; at time.  Later we may want to experiment with MD_SCHED macros modeling the
;; decoders independently on the functional units.

;(define_function_unit "athlon_agu" 3 0
;  (and (eq_attr "cpu" "athlon")
;       (and (eq_attr "memory" "!none")
;            (eq_attr "athlon_fpunits" "none")))
;  1 1)

;; Model load unit to avoid too long sequences of loads.  We don't need to
;; model store queue, since it is hardly going to be bottleneck.

(define_function_unit "athlon_load" 2 0
  (and (eq_attr "cpu" "athlon")
       (eq_attr "memory" "load,both"))
  1 1)


;; Compare instructions.

;; All compare insns have expanders that save the operands away without
;; actually generating RTL.  The bCOND or sCOND (emitted immediately
;; after the cmp) will actually emit the cmpM.

(define_expand "cmpdi"
  [(set (reg:CC 17)
	(compare:CC (match_operand:DI 0 "general_operand" "")
		    (match_operand:DI 1 "general_operand" "")))]
  ""
  "
{
  if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
    operands[0] = force_reg (DImode, operands[0]);
  ix86_compare_op0 = operands[0];
  ix86_compare_op1 = operands[1];
  DONE;
}")

(define_expand "cmpsi"
  [(set (reg:CC 17)
	(compare:CC (match_operand:SI 0 "cmpsi_operand" "")
		    (match_operand:SI 1 "general_operand" "")))]
  ""
  "
{
  if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
    operands[0] = force_reg (SImode, operands[0]);
  ix86_compare_op0 = operands[0];
  ix86_compare_op1 = operands[1];
  DONE;
}")

(define_expand "cmphi"
  [(set (reg:CC 17)
	(compare:CC (match_operand:HI 0 "general_operand" "")
		    (match_operand:HI 1 "general_operand" "")))]
  ""
  "
{
  if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
    operands[0] = force_reg (HImode, operands[0]);
  ix86_compare_op0 = operands[0];
  ix86_compare_op1 = operands[1];
  DONE;
}")

(define_expand "cmpqi"
  [(set (reg:CC 17)
	(compare:CC (match_operand:QI 0 "general_operand" "")
		    (match_operand:QI 1 "general_operand" "")))]
  "TARGET_QIMODE_MATH"
  "
{
  if ((GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
      || (CONSTANT_P (operands[0]) && CONSTANT_P (operands[1])))
    operands[0] = force_reg (QImode, operands[0]);
  ix86_compare_op0 = operands[0];
  ix86_compare_op1 = operands[1];
  DONE;
}")

(define_insn "cmpsi_ccz_1"
  [(set (reg:CCZ 17)
	(compare:CCZ (match_operand:SI 0 "nonimmediate_operand" "r,?mr")
		     (match_operand:SI 1 "const0_operand" "n,n")))]
  ""
  "@
   test{l}\\t{%0, %0|%0, %0}
   cmp{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test,icmp")
   (set_attr "length_immediate" "0,1")
   (set_attr "mode" "SI")])

(define_insn "cmpsi_ccno_1"
  [(set (reg:CCNO 17)
	(compare:CCNO (match_operand:SI 0 "nonimmediate_operand" "r,?mr")
		      (match_operand:SI 1 "const0_operand" "n,n")))]
  ""
  "@
   test{l}\\t{%0, %0|%0, %0}
   cmp{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test,icmp")
   (set_attr "length_immediate" "0,1")
   (set_attr "mode" "SI")])

(define_insn "cmpsi_1"
  [(set (reg:CC 17)
	(compare:CC (match_operand:SI 0 "nonimmediate_operand" "rm,r")
		    (match_operand:SI 1 "general_operand" "ri,mr")))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "cmp{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "icmp")
   (set_attr "mode" "SI")])

(define_insn "*cmphi_0"
  [(set (reg 17)
	(compare (match_operand:HI 0 "nonimmediate_operand" "r,?mr")
		 (match_operand:HI 1 "const0_operand" "n,n")))]
  "ix86_match_ccmode (insn, CCNOmode)"
  "@
   test{w}\\t{%0, %0|%0, %0}
   cmp{w}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test,icmp")
   (set_attr "length_immediate" "0,1")
   (set_attr "mode" "HI")])

(define_insn "*cmphi_1"
  [(set (reg:CC 17)
	(compare:CC (match_operand:HI 0 "nonimmediate_operand" "rm,r")
		    (match_operand:HI 1 "general_operand" "ri,mr")))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "cmp{w}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "icmp")
   (set_attr "mode" "HI")])

(define_insn "cmpqi_ccz_1"
  [(set (reg:CCZ 17)
	(compare:CCZ (match_operand:QI 0 "nonimmediate_operand" "q,?mq")
		     (match_operand:QI 1 "const0_operand" "n,n")))]
  ""
  "@
   test{b}\\t{%0, %0|%0, %0}
   cmp{b}\\t{$0, %0|%0, 0}"
  [(set_attr "type" "test,icmp")
   (set_attr "length_immediate" "0,1")
   (set_attr "mode" "QI")])

(define_insn "*cmpqi_ccno_1"
  [(set (reg:CCNO 17)
	(compare:CCNO (match_operand:QI 0 "nonimmediate_operand" "q,?mq")
		      (match_operand:QI 1 "const0_operand" "n,n")))]
  ""
  "@
   test{b}\\t{%0, %0|%0, %0}
   cmp{b}\\t{$0, %0|%0, 0}"
  [(set_attr "type" "test,icmp")
   (set_attr "length_immediate" "0,1")
   (set_attr "mode" "QI")])

(define_insn "*cmpqi_1"
  [(set (reg:CC 17)
	(compare:CC (match_operand:QI 0 "nonimmediate_operand" "qm,q")
		    (match_operand:QI 1 "general_operand" "qi,mq")))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "cmp{b}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "icmp")
   (set_attr "mode" "QI")])

(define_insn "*cmpqi_ext_1"
  [(set (reg:CC 17)
	(compare:CC
	  (match_operand:QI 0 "general_operand" "qm")
	  (subreg:QI
	    (zero_extract:SI
	      (match_operand 1 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8)) 0)))]
  ""
  "cmp{b}\\t{%h1, %0|%0, %h1}"
  [(set_attr "type" "icmp")
   (set_attr "mode" "QI")])

(define_insn "*cmpqi_ext_2"
  [(set (reg 17)
	(compare
	  (subreg:QI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8)) 0)
	  (match_operand:QI 1 "const0_operand" "n")))]
  "ix86_match_ccmode (insn, CCNOmode)"
  "test{b}\\t%h0, %h0"
  [(set_attr "type" "test")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "QI")])

(define_insn "cmpqi_ext_3"
  [(set (reg:CC 17)
	(compare:CC
	  (subreg:QI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8)) 0)
	  (match_operand:QI 1 "general_operand" "qmn")))]
  ""
  "cmp{b}\\t{%1, %h0|%h0, %1}"
  [(set_attr "type" "icmp")
   (set_attr "mode" "QI")])

(define_insn "*cmpqi_ext_4"
  [(set (reg:CC 17)
	(compare:CC
	  (subreg:QI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8)) 0)
	  (subreg:QI
	    (zero_extract:SI
	      (match_operand 1 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8)) 0)))]
  ""
  "cmp{b}\\t{%h1, %h0|%h0, %h1}"
  [(set_attr "type" "icmp")
   (set_attr "mode" "QI")])

;; These implement float point compares.
;; %%% See if we can get away with VOIDmode operands on the actual insns,
;; which would allow mix and match FP modes on the compares.  Which is what
;; the old patterns did, but with many more of them.

(define_expand "cmpxf"
  [(set (reg:CC 17)
	(compare:CC (match_operand:XF 0 "cmp_fp_expander_operand" "")
		    (match_operand:XF 1 "cmp_fp_expander_operand" "")))]
  "TARGET_80387"
  "
{
  ix86_compare_op0 = operands[0];
  ix86_compare_op1 = operands[1];
  DONE;
}")

(define_expand "cmpdf"
  [(set (reg:CC 17)
	(compare:CC (match_operand:DF 0 "cmp_fp_expander_operand" "")
		    (match_operand:DF 1 "cmp_fp_expander_operand" "")))]
  "TARGET_80387"
  "
{
  ix86_compare_op0 = operands[0];
  ix86_compare_op1 = operands[1];
  DONE;
}")

(define_expand "cmpsf"
  [(set (reg:CC 17)
	(compare:CC (match_operand:SF 0 "cmp_fp_expander_operand" "")
		    (match_operand:SF 1 "cmp_fp_expander_operand" "")))]
  "TARGET_80387"
  "
{
  ix86_compare_op0 = operands[0];
  ix86_compare_op1 = operands[1];
  DONE;
}")

;; FP compares, step 1:
;; Set the FP condition codes.
;;
;; CCFPmode	compare with exceptions
;; CCFPUmode	compare with no exceptions

;; %%% It is an unfortunate fact that ftst has no non-popping variant,
;; and that fp moves clobber the condition codes, and that there is
;; currently no way to describe this fact to reg-stack.  So there are
;; no splitters yet for this.

;; %%% YIKES!  This scheme does not retain a strong connection between 
;; the real compare and the ultimate cc0 user, so CC_REVERSE does not
;; work!  Only allow tos/mem with tos in op 0.
;;
;; Hmm, of course, this is what the actual _hardware_ does.  Perhaps
;; things aren't as bad as they sound...

(define_insn "*cmpfp_0"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(unspec:HI
	  [(compare:CCFP (match_operand 1 "register_operand" "f")
		         (match_operand 2 "const0_operand" "X"))] 9))]
  "TARGET_80387
   && FLOAT_MODE_P (GET_MODE (operands[1]))
   && GET_MODE (operands[1]) == GET_MODE (operands[2])"
  "*
{
  if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
    return \"ftst\;fnstsw\\t%0\;fstp\\t%y0\";
  else
    return \"ftst\;fnstsw\\t%0\";
}"
  [(set_attr "type" "multi")
   (set_attr "mode" "unknownfp")])

;; We may not use "#" to split and emit these, since the REG_DEAD notes
;; used to manage the reg stack popping would not be preserved.

(define_insn "*cmpfp_2_sf"
  [(set (reg:CCFP 18)
	(compare:CCFP
	  (match_operand:SF 0 "register_operand" "f")
	  (match_operand:SF 1 "nonimmediate_operand" "fm")))]
  "TARGET_80387"
  "* return output_fp_compare (insn, operands, 0, 0);"
  [(set_attr "type" "fcmp")
   (set_attr "mode" "SF")])

(define_insn "*cmpfp_2_sf_1"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(unspec:HI
	  [(compare:CCFP
	     (match_operand:SF 1 "register_operand" "f")
	     (match_operand:SF 2 "nonimmediate_operand" "fm"))] 9))]
  "TARGET_80387"
  "* return output_fp_compare (insn, operands, 2, 0);"
  [(set_attr "type" "fcmp")
   (set_attr "mode" "SF")])

(define_insn "*cmpfp_2_df"
  [(set (reg:CCFP 18)
	(compare:CCFP
	  (match_operand:DF 0 "register_operand" "f")
	  (match_operand:DF 1 "nonimmediate_operand" "fm")))]
  "TARGET_80387"
  "* return output_fp_compare (insn, operands, 0, 0);"
  [(set_attr "type" "fcmp")
   (set_attr "mode" "DF")])

(define_insn "*cmpfp_2_df_1"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(unspec:HI
	  [(compare:CCFP
	     (match_operand:DF 1 "register_operand" "f")
	     (match_operand:DF 2 "nonimmediate_operand" "fm"))] 9))]
  "TARGET_80387"
  "* return output_fp_compare (insn, operands, 2, 0);"
  [(set_attr "type" "multi")
   (set_attr "mode" "DF")])

(define_insn "*cmpfp_2_xf"
  [(set (reg:CCFP 18)
	(compare:CCFP
	  (match_operand:XF 0 "register_operand" "f")
	  (match_operand:XF 1 "register_operand" "f")))]
  "TARGET_80387"
  "* return output_fp_compare (insn, operands, 0, 0);"
  [(set_attr "type" "fcmp")
   (set_attr "mode" "XF")])

(define_insn "*cmpfp_2_xf_1"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(unspec:HI
	  [(compare:CCFP
	     (match_operand:XF 1 "register_operand" "f")
	     (match_operand:XF 2 "register_operand" "f"))] 9))]
  "TARGET_80387"
  "* return output_fp_compare (insn, operands, 2, 0);"
  [(set_attr "type" "multi")
   (set_attr "mode" "XF")])

(define_insn "*cmpfp_2u"
  [(set (reg:CCFPU 18)
	(compare:CCFPU
	  (match_operand 0 "register_operand" "f")
	  (match_operand 1 "register_operand" "f")))]
  "TARGET_80387
   && FLOAT_MODE_P (GET_MODE (operands[0]))
   && GET_MODE (operands[0]) == GET_MODE (operands[1])"
  "* return output_fp_compare (insn, operands, 0, 1);"
  [(set_attr "type" "fcmp")
   (set_attr "mode" "unknownfp")])

(define_insn "*cmpfp_2u_1"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(unspec:HI
	  [(compare:CCFPU
	     (match_operand 1 "register_operand" "f")
	     (match_operand 2 "register_operand" "f"))] 9))]
  "TARGET_80387
   && FLOAT_MODE_P (GET_MODE (operands[1]))
   && GET_MODE (operands[1]) == GET_MODE (operands[2])"
  "* return output_fp_compare (insn, operands, 2, 1);"
  [(set_attr "type" "multi")
   (set_attr "mode" "unknownfp")])

;; Patterns to match the SImode-in-memory ficom instructions.
;;
;; %%% Play games with accepting gp registers, as otherwise we have to
;; force them to memory during rtl generation, which is no good.  We
;; can get rid of this once we teach reload to do memory input reloads 
;; via pushes.

(define_insn "*ficom_1"
  [(set (reg:CCFP 18)
	(compare:CCFP
	  (match_operand 0 "register_operand" "f,f")
	  (float (match_operand:SI 1 "nonimmediate_operand" "m,?r"))))]
  "0 && TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[0]))
   && GET_MODE (XEXP (SET_SRC (PATTERN (insn)), 1)) == GET_MODE (operands[0])"
  "#")

;; Split the not-really-implemented gp register case into a
;; push-op-pop sequence.
;;
;; %%% This is most efficient, but am I gonna get in trouble
;; for separating cc0_setter and cc0_user?

(define_split
  [(set (reg:CCFP 18)
	(compare:CCFP
	  (match_operand:SF 0 "register_operand" "")
	  (float (match_operand:SI 1 "register_operand" ""))))]
  "0 && TARGET_80387 && reload_completed"
  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
   (set (reg:CCFP 18) (compare:CCFP (match_dup 0) (match_dup 2)))
   (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
              (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "operands[2] = gen_rtx_MEM (Pmode, stack_pointer_rtx);
   operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]), operands[2]);")

;; FP compares, step 2
;; Move the fpsw to ax.

(define_insn "x86_fnstsw_1"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(unspec:HI [(reg 18)] 9))]
  "TARGET_80387"
  "fnstsw\\t%0"
  [(set_attr "length" "2")
   (set_attr "mode" "SI")
   (set_attr "i387" "1")
   (set_attr "ppro_uops" "few")])

;; FP compares, step 3
;; Get ax into flags, general case.

(define_insn "x86_sahf_1"
  [(set (reg:CC 17)
	(unspec:CC [(match_operand:HI 0 "register_operand" "a")] 10))]
  ""
  "sahf"
  [(set_attr "length" "1")
   (set_attr "athlon_decode" "vector")
   (set_attr "mode" "SI")
   (set_attr "ppro_uops" "one")])

;; Pentium Pro can do steps 1 through 3 in one go.

(define_insn "*cmpfp_i"
  [(set (reg:CCFP 17)
	(compare:CCFP (match_operand 0 "register_operand" "f")
		      (match_operand 1 "register_operand" "f")))]
  "TARGET_80387 && TARGET_CMOVE
   && FLOAT_MODE_P (GET_MODE (operands[0]))
   && GET_MODE (operands[0]) == GET_MODE (operands[0])"
  "* return output_fp_compare (insn, operands, 1, 0);"
  [(set_attr "type" "fcmp")
   (set_attr "mode" "unknownfp")
   (set_attr "athlon_decode" "vector")])

(define_insn "*cmpfp_iu"
  [(set (reg:CCFPU 17)
	(compare:CCFPU (match_operand 0 "register_operand" "f")
		       (match_operand 1 "register_operand" "f")))]
  "TARGET_80387 && TARGET_CMOVE
   && FLOAT_MODE_P (GET_MODE (operands[0]))
   && GET_MODE (operands[0]) == GET_MODE (operands[1])"
  "* return output_fp_compare (insn, operands, 1, 1);"
  [(set_attr "type" "fcmp")
   (set_attr "mode" "unknownfp")
   (set_attr "athlon_decode" "vector")])

;; Move instructions.

;; General case of fullword move.

(define_expand "movsi"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(match_operand:SI 1 "general_operand" ""))]
  ""
  "ix86_expand_move (SImode, operands); DONE;")

;; Push/pop instructions.  They are separate since autoinc/dec is not a
;; general_operand.
;;
;; %%% We don't use a post-inc memory reference because x86 is not a 
;; general AUTO_INC_DEC host, which impacts how it is treated in flow.
;; Changing this impacts compiler performance on other non-AUTO_INC_DEC
;; targets without our curiosities, and it is just as easy to represent
;; this differently.

(define_insn "pushsi2"
  [(set (match_operand:SI 0 "push_operand" "=<")
	(match_operand:SI 1 "general_no_elim_operand" "ri*m"))]
  ""
  "push{l}\\t%1"
  [(set_attr "type" "push")
   (set_attr "mode" "SI")])

(define_insn "*pushsi2_prologue"
  [(set (match_operand:SI 0 "push_operand" "=<")
	(match_operand:SI 1 "general_no_elim_operand" "ri*m"))
   (set (reg:SI 6) (reg:SI 6))]
  ""
  "push{l}\\t%1"
  [(set_attr "type" "push")
   (set_attr "mode" "SI")])

(define_insn "*popsi1_epilogue"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m")
	(mem:SI (reg:SI 7)))
   (set (reg:SI 7)
	(plus:SI (reg:SI 7) (const_int 4)))
   (set (reg:SI 6) (reg:SI 6))]
  ""
  "pop{l}\\t%0"
  [(set_attr "type" "pop")
   (set_attr "mode" "SI")])

(define_insn "popsi1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r*m")
	(mem:SI (reg:SI 7)))
   (set (reg:SI 7)
	(plus:SI (reg:SI 7) (const_int 4)))]
  ""
  "pop{l}\\t%0"
  [(set_attr "type" "pop")
   (set_attr "mode" "SI")])

(define_insn "*movsi_xor"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(match_operand:SI 1 "const0_operand" "i"))
   (clobber (reg:CC 17))]
  "reload_completed && (!TARGET_USE_MOV0 || optimize_size)"
  "xor{l}\\t{%0, %0|%0, %0}"
  [(set_attr "type" "alu1")
   (set_attr "mode" "SI")
   (set_attr "length_immediate" "0")])

(define_insn "*movsi_or"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(match_operand:SI 1 "immediate_operand" "i"))
   (clobber (reg:CC 17))]
  "reload_completed && GET_CODE (operands[1]) == CONST_INT
   && INTVAL (operands[1]) == -1
   && (TARGET_PENTIUM || optimize_size)"
  "*
{
  operands[1] = constm1_rtx;
  return \"or{l}\\t{%1, %0|%1, %0}\";
}"
  [(set_attr "type" "alu1")
   (set_attr "mode" "SI")
   (set_attr "length_immediate" "1")])

(define_insn "*movsi_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=*a,r,*a,m")
	(match_operand:SI 1 "general_operand" "im,rinm,rinm,rin"))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_LEA:
      return \"lea{l}\\t{%1, %0|%0, %1}\";
    default:
      if (flag_pic && SYMBOLIC_CONST (operands[1]))
	abort();
      return \"mov{l}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(and (ne (symbol_ref "flag_pic") (const_int 0))
		 (match_operand:SI 1 "symbolic_operand" ""))
	      (const_string "lea")
	   ]
	   (const_string "imov")))
   (set_attr "modrm" "0,*,0,*")
   (set_attr "mode" "SI")])

(define_insn "*swapsi"
  [(set (match_operand:SI 0 "register_operand" "+r")
	(match_operand:SI 1 "register_operand" "+r"))
   (set (match_dup 1)
	(match_dup 0))]
  ""
  "xchg{l}\\t%1, %0"
  [(set_attr "type" "imov")
   (set_attr "pent_pair" "np")
   (set_attr "athlon_decode" "vector")
   (set_attr "mode" "SI")
   (set_attr "modrm" "0")
   (set_attr "ppro_uops" "few")])

(define_expand "movhi"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
        (match_operand:HI 1 "general_operand" ""))]
  ""
  "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"))]
  ""
  "@
   push{w}\\t{|WORD PTR }%1
   push{w}\\t%1"
  [(set_attr "type" "push")
   (set_attr "mode" "HI")])

(define_insn "pophi1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=r*m")
	(mem:HI (reg:SI 7)))
   (set (reg:SI 7)
	(plus:SI (reg:SI 7) (const_int 2)))]
  ""
  "pop{w}\\t%0"
  [(set_attr "type" "pop")
   (set_attr "mode" "HI")])

(define_insn "*movhi_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=*a,r,r,*a,r,m")
	(match_operand:HI 1 "general_operand" "i,r,rn,rm,rm,rn"))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_IMOVX:
      /* movzwl is faster than movw on p2 due to partial word stalls,
	 though not as fast as an aligned movl.  */
      return \"movz{wl|x}\\t{%1, %k0|%k0, %1}\";
    default:
      if (get_attr_mode (insn) == MODE_SI)
        return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
      else
        return \"mov{w}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(and (eq_attr "alternative" "0,1")
		 (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
			  (const_int 0))
		      (eq (symbol_ref "TARGET_HIMODE_MATH")
			  (const_int 0))))
	      (const_string "imov")
	    (and (eq_attr "alternative" "2,3,4")
		 (match_operand:HI 1 "aligned_operand" ""))
	      (const_string "imov")
	    (and (ne (symbol_ref "TARGET_MOVX")
		     (const_int 0))
		 (eq_attr "alternative" "0,1,3,4"))
	      (const_string "imovx")
	   ]
	   (const_string "imov")))
    (set (attr "mode")
      (cond [(eq_attr "type" "imovx")
	       (const_string "SI")
	     (and (eq_attr "alternative" "2,3,4")
		  (match_operand:HI 1 "aligned_operand" ""))
	       (const_string "SI")
	     (and (eq_attr "alternative" "0,1")
		  (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
			   (const_int 0))
		       (eq (symbol_ref "TARGET_HIMODE_MATH")
			   (const_int 0))))
	       (const_string "SI")
	    ]
	    (const_string "HI")))
   (set_attr "modrm" "0,*,*,0,*,*")])

(define_insn "*swaphi_1"
  [(set (match_operand:HI 0 "register_operand" "+r")
	(match_operand:HI 1 "register_operand" "+r"))
   (set (match_dup 1)
	(match_dup 0))]
  "TARGET_PARTIAL_REG_STALL"
  "xchg{w}\\t%1, %0"
  [(set_attr "type" "imov")
   (set_attr "pent_pair" "np")
   (set_attr "mode" "HI")
   (set_attr "modrm" "0")
   (set_attr "ppro_uops" "few")])

(define_insn "*swaphi_2"
  [(set (match_operand:HI 0 "register_operand" "+r")
	(match_operand:HI 1 "register_operand" "+r"))
   (set (match_dup 1)
	(match_dup 0))]
  "! TARGET_PARTIAL_REG_STALL"
  "xchg{l}\\t%k1, %k0"
  [(set_attr "type" "imov")
   (set_attr "pent_pair" "np")
   (set_attr "mode" "SI")
   (set_attr "modrm" "0")
   (set_attr "ppro_uops" "few")])

(define_expand "movstricthi"
  [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" ""))
	(match_operand:HI 1 "general_operand" ""))]
  "! TARGET_PARTIAL_REG_STALL"
  "
{
  /* Don't generate memory->memory moves, go through a register */
  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
    operands[1] = force_reg (HImode, operands[1]);
}")

(define_insn "*movstricthi_1"
  [(set (strict_low_part (match_operand:HI 0 "nonimmediate_operand" "+rm,r"))
	(match_operand:HI 1 "general_operand" "rn,m"))]
  "! TARGET_PARTIAL_REG_STALL
   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
  "mov{w}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "imov")
   (set_attr "mode" "HI")])

(define_insn "*movstricthi_xor"
  [(set (strict_low_part (match_operand:HI 0 "register_operand" "=r"))
	(match_operand:HI 1 "const0_operand" "i"))
   (clobber (reg:CC 17))]
  "reload_completed && (!TARGET_USE_MOV0 || optimize_size)"
  "xor{w}\\t{%0, %0|%0, %0}"
  [(set_attr "type" "alu1")
   (set_attr "mode" "HI")
   (set_attr "length_immediate" "0")])

(define_expand "movqi"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(match_operand:QI 1 "general_operand" ""))]
  ""
  "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.

(define_insn "pushqi2"
  [(set (match_operand:QI 0 "push_operand" "=<,<")
	(match_operand:QI 1 "nonmemory_no_elim_operand" "n,r"))]
  ""
  "@
   push{w}\\t{|word ptr }%1
   push{w}\\t%w1"
  [(set_attr "type" "push")
   (set_attr "mode" "HI")])

(define_insn "popqi1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=r*m")
	(mem:QI (reg:SI 7)))
   (set (reg:SI 7)
	(plus:SI (reg:SI 7) (const_int 2)))]
  ""
  "pop{w}\\t%0"
  [(set_attr "type" "pop")
   (set_attr "mode" "HI")])

;; 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 dependency machines (such as AMD Athlon), where QImode
;; moves issue extra dependency and for partial register stalls machines
;; that don't use QImode patterns (and QImode move cause stall on the next
;; instruction).
;;
;; For loads of Q_REG to NONQ_REG we use full sized moves except for partial
;; register stall machines with, where we use QImode instructions, since
;; 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,qm,qn"))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_IMOVX:
      if (!QI_REG_P (operands[1]) && GET_CODE (operands[1]) != MEM)
	abort ();
      return \"movz{bl|x}\\t{%1, %k0|%k0, %1}\";
    default:
      if (get_attr_mode (insn) == MODE_SI)
        return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
      else
        return \"mov{b}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(and (eq_attr "alternative" "3")
		 (ior (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
			  (const_int 0))
		      (eq (symbol_ref "TARGET_QIMODE_MATH")
			  (const_int 0))))
	      (const_string "imov")
	    (eq_attr "alternative" "3,5")
	      (const_string "imovx")
	    (and (ne (symbol_ref "TARGET_MOVX")
		     (const_int 0))
		 (eq_attr "alternative" "2"))
	      (const_string "imovx")
	   ]
	   (const_string "imov")))
   (set (attr "mode")
      (cond [(eq_attr "alternative" "3,4,5")
	       (const_string "SI")
	     (eq_attr "alternative" "6")
	       (const_string "QI")
	     (eq_attr "type" "imovx")
	       (const_string "SI")
	     (and (eq_attr "type" "imov")
		  (and (eq_attr "alternative" "0,1,2")
		       (ne (symbol_ref "TARGET_PARTIAL_REG_DEPENDENCY")
			   (const_int 0))))
	       (const_string "SI")
	     ;; Avoid partial register stalls when not using QImode arithmetic
	     (and (eq_attr "type" "imov")
		  (and (eq_attr "alternative" "0,1,2")
		       (and (ne (symbol_ref "TARGET_PARTIAL_REG_STALL")
				(const_int 0))
			    (eq (symbol_ref "TARGET_QIMODE_MATH")
				(const_int 0)))))
	       (const_string "SI")
	   ]
	   (const_string "QI")))])

(define_expand "reload_outqi"
  [(parallel [(match_operand:QI 0 "" "=m")
              (match_operand:QI 1 "register_operand" "r")
              (match_operand:QI 2 "register_operand" "=&q")])]
  ""
  "
{
  rtx op0, op1, op2;
  op0 = operands[0]; op1 = operands[1]; op2 = operands[2];

  if (reg_overlap_mentioned_p (op2, op0))
    abort ();
  if (! q_regs_operand (op1, QImode))
    {
      emit_insn (gen_movqi (op2, op1));
      op1 = op2;
    }
  emit_insn (gen_movqi (op0, op1));
  DONE;
}")

(define_insn "*swapqi"
  [(set (match_operand:QI 0 "register_operand" "+r")
	(match_operand:QI 1 "register_operand" "+r"))
   (set (match_dup 1)
	(match_dup 0))]
  ""
  "xchg{b}\\t%1, %0"
  [(set_attr "type" "imov")
   (set_attr "pent_pair" "np")
   (set_attr "mode" "QI")
   (set_attr "modrm" "0")
   (set_attr "ppro_uops" "few")])

(define_expand "movstrictqi"
  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" ""))
	(match_operand:QI 1 "general_operand" ""))]
  "! TARGET_PARTIAL_REG_STALL"
  "
{
  /* Don't generate memory->memory moves, go through a register */
  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
    operands[1] = force_reg (QImode, operands[1]);
}")

(define_insn "*movstrictqi_1"
  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm,q"))
	(match_operand:QI 1 "general_operand" "*qn,m"))]
  "! TARGET_PARTIAL_REG_STALL
   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)"
  "mov{b}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "imov")
   (set_attr "mode" "QI")])

(define_insn "*movstrictqi_xor"
  [(set (strict_low_part (match_operand:QI 0 "q_regs_operand" "+q"))
	(match_operand:QI 1 "const0_operand" "i"))
   (clobber (reg:CC 17))]
  "reload_completed && (!TARGET_USE_MOV0 || optimize_size)"
  "xor{b}\\t{%0, %0|%0, %0}"
  [(set_attr "type" "alu1")
   (set_attr "mode" "QI")
   (set_attr "length_immediate" "0")])

(define_insn "*movsi_extv_1"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(sign_extract:SI (match_operand:SI 1 "register_operand" "q")
			 (const_int 8)
			 (const_int 8)))]
  ""
  "movs{bl|x}\\t{%h1, %0|%0, %h1}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "SI")])

(define_insn "*movhi_extv_1"
  [(set (match_operand:HI 0 "register_operand" "=r")
	(sign_extract:HI (match_operand:SI 1 "register_operand" "q")
			 (const_int 8)
			 (const_int 8)))]
  ""
  "movs{bl|x}\\t{%h1, %k0|%k0, %h1}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "SI")])

(define_insn "*movqi_extv_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,?r")
        (sign_extract:QI (match_operand:SI 1 "register_operand" "q,q")
                         (const_int 8)
                         (const_int 8)))]
  ""
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_IMOVX:
      return \"movs{bl|x}\\t{%h1, %k0|%k0, %h1}\";
    default:
      return \"mov{b}\\t{%h1, %0|%0, %h1}\";
    }
}"
  [(set (attr "type")
     (if_then_else (and (match_operand:QI 0 "register_operand" "")
			(ior (not (match_operand:QI 0 "q_regs_operand" ""))
			     (ne (symbol_ref "TARGET_MOVX")
				 (const_int 0))))
	(const_string "imovx")
	(const_string "imov")))
   (set (attr "mode")
     (if_then_else (eq_attr "type" "imovx")
	(const_string "SI")
	(const_string "QI")))])

(define_insn "*movsi_extzv_1"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(zero_extract:SI (match_operand 1 "ext_register_operand" "q")
			 (const_int 8)
			 (const_int 8)))]
  ""
  "movz{bl|x}\\t{%h1, %0|%0, %h1}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "SI")])

(define_insn "*movqi_extzv_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,?r")
        (subreg:QI (zero_extract:SI (match_operand 1 "ext_register_operand" "q,q")
				    (const_int 8)
				    (const_int 8)) 0))]
  ""
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_IMOVX:
      return \"movz{bl|x}\\t{%h1, %k0|%k0, %h1}\";
    default:
      return \"mov{b}\\t{%h1, %0|%0, %h1}\";
    }
}"
  [(set (attr "type")
     (if_then_else (and (match_operand:QI 0 "register_operand" "")
			(ior (not (match_operand:QI 0 "q_regs_operand" ""))
			     (ne (symbol_ref "TARGET_MOVX")
				 (const_int 0))))
	(const_string "imovx")
	(const_string "imov")))
   (set (attr "mode")
     (if_then_else (eq_attr "type" "imovx")
	(const_string "SI")
	(const_string "QI")))])

(define_insn "*movsi_insv_1"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+q")
			 (const_int 8)
			 (const_int 8))
	(match_operand:SI 1 "nonimmediate_operand" "qm"))]
  ""
  "mov{b}\\t{%b1, %h0|%h0, %b1}"
  [(set_attr "type" "imov")
   (set_attr "mode" "QI")])

(define_insn "*movqi_insv_2"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "+q")
			 (const_int 8)
			 (const_int 8))
	(and:SI (lshiftrt:SI (match_operand:SI 1 "register_operand" "q")
			     (const_int 8))
		(const_int 255)))]
  ""
  "mov{b}\\t{%h1, %h0|%h0, %h1}"
  [(set_attr "type" "imov")
   (set_attr "mode" "QI")])

(define_expand "movdi"
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
	(match_operand:DI 1 "general_operand" ""))]
  ""
  "ix86_expand_move (DImode, operands); DONE;")

(define_insn "*pushdi"
  [(set (match_operand:DI 0 "push_operand" "=<")
	(match_operand:DI 1 "general_no_elim_operand" "riF*m"))]
  ""
  "#")

(define_insn "*movdi_2"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
	(match_operand:DI 1 "general_operand" "riFo,riF"))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "#")

(define_split
  [(set (match_operand:DI 0 "push_operand" "")
        (match_operand:DI 1 "general_operand" ""))]
  "reload_completed"
  [(const_int 0)]
  "if (!ix86_split_long_move (operands)) abort (); DONE;")

;; %%% This multiword shite has got to go.
(define_split
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
        (match_operand:DI 1 "general_operand" ""))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 5))
   (set (match_dup 3) (match_dup 6))]
  "if (ix86_split_long_move (operands)) DONE;")
  
(define_expand "movsf"
  [(set (match_operand:SF 0 "nonimmediate_operand" "")
	(match_operand:SF 1 "general_operand" ""))]
  ""
  "ix86_expand_move (SFmode, operands); DONE;")

(define_insn "*pushsf"
  [(set (match_operand:SF 0 "push_operand" "=<,<")
	(match_operand:SF 1 "general_no_elim_operand" "f#r,rFm#f"))]
  ""
  "*
{
  switch (which_alternative)
    {
    case 0:
      /* %%% We loose REG_DEAD notes for controling pops if we split late.  */
      operands[0] = gen_rtx_MEM (SFmode, stack_pointer_rtx);
      operands[2] = stack_pointer_rtx;
      operands[3] = GEN_INT (4);
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
      else
	return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";

    case 1:
      return \"push{l}\\t%1\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "multi,push")
   (set_attr "mode" "SF,SI")])

(define_split
  [(set (match_operand:SF 0 "push_operand" "")
	(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))"
  [(set (match_dup 0)
	(match_dup 1))]
  "operands[1] = get_pool_constant (XEXP (operands[1], 0));")


;; %%% Kill this when call knows how to work this out.
(define_split
  [(set (match_operand:SF 0 "push_operand" "")
	(match_operand:SF 1 "register_operand" ""))]
  "FP_REGNO_P (REGNO (operands[1]))"
  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4)))
   (set (mem:SF (reg:SI 7)) (match_dup 1))])

(define_insn "*movsf_1"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,m")
	(match_operand:SF 1 "general_operand" "fm#r,f#r,G,rmF#f,Fr#f"))]
  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
   && (reload_in_progress || reload_completed
       || GET_CODE (operands[1]) != CONST_DOUBLE
       || memory_operand (operands[0], SFmode))" 
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\";
      else
        return \"fst%z0\\t%y0\";

    case 2:
      switch (standard_80387_constant_p (operands[1]))
        {
        case 1:
	  return \"fldz\";
	case 2:
	  return \"fld1\";
	}
      abort();

    case 3:
    case 4:
      return \"mov{l}\\t{%1, %0|%0, %1}\";

    default:
      abort();
    }
}"
  [(set_attr "type" "fmov,fmov,fmov,imov,imov")
   (set_attr "mode" "SF,SF,SF,SI,SI")])

(define_split
  [(set (match_operand:SF 0 "nonimmediate_operand" "")
	(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))
   && (!(FP_REG_P (operands[0]) || 
	 (GET_CODE (operands[0]) == SUBREG
	  && FP_REG_P (SUBREG_REG (operands[0]))))
       || standard_80387_constant_p (get_pool_constant (XEXP (operands[1], 0))))"
  [(set (match_dup 0)
	(match_dup 1))]
  "operands[1] = get_pool_constant (XEXP (operands[1], 0));")

(define_insn "swapsf"
  [(set (match_operand:SF 0 "register_operand" "+f")
	(match_operand:SF 1 "register_operand" "+f"))
   (set (match_dup 1)
	(match_dup 0))]
  ""
  "*
{
  if (STACK_TOP_P (operands[0]))
    return \"fxch\\t%1\";
  else
    return \"fxch\\t%0\";
}"
  [(set_attr "type" "fxch")
   (set_attr "mode" "SF")])

(define_expand "movdf"
  [(set (match_operand:DF 0 "nonimmediate_operand" "")
	(match_operand:DF 1 "general_operand" ""))]
  ""
  "ix86_expand_move (DFmode, operands); DONE;")

;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size.
;; Size of pushdf using integer insturctions is 2+2*memory operand size
;; On the average, pushdf using integers can be still shorter.  Allow this
;; pattern for optimize_size too.

(define_insn "*pushdf_nointeger"
  [(set (match_operand:DF 0 "push_operand" "=<,<,<")
	(match_operand:DF 1 "general_no_elim_operand" "f,Fo#f,*r#f"))]
  "!TARGET_INTEGER_DFMODE_MOVES"
  "*
{
  switch (which_alternative)
    {
    case 0:
      /* %%% We loose REG_DEAD notes for controling pops if we split late.  */
      operands[0] = gen_rtx_MEM (DFmode, stack_pointer_rtx);
      operands[2] = stack_pointer_rtx;
      operands[3] = GEN_INT (8);
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
      else
	return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";

    case 1:
    case 2:
      return \"#\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "multi")
   (set_attr "mode" "DF,SI,SI")])

(define_insn "*pushdf_integer"
  [(set (match_operand:DF 0 "push_operand" "=<,<")
	(match_operand:DF 1 "general_no_elim_operand" "f#r,rFo#f"))]
  "TARGET_INTEGER_DFMODE_MOVES"
  "*
{
  switch (which_alternative)
    {
    case 0:
      /* %%% We loose REG_DEAD notes for controling pops if we split late.  */
      operands[0] = gen_rtx_MEM (DFmode, stack_pointer_rtx);
      operands[2] = stack_pointer_rtx;
      operands[3] = GEN_INT (8);
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
      else
	return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";

    case 1:
      return \"#\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "multi")
   (set_attr "mode" "DF,SI")])

;; %%% Kill this when call knows how to work this out.
(define_split
  [(set (match_operand:DF 0 "push_operand" "")
	(match_operand:DF 1 "register_operand" ""))]
  "reload_completed && FP_REGNO_P (REGNO (operands[1]))"
  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8)))
   (set (mem:DF (reg:SI 7)) (match_dup 1))]
  "")

(define_split
  [(set (match_operand:DF 0 "push_operand" "")
	(match_operand:DF 1 "general_operand" ""))]
  "reload_completed"
  [(const_int 0)]
  "if (!ix86_split_long_move (operands)) abort (); DONE;")

;; Moving is usually shorter when only FP registers are used. This separate
;; movdf pattern avoids the use of integer registers for FP operations
;; when optimizing for size.

(define_insn "*movdf_nointeger"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,f,*r,o")
	(match_operand:DF 1 "general_operand" "fm,f,G,*roF,F*r"))]
  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
   && (optimize_size || !TARGET_INTEGER_DFMODE_MOVES)
   && (reload_in_progress || reload_completed
       || GET_CODE (operands[1]) != CONST_DOUBLE
       || memory_operand (operands[0], DFmode))" 
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\";
      else
        return \"fst%z0\\t%y0\";

    case 2:
      switch (standard_80387_constant_p (operands[1]))
        {
        case 1:
	  return \"fldz\";
	case 2:
	  return \"fld1\";
	}
      abort();

    case 3:
    case 4:
      return \"#\";

    default:
      abort();
    }
}"
  [(set_attr "type" "fmov,fmov,fmov,multi,multi")
   (set_attr "mode" "DF,DF,DF,SI,SI")])

(define_insn "*movdf_integer"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,m,f#r,r#f,o")
	(match_operand:DF 1 "general_operand" "fm#r,f#r,G,roF#f,Fr#f"))]
  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
   && !optimize_size && TARGET_INTEGER_DFMODE_MOVES
   && (reload_in_progress || reload_completed
       || GET_CODE (operands[1]) != CONST_DOUBLE
       || memory_operand (operands[0], DFmode))" 
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\";
      else
        return \"fst%z0\\t%y0\";

    case 2:
      switch (standard_80387_constant_p (operands[1]))
        {
        case 1:
	  return \"fldz\";
	case 2:
	  return \"fld1\";
	}
      abort();

    case 3:
    case 4:
      return \"#\";

    default:
      abort();
    }
}"
  [(set_attr "type" "fmov,fmov,fmov,multi,multi")
   (set_attr "mode" "DF,DF,DF,SI,SI")])

(define_split
  [(set (match_operand:DF 0 "nonimmediate_operand" "")
	(match_operand:DF 1 "general_operand" ""))]
  "reload_completed
   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
   && ! (FP_REG_P (operands[0]) || 
	 (GET_CODE (operands[0]) == SUBREG
	  && FP_REG_P (SUBREG_REG (operands[0]))))
   && ! (FP_REG_P (operands[1]) || 
	 (GET_CODE (operands[1]) == SUBREG
	  && FP_REG_P (SUBREG_REG (operands[1]))))"
  [(set (match_dup 2) (match_dup 5))
   (set (match_dup 3) (match_dup 6))]
  "if (ix86_split_long_move (operands)) DONE;")

(define_split
  [(set (match_operand:DF 0 "register_operand" "")
	(match_operand:DF 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))
   && standard_80387_constant_p (get_pool_constant (XEXP (operands[1], 0)))"
  [(set (match_dup 0)
	(match_dup 1))]
  "operands[1] = get_pool_constant (XEXP (operands[1], 0));")

(define_insn "swapdf"
  [(set (match_operand:DF 0 "register_operand" "+f")
	(match_operand:DF 1 "register_operand" "+f"))
   (set (match_dup 1)
	(match_dup 0))]
  ""
  "*
{
  if (STACK_TOP_P (operands[0]))
    return \"fxch\\t%1\";
  else
    return \"fxch\\t%0\";
}"
  [(set_attr "type" "fxch")
   (set_attr "mode" "DF")])

(define_expand "movxf"
  [(set (match_operand:XF 0 "nonimmediate_operand" "")
	(match_operand:XF 1 "general_operand" ""))]
  ""
  "ix86_expand_move (XFmode, operands); DONE;")

;; Size of pushdf is 3 (for sub) + 2 (for fstp) + memory operand size.
;; Size of pushdf using integer insturctions is 3+3*memory operand size
;; Pushing using integer instructions is longer except for constants
;; and direct memory references.
;; (assuming that any given constant is pushed only once, but this ought to be
;;  handled elsewhere).

(define_insn "*pushxf_nointeger"
  [(set (match_operand:XF 0 "push_operand" "=<,<,<")
	(match_operand:XF 1 "general_no_elim_operand" "f,Fo,*r"))]
  "optimize_size"
  "*
{
  switch (which_alternative)
    {
    case 0:
      /* %%% We loose REG_DEAD notes for controling pops if we split late.  */
      operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
      operands[2] = stack_pointer_rtx;
      operands[3] = GEN_INT (12);
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
      else
	return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";

    case 1:
    case 2:
      return \"#\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "multi")
   (set_attr "mode" "XF,SI,SI")])

(define_insn "*pushxf_integer"
  [(set (match_operand:XF 0 "push_operand" "=<,<")
	(match_operand:XF 1 "general_no_elim_operand" "f#r,rFo#f"))]
  "!optimize_size"
  "*
{
  switch (which_alternative)
    {
    case 0:
      /* %%% We loose REG_DEAD notes for controling pops if we split late.  */
      operands[0] = gen_rtx_MEM (XFmode, stack_pointer_rtx);
      operands[2] = stack_pointer_rtx;
      operands[3] = GEN_INT (12);
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"sub{l}\\t{%3, %2|%2, %3}\;fstp%z0\\t%y0\";
      else
	return \"sub{l}\\t{%3, %2|%2, %3}\;fst%z0\\t%y0\";

    case 1:
      return \"#\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "multi")
   (set_attr "mode" "XF,SI")])

(define_split
  [(set (match_operand:XF 0 "push_operand" "")
	(match_operand:XF 1 "general_operand" ""))]
  "reload_completed
   && (!REG_P (operands[1]) || !FP_REGNO_P (REGNO (operands[1])))"
  [(const_int 0)]
  "if (!ix86_split_long_move (operands)) abort (); DONE;")

(define_split
  [(set (match_operand:XF 0 "push_operand" "")
	(match_operand:XF 1 "register_operand" ""))]
  "FP_REGNO_P (REGNO (operands[1]))"
  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
   (set (mem:XF (reg:SI 7)) (match_dup 1))])

;; Do not use integer registers when optimizing for size
(define_insn "*movxf_nointeger"
  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*r,o")
	(match_operand:XF 1 "general_operand" "fm,f,G,*roF,F*r"))]
  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
   && optimize_size
   && (reload_in_progress || reload_completed
       || GET_CODE (operands[1]) != CONST_DOUBLE
       || memory_operand (operands[0], XFmode))" 
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      /* There is no non-popping store to memory for XFmode.  So if
	 we need one, follow the store with a load.  */
      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\;fld%z0\\t%y0\";
      else
        return \"fstp%z0\\t%y0\";

    case 2:
      switch (standard_80387_constant_p (operands[1]))
        {
        case 1:
	  return \"fldz\";
	case 2:
	  return \"fld1\";
	}
      break;

    case 3: case 4:
      return \"#\";
    }
  abort();
}"
  [(set_attr "type" "fmov,fmov,fmov,multi,multi")
   (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"))]
  "(GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
   && !optimize_size
   && (reload_in_progress || reload_completed
       || GET_CODE (operands[1]) != CONST_DOUBLE
       || memory_operand (operands[0], XFmode))" 
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      /* There is no non-popping store to memory for XFmode.  So if
	 we need one, follow the store with a load.  */
      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\;fld%z0\\t%y0\";
      else
        return \"fstp%z0\\t%y0\";

    case 2:
      switch (standard_80387_constant_p (operands[1]))
        {
        case 1:
	  return \"fldz\";
	case 2:
	  return \"fld1\";
	}
      break;

    case 3: case 4:
      return \"#\";
    }
  abort();
}"
  [(set_attr "type" "fmov,fmov,fmov,multi,multi")
   (set_attr "mode" "XF,XF,XF,SI,SI")])

(define_split
  [(set (match_operand:XF 0 "nonimmediate_operand" "")
	(match_operand:XF 1 "general_operand" ""))]
  "reload_completed
   && (GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM)
   && ! (FP_REG_P (operands[0]) || 
	 (GET_CODE (operands[0]) == SUBREG
	  && FP_REG_P (SUBREG_REG (operands[0]))))
   && ! (FP_REG_P (operands[1]) || 
	 (GET_CODE (operands[1]) == SUBREG
	  && FP_REG_P (SUBREG_REG (operands[1]))))"
  [(set (match_dup 2) (match_dup 5))
   (set (match_dup 3) (match_dup 6))
   (set (match_dup 4) (match_dup 7))]
  "if (ix86_split_long_move (operands)) DONE;")

(define_split
  [(set (match_operand:XF 0 "register_operand" "")
	(match_operand:XF 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))
   && standard_80387_constant_p (get_pool_constant (XEXP (operands[1], 0)))"
  [(set (match_dup 0)
	(match_dup 1))]
  "operands[1] = get_pool_constant (XEXP (operands[1], 0));")

(define_insn "swapxf"
  [(set (match_operand:XF 0 "register_operand" "+f")
	(match_operand:XF 1 "register_operand" "+f"))
   (set (match_dup 1)
	(match_dup 0))]
  ""
  "*
{
  if (STACK_TOP_P (operands[0]))
    return \"fxch\\t%1\";
  else
    return \"fxch\\t%0\";
}"
  [(set_attr "type" "fxch")
   (set_attr "mode" "XF")])

;; Zero extension instructions

(define_expand "zero_extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "")
     (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))]
  ""
  "
{
  if (TARGET_ZERO_EXTEND_WITH_AND && !optimize_size)
    {
      operands[1] = force_reg (HImode, operands[1]);
      emit_insn (gen_zero_extendhisi2_and (operands[0], operands[1]));
      DONE;
    }
}")

(define_insn "zero_extendhisi2_and"
  [(set (match_operand:SI 0 "register_operand" "=r")
     (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))
   (clobber (reg:CC 17))]
  "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size"
  "#"
  [(set_attr "type" "alu1")
   (set_attr "mode" "SI")])

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(zero_extend:SI (match_operand:HI 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed && TARGET_ZERO_EXTEND_WITH_AND && !optimize_size"
  [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535)))
	      (clobber (reg:CC 17))])]
  "")

(define_insn "*zero_extendhisi2_movzwl"
  [(set (match_operand:SI 0 "register_operand" "=r")
     (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "rm")))]
  "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size"
  "movz{wl|x}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "SI")])

(define_expand "zero_extendqihi2"
  [(parallel
    [(set (match_operand:HI 0 "register_operand" "")
       (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))
     (clobber (reg:CC 17))])]
  ""
  "")

(define_insn "*zero_extendqihi2_and"
  [(set (match_operand:HI 0 "register_operand" "=r,?&q")
     (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,qm")))
   (clobber (reg:CC 17))]
  "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size"
  "#"
  [(set_attr "type" "alu1")
   (set_attr "mode" "HI")])

(define_insn "*zero_extendqihi2_movzbw_and"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
     (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "qm,0")))
   (clobber (reg:CC 17))]
  "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size"
  "#"
  [(set_attr "type" "imovx,alu1")
   (set_attr "mode" "HI")])

(define_insn "*zero_extendqihi2_movzbw"
  [(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}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "HI")])

;; For the movzbw case strip only the clobber
(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed 
   && (!TARGET_ZERO_EXTEND_WITH_AND || optimize_size)
   && (!REG_P (operands[1]) || QI_REG_P (operands[1]))"
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))])

;; When source and destination does not overlap, clear destination
;; first and then do the movb
(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && QI_REG_P (operands[0])
   && (TARGET_ZERO_EXTEND_WITH_AND && !optimize_size)
   && !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_lowpart (QImode, operands[0]);")

;; Rest is handled by single and.
(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extend:HI (match_operand:QI 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && true_regnum (operands[0]) == true_regnum (operands[1])"
  [(parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255)))
	      (clobber (reg:CC 17))])]
  "")

(define_expand "zero_extendqisi2"
  [(parallel
    [(set (match_operand:SI 0 "register_operand" "")
       (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))
     (clobber (reg:CC 17))])]
  ""
  "")

(define_insn "*zero_extendqisi2_and"
  [(set (match_operand:SI 0 "register_operand" "=r,?&q")
     (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,qm")))
   (clobber (reg:CC 17))]
  "TARGET_ZERO_EXTEND_WITH_AND && !optimize_size"
  "#"
  [(set_attr "type" "alu1")
   (set_attr "mode" "SI")])

(define_insn "*zero_extendqisi2_movzbw_and"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
     (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm,0")))
   (clobber (reg:CC 17))]
  "!TARGET_ZERO_EXTEND_WITH_AND || optimize_size"
  "#"
  [(set_attr "type" "imovx,alu1")
   (set_attr "mode" "SI")])

(define_insn "*zero_extendqisi2_movzbw"
  [(set (match_operand:SI 0 "register_operand" "=r")
     (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
  "(!TARGET_ZERO_EXTEND_WITH_AND || optimize_size) && reload_completed"
  "movz{bl|x}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "SI")])

;; For the movzbl case strip only the clobber
(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed 
   && (!TARGET_ZERO_EXTEND_WITH_AND || optimize_size)
   && (!REG_P (operands[1]) || QI_REG_P (operands[1]))"
  [(set (match_dup 0)
	(zero_extend:SI (match_dup 1)))])

;; When source and destination does not overlap, clear destination
;; first and then do the movb
(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && QI_REG_P (operands[0])
   && (QI_REG_P (operands[1]) || GET_CODE (operands[1]) == MEM)
   && (TARGET_ZERO_EXTEND_WITH_AND && !optimize_size)
   && !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_lowpart (QImode, operands[0]);")

;; Rest is handled by single and.
(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(zero_extend:SI (match_operand:QI 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && true_regnum (operands[0]) == true_regnum (operands[1])"
  [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 255)))
	      (clobber (reg:CC 17))])]
  "")

;; %%% Kill me once multi-word ops are sane.
(define_insn "zero_extendsidi2"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,?r,?*o")
	(zero_extend:DI (match_operand:SI 1 "general_operand" "0,rm,r")))
   (clobber (reg:CC 17))]
  ""
  "#"
  [(set_attr "mode" "SI")])

(define_split 
  [(set (match_operand:DI 0 "register_operand" "")
	(zero_extend:DI (match_operand:SI 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed && true_regnum (operands[0]) == true_regnum (operands[1])"
  [(set (match_dup 4) (const_int 0))]
  "split_di (&operands[0], 1, &operands[3], &operands[4]);")

(define_split 
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
	(zero_extend:DI (match_operand:SI 1 "general_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(set (match_dup 3) (match_dup 1))
   (set (match_dup 4) (const_int 0))]
  "split_di (&operands[0], 1, &operands[3], &operands[4]);")

;; Sign extension instructions

(define_insn "extendsidi2"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=*A,r,?r,?*o")
	(sign_extend:DI (match_operand:SI 1 "register_operand" "0,0,r,r")))
   (clobber (reg:CC 17))
   (clobber (match_scratch:SI 2 "=X,X,X,&r"))]
  ""
  "#")

;; Extend to memory case when source register does die.
(define_split 
  [(set (match_operand:DI 0 "memory_operand" "")
	(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
   (clobber (reg:CC 17))
   (clobber (match_operand:SI 2 "register_operand" ""))]
  "(reload_completed
    && dead_or_set_p (insn, operands[1])
    && !reg_mentioned_p (operands[1], operands[0]))"
  [(set (match_dup 3) (match_dup 1))
   (parallel [(set (match_dup 1) (ashiftrt:SI (match_dup 1) (const_int 31)))
	      (clobber (reg:CC 17))])
   (set (match_dup 4) (match_dup 1))]
  "split_di (&operands[0], 1, &operands[3], &operands[4]);")

;; Extend to memory case when source register does not die.
(define_split 
  [(set (match_operand:DI 0 "memory_operand" "")
	(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
   (clobber (reg:CC 17))
   (clobber (match_operand:SI 2 "register_operand" ""))]
  "reload_completed"
  [(const_int 0)]
  "
{
  split_di (&operands[0], 1, &operands[3], &operands[4]);

  emit_move_insn (operands[3], operands[1]);

  /* Generate a cltd if possible and doing so it profitable.  */
  if (true_regnum (operands[1]) == 0
      && true_regnum (operands[2]) == 1
      && (optimize_size || TARGET_USE_CLTD))
    {
      emit_insn (gen_ashrsi3_31 (operands[2], operands[1], GEN_INT (31)));
    }
  else
    {
      emit_move_insn (operands[2], operands[1]);
      emit_insn (gen_ashrsi3_31 (operands[2], operands[2], GEN_INT (31)));
    }
  emit_move_insn (operands[4], operands[2]);
  DONE;
}")

;; Extend to register case.  Optimize case where source and destination
;; registers match and cases where we can use cltd.
(define_split 
  [(set (match_operand:DI 0 "register_operand" "")
	(sign_extend:DI (match_operand:SI 1 "register_operand" "")))
   (clobber (reg:CC 17))
   (clobber (match_scratch:SI 2 ""))]
  "reload_completed"
  [(const_int 0)]
  "
{
  split_di (&operands[0], 1, &operands[3], &operands[4]);

  if (true_regnum (operands[3]) != true_regnum (operands[1]))
    emit_move_insn (operands[3], operands[1]);

  /* Generate a cltd if possible and doing so it profitable.  */
  if (true_regnum (operands[3]) == 0
      && (optimize_size || TARGET_USE_CLTD))
    {
      emit_insn (gen_ashrsi3_31 (operands[4], operands[3], GEN_INT (31)));
      DONE;
    }

  if (true_regnum (operands[4]) != true_regnum (operands[1]))
    emit_move_insn (operands[4], operands[1]);

  emit_insn (gen_ashrsi3_31 (operands[4], operands[4], GEN_INT (31)));
  DONE;
}")

(define_insn "extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "=*a,r")
	(sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "*0,rm")))]
  ""
  "*
{
  switch (get_attr_prefix_0f (insn))
    {
    case 0:
      return \"{cwtl|cwde}\";
    default:
      return \"movs{wl|x}\\t{%1,%0|%0, %1}\";
    }
}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "SI")
   (set (attr "prefix_0f")
     ;; movsx is short decodable while cwtl is vector decoded.
     (if_then_else (and (eq_attr "cpu" "!k6")
			(eq_attr "alternative" "0"))
	(const_string "0")
	(const_string "1")))
   (set (attr "modrm")
     (if_then_else (eq_attr "prefix_0f" "0")
	(const_string "0")
	(const_string "1")))])

(define_insn "extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=*a,r")
	(sign_extend:HI (match_operand:QI 1 "nonimmediate_operand" "*0,qm")))]
  ""
  "*
{
  switch (get_attr_prefix_0f (insn))
    {
    case 0:
      return \"{cbtw|cbw}\";
    default:
      return \"movs{bw|x}\\t{%1,%0|%0, %1}\";
    }
}"
  [(set_attr "type" "imovx")
   (set_attr "mode" "HI")
   (set (attr "prefix_0f")
     ;; movsx is short decodable while cwtl is vector decoded.
     (if_then_else (and (eq_attr "cpu" "!k6")
			(eq_attr "alternative" "0"))
	(const_string "0")
	(const_string "1")))
   (set (attr "modrm")
     (if_then_else (eq_attr "prefix_0f" "0")
	(const_string "0")
	(const_string "1")))])

(define_insn "extendqisi2"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "qm")))]
  ""
  "movs{bl|x}\\t{%1,%0|%0, %1}"
   [(set_attr "type" "imovx")
    (set_attr "mode" "SI")])

;; Conversions between float and double.

;; These are all no-ops in the model used for the 80387.  So just
;; emit moves.

;; %%% Kill these when call knows how to work out a DFmode push earlier. 
(define_insn "*dummy_extendsfdf2"
  [(set (match_operand:DF 0 "push_operand" "=<")
	(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "f")))]
  "0"
  "#")

(define_split
  [(set (match_operand:DF 0 "push_operand" "")
	(float_extend:DF (match_operand:SF 1 "register_operand" "")))]
  "FP_REGNO_P (REGNO (operands[1]))"
  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8)))
   (set (mem:DF (reg:SI 7)) (float_extend:DF (match_dup 1)))])

(define_insn "*dummy_extendsfxf2"
  [(set (match_operand:XF 0 "push_operand" "=<")
	(float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "f")))]
  "0"
  "#")

(define_split
  [(set (match_operand:XF 0 "push_operand" "")
	(float_extend:XF (match_operand:SF 1 "register_operand" "")))]
  "FP_REGNO_P (REGNO (operands[1]))"
  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
   (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))])

(define_insn "*dummy_extenddfxf2"
  [(set (match_operand:XF 0 "push_operand" "=<")
	(float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "f")))]
  "0"
  "#")

(define_split
  [(set (match_operand:XF 0 "push_operand" "")
	(float_extend:XF (match_operand:DF 1 "register_operand" "")))]
  "FP_REGNO_P (REGNO (operands[1]))"
  [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -12)))
   (set (mem:DF (reg:SI 7)) (float_extend:XF (match_dup 1)))])

(define_expand "extendsfdf2"
  [(set (match_operand:DF 0 "nonimmediate_operand" "")
        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "
{
  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
    operands[1] = force_reg (SFmode, operands[1]);
}")

(define_insn "*extendsfdf2_1"
  [(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)"
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\";

      else
        return \"fst%z0\\t%y0\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "fmov")
   (set_attr "mode" "SF,XF")])

(define_expand "extendsfxf2"
  [(set (match_operand:XF 0 "nonimmediate_operand" "")
        (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "
{
  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
    operands[1] = force_reg (SFmode, operands[1]);
}")

(define_insn "*extendsfxf2_1"
  [(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)"
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      /* There is no non-popping store to memory for XFmode.  So if
	 we need one, follow the store with a load.  */
      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\\n\\tfld%z0\\t%y0\";
      else
        return \"fstp%z0\\t%y0\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "fmov")
   (set_attr "mode" "SF,XF")])

(define_expand "extenddfxf2"
  [(set (match_operand:XF 0 "nonimmediate_operand" "")
        (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "
{
  if (GET_CODE (operands[0]) == MEM && GET_CODE (operands[1]) == MEM)
    operands[1] = force_reg (DFmode, operands[1]);
}")

(define_insn "*extenddfxf2_1"
  [(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)"
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (REG_P (operands[1])
          && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp\\t%y0\";
      else if (STACK_TOP_P (operands[0]))
        return \"fld%z1\\t%y1\";
      else
        return \"fst\\t%y0\";

    case 1:
      /* There is no non-popping store to memory for XFmode.  So if
	 we need one, follow the store with a load.  */
      if (! find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
        return \"fstp%z0\\t%y0\\n\\tfld%z0\\t%y0\";
      else
        return \"fstp%z0\\t%y0\";

    default:
      abort ();
    }
}"
  [(set_attr "type" "fmov")
   (set_attr "mode" "DF,XF")])

;; %%% This seems bad bad news.
;; This cannot output into an f-reg because there is no way to be sure
;; of truncating in that case.  Otherwise this is just like a simple move
;; insn.  So we pretend we can output to a reg in order to get better
;; register preferencing, but we really use a stack slot.

(define_expand "truncdfsf2"
  [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
		   (float_truncate:SF
		    (match_operand:DF 1 "register_operand" "")))
	      (clobber (match_dup 2))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SFmode, 0);")

(define_insn "*truncdfsf2_1"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,f")
	(float_truncate:SF
	 (match_operand:DF 1 "register_operand" "f,0")))
   (clobber (match_operand:SF 2 "memory_operand" "=m,m"))]
  "TARGET_80387"
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"fstp%z0\\t%y0\";
      else
	return \"fst%z0\\t%y0\";
    case 1:
      return \"fstp%z2\\t%y2\;fld%z2\\t%y2\";
    }
  abort ();
}"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "SF")])

(define_insn "*truncdfsf2_2"
  [(set (match_operand:SF 0 "memory_operand" "=m")
	(float_truncate:SF
	 (match_operand:DF 1 "register_operand" "f")))]
  "TARGET_80387"
  "*
{
  if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
    return \"fstp%z0\\t%y0\";
  else
    return \"fst%z0\\t%y0\";
}"
  [(set_attr "type" "fmov")
   (set_attr "mode" "SF")])

(define_split
  [(set (match_operand:SF 0 "memory_operand" "")
	(float_truncate:SF
	 (match_operand:DF 1 "register_operand" "")))
   (clobber (match_operand:SF 2 "memory_operand" ""))]
  "TARGET_80387"
  [(set (match_dup 0) (float_truncate:SF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:SF 0 "register_operand" "")
	(float_truncate:SF
	 (match_operand:DF 1 "register_operand" "")))
   (clobber (match_operand:SF 2 "memory_operand" ""))]
  "TARGET_80387 && reload_completed"
  [(set (match_dup 2) (float_truncate:SF (match_dup 1)))
   (set (match_dup 0) (match_dup 2))]
  "")

(define_expand "truncxfsf2"
  [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
		   (float_truncate:SF
		    (match_operand:XF 1 "register_operand" "")))
	      (clobber (match_dup 2))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SFmode, 0);")

(define_insn "*truncxfsf2_1"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=m,f")
	(float_truncate:SF
	 (match_operand:XF 1 "register_operand" "f,0")))
   (clobber (match_operand:SF 2 "memory_operand" "=m,m"))]
  "TARGET_80387"
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"fstp%z0\\t%y0\";
      else
	return \"fst%z0\\t%y0\";
    case 1:
      return \"fstp%z2\\t%y2\;fld%z2\\t%y2\";
    }
  abort ();
}"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "SF")])

(define_insn "*truncxfsf2_2"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=m")
	(float_truncate:SF
	 (match_operand:XF 1 "register_operand" "f")))]
  "TARGET_80387"
  "*
{
  if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
    return \"fstp%z0\\t%y0\";
  else
    return \"fst%z0\\t%y0\";
}"
  [(set_attr "type" "fmov")
   (set_attr "mode" "SF")])

(define_split
  [(set (match_operand:SF 0 "memory_operand" "")
	(float_truncate:SF
	 (match_operand:XF 1 "register_operand" "")))
   (clobber (match_operand:SF 2 "memory_operand" ""))]
  "TARGET_80387"
  [(set (match_dup 0) (float_truncate:SF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:SF 0 "register_operand" "")
	(float_truncate:SF
	 (match_operand:XF 1 "register_operand" "")))
   (clobber (match_operand:SF 2 "memory_operand" ""))]
  "TARGET_80387 && reload_completed"
  [(set (match_dup 2) (float_truncate:SF (match_dup 1)))
   (set (match_dup 0) (match_dup 2))]
  "")

(define_expand "truncxfdf2"
  [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
		   (float_truncate:DF
		    (match_operand:XF 1 "register_operand" "")))
	      (clobber (match_dup 2))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (DFmode, 0);")

(define_insn "*truncxfdf2_1"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=m,f")
	(float_truncate:DF
	 (match_operand:XF 1 "register_operand" "f,0")))
   (clobber (match_operand:DF 2 "memory_operand" "=m,m"))]
  "TARGET_80387"
  "*
{
  switch (which_alternative)
    {
    case 0:
      if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
	return \"fstp%z0\\t%y0\";
      else
	return \"fst%z0\\t%y0\";
    case 1:
      return \"fstp%z2\\t%y2\;fld%z2\\t%y2\";
    }
  abort ();
}"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "DF")])

(define_insn "*truncxfdf2_2"
  [(set (match_operand:DF 0 "memory_operand" "=m")
	(float_truncate:DF
	  (match_operand:XF 1 "register_operand" "f")))]
  "TARGET_80387"
  "*
{
  if (find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
    return \"fstp%z0\\t%y0\";
  else
    return \"fst%z0\\t%y0\";
}"
  [(set_attr "type" "fmov")
   (set_attr "mode" "DF")])

(define_split
  [(set (match_operand:DF 0 "memory_operand" "")
	(float_truncate:DF
	 (match_operand:XF 1 "register_operand" "")))
   (clobber (match_operand:DF 2 "memory_operand" ""))]
  "TARGET_80387"
  [(set (match_dup 0) (float_truncate:DF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:DF 0 "register_operand" "")
	(float_truncate:DF
	 (match_operand:XF 1 "register_operand" "")))
   (clobber (match_operand:DF 2 "memory_operand" ""))]
  "TARGET_80387 && reload_completed"
  [(set (match_dup 2) (float_truncate:DF (match_dup 1)))
   (set (match_dup 0) (match_dup 2))]
  "")


;; %%% Break up all these bad boys.

;; Signed conversion to DImode.

(define_expand "fix_truncxfdi2"
  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
		   (fix:DI (match_operand:XF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))
	      (clobber (match_scratch:XF 5 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (DImode, 1);")

(define_expand "fix_truncdfdi2"
  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
		   (fix:DI (match_operand:DF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))
	      (clobber (match_scratch:DF 5 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (DImode, 1);")

(define_expand "fix_truncsfdi2"
  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
		   (fix:DI (match_operand:SF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))
	      (clobber (match_scratch:SF 5 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (DImode, 1);")

(define_insn "*fix_truncdi_1"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=m,?r")
	(fix:DI (match_operand 1 "register_operand" "f,f")))
   (clobber (match_operand:SI 2 "memory_operand" "=o,o"))
   (clobber (match_operand:DI 3 "memory_operand" "=m,m"))
   (clobber (match_scratch:SI 4 "=&r,&r"))
   (clobber (match_scratch 5 "=&f,&f"))]
  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))"
  "* return output_fix_trunc (insn, operands);"
  [(set_attr "type" "multi")])

(define_split 
  [(set (match_operand:DI 0 "register_operand" "")
	(fix:DI (match_operand 1 "register_operand" "")))
   (clobber (match_operand:SI 2 "memory_operand" ""))
   (clobber (match_operand:DI 3 "memory_operand" ""))
   (clobber (match_scratch:SI 4 ""))
   (clobber (match_scratch 5 ""))]
  "reload_completed && !reg_overlap_mentioned_p (operands[4], operands[3])"
  [(parallel [(set (match_dup 3) (fix:DI (match_dup 1)))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))
	      (clobber (match_dup 5))])
   (set (match_dup 0) (match_dup 3))]
  "")

;; Signed conversion to SImode.

(define_expand "fix_truncxfsi2"
  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
		   (fix:SI (match_operand:XF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (SImode, 1);")

(define_expand "fix_truncdfsi2"
  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
		   (fix:SI (match_operand:DF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (SImode, 1);")

(define_expand "fix_truncsfsi2"
  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
		   (fix:SI (match_operand:SF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (SImode, 1);")

(define_insn "*fix_truncsi_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=m,?r")
	(fix:SI (match_operand 1 "register_operand" "f,f")))
   (clobber (match_operand:SI 2 "memory_operand" "=o,o"))
   (clobber (match_operand:SI 3 "memory_operand" "=m,m"))
   (clobber (match_scratch:SI 4 "=&r,r"))]
  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))"
  "* return output_fix_trunc (insn, operands);"
  [(set_attr "type" "multi")])

(define_split 
  [(set (match_operand:SI 0 "register_operand" "")
	(fix:SI (match_operand 1 "register_operand" "")))
   (clobber (match_operand:SI 2 "memory_operand" ""))
   (clobber (match_operand:SI 3 "memory_operand" ""))
   (clobber (match_scratch:SI 4 ""))]
  "reload_completed"
  [(parallel [(set (match_dup 3) (fix:SI (match_dup 1)))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))])
   (set (match_dup 0) (match_dup 3))]
  "")

;; Signed conversion to HImode.

(define_expand "fix_truncxfhi2"
  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
		   (fix:HI (match_operand:XF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (HImode, 1);")

(define_expand "fix_truncdfhi2"
  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
		   (fix:HI (match_operand:DF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (HImode, 1);")

(define_expand "fix_truncsfhi2"
  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
		   (fix:HI (match_operand:SF 1 "register_operand" "")))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))])]
  "TARGET_80387"
  "operands[2] = assign_386_stack_local (SImode, 0);
   operands[3] = assign_386_stack_local (HImode, 1);")

(define_insn "*fix_trunchi_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=m,?r")
	(fix:HI (match_operand 1 "register_operand" "f,f")))
   (clobber (match_operand:SI 2 "memory_operand" "=o,o"))
   (clobber (match_operand:HI 3 "memory_operand" "=m,m"))
   (clobber (match_scratch:SI 4 "=&r,r"))]
  "TARGET_80387 && FLOAT_MODE_P (GET_MODE (operands[1]))"
  "* return output_fix_trunc (insn, operands);"
  [(set_attr "type" "multi")])

(define_split 
  [(set (match_operand:HI 0 "register_operand" "")
	(fix:HI (match_operand 1 "register_operand" "")))
   (clobber (match_operand:SI 2 "memory_operand" ""))
   (clobber (match_operand:HI 3 "memory_operand" ""))
   (clobber (match_scratch:SI 4 ""))]
  "reload_completed"
  [(parallel [(set (match_dup 3) (fix:HI (match_dup 1)))
	      (clobber (match_dup 2))
	      (clobber (match_dup 3))
	      (clobber (match_dup 4))])
   (set (match_dup 0) (match_dup 3))]
  "")

;; %% Not used yet.
(define_insn "x86_fnstcw_1"
  [(set (match_operand:HI 0 "memory_operand" "=m")
	(unspec:HI [(reg:HI 18)] 11))]
  "TARGET_80387"
  "fnstcw\\t%0"
  [(set_attr "length" "2")
   (set_attr "mode" "HI")
   (set_attr "i387" "1")
   (set_attr "ppro_uops" "few")])

(define_insn "x86_fldcw_1"
  [(set (reg:HI 18)
	(unspec:HI [(match_operand:HI 0 "memory_operand" "m")] 12))]
  "TARGET_80387"
  "fldcw\\t%0"
  [(set_attr "length" "2")
   (set_attr "mode" "HI")
   (set_attr "i387" "1")
   (set_attr "athlon_decode" "vector")
   (set_attr "ppro_uops" "few")])

;; Conversion between fixed point and floating point.

;; Even though we only accept memory inputs, the backend _really_
;; wants to be able to do this between registers.

(define_insn "floathisf2"
  [(set (match_operand:SF 0 "register_operand" "=f,f")
	(float:SF (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "SF")
   (set_attr "fp_int_src" "true")])

(define_insn "floatsisf2"
  [(set (match_operand:SF 0 "register_operand" "=f,f")
	(float:SF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "SF")
   (set_attr "fp_int_src" "true")])

(define_insn "floatdisf2"
  [(set (match_operand:SF 0 "register_operand" "=f,f")
	(float:SF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "SF")
   (set_attr "fp_int_src" "true")])

(define_insn "floathidf2"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(float:DF (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "DF")
   (set_attr "fp_int_src" "true")])

(define_insn "floatsidf2"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(float:DF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "DF")
   (set_attr "fp_int_src" "true")])

(define_insn "floatdidf2"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(float:DF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "DF")
   (set_attr "fp_int_src" "true")])

(define_insn "floathixf2"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(float:XF (match_operand:HI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "XF")
   (set_attr "fp_int_src" "true")])

(define_insn "floatsixf2"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(float:XF (match_operand:SI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "XF")
   (set_attr "fp_int_src" "true")])

(define_insn "floatdixf2"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(float:XF (match_operand:DI 1 "nonimmediate_operand" "m,r")))]
  "TARGET_80387"
  "@
   fild%z1\\t%1
   #"
  [(set_attr "type" "fmov,multi")
   (set_attr "mode" "XF")
   (set_attr "fp_int_src" "true")])

;; %%% Kill these when reload knows how to do it.
(define_split
  [(set (match_operand 0 "register_operand" "")
	(float (match_operand:HI 1 "register_operand" "")))]
  "reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))"
  [(set (mem:HI (pre_dec:SI (reg:SI 7))) (match_dup 1))
   (set (match_dup 0) (match_dup 2))
   (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 2)))]
  "operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]),
			       	gen_rtx_MEM (HImode, stack_pointer_rtx));")

(define_split
  [(set (match_operand 0 "register_operand" "")
	(float (match_operand:SI 1 "register_operand" "")))]
  "reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))"
  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
   (set (match_dup 0) (match_dup 2))
   (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "operands[2] = gen_rtx_FLOAT (GET_MODE (operands[0]),
			       	gen_rtx_MEM (SImode, stack_pointer_rtx));")

(define_split
  [(set (match_operand 0 "register_operand" "")
	(float (match_operand:DI 1 "nonmemory_operand" "")))]
  "reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))"
  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))
   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
   (set (match_dup 0) (match_dup 3))
   (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])
   (parallel [(set (match_dup 2) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "split_di (operands+1, 1, operands+1, operands+2);
   operands[3] = gen_rtx_FLOAT (GET_MODE (operands[0]),
			       	gen_rtx_MEM (DImode, stack_pointer_rtx));")

;; Add instructions

;; %%% define_expand from the very first?
;; %%% splits for addsidi3
;  [(set (match_operand:DI 0 "nonimmediate_operand" "")
;	(plus:DI (match_operand:DI 1 "general_operand" "")
;		 (zero_extend:DI (match_operand:SI 2 "general_operand" ""))))]

(define_insn "adddi3"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
	(plus:DI (match_operand:DI 1 "nonimmediate_operand" "%0,0")
		 (match_operand:DI 2 "general_operand" "roiF,riF")))
   (clobber (reg:CC 17))]
  ""
  "#")

(define_split
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
	(plus:DI (match_operand:DI 1 "nonimmediate_operand" "")
		 (match_operand:DI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(parallel [(set (reg:CC 17) (plus:CC (match_dup 1) (match_dup 2)))
	      (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))])
   (parallel [(set (match_dup 3)
		   (plus:SI (match_dup 4)
		   (plus:SI (match_dup 5)
			    (ltu:SI (reg:CC 17) (const_int 0)))))
	      (clobber (reg:CC 17))])]
  "split_di (operands+0, 1, operands+0, operands+3);
   split_di (operands+1, 1, operands+1, operands+4);
   split_di (operands+2, 1, operands+2, operands+5);")

(define_insn "*addsi3_cc"
  [(set (reg:CC 17) (plus:CC (match_operand:SI 1 "nonimmediate_operand" "%0,0")
		    (match_operand:SI 2 "general_operand" "ri,rm")))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
	(plus:SI (match_dup 1) (match_dup 2)))]
  "ix86_binary_operator_ok (PLUS, SImode, operands)"
  "add{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_insn "addqi3_cc"
  [(set (reg:CC 17) (plus:CC (match_operand:QI 1 "nonimmediate_operand" "%0,0")
		    (match_operand:QI 2 "general_operand" "qi,qm")))
   (set (match_operand:QI 0 "nonimmediate_operand" "=qm,q")
	(plus:QI (match_dup 1) (match_dup 2)))]
  "ix86_binary_operator_ok (PLUS, QImode, operands)"
  "add{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

(define_insn "*addsi3_carry"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
	  (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
	    (plus:SI (match_operand:SI 2 "general_operand" "ri,rm")
	      (ltu:SI (reg:CC 17) (const_int 0)))))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (PLUS, SImode, operands)"
  "adc{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "pent_pair" "pu")
   (set_attr "mode" "SI")
   (set_attr "ppro_uops" "few")])

(define_expand "addsi3"
  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
		   (plus:SI (match_operand:SI 1 "nonimmediate_operand" "")
			    (match_operand:SI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "ix86_expand_binary_operator (PLUS, SImode, operands); DONE;")

(define_insn "*lea_0"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(match_operand:SI 1 "address_operand" "p"))]
  ""
  "lea{l}\\t{%a1, %0|%0, %a1}"
  [(set_attr "type" "lea")
   (set_attr "mode" "SI")])

;; The lea patterns for non-Pmodes needs to be matched by several
;; insns converted to real lea by splitters.

(define_insn_and_split "*lea_general_1"
  [(set (match_operand 0 "register_operand" "=r")
	(plus (plus (match_operand 1 "register_operand" "r")
		    (match_operand 2 "register_operand" "r"))
	      (match_operand 3 "immediate_operand" "i")))]
  "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode)
   && (!TARGET_PARTIAL_REG_STALL || optimize_size)
   && GET_MODE (operands[0]) == GET_MODE (operands[1])
   && GET_MODE (operands[0]) == GET_MODE (operands[2])
   && (GET_MODE (operands[0]) == GET_MODE (operands[3])
       || GET_MODE (operands[3]) == VOIDmode)"
  "#"
  "reload_completed"
  [(const_int 0)]
  "
{
  rtx pat;
  operands[0] = gen_lowpart (SImode, operands[0]);
  operands[1] = gen_lowpart (Pmode, operands[1]);
  operands[2] = gen_lowpart (Pmode, operands[2]);
  operands[3] = gen_lowpart (Pmode, operands[3]);
  pat = gen_rtx_PLUS (Pmode, gen_rtx_PLUS (Pmode, operands[1], operands[2]),
  		      operands[3]);
  if (Pmode != SImode)
    pat = gen_rtx_SUBREG (SImode, pat, 0);
  emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
  DONE;
}"
  [(set_attr "type" "lea")
   (set_attr "mode" "SI")])

(define_insn_and_split "*lea_general_2"
  [(set (match_operand 0 "register_operand" "=r")
	(plus (mult (match_operand 1 "register_operand" "r")
		    (match_operand 2 "const248_operand" "i"))
	      (match_operand 3 "nonmemory_operand" "ri")))]
  "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode)
   && (!TARGET_PARTIAL_REG_STALL || optimize_size)
   && GET_MODE (operands[0]) == GET_MODE (operands[1])
   && (GET_MODE (operands[0]) == GET_MODE (operands[3])
       || GET_MODE (operands[3]) == VOIDmode)"
  "#"
  "reload_completed"
  [(const_int 0)]
  "
{
  rtx pat;
  operands[0] = gen_lowpart (SImode, operands[0]);
  operands[1] = gen_lowpart (Pmode, operands[1]);
  operands[3] = gen_lowpart (Pmode, operands[3]);
  pat = gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1], operands[2]),
  		      operands[3]);
  if (Pmode != SImode)
    pat = gen_rtx_SUBREG (SImode, pat, 0);
  emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
  DONE;
}"
  [(set_attr "type" "lea")
   (set_attr "mode" "SI")])

(define_insn_and_split "*lea_general_3"
  [(set (match_operand 0 "register_operand" "=r")
	(plus (plus (mult (match_operand 1 "register_operand" "r")
			  (match_operand 2 "const248_operand" "i"))
		    (match_operand 3 "register_operand" "r"))
	      (match_operand 4 "immediate_operand" "i")))]
  "(GET_MODE (operands[0]) == QImode || GET_MODE (operands[0]) == HImode)
   && (!TARGET_PARTIAL_REG_STALL || optimize_size)
   && GET_MODE (operands[0]) == GET_MODE (operands[1])
   && GET_MODE (operands[0]) == GET_MODE (operands[3])"
  "#"
  "reload_completed"
  [(const_int 0)]
  "
{
  rtx pat;
  operands[0] = gen_lowpart (SImode, operands[0]);
  operands[1] = gen_lowpart (Pmode, operands[1]);
  operands[3] = gen_lowpart (Pmode, operands[3]);
  operands[4] = gen_lowpart (Pmode, operands[4]);
  pat = gen_rtx_PLUS (Pmode,
  		      gen_rtx_PLUS (Pmode, gen_rtx_MULT (Pmode, operands[1],
		      					 operands[2]),
				    operands[3]),
  		      operands[4]);
  if (Pmode != SImode)
    pat = gen_rtx_SUBREG (SImode, pat, 0);
  emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
  DONE;
}"
  [(set_attr "type" "lea")
   (set_attr "mode" "SI")])

(define_insn "*addsi_1"
  [(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" "rmni,rni,rni")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (PLUS, SImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_LEA:
      operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
      return \"lea{l}\\t{%a2, %0|%0, %a2}\";

    case TYPE_INCDEC:
      if (! rtx_equal_p (operands[0], operands[1]))
	abort ();
      if (operands[2] == const1_rtx)
        return \"inc{l}\\t%0\";
      else if (operands[2] == constm1_rtx)
        return \"dec{l}\\t%0\";
      else
	abort();

    default:
      if (! rtx_equal_p (operands[0], operands[1]))
	abort ();

      /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
	 Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
		  && INTVAL (operands[2]) != -128)))
        {
          operands[2] = GEN_INT (-INTVAL (operands[2]));
          return \"sub{l}\\t{%2, %0|%0, %2}\";
        }
      return \"add{l}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (cond [(eq_attr "alternative" "2")
	      (const_string "lea")
	    ; Current assemblers are broken and do not allow @GOTOFF in
	    ; ought but a memory context.
	    (match_operand:SI 2 "pic_symbolic_operand" "")
	      (const_string "lea")
	    (match_operand:SI 2 "incdec_operand" "")
	      (const_string "incdec")
	   ]
	   (const_string "alu")))
   (set_attr "mode" "SI")])

;; Convert lea to the lea pattern to avoid flags dependency.
(define_split
  [(set (match_operand 0 "register_operand" "")
	(plus (match_operand 1 "register_operand" "")
              (match_operand 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && true_regnum (operands[0]) != true_regnum (operands[1])"
  [(const_int 0)]
  "
{
  rtx pat;
  /* In -fPIC mode the constructs like (const (unspec [symbol_ref]))
     may confuse gen_lowpart.  */
  if (GET_MODE (operands[0]) != Pmode)
    {
      operands[1] = gen_lowpart (Pmode, operands[1]);
      operands[2] = gen_lowpart (Pmode, operands[2]);
    }
  operands[0] = gen_lowpart (SImode, operands[0]);
  pat = gen_rtx_PLUS (Pmode, operands[1], operands[2]);
  if (Pmode != SImode)
    pat = gen_rtx_SUBREG (SImode, pat, 0);
  emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
  DONE;
}")

(define_insn "*addsi_2"
  [(set (reg 17)
	(compare
	  (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
		   (match_operand:SI 2 "general_operand" "rmni,rni"))
	  (const_int 0)))			
   (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
	(plus:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (PLUS, SImode, operands)
   /* Current assemblers are broken and do not allow @GOTOFF in
      ought but a memory context. */
   && ! pic_symbolic_operand (operands[2], VOIDmode)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_INCDEC:
      if (! rtx_equal_p (operands[0], operands[1]))
	abort ();
      if (operands[2] == const1_rtx)
        return \"inc{l}\\t%0\";
      else if (operands[2] == constm1_rtx)
        return \"dec{l}\\t%0\";
      else
	abort();

    default:
      if (! rtx_equal_p (operands[0], operands[1]))
	abort ();
      /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
	 Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
		  && INTVAL (operands[2]) != -128)))
        {
          operands[2] = GEN_INT (-INTVAL (operands[2]));
          return \"sub{l}\\t{%2, %0|%0, %2}\";
        }
      return \"add{l}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (match_operand:SI 2 "incdec_operand" "")
	(const_string "incdec")
	(const_string "alu")))
   (set_attr "mode" "SI")])

(define_insn "*addsi_3"
  [(set (reg:CC 17)
	(compare:CC (plus:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
			     (match_operand:SI 2 "general_operand" "rmni,rni"))
		    (const_int 0)))			
   (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
	(plus:SI (match_dup 1) (match_dup 2)))]
  "ix86_binary_operator_ok (PLUS, SImode, operands)
   /* Current assemblers are broken and do not allow @GOTOFF in
      ought but a memory context. */
   && ! pic_symbolic_operand (operands[2], VOIDmode)"
  "add{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_expand "addhi3"
  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
		   (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
			    (match_operand:HI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (PLUS, HImode, operands); DONE;")

;; %%% After Dave's SUBREG_BYTE stuff goes in, re-enable incb %ah
;; type optimizations enabled by define-splits.  This is not important
;; for PII, and in fact harmful because of partial register stalls.

(define_insn "*addhi_1_lea"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r")
	(plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,r")
		 (match_operand:HI 2 "general_operand" "ri,rm,rni")))
   (clobber (reg:CC 17))]
  "!TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (PLUS, HImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_LEA:
      return \"#\";
    case TYPE_INCDEC:
      if (operands[2] == const1_rtx)
	return \"inc{w}\\t%0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 65535))
	return \"dec{w}\\t%0\";
      abort();

    default:
      /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
	 Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
		  && INTVAL (operands[2]) != -128)))
	{
	  operands[2] = GEN_INT (-INTVAL (operands[2]));
	  return \"sub{w}\\t{%2, %0|%0, %2}\";
	}
      return \"add{w}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (eq_attr "alternative" "2")
	(const_string "lea")
	(if_then_else (match_operand:HI 2 "incdec_operand" "")
	   (const_string "incdec")
	   (const_string "alu"))))
   (set_attr "mode" "HI,HI,SI")])

(define_insn "*addhi_1"
  [(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")))
   (clobber (reg:CC 17))]
  "TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (PLUS, HImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_INCDEC:
      if (operands[2] == const1_rtx)
	return \"inc{w}\\t%0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 65535))
	return \"dec{w}\\t%0\";
      abort();

    default:
      /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
	 Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
		  && INTVAL (operands[2]) != -128)))
	{
	  operands[2] = GEN_INT (-INTVAL (operands[2]));
	  return \"sub{w}\\t{%2, %0|%0, %2}\";
	}
      return \"add{w}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (match_operand:HI 2 "incdec_operand" "")
	(const_string "incdec")
	(const_string "alu")))
   (set_attr "mode" "HI")])

(define_insn "*addhi_2"
  [(set (reg 17)
	(compare
	  (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
		   (match_operand:HI 2 "general_operand" "rmni,rni"))
	  (const_int 0)))			
   (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
	(plus:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (PLUS, HImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_INCDEC:
      if (operands[2] == const1_rtx)
	return \"inc{w}\\t%0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 65535))
	return \"dec{w}\\t%0\";
      abort();

    default:
      /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
	 Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
		  && INTVAL (operands[2]) != -128)))
	{
	  operands[2] = GEN_INT (-INTVAL (operands[2]));
	  return \"sub{w}\\t{%2, %0|%0, %2}\";
	}
      return \"add{w}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (match_operand:HI 2 "incdec_operand" "")
	(const_string "incdec")
	(const_string "alu")))
   (set_attr "mode" "HI")])

(define_insn "*addhi_3"
  [(set (reg:CC 17)
	(compare:CC (plus:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
			     (match_operand:HI 2 "general_operand" "rmni,rni"))
		    (const_int 0)))			
   (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
	(plus:HI (match_dup 1) (match_dup 2)))]
  "ix86_binary_operator_ok (PLUS, HImode, operands)"
  "add{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_expand "addqi3"
  [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "")
		   (plus:QI (match_operand:QI 1 "nonimmediate_operand" "")
			    (match_operand:QI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (PLUS, QImode, operands); DONE;")

;; %%% Potential partial reg stall on alternative 2.  What to do?
(define_insn "*addqi_1_lea"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r,r")
	(plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0,r")
		 (match_operand:QI 2 "general_operand" "qn,qmn,rn,rn")))
   (clobber (reg:CC 17))]
  "!TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (PLUS, QImode, operands)"
  "*
{
  int widen = (which_alternative == 2);
  switch (get_attr_type (insn))
    {
    case TYPE_LEA:
      return \"#\";
    case TYPE_INCDEC:
      if (operands[2] == const1_rtx)
	return widen ? \"inc{l}\\t%k0\" : \"inc{b}\\t%0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 255))
	return widen ? \"dec{l}\\t%k0\" : \"dec{b}\\t%0\";
      abort();

    default:
      /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
	 Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
		  && INTVAL (operands[2]) != -128)))
	{
	  operands[2] = GEN_INT (-INTVAL (operands[2]));
	  if (widen)
	    return \"sub{l}\\t{%2, %k0|%k0, %2}\";
	  else
	    return \"sub{b}\\t{%2, %0|%0, %2}\";
	}
      if (widen)
        return \"add{l}\\t{%k2, %k0|%k0, %k2}\";
      else
        return \"add{b}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (eq_attr "alternative" "3")
	(const_string "lea")
	(if_then_else (match_operand:HI 2 "incdec_operand" "")
	   (const_string "incdec")
	   (const_string "alu"))))
   (set_attr "mode" "HI,HI,SI,SI")])

(define_insn "*addqi_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r")
	(plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
		 (match_operand:QI 2 "general_operand" "qn,qmn,rn")))
   (clobber (reg:CC 17))]
  "TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (PLUS, QImode, operands)"
  "*
{
  int widen = (which_alternative == 2);
  switch (get_attr_type (insn))
    {
    case TYPE_INCDEC:
      if (operands[2] == const1_rtx)
	return widen ? \"inc{l}\\t%k0\" : \"inc{b}\\t%0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 255))
	return widen ? \"dec{l}\\t%k0\" : \"dec{b}\\t%0\";
      abort();

    default:
      /* Make things pretty and `subl $4,%eax' rather than `addl $-4, %eax'.
	 Exceptions: -128 encodes smaller than 128, so swap sign and op.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
		  && INTVAL (operands[2]) != -128)))
	{
	  operands[2] = GEN_INT (-INTVAL (operands[2]));
	  if (widen)
	    return \"sub{l}\\t{%2, %k0|%k0, %2}\";
	  else
	    return \"sub{b}\\t{%2, %0|%0, %2}\";
	}
      if (widen)
        return \"add{l}\\t{%k2, %k0|%k0, %k2}\";
      else
        return \"add{b}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (match_operand:QI 2 "incdec_operand" "")
	(const_string "incdec")
	(const_string "alu")))
   (set_attr "mode" "QI,QI,SI")])

(define_insn "*addqi_2"
  [(set (reg 17)
	(compare
	  (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
		   (match_operand:QI 2 "general_operand" "qmni,qni"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
	(plus:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (PLUS, QImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_INCDEC:
      if (operands[2] == const1_rtx)
	return \"inc{b}\\t%0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 255))
	return \"dec{b}\\t%0\";
      abort();

    default:
      /* Make things pretty and `subb $4,%al' rather than `addb $-4, %al'.  */
      if (GET_CODE (operands[2]) == CONST_INT
          && INTVAL (operands[2]) < 0)
	{
	  operands[2] = GEN_INT (-INTVAL (operands[2]));
	  return \"sub{b}\\t{%2, %0|%0, %2}\";
	}
      return \"add{b}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (match_operand:QI 2 "incdec_operand" "")
	(const_string "incdec")
	(const_string "alu")))
   (set_attr "mode" "QI")])

(define_insn "*addqi_3"
  [(set (reg:CC 17)
	(compare:CC (plus:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
			     (match_operand:QI 2 "general_operand" "qmni,qni"))
		    (const_int 0)))			
   (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
	(plus:QI (match_dup 1) (match_dup 2)))]
  "ix86_binary_operator_ok (PLUS, QImode, operands)"
  "add{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])


(define_insn "addqi_ext_1"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(plus:SI
	  (zero_extract:SI
	    (match_operand 1 "ext_register_operand" "0")
	    (const_int 8)
	    (const_int 8))
	  (match_operand:QI 2 "general_operand" "qmn")))
   (clobber (reg:CC 17))]
  ""
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_INCDEC:
      if (operands[2] == const1_rtx)
	return \"inc{b}\\t%h0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 255))
	return \"dec{b}\\t%h0\";
      abort();

    default:
      return \"add{b}\\t{%2, %h0|%h0, %2}\";
    }
}"
  [(set (attr "type")
     (if_then_else (match_operand:QI 2 "incdec_operand" "")
	(const_string "incdec")
	(const_string "alu")))
   (set_attr "mode" "QI")])

(define_insn "*addqi_ext_2"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(plus:SI
	  (zero_extract:SI
	    (match_operand 1 "ext_register_operand" "%0")
	    (const_int 8)
	    (const_int 8))
	  (zero_extract:SI
	    (match_operand 2 "ext_register_operand" "q")
	    (const_int 8)
	    (const_int 8))))
   (clobber (reg:CC 17))]
  ""
  "add{b}\\t{%h2, %h0|%h0, %h2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

;; 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 "register_operand" "")
		 (match_operand:XF 2 "register_operand" "")))]
  "TARGET_80387"
  "")

(define_expand "adddf3"
  [(set (match_operand:DF 0 "register_operand" "")
	(plus:DF (match_operand:DF 1 "register_operand" "")
		 (match_operand:DF 2 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "")

(define_expand "addsf3"
  [(set (match_operand:SF 0 "register_operand" "")
	(plus:SF (match_operand:SF 1 "register_operand" "")
		 (match_operand:SF 2 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "")

;; Subtract instructions

;; %%% define_expand from the very first?
;; %%% splits for subsidi3

(define_insn "subdi3"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,o")
	(minus:DI (match_operand:DI 1 "nonimmediate_operand" "0,0")
		  (match_operand:DI 2 "general_operand" "roiF,riF")))
   (clobber (reg:CC 17))]
  ""
  "#")

(define_split
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
	(minus:DI (match_operand:DI 1 "nonimmediate_operand" "")
		  (match_operand:DI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(parallel [(set (reg:CC 17) (minus:CC (match_dup 1) (match_dup 2)))
	      (set (match_dup 0) (minus:SI (match_dup 1) (match_dup 2)))])
   (parallel [(set (match_dup 3)
		   (minus:SI (match_dup 4)
			     (plus:SI (match_dup 5)
			     (ltu:SI (reg:CC 17) (const_int 0)))))
	      (clobber (reg:CC 17))])]
  "split_di (operands+0, 1, operands+0, operands+3);
   split_di (operands+1, 1, operands+1, operands+4);
   split_di (operands+2, 1, operands+2, operands+5);")

(define_insn "*subsi3_cc"
  [(set (reg:CC 17) (minus:CC (match_operand:SI 1 "nonimmediate_operand" "0,0")
			      (match_operand:SI 2 "general_operand" "ri,rm")))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
	(minus:SI (match_dup 1) (match_dup 2)))]
  "ix86_binary_operator_ok (MINUS, SImode, operands)"
  "sub{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_insn "subsi3_carry"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
	  (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
	    (plus:SI (match_operand:SI 2 "general_operand" "ri,rm")
	      (ltu:SI (reg:CC 17) (const_int 0)))))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (MINUS, SImode, operands)"
  "sbb{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "pent_pair" "pu")
   (set_attr "ppro_uops" "few")
   (set_attr "mode" "SI")])

(define_expand "subsi3"
  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
		   (minus:SI (match_operand:SI 1 "nonimmediate_operand" "")
			     (match_operand:SI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "ix86_expand_binary_operator (MINUS, SImode, operands); DONE;")

(define_insn "*subsi_1"
  [(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")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (MINUS, SImode, operands)"
  "sub{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_insn "*subsi_2"
  [(set (reg 17)
	(compare
	  (minus:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		    (match_operand:SI 2 "general_operand" "ri,rm"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
	(minus:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCmode)
   && ix86_binary_operator_ok (MINUS, SImode, operands)"
  "sub{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_expand "subhi3"
  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
		   (minus:HI (match_operand:HI 1 "nonimmediate_operand" "")
			     (match_operand:HI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (MINUS, HImode, operands); DONE;")

(define_insn "*subhi_1"
  [(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")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (MINUS, HImode, operands)"
  "sub{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_insn "*subhi_2"
  [(set (reg 17)
	(compare
	  (minus:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		    (match_operand:HI 2 "general_operand" "ri,rm"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
	(minus:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCmode)
   && ix86_binary_operator_ok (MINUS, HImode, operands)"
  "sub{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_expand "subqi3"
  [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "")
		   (minus:QI (match_operand:QI 1 "nonimmediate_operand" "")
			     (match_operand:QI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (MINUS, QImode, operands); DONE;")

(define_insn "*subqi_1"
  [(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")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (MINUS, QImode, operands)"
  "sub{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

(define_insn "*subqi_2"
  [(set (reg 17)
	(compare
	  (minus:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		    (match_operand:QI 2 "general_operand" "qi,qm"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=qm,q")
	(minus:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCmode)
   && ix86_binary_operator_ok (MINUS, QImode, operands)"
  "sub{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

;; 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 "register_operand" "")
		  (match_operand:XF 2 "register_operand" "")))]
  "TARGET_80387"
  "")

(define_expand "subdf3"
  [(set (match_operand:DF 0 "register_operand" "")
	(minus:DF (match_operand:DF 1 "register_operand" "")
		  (match_operand:DF 2 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "")

(define_expand "subsf3"
  [(set (match_operand:SF 0 "register_operand" "")
	(minus:SF (match_operand:SF 1 "register_operand" "")
		  (match_operand:SF 2 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "")

;; Multiply instructions

(define_expand "mulsi3"
  [(parallel [(set (match_operand:SI 0 "register_operand" "")
		   (mult:SI (match_operand:SI 1 "register_operand" "")
			    (match_operand:SI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "")

(define_insn "*mulsi3_1"
  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
	(mult:SI (match_operand:SI 1 "nonimmediate_operand" "%rm,0,0")
		 (match_operand:SI 2 "general_operand" "K,i,mr")))
   (clobber (reg:CC 17))]
  "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM"
  ; For the {r,0,i} alternative (i.e., register <- register * immediate),
  ; there are two ways of writing the exact same machine instruction
  ; in assembly language.  One, for example, is:
  ;
  ;   imul $12, %eax
  ;
  ; while the other is:
  ;
  ;   imul $12, %eax, %eax
  ;
  ; The first is simply short-hand for the latter.  But, some assemblers,
  ; like the SCO OSR5 COFF assembler, don't handle the first form.
  "@
   imul{l}\\t{%2, %1, %0|%0, %1, %2}
   imul{l}\\t{%2, %1, %0|%0, %1, %2}
   imul{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "imul")
   (set_attr "prefix_0f" "0,0,1")
   (set_attr "mode" "SI")])

(define_expand "mulhi3"
  [(parallel [(set (match_operand:HI 0 "register_operand" "")
		   (mult:HI (match_operand:HI 1 "register_operand" "")
			    (match_operand:HI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_HIMODE_MATH"
  "")

(define_insn "*mulhi3_1"
  [(set (match_operand:HI 0 "register_operand" "=r,r,r")
	(mult:HI (match_operand:HI 1 "nonimmediate_operand" "%rm,0,0")
		 (match_operand:HI 2 "general_operand" "K,i,mr")))
   (clobber (reg:CC 17))]
  "GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM"
  ; %%% There was a note about "Assembler has weird restrictions",
  ; concerning alternative 1 when op1 == op0.  True?
  "@
   imul{w}\\t{%2, %1, %0|%0, %1, %2}
   imul{w}\\t{%2, %1, %0|%0, %1, %2}
   imul{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "imul")
   (set_attr "prefix_0f" "0,0,1")
   (set_attr "mode" "HI")])

(define_insn "mulqi3"
  [(set (match_operand:QI 0 "register_operand" "=a")
	(mult:QI (match_operand:QI 1 "register_operand" "%0")
		 (match_operand:QI 2 "nonimmediate_operand" "qm")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "mul{b}\\t%2"
  [(set_attr "type" "imul")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "QI")])

(define_insn "umulqihi3"
  [(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"))))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "mul{b}\\t%2"
  [(set_attr "type" "imul")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "QI")])

(define_insn "mulqihi3"
  [(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"))))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "imul{b}\\t%2"
  [(set_attr "type" "imul")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "QI")])

(define_insn "umulsidi3"
  [(set (match_operand:DI 0 "register_operand" "=A")
	(mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%0"))
		 (zero_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))
   (clobber (reg:CC 17))]
  ""
  "mul{l}\\t%2"
  [(set_attr "type" "imul")
   (set_attr "ppro_uops" "few")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "SI")])

(define_insn "mulsidi3"
  [(set (match_operand:DI 0 "register_operand" "=A")
	(mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%0"))
		 (sign_extend:DI (match_operand:SI 2 "nonimmediate_operand" "rm"))))
   (clobber (reg:CC 17))]
  ""
  "imul{l}\\t%2"
  [(set_attr "type" "imul")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "SI")])

(define_insn "umulsi3_highpart"
  [(set (match_operand:SI 0 "register_operand" "=d")
	(truncate:SI
	  (lshiftrt:DI
	    (mult:DI (zero_extend:DI
		       (match_operand:SI 1 "register_operand" "%a"))
		     (zero_extend:DI
		       (match_operand:SI 2 "nonimmediate_operand" "rm")))
	    (const_int 32))))
   (clobber (match_scratch:SI 3 "=a"))
   (clobber (reg:CC 17))]
  ""
  "mul{l}\\t%2"
  [(set_attr "type" "imul")
   (set_attr "ppro_uops" "few")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "SI")])

(define_insn "smulsi3_highpart"
  [(set (match_operand:SI 0 "register_operand" "=d")
	(truncate:SI
	  (lshiftrt:DI
	    (mult:DI (sign_extend:DI
		       (match_operand:SI 1 "register_operand" "%a"))
		     (sign_extend:DI
		       (match_operand:SI 2 "nonimmediate_operand" "rm")))
	    (const_int 32))))
   (clobber (match_scratch:SI 3 "=a"))
   (clobber (reg:CC 17))]
  ""
  "imul{l}\\t%2"
  [(set_attr "type" "imul")
   (set_attr "ppro_uops" "few")
   (set_attr "mode" "SI")])

;; The patterns that match these are at the end of this file.

(define_expand "mulxf3"
  [(set (match_operand:XF 0 "register_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 "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 "register_operand" "")
		 (match_operand:SF 2 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "")

;; Divide instructions

(define_insn "divqi3"
  [(set (match_operand:QI 0 "register_operand" "=a")
	(div:QI (match_operand:HI 1 "register_operand" "0")
		(match_operand:QI 2 "nonimmediate_operand" "qm")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "idiv{b}\\t%2"
  [(set_attr "type" "idiv")
   (set_attr "mode" "QI")
   (set_attr "ppro_uops" "few")])

(define_insn "udivqi3"
  [(set (match_operand:QI 0 "register_operand" "=a")
	(udiv:QI (match_operand:HI 1 "register_operand" "0")
		 (match_operand:QI 2 "nonimmediate_operand" "qm")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "div{b}\\t%2"
  [(set_attr "type" "idiv")
   (set_attr "mode" "QI")
   (set_attr "ppro_uops" "few")])

;; The patterns that match these are at the end of this file.

(define_expand "divxf3"
  [(set (match_operand:XF 0 "register_operand" "")
	(div:XF (match_operand:XF 1 "register_operand" "")
		(match_operand:XF 2 "register_operand" "")))]
  "TARGET_80387"
  "")

(define_expand "divdf3"
  [(set (match_operand:DF 0 "register_operand" "")
 	(div:DF (match_operand:DF 1 "register_operand" "")
 		(match_operand:DF 2 "nonimmediate_operand" "")))]
   "TARGET_80387"
   "")
 
(define_expand "divsf3"
  [(set (match_operand:SF 0 "register_operand" "")
	(div:SF (match_operand:SF 1 "register_operand" "")
		(match_operand:SF 2 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "")

;; Remainder instructions.
(define_expand "divmodsi4"
  [(parallel [(set (match_operand:SI 0 "register_operand" "")
		   (div:SI (match_operand:SI 1 "register_operand" "")
			   (match_operand:SI 2 "nonimmediate_operand" "")))
	      (set (match_operand:SI 3 "register_operand" "")
		   (mod:SI (match_dup 1) (match_dup 2)))
	      (clobber (reg:CC 17))])]
  ""
  "")

;; Allow to come the parameter in eax or edx to avoid extra moves.
;; Penalize eax case sligthly because it results in worse scheduling
;; of code.
(define_insn "*divmodsi4_nocltd"
  [(set (match_operand:SI 0 "register_operand" "=&a,?a")
	(div:SI (match_operand:SI 2 "register_operand" "1,0")
		(match_operand:SI 3 "nonimmediate_operand" "rm,rm")))
   (set (match_operand:SI 1 "register_operand" "=&d,&d")
	(mod:SI (match_dup 2) (match_dup 3)))
   (clobber (reg:CC 17))]
  "!optimize_size && !TARGET_USE_CLTD"
  "#"
  [(set_attr "type" "multi")])

(define_insn "*divmodsi4_cltd"
  [(set (match_operand:SI 0 "register_operand" "=a")
	(div:SI (match_operand:SI 2 "register_operand" "a")
		(match_operand:SI 3 "nonimmediate_operand" "rm")))
   (set (match_operand:SI 1 "register_operand" "=&d")
	(mod:SI (match_dup 2) (match_dup 3)))
   (clobber (reg:CC 17))]
  "optimize_size || TARGET_USE_CLTD"
  "#"
  [(set_attr "type" "multi")])

(define_insn "*divmodsi_noext"
  [(set (match_operand:SI 0 "register_operand" "=a")
	(div:SI (match_operand:SI 1 "register_operand" "0")
		(match_operand:SI 2 "nonimmediate_operand" "rm")))
   (set (match_operand:SI 3 "register_operand" "=d")
	(mod:SI (match_dup 1) (match_dup 2)))
   (use (match_operand:SI 4 "register_operand" "3"))
   (clobber (reg:CC 17))]
  ""
  "idiv{l}\\t%2"
  [(set_attr "type" "idiv")
   (set_attr "mode" "SI")
   (set_attr "ppro_uops" "few")])

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(div:SI (match_operand:SI 1 "register_operand" "")
		(match_operand:SI 2 "nonimmediate_operand" "")))
   (set (match_operand:SI 3 "register_operand" "")
	(mod:SI (match_dup 1) (match_dup 2)))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(parallel [(set (match_dup 3)
		   (ashiftrt:SI (match_dup 4) (const_int 31)))
	      (clobber (reg:CC 17))])
   (parallel [(set (match_dup 0)
	           (div:SI (reg:SI 0) (match_dup 2)))
	      (set (match_dup 3)
		   (mod:SI (reg:SI 0) (match_dup 2)))
	      (use (match_dup 3))
	      (clobber (reg:CC 17))])]
  "
{
  /* Avoid use of cltd in favour of a mov+shift.  */
  if (!TARGET_USE_CLTD && !optimize_size)
    {
      if (true_regnum (operands[1]))
        emit_move_insn (operands[0], operands[1]);
      else
	emit_move_insn (operands[3], operands[1]);
      operands[4] = operands[3];
    }
  else
    {
      if (true_regnum (operands[1]))
	abort();
      operands[4] = operands[1];
    }
}")
;; %%% Split me.
(define_insn "divmodhi4"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(div:HI (match_operand:HI 1 "register_operand" "0")
		(match_operand:HI 2 "nonimmediate_operand" "rm")))
   (set (match_operand:HI 3 "register_operand" "=&d")
	(mod:HI (match_dup 1) (match_dup 2)))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "cwtd\;idiv{w}\\t%2"
  [(set_attr "type" "multi")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "SI")])

(define_insn "udivmodsi4"
  [(set (match_operand:SI 0 "register_operand" "=a")
	(udiv:SI (match_operand:SI 1 "register_operand" "0")
		 (match_operand:SI 2 "nonimmediate_operand" "rm")))
   (set (match_operand:SI 3 "register_operand" "=&d")
	(umod:SI (match_dup 1) (match_dup 2)))
   (clobber (reg:CC 17))]
  ""
  "xor{l}\\t%3, %3\;div{l}\\t%2"
  [(set_attr "type" "multi")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "SI")])

(define_insn "*udivmodsi4_noext"
  [(set (match_operand:SI 0 "register_operand" "=a")
	(udiv:SI (match_operand:SI 1 "register_operand" "0")
		 (match_operand:SI 2 "nonimmediate_operand" "rm")))
   (set (match_operand:SI 3 "register_operand" "=d")
	(umod:SI (match_dup 1) (match_dup 2)))
   (use (match_dup 3))
   (clobber (reg:CC 17))]
  ""
  "div{l}\\t%2"
  [(set_attr "type" "idiv")
   (set_attr "ppro_uops" "few")
   (set_attr "mode" "SI")])

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(udiv:SI (match_operand:SI 1 "register_operand" "")
		 (match_operand:SI 2 "nonimmediate_operand" "")))
   (set (match_operand:SI 3 "register_operand" "")
	(umod:SI (match_dup 1) (match_dup 2)))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(set (match_dup 3) (const_int 0))
   (parallel [(set (match_dup 0)
		   (udiv:SI (match_dup 1) (match_dup 2)))
	      (set (match_dup 3)
		   (umod:SI (match_dup 1) (match_dup 2)))
	      (use (match_dup 3))
	      (clobber (reg:CC 17))])]
  "")

(define_expand "udivmodhi4"
  [(set (match_dup 4) (const_int 0))
   (parallel [(set (match_operand:HI 0 "register_operand" "")
		   (udiv:HI (match_operand:HI 1 "register_operand" "")
		 	    (match_operand:HI 2 "nonimmediate_operand" "")))
	      (set (match_operand:HI 3 "register_operand" "")
	   	   (umod:HI (match_dup 1) (match_dup 2)))
	      (use (match_dup 4))
	      (clobber (reg:CC 17))])]
  "TARGET_HIMODE_MATH"
  "operands[4] = gen_reg_rtx (HImode);")

(define_insn "*udivmodhi_noext"
  [(set (match_operand:HI 0 "register_operand" "=a")
	(udiv:HI (match_operand:HI 1 "register_operand" "0")
		 (match_operand:HI 2 "nonimmediate_operand" "rm")))
   (set (match_operand:HI 3 "register_operand" "=d")
	(umod:HI (match_dup 1) (match_dup 2)))
   (use (match_operand:HI 4 "register_operand" "3"))
   (clobber (reg:CC 17))]
  ""
  "div{w}\\t%2"
  [(set_attr "type" "idiv")
   (set_attr "mode" "HI")
   (set_attr "ppro_uops" "few")])

;; We can not use div/idiv for double division, because it causes
;; "division by zero" on the overflow and that's not what we expect
;; from truncate.  Because true (non truncating) double division is
;; never generated, we can't create this insn anyway.
;
;(define_insn ""
;  [(set (match_operand:SI 0 "register_operand" "=a")
;	(truncate:SI
;	  (udiv:DI (match_operand:DI 1 "register_operand" "A")
;		   (zero_extend:DI
;		     (match_operand:SI 2 "nonimmediate_operand" "rm")))))
;   (set (match_operand:SI 3 "register_operand" "=d")
;	(truncate:SI
;	  (umod:DI (match_dup 1) (zero_extend:DI (match_dup 2)))))
;   (clobber (reg:CC 17))]
;  ""
;  "div{l}\\t{%2, %0|%0, %2}"
;  [(set_attr "type" "idiv")
;   (set_attr "ppro_uops" "few")])

;;- Logical AND instructions

;; On Pentium, "test imm, reg" is pairable only with eax, ax, and al.
;; Note that this excludes ah.

(define_insn "*testsi_ccz_1"
  [(set (reg:CCZ 17)
	(compare:CCZ
	  (and:SI (match_operand:SI 0 "nonimmediate_operand" "%*a,r,rm")
		  (match_operand:SI 1 "nonmemory_operand" "in,in,rin"))
	  (const_int 0)))]
  ""
  "test{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test")
   (set_attr "modrm" "0,1,1")
   (set_attr "mode" "SI")
   (set_attr "pent_pair" "uv,np,uv")])

(define_insn "testsi_ccno_1"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (and:SI (match_operand:SI 0 "nonimmediate_operand" "%*a,r,rm")
		  (match_operand:SI 1 "nonmemory_operand" "in,in,rin"))
	  (const_int 0)))]
  ""
  "test{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test")
   (set_attr "modrm" "0,1,1")
   (set_attr "mode" "SI")
   (set_attr "pent_pair" "uv,np,uv")])

(define_insn "*testhi_1"
  [(set (reg 17)
        (compare (and:HI (match_operand:HI 0 "nonimmediate_operand" "%*a,r,rm")
			 (match_operand:HI 1 "nonmemory_operand" "n,n,rn"))
		 (const_int 0)))]
  "ix86_match_ccmode (insn, CCNOmode)"
  "test{w}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test")
   (set_attr "modrm" "0,1,1")
   (set_attr "mode" "HI")
   (set_attr "pent_pair" "uv,np,uv")])

(define_insn "testqi_ccz_1"
  [(set (reg:CCZ 17)
        (compare:CCZ
	  (and:QI (match_operand:QI 0 "nonimmediate_operand" "%*a,q,qm")
		  (match_operand:QI 1 "nonmemory_operand" "n,n,qn"))
	  (const_int 0)))]
  ""
  "test{b}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test")
   (set_attr "modrm" "0,1,1")
   (set_attr "mode" "QI")
   (set_attr "pent_pair" "uv,np,uv")])

(define_insn "testqi_ccno_1"
  [(set (reg:CCNO 17)
        (compare:CCNO (and:QI (match_operand:QI 0 "nonimmediate_operand" "%*a,q,qm,r")
			      (match_operand:QI 1 "nonmemory_operand" "n,n,qn,n"))
		      (const_int 0)))]
  ""
  "@
   test{b}\\t{%1, %0|%0, %1} 
   test{b}\\t{%1, %0|%0, %1} 
   test{b}\\t{%1, %0|%0, %1} 
   test{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "test")
   (set_attr "modrm" "0,1,1,1")
   (set_attr "mode" "QI,QI,QI,SI")
   (set_attr "pent_pair" "uv,np,uv,np")])

(define_insn "*testqi_ext_ccz_0"
  [(set (reg:CCZ 17)
	(compare:CCZ
	  (and:SI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8))
	    (match_operand 1 "const_int_operand" "n"))
	  (const_int 0)))]
  "(unsigned HOST_WIDE_INT) INTVAL (operands[1]) <= 0xff"
  "test{b}\\t{%1, %h0|%h0, %1}"
  [(set_attr "type" "test")
   (set_attr "mode" "QI")
   (set_attr "length_immediate" "1")
   (set_attr "pent_pair" "np")])

(define_insn "testqi_ext_ccno_0"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (and:SI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8))
	    (match_operand 1 "const_int_operand" "n"))
	  (const_int 0)))]
  "(unsigned HOST_WIDE_INT) INTVAL (operands[1]) <= 0xff"
  "test{b}\\t{%1, %h0|%h0, %1}"
  [(set_attr "type" "test")
   (set_attr "mode" "QI")
   (set_attr "length_immediate" "1")
   (set_attr "pent_pair" "np")])

(define_insn "*testqi_ext_1"
  [(set (reg 17)
	(compare
	  (and:SI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8))
	    (zero_extend:SI
	      (match_operand:QI 1 "nonimmediate_operand" "qm")))
	  (const_int 0)))]
  "ix86_match_ccmode (insn, CCNOmode)"
  "test{b}\\t{%1, %h0|%h0, %1}"
  [(set_attr "type" "test")
   (set_attr "mode" "QI")])

(define_insn "*testqi_ext_2"
  [(set (reg 17)
	(compare
	  (and:SI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8))
	    (zero_extract:SI
	      (match_operand 1 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8)))
	  (const_int 0)))]
  "ix86_match_ccmode (insn, CCNOmode)"
  "test{b}\\t{%h1, %h0|%h0, %h1}"
  [(set_attr "type" "test")
   (set_attr "mode" "QI")])

;; Combine likes to form bit extractions for some tests.  Humor it.
(define_insn "*testqi_ext_3"
  [(set (reg 17)
        (compare (zero_extract:SI
		   (match_operand 0 "nonimmediate_operand" "rm")
		   (match_operand:SI 1 "const_int_operand" "")
		   (match_operand:SI 2 "const_int_operand" ""))
		 (const_int 0)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (GET_MODE (operands[0]) == SImode
       || GET_MODE (operands[0]) == HImode
       || GET_MODE (operands[0]) == QImode)"
  "#")

(define_split
  [(set (reg 17)
        (compare (zero_extract:SI
		   (match_operand 0 "nonimmediate_operand" "rm")
		   (match_operand:SI 1 "const_int_operand" "")
		   (match_operand:SI 2 "const_int_operand" ""))
		 (const_int 0)))]
  "ix86_match_ccmode (insn, CCNOmode)"
  [(set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))]
  "
{
  HOST_WIDE_INT len = INTVAL (operands[1]);
  HOST_WIDE_INT pos = INTVAL (operands[2]);
  HOST_WIDE_INT mask;
  enum machine_mode mode;

  mode = GET_MODE (operands[0]);
  if (GET_CODE (operands[0]) == MEM)
    {
      /* ??? Combine likes to put non-volatile mem extractions in QImode
	 no matter the size of the test.  So find a mode that works.  */
      if (! MEM_VOLATILE_P (operands[0]))
	{
	  mode = smallest_mode_for_size (pos + len, MODE_INT);
	  operands[0] = change_address (operands[0], mode, NULL_RTX);
	}
    }
  else if (mode == HImode && pos + len <= 8)
    {
      /* Small HImode tests can be converted to QImode.  */
      mode = QImode;
      operands[0] = gen_lowpart (QImode, operands[0]);
    }

  mask  = ((HOST_WIDE_INT)1 << (pos + len)) - 1;
  mask &= ~(((HOST_WIDE_INT)1 << pos) - 1);

  operands[3] = gen_rtx_AND (mode, operands[0], GEN_INT (mask));
}")

;; %%% This used to optimize known byte-wide and operations to memory,
;; and sometimes to QImode registers.  If this is considered useful,
;; it should be done with splitters.

(define_expand "andsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(and:SI (match_operand:SI 1 "nonimmediate_operand" "")
		(match_operand:SI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (AND, SImode, operands); DONE;")

(define_insn "*andsi_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r,r")
	(and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0,qm")
		(match_operand:SI 2 "general_operand" "ri,rm,L")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (AND, SImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_IMOVX:
      {
	enum machine_mode mode;

	if (GET_CODE (operands[2]) != CONST_INT)
	  abort ();
        if (INTVAL (operands[2]) == 0xff)
	  mode = QImode;
	else if (INTVAL (operands[2]) == 0xffff)
	  mode = HImode;
	else
	  abort ();
	
	operands[1] = gen_lowpart (mode, operands[1]);
	if (mode == QImode)
	  return \"movz{bl|x}\\t{%1,%0|%0, %1}\";
	else
	  return \"movz{wl|x}\\t{%1,%0|%0, %1}\";
      }

    default:
      if (! rtx_equal_p (operands[0], operands[1]))
	abort ();
      return \"and{l}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set_attr "type" "alu,alu,imovx")
   (set_attr "length_immediate" "*,*,0")
   (set_attr "mode" "SI")])

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(and:SI (match_dup 0)
		(const_int -65536)))
   (clobber (reg:CC 17))]
  "optimize_size"
  [(set (strict_low_part (match_dup 1)) (const_int 0))]
  "operands[1] = gen_lowpart (HImode, operands[0]);")

(define_split
  [(set (match_operand 0 "q_regs_operand" "")
	(and (match_dup 0)
		(const_int -256)))
   (clobber (reg:CC 17))]
  "(optimize_size || !TARGET_PARTIAL_REG_STALL)
   && (GET_MODE (operands[0]) == SImode || GET_MODE (operands[0]) == HImode)"
  [(set (strict_low_part (match_dup 1)) (const_int 0))]
  "operands[1] = gen_lowpart (QImode, operands[0]);")

(define_split
  [(set (match_operand 0 "q_regs_operand" "")
	(and (match_dup 0)
	     (const_int -65281)))
   (clobber (reg:CC 17))]
  "(optimize_size || !TARGET_PARTIAL_REG_STALL)
   && (GET_MODE (operands[0]) == SImode || GET_MODE (operands[0]) == HImode)"
  [(parallel [(set (zero_extract:SI (match_dup 0)
				    (const_int 8)
				    (const_int 8))
		   (xor:SI 
		     (zero_extract:SI (match_dup 0)
				      (const_int 8)
				      (const_int 8))
		     (zero_extract:SI (match_dup 0)
				      (const_int 8)
				      (const_int 8))))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);")

(define_insn "*andsi_2"
  [(set (reg 17)
	(compare (and:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
			 (match_operand:SI 2 "general_operand" "rim,ri"))
		 (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
	(and:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (AND, SImode, operands)"
  "and{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_expand "andhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(and:HI (match_operand:HI 1 "nonimmediate_operand" "")
		(match_operand:HI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (AND, HImode, operands); DONE;")

(define_insn "*andhi_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r,r")
	(and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0,qm")
		(match_operand:HI 2 "general_operand" "ri,rm,L")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (AND, HImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_IMOVX:
      if (GET_CODE (operands[2]) != CONST_INT)
	abort ();
      if (INTVAL (operands[2]) == 0xff)
	return \"movz{bl|x}\\t{%b1, %k0|%k0, %b1}\";
      abort ();

    default:
      if (! rtx_equal_p (operands[0], operands[1]))
	abort ();

      return \"and{w}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set_attr "type" "alu,alu,imovx")
   (set_attr "length_immediate" "*,*,0")
   (set_attr "mode" "HI,HI,SI")])

(define_insn "*andhi_2"
  [(set (reg 17)
	(compare (and:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
			 (match_operand:HI 2 "general_operand" "rim,ri"))
		 (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
	(and:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (AND, HImode, operands)"
  "and{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_expand "andqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(and:QI (match_operand:QI 1 "nonimmediate_operand" "")
		(match_operand:QI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (AND, QImode, operands); DONE;")

;; %%% Potential partial reg stall on alternative 2.  What to do?
(define_insn "*andqi_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,q,r")
	(and:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
		(match_operand:QI 2 "general_operand" "qi,qmi,ri")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (AND, QImode, operands)"
  "@
   and{b}\\t{%2, %0|%0, %2}
   and{b}\\t{%2, %0|%0, %2}
   and{l}\\t{%k2, %k0|%k0, %k2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI,QI,SI")])

(define_insn "*andqi_2"
  [(set (reg 17)
	(compare (and:QI
		   (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
		   (match_operand:QI 2 "general_operand" "qim,qi,i"))
		 (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm,*r")
	(and:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (AND, QImode, operands)"
  "@
   and{b}\\t{%2, %0|%0, %2}
   and{b}\\t{%2, %0|%0, %2}
   and{l}\\t{%2, %k0|%k0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI,QI,SI")])

;; ??? A bug in recog prevents it from recognizing a const_int as an
;; operand to zero_extend in andqi_ext_1.  It was checking explicitly
;; for a QImode operand, which of course failed.

(define_insn "andqi_ext_0"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(and:SI 
	  (zero_extract:SI
	    (match_operand 1 "ext_register_operand" "0")
	    (const_int 8)
	    (const_int 8))
	  (match_operand 2 "const_int_operand" "n")))
   (clobber (reg:CC 17))]
  "(unsigned HOST_WIDE_INT)INTVAL (operands[2]) <= 0xff"
  "and{b}\\t{%2, %h0|%h0, %2}"
  [(set_attr "type" "alu")
   (set_attr "length_immediate" "1")
   (set_attr "mode" "QI")])

;; Generated by peephole translating test to and.  This shows up
;; often in fp comparisons.

(define_insn "*andqi_ext_0_cc"
  [(set (reg 17)
	(compare
	  (and:SI
	    (zero_extract:SI
	      (match_operand 1 "ext_register_operand" "q")
		(const_int 8)
	      (const_int 8))
	    (match_operand 2 "const_int_operand" "n"))
	  (const_int 0)))
   (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(and:SI 
	  (zero_extract:SI
	    (match_dup 1)
	    (const_int 8)
	    (const_int 8))
	  (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (unsigned HOST_WIDE_INT)INTVAL (operands[2]) <= 0xff"
  "and{b}\\t{%2, %h0|%h0, %2}"
  [(set_attr "type" "alu")
   (set_attr "length_immediate" "1")
   (set_attr "mode" "QI")])

(define_insn "*andqi_ext_1"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(and:SI 
	  (zero_extract:SI
	    (match_operand 1 "ext_register_operand" "0")
	    (const_int 8)
	    (const_int 8))
	  (zero_extend:SI
	    (match_operand:QI 2 "general_operand" "qm"))))
   (clobber (reg:CC 17))]
  ""
  "and{b}\\t{%2, %h0|%h0, %2}"
  [(set_attr "type" "alu")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "QI")])

(define_insn "*andqi_ext_2"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(and:SI
	  (zero_extract:SI
	    (match_operand 1 "ext_register_operand" "%0")
	    (const_int 8)
	    (const_int 8))
	  (zero_extract:SI
	    (match_operand 2 "ext_register_operand" "q")
	    (const_int 8)
	    (const_int 8))))
   (clobber (reg:CC 17))]
  ""
  "and{b}\\t{%h2, %h0|%h0, %h2}"
  [(set_attr "type" "alu")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "QI")])

;; Logical inclusive OR instructions

;; %%% This used to optimize known byte-wide and operations to memory.
;; If this is considered useful, it should be done with splitters.

(define_expand "iorsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(ior:SI (match_operand:SI 1 "nonimmediate_operand" "")
		(match_operand:SI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (IOR, SImode, operands); DONE;")

(define_insn "*iorsi_1"
  [(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,rmi")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (IOR, SImode, operands)"
  "or{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_insn "*iorsi_2"
  [(set (reg 17)
	(compare (ior:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
			 (match_operand:SI 2 "general_operand" "rim,ri"))
		 (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
	(ior:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (IOR, SImode, operands)"
  "or{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_expand "iorhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(ior:HI (match_operand:HI 1 "nonimmediate_operand" "")
		(match_operand:HI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (IOR, HImode, operands); DONE;")

(define_insn "*iorhi_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m")
	(ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
		(match_operand:HI 2 "general_operand" "rmi,ri")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (IOR, HImode, operands)"
  "or{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_insn "*iorhi_2"
  [(set (reg 17)
	(compare (ior:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
			 (match_operand:HI 2 "general_operand" "rim,ri"))
		 (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
	(ior:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (IOR, HImode, operands)"
  "or{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_expand "iorqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(ior:QI (match_operand:QI 1 "nonimmediate_operand" "")
		(match_operand:QI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (IOR, QImode, operands); DONE;")

;; %%% Potential partial reg stall on alternative 2.  What to do?
(define_insn "*iorqi_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r")
	(ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
		(match_operand:QI 2 "general_operand" "qmi,qi,ri")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (IOR, QImode, operands)"
  "@
   or{b}\\t{%2, %0|%0, %2}
   or{b}\\t{%2, %0|%0, %2}
   or{l}\\t{%k2, %k0|%k0, %k2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

(define_insn "*iorqi_2"
  [(set (reg 17)
	(compare (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
			 (match_operand:QI 2 "general_operand" "qim,qi"))
		 (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
	(ior:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (IOR, QImode, operands)"
  "or{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

;; Logical XOR instructions

;; %%% This used to optimize known byte-wide and operations to memory.
;; If this is considered useful, it should be done with splitters.

(define_expand "xorsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(xor:SI (match_operand:SI 1 "nonimmediate_operand" "")
		(match_operand:SI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (XOR, SImode, operands); DONE;")

(define_insn "*xorsi_1"
  [(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")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (XOR, SImode, operands)"
  "xor{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_insn "*xorsi_2"
  [(set (reg 17)
	(compare (xor:SI (match_operand:SI 1 "nonimmediate_operand" "%0,0")
			 (match_operand:SI 2 "general_operand" "rim,ri"))
		 (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=r,rm")
	(xor:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (XOR, SImode, operands)"
  "xor{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "SI")])

(define_expand "xorhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(xor:HI (match_operand:HI 1 "nonimmediate_operand" "")
		(match_operand:HI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (XOR, HImode, operands); DONE;")

(define_insn "*xorhi_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,m")
	(xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
		(match_operand:HI 2 "general_operand" "rmi,ri")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (XOR, HImode, operands)"
  "xor{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_insn "*xorhi_2"
  [(set (reg 17)
	(compare (xor:HI (match_operand:HI 1 "nonimmediate_operand" "%0,0")
			 (match_operand:HI 2 "general_operand" "rim,ri"))
		 (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=r,rm")
	(xor:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (XOR, HImode, operands)"
  "xor{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "HI")])

(define_expand "xorqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(xor:QI (match_operand:QI 1 "nonimmediate_operand" "")
		(match_operand:QI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (XOR, QImode, operands); DONE;")

;; %%% Potential partial reg stall on alternative 2.  What to do?
(define_insn "*xorqi_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,m,r")
	(xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
		(match_operand:QI 2 "general_operand" "qmi,qi,ri")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (XOR, QImode, operands)"
  "@
   xor{b}\\t{%2, %0|%0, %2}
   xor{b}\\t{%2, %0|%0, %2}
   xor{l}\\t{%k2, %k0|%k0, %k2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI,QI,SI")])

(define_insn "xorqi_ext_1"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(xor:SI 
	  (zero_extract:SI (match_operand 1 "ext_register_operand" "0")
	  		   (const_int 8)
			   (const_int 8))
	  (zero_extract:SI (match_operand 2 "ext_register_operand" "q")
	  		   (const_int 8)
			   (const_int 8))))
   (clobber (reg:CC 17))]
  ""
  "xor{b}\\t{%h2, %h0|%h0, %h2}"
  [(set_attr "type" "alu")
   (set_attr "length_immediate" "0")
   (set_attr "mode" "QI")])

(define_insn "*xorqi_cc_1"
  [(set (reg 17)
	(compare
	  (xor:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0")
		  (match_operand:QI 2 "general_operand" "qim,qi"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=q,qm")
	(xor:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (XOR, QImode, operands)"
  "xor{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

(define_insn "xorqi_cc_ext_1"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (xor:SI
	    (zero_extract:SI
	      (match_operand 1 "ext_register_operand" "0")
	      (const_int 8)
	      (const_int 8))
	    (match_operand:QI 2 "general_operand" "qmn"))
	  (const_int 0)))
   (set (zero_extract:SI (match_operand 0 "ext_register_operand" "=q")
			 (const_int 8)
			 (const_int 8))
	(xor:SI 
	  (zero_extract:SI (match_dup 1) (const_int 8) (const_int 8))
	  (match_dup 2)))]
  ""
  "xor{b}\\t{%2, %h0|%h0, %2}"
  [(set_attr "type" "alu")
   (set_attr "mode" "QI")])

;; Negation instructions

;; %%% define_expand from the very first?

(define_expand "negdi2"
  [(parallel [(set (match_operand:DI 0 "nonimmediate_operand" "")
		   (neg:DI (match_operand:DI 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "ix86_expand_unary_operator (NEG, DImode, operands); DONE;")

(define_insn "*negdi2_1"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=ro")
	(neg:DI (match_operand:DI 1 "general_operand" "0")))
   (clobber (reg:CC 17))]
  "ix86_unary_operator_ok (NEG, DImode, operands)"
  "#")

(define_split
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
	(neg:DI (match_operand:DI 1 "general_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(parallel
    [(set (reg:CCZ 17)
	  (compare:CCZ (neg:SI (match_dup 2)) (const_int 0)))
     (set (match_dup 0) (neg:SI (match_dup 2)))])
   (parallel
    [(set (match_dup 1)
	  (plus:SI (match_dup 3)
	    (plus:SI (const_int 0)
	      (ltu:SI (reg:CC 17) (const_int 0)))))
     (clobber (reg:CC 17))])
   (parallel
    [(set (match_dup 1)
	  (neg:SI (match_dup 1)))
     (clobber (reg:CC 17))])]
  "split_di (operands+1, 1, operands+2, operands+3);
   split_di (operands+0, 1, operands+0, operands+1);")

(define_expand "negsi2"
  [(parallel [(set (match_operand:SI 0 "nonimmediate_operand" "")
		   (neg:SI (match_operand:SI 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "ix86_expand_unary_operator (NEG, SImode, operands); DONE;")

(define_insn "*negsi2_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))
   (clobber (reg:CC 17))]
  "ix86_unary_operator_ok (NEG, SImode, operands)"
  "neg{l}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "SI")])

;; The problem with neg is that it does not perform (compare x 0),
;; it really performs (compare 0 x), which leaves us with the zero
;; flag being the only useful item.

(define_insn "*negsi2_cmpz"
  [(set (reg:CCZ 17)
	(compare:CCZ (neg:SI (match_operand:SI 1 "nonimmediate_operand" "0"))
		     (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(neg:SI (match_dup 1)))]
  "ix86_unary_operator_ok (NEG, SImode, operands)"
  "neg{l}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "SI")])

(define_expand "neghi2"
  [(parallel [(set (match_operand:HI 0 "nonimmediate_operand" "")
		   (neg:HI (match_operand:HI 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_HIMODE_MATH"
  "ix86_expand_unary_operator (NEG, HImode, operands); DONE;")

(define_insn "*neghi2_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))
   (clobber (reg:CC 17))]
  "ix86_unary_operator_ok (NEG, HImode, operands)"
  "neg{w}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "HI")])

(define_insn "*neghi2_cmpz"
  [(set (reg:CCZ 17)
	(compare:CCZ (neg:HI (match_operand:HI 1 "nonimmediate_operand" "0"))
		     (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(neg:HI (match_dup 1)))]
  "ix86_unary_operator_ok (NEG, HImode, operands)"
  "neg{w}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "HI")])

(define_expand "negqi2"
  [(parallel [(set (match_operand:QI 0 "nonimmediate_operand" "")
		   (neg:QI (match_operand:QI 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_QIMODE_MATH"
  "ix86_expand_unary_operator (NEG, QImode, operands); DONE;")

(define_insn "*negqi2_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))
   (clobber (reg:CC 17))]
  "ix86_unary_operator_ok (NEG, QImode, operands)"
  "neg{b}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "QI")])

(define_insn "*negqi2_cmpz"
  [(set (reg:CCZ 17)
	(compare:CCZ (neg:QI (match_operand:QI 1 "nonimmediate_operand" "0"))
		     (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(neg:QI (match_dup 1)))]
  "ix86_unary_operator_ok (NEG, QImode, operands)"
  "neg{b}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "QI")])

;; Changing of sign for FP values is doable using integer unit too.

(define_expand "negsf2"
  [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
		   (neg:SF (match_operand:SF 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_80387"
  "ix86_expand_unary_operator (NEG, SFmode, operands); DONE;")

;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
;; because of secondary memory needed to reload from class FLOAT_INT_REGS
;; to itself.
(define_insn "*negsf2_if"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,rm#f")
	(neg:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && ix86_unary_operator_ok (NEG, SFmode, operands)"
  "#")

(define_split
  [(set (match_operand:SF 0 "register_operand" "")
	(neg:SF (match_operand:SF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed"
  [(set (match_dup 0)
	(neg:SF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:SF 0 "register_operand" "")
	(neg:SF (match_operand:SF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
  [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "operands[1] = GEN_INT (0x80000000);
   operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));")

(define_split
  [(set (match_operand 0 "memory_operand" "")
	(neg (match_operand 1 "memory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))"
  [(parallel [(set (match_dup 0) (xor:QI (match_dup 0) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "
{
  int size = GET_MODE_SIZE (GET_MODE (operands[1]));

  /* XFmode's size is 12, but only 10 bytes are used.  */
  if (size == 12)
    size = 10;
  operands[0] = gen_rtx_MEM (QImode, XEXP (operands[0], 0));
  operands[0] = adj_offsettable_operand (operands[0], size - 1);
  operands[1] = GEN_INT (0x80);
}")

(define_expand "negdf2"
  [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
		   (neg:DF (match_operand:DF 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_80387"
  "ix86_expand_unary_operator (NEG, DFmode, operands); DONE;")

;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
;; because of secondary memory needed to reload from class FLOAT_INT_REGS
;; to itself.
(define_insn "*negdf2_if"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,rm#f")
	(neg:DF (match_operand:DF 1 "nonimmediate_operand" "0,0")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && ix86_unary_operator_ok (NEG, DFmode, operands)"
  "#")

(define_split
  [(set (match_operand:DF 0 "register_operand" "")
	(neg:DF (match_operand:DF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed"
  [(set (match_dup 0)
	(neg:DF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:DF 0 "register_operand" "")
	(neg:DF (match_operand:DF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
  [(parallel [(set (match_dup 3) (xor:SI (match_dup 3) (match_dup 4)))
	      (clobber (reg:CC 17))])]
  "operands[4] = GEN_INT (0x80000000);
   split_di (operands+0, 1, operands+2, operands+3);")

(define_expand "negxf2"
  [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
		   (neg:XF (match_operand:XF 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_80387"
  "ix86_expand_unary_operator (NEG, XFmode, operands); DONE;")

;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
;; because of secondary memory needed to reload from class FLOAT_INT_REGS
;; to itself.
(define_insn "*negxf2_if"
  [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,rm#f")
	(neg:XF (match_operand:XF 1 "nonimmediate_operand" "0,0")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && ix86_unary_operator_ok (NEG, XFmode, operands)"
  "#")

(define_split
  [(set (match_operand:XF 0 "register_operand" "")
	(neg:XF (match_operand:XF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed"
  [(set (match_dup 0)
	(neg:XF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:XF 0 "register_operand" "")
	(neg:XF (match_operand:XF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
  [(parallel [(set (match_dup 0) (xor:SI (match_dup 0) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "operands[1] = GEN_INT (0x8000);
   operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]) + 2);")

;; Conditionize these after reload. If they matches before reload, we 
;; lose the clobber and ability to use integer instructions.

(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"
  "fchs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "SF")
   (set_attr "ppro_uops" "few")])

(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"
  "fchs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "DF")
   (set_attr "ppro_uops" "few")])

(define_insn "*negextendsfdf2"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(neg:DF (float_extend:DF
		  (match_operand:SF 1 "register_operand" "0"))))]
  "TARGET_80387"
  "fchs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "DF")
   (set_attr "ppro_uops" "few")])

(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"
  "fchs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "XF")
   (set_attr "ppro_uops" "few")])

(define_insn "*negextenddfxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(neg:XF (float_extend:XF
		  (match_operand:DF 1 "register_operand" "0"))))]
  "TARGET_80387"
  "fchs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "XF")
   (set_attr "ppro_uops" "few")])

(define_insn "*negextendsfxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(neg:XF (float_extend:XF
		  (match_operand:SF 1 "register_operand" "0"))))]
  "TARGET_80387"
  "fchs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "XF")
   (set_attr "ppro_uops" "few")])

;; Absolute value instructions

(define_expand "abssf2"
  [(parallel [(set (match_operand:SF 0 "nonimmediate_operand" "")
		   (neg:SF (match_operand:SF 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_80387"
  "ix86_expand_unary_operator (ABS, SFmode, operands); DONE;")

;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
;; because of secondary memory needed to reload from class FLOAT_INT_REGS
;; to itself.
(define_insn "*abssf2_if"
  [(set (match_operand:SF 0 "nonimmediate_operand" "=f#r,rm#f")
	(abs:SF (match_operand:SF 1 "nonimmediate_operand" "0,0")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && ix86_unary_operator_ok (ABS, SFmode, operands)"
  "#")

(define_split
  [(set (match_operand:SF 0 "register_operand" "")
	(abs:SF (match_operand:SF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0]))"
  [(set (match_dup 0)
	(abs:SF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:SF 0 "register_operand" "")
	(abs:SF (match_operand:SF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
  [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "operands[1] = GEN_INT (~0x80000000);
   operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));")

(define_split
  [(set (match_operand 0 "memory_operand" "")
	(abs (match_operand 1 "memory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && FLOAT_MODE_P (GET_MODE (operands[0]))"
  [(parallel [(set (match_dup 0) (and:QI (match_dup 0) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "
{
  int size = GET_MODE_SIZE (GET_MODE (operands[1]));

  /* XFmode's size is 12, but only 10 bytes are used.  */
  if (size == 12)
    size = 10;
  operands[0] = gen_rtx_MEM (QImode, XEXP (operands[0], 0));
  operands[0] = adj_offsettable_operand (operands[0], size - 1);
  operands[1] = GEN_INT (~0x80);
}")

(define_expand "absdf2"
  [(parallel [(set (match_operand:DF 0 "nonimmediate_operand" "")
		   (neg:DF (match_operand:DF 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_80387"
  "ix86_expand_unary_operator (ABS, DFmode, operands); DONE;")

;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
;; because of secondary memory needed to reload from class FLOAT_INT_REGS
;; to itself.
(define_insn "*absdf2_if"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=f#r,rm#f")
	(abs:DF (match_operand:DF 1 "nonimmediate_operand" "0,0")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && ix86_unary_operator_ok (ABS, DFmode, operands)"
  "#")

(define_split
  [(set (match_operand:DF 0 "register_operand" "")
	(abs:DF (match_operand:DF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed"
  [(set (match_dup 0)
	(abs:DF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:DF 0 "register_operand" "")
	(abs:DF (match_operand:DF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
  [(parallel [(set (match_dup 3) (and:SI (match_dup 3) (match_dup 4)))
	      (clobber (reg:CC 17))])]
  "operands[4] = GEN_INT (~0x80000000);
   split_di (operands+0, 1, operands+2, operands+3);")

(define_expand "absxf2"
  [(parallel [(set (match_operand:XF 0 "nonimmediate_operand" "")
		   (neg:XF (match_operand:XF 1 "nonimmediate_operand" "")))
	      (clobber (reg:CC 17))])]
  "TARGET_80387"
  "ix86_expand_unary_operator (ABS, XFmode, operands); DONE;")

;; Keep 'f' and 'r' in separate alternatives to avoid reload problems
;; because of secondary memory needed to reload from class FLOAT_INT_REGS
;; to itself.
(define_insn "*absxf2_if"
  [(set (match_operand:XF 0 "nonimmediate_operand" "=f#r,rm#f")
	(abs:XF (match_operand:XF 1 "nonimmediate_operand" "0,0")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && ix86_unary_operator_ok (ABS, XFmode, operands)"
  "#")

(define_split
  [(set (match_operand:XF 0 "register_operand" "")
	(abs:XF (match_operand:XF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && FP_REGNO_P (REGNO (operands[0])) && reload_completed"
  [(set (match_dup 0)
	(abs:XF (match_dup 1)))]
  "")

(define_split
  [(set (match_operand:XF 0 "register_operand" "")
	(abs:XF (match_operand:XF 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_80387 && reload_completed && !FP_REGNO_P (REGNO (operands[0]))"
  [(parallel [(set (match_dup 0) (and:SI (match_dup 0) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "operands[1] = GEN_INT (~0x8000);
   operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]) + 2);")

(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"
  "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"
  "fabs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "DF")])

(define_insn "*absextendsfdf2"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(abs:DF (float_extend:DF
		  (match_operand:SF 1 "register_operand" "0"))))]
  "TARGET_80387"
  "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"
  "fabs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "DF")])

(define_insn "*absextenddfxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(abs:XF (float_extend:XF
	  (match_operand:DF 1 "register_operand" "0"))))]
  "TARGET_80387"
  "fabs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "XF")])

(define_insn "*absextendsfxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(abs:XF (float_extend:XF
	  (match_operand:SF 1 "register_operand" "0"))))]
  "TARGET_80387"
  "fabs"
  [(set_attr "type" "fsgn")
   (set_attr "mode" "XF")])

;; One complement instructions

(define_expand "one_cmplsi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(not:SI (match_operand:SI 1 "nonimmediate_operand" "")))]
  ""
  "ix86_expand_unary_operator (NOT, SImode, operands); DONE;")

(define_insn "*one_cmplsi2_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
  "ix86_unary_operator_ok (NOT, SImode, operands)"
  "not{l}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "SI")])

(define_insn "*one_cmplsi2_2"
  [(set (reg 17)
	(compare (not:SI (match_operand:SI 1 "nonimmediate_operand" "0"))
		 (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(not:SI (match_dup 1)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_unary_operator_ok (NOT, SImode, operands)"
  "#"
  [(set_attr "type" "alu1")
   (set_attr "mode" "SI")])

(define_split
  [(set (reg 17)
	(compare (not:SI (match_operand:SI 1 "nonimmediate_operand" ""))
		 (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "")
	(not:SI (match_dup 1)))]
  "ix86_match_ccmode (insn, CCNOmode)"
  [(parallel [(set (reg:CCNO 17)
		   (compare:CCNO (xor:SI (match_dup 1) (const_int -1))
				 (const_int 0)))
	      (set (match_dup 0)
		   (xor:SI (match_dup 1) (const_int -1)))])]
  "")

(define_expand "one_cmplhi2"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(not:HI (match_operand:HI 1 "nonimmediate_operand" "")))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_unary_operator (NOT, HImode, operands); DONE;")

(define_insn "*one_cmplhi2_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
  "ix86_unary_operator_ok (NOT, HImode, operands)"
  "not{w}\\t%0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "HI")])

(define_insn "*one_cmplhi2_2"
  [(set (reg 17)
	(compare (not:HI (match_operand:HI 1 "nonimmediate_operand" "0"))
		 (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(not:HI (match_dup 1)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_unary_operator_ok (NEG, HImode, operands)"
  "#"
  [(set_attr "type" "alu1")
   (set_attr "mode" "HI")])

(define_split
  [(set (reg 17)
	(compare (not:HI (match_operand:HI 1 "nonimmediate_operand" ""))
		 (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "")
	(not:HI (match_dup 1)))]
  "ix86_match_ccmode (insn, CCNOmode)"
  [(parallel [(set (reg:CCNO 17)
		   (compare:CCNO (xor:HI (match_dup 1) (const_int -1))
		      		 (const_int 0)))
	      (set (match_dup 0)
		   (xor:HI (match_dup 1) (const_int -1)))])]
  "")

;; %%% Potential partial reg stall on alternative 1.  What to do?
(define_expand "one_cmplqi2"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(not:QI (match_operand:QI 1 "nonimmediate_operand" "")))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_unary_operator (NOT, QImode, operands); DONE;")

(define_insn "*one_cmplqi2_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r")
	(not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))]
  "ix86_unary_operator_ok (NOT, QImode, operands)"
  "@
   not{b}\\t%0
   not{l}\\t%k0"
  [(set_attr "type" "negnot")
   (set_attr "mode" "QI,SI")])

(define_insn "*one_cmplqi2_2"
  [(set (reg 17)
	(compare (not:QI (match_operand:QI 1 "nonimmediate_operand" "0"))
		 (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(not:QI (match_dup 1)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_unary_operator_ok (NOT, QImode, operands)"
  "#"
  [(set_attr "type" "alu1")
   (set_attr "mode" "QI")])

(define_split
  [(set (reg 17)
	(compare (not:QI (match_operand:QI 1 "nonimmediate_operand" ""))
		 (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "")
	(not:QI (match_dup 1)))]
  "ix86_match_ccmode (insn, CCNOmode)"
  [(parallel [(set (reg:CCNO 17)
		   (compare:CCNO (xor:QI (match_dup 1) (const_int -1))
		      		 (const_int 0)))
	      (set (match_dup 0)
		   (xor:QI (match_dup 1) (const_int -1)))])]
  "")

;; Arithmetic shift instructions

;; DImode shifts are implemented using the i386 "shift double" opcode,
;; which is written as "sh[lr]d[lw] imm,reg,reg/mem".  If the shift count
;; is variable, then the count is in %cl and the "imm" operand is dropped
;; from the assembler input.
;;
;; This instruction shifts the target reg/mem as usual, but instead of
;; shifting in zeros, bits are shifted in from reg operand.  If the insn
;; is a left shift double, bits are taken from the high order bits of
;; reg, else if the insn is a shift right double, bits are taken from the
;; low order bits of reg.  So if %eax is "1234" and %edx is "5678",
;; "shldl $8,%edx,%eax" leaves %edx unchanged and sets %eax to "2345".
;;
;; Since sh[lr]d does not change the `reg' operand, that is done
;; separately, making all shifts emit pairs of shift double and normal
;; shift.  Since sh[lr]d does not shift more than 31 bits, and we wish to
;; support a 63 bit shift, each shift where the count is in a reg expands
;; to a pair of shifts, a branch, a shift by 32 and a label.
;;
;; If the shift count is a constant, we need never emit more than one
;; shift pair, instead using moves and sign extension for counts greater
;; than 31.

(define_expand "ashldi3"
  [(parallel [(set (match_operand:DI 0 "register_operand" "=r")
		   (ashift:DI (match_operand:DI 1 "register_operand" "0")
			      (match_operand:QI 2 "nonmemory_operand" "Jc")))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_CMOVE && ! immediate_operand (operands[2], QImode))
    {
      emit_insn (gen_ashldi3_1 (operands[0], operands[1], operands[2]));
      DONE;
    }
}")

(define_insn "ashldi3_1"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(ashift:DI (match_operand:DI 1 "register_operand" "0")
		   (match_operand:QI 2 "nonmemory_operand" "Jc")))
   (clobber (match_scratch:SI 3 "=&r"))
   (clobber (reg:CC 17))]
  "TARGET_CMOVE"
  "#"
  [(set_attr "type" "multi")])

(define_insn "*ashldi3_2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(ashift:DI (match_operand:DI 1 "register_operand" "0")
		   (match_operand:QI 2 "nonmemory_operand" "Jc")))
   (clobber (reg:CC 17))]
  ""
  "#"
  [(set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(ashift:DI (match_operand:DI 1 "register_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_CMOVE && reload_completed"
  [(const_int 0)]
  "ix86_split_ashldi (operands, operands[3]); DONE;")

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(ashift:DI (match_operand:DI 1 "register_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(const_int 0)]
  "ix86_split_ashldi (operands, NULL_RTX); DONE;")

(define_insn "x86_shld_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m")
        (ior:SI (ashift:SI (match_dup 0)
		  (match_operand:QI 2 "nonmemory_operand" "I,c"))
		(lshiftrt:SI (match_operand:SI 1 "register_operand" "r,r")
		  (minus:QI (const_int 32) (match_dup 2)))))
   (clobber (reg:CC 17))]
  ""
  "@
   shld{l}\\t{%2, %1, %0|%0, %1, %2}
   shld{l}\\t{%s2%1, %0|%0, %1, %2}"
  [(set_attr "type" "ishift")
   (set_attr "prefix_0f" "1")
   (set_attr "mode" "SI")
   (set_attr "pent_pair" "np")
   (set_attr "athlon_decode" "vector")
   (set_attr "ppro_uops" "few")])

(define_expand "x86_shift_adj_1"
  [(set (reg:CCZ 17)
	(compare:CCZ (and:QI (match_operand:QI 2 "register_operand" "")
			     (const_int 32))
		     (const_int 0)))
   (set (match_operand:SI 0 "register_operand" "")
        (if_then_else:SI (ne (reg:CCZ 17) (const_int 0))
			 (match_operand:SI 1 "register_operand" "")
			 (match_dup 0)))
   (set (match_dup 1)
	(if_then_else:SI (ne (reg:CCZ 17) (const_int 0))
			 (match_operand:SI 3 "register_operand" "r")
			 (match_dup 1)))]
  "TARGET_CMOVE"
  "")

(define_expand "x86_shift_adj_2"
  [(use (match_operand:SI 0 "register_operand" ""))
   (use (match_operand:SI 1 "register_operand" ""))
   (use (match_operand:QI 2 "register_operand" ""))]
  ""
  "
{
  rtx label = gen_label_rtx ();
  rtx tmp;

  emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (32)));

  tmp = gen_rtx_REG (CCZmode, FLAGS_REG);
  tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
  tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
			      gen_rtx_LABEL_REF (VOIDmode, label),
			      pc_rtx);
  tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
  JUMP_LABEL (tmp) = label;

  emit_move_insn (operands[0], operands[1]);
  emit_move_insn (operands[1], const0_rtx);

  emit_label (label);
  LABEL_NUSES (label) = 1;

  DONE;
}")

(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(ashift:SI (match_operand:SI 1 "nonimmediate_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (ASHIFT, SImode, operands); DONE;")

(define_insn "*ashlsi3_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,r")
	(ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0,r")
		   (match_operand:QI 2 "nonmemory_operand" "cI,M")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ASHIFT, SImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      if (!rtx_equal_p (operands[0], operands[1]))
	abort ();
      return \"add{l}\\t{%0, %0|%0, %0}\";

    case TYPE_LEA:
      if (GET_CODE (operands[2]) != CONST_INT
	  || (unsigned HOST_WIDE_INT) INTVAL (operands[2]) > 3)
	abort ();
      operands[1] = gen_rtx_MULT (SImode, operands[1],
				  GEN_INT (1 << INTVAL (operands[2])));
      return \"lea{l}\\t{%a1, %0|%0, %a1}\";

    default:
      if (REG_P (operands[2]))
	return \"sal{l}\\t{%b2, %0|%0, %b2}\";
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	return \"sal{l}\\t%0\";
      else
	return \"sal{l}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (cond [(eq_attr "alternative" "1")
	      (const_string "lea")
            (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")])

;; Convert lea to the lea pattern to avoid flags dependency.
(define_split
  [(set (match_operand 0 "register_operand" "")
	(ashift (match_operand 1 "register_operand" "")
                (match_operand:QI 2 "const_int_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && true_regnum (operands[0]) != true_regnum (operands[1])"
  [(const_int 0)]
  "
{
  rtx pat;
  operands[0] = gen_lowpart (SImode, operands[0]);
  operands[1] = gen_lowpart (Pmode, operands[1]);
  operands[2] = GEN_INT (1 << INTVAL (operands[2]));
  pat = gen_rtx_MULT (Pmode, operands[1], operands[2]);
  if (Pmode != SImode)
    pat = gen_rtx_SUBREG (SImode, pat, 0);
  emit_insn (gen_rtx_SET (VOIDmode, operands[0], pat));
  DONE;
}")

;; 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.
(define_insn "*ashlsi3_cmpno"
  [(set (reg 17)
	(compare
	  (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(ashift:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (ASHIFT, SImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      return \"add{l}\\t{%0, %0|%0, %0}\";

    default:
      if (REG_P (operands[2]))
	return \"sal{l}\\t{%b2, %0|%0, %b2}\";
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	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_expand "ashlhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(ashift:HI (match_operand:HI 1 "nonimmediate_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (ASHIFT, HImode, operands); DONE;")

(define_insn "*ashlhi3_1_lea"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,r")
	(ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0,r")
		   (match_operand:QI 2 "nonmemory_operand" "cI,M")))
   (clobber (reg:CC 17))]
  "!TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (ASHIFT, HImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_LEA:
      return \"#\";
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      return \"add{w}\\t{%0, %0|%0, %0}\";

    default:
      if (REG_P (operands[2]))
	return \"sal{w}\\t{%b2, %0|%0, %b2}\";
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	return \"sal{w}\\t%0\";
      else
	return \"sal{w}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set (attr "type")
     (cond [(eq_attr "alternative" "1")
	      (const_string "lea")
            (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,SI")])

(define_insn "*ashlhi3_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		   (match_operand:QI 2 "nonmemory_operand" "cI")))
   (clobber (reg:CC 17))]
  "TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (ASHIFT, HImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      return \"add{w}\\t{%0, %0|%0, %0}\";

    default:
      if (REG_P (operands[2]))
	return \"sal{w}\\t{%b2, %0|%0, %b2}\";
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	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")])

;; 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.
(define_insn "*ashlhi3_cmpno"
  [(set (reg 17)
	(compare
	  (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(ashift:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (ASHIFT, HImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      return \"add{w}\\t{%0, %0|%0, %0}\";

    default:
      if (REG_P (operands[2]))
	return \"sal{w}\\t{%b2, %0|%0, %b2}\";
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	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_expand "ashlqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(ashift:QI (match_operand:QI 1 "nonimmediate_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (ASHIFT, QImode, operands); DONE;")

;; %%% Potential partial reg stall on alternative 2.  What to do?

(define_insn "*ashlqi3_1_lea"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r,r")
	(ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0,r")
		   (match_operand:QI 2 "nonmemory_operand" "cI,cI,M")))
   (clobber (reg:CC 17))]
  "!TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (ASHIFT, QImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_LEA:
      return \"#\";
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      if (NON_QI_REG_P (operands[1]))
        return \"add{l}\\t{%k0, %k0|%k0, %k0}\";
      else
        return \"add{b}\\t{%0, %0|%0, %0}\";

    default:
      if (REG_P (operands[2]))
	{
	  if (get_attr_mode (insn) == MODE_SI)
	    return \"sal{l}\\t{%b2, %k0|%k0, %b2}\";
	  else
	    return \"sal{b}\\t{%b2, %0|%0, %b2}\";
	}
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	{
	  if (get_attr_mode (insn) == MODE_SI)
	    return \"sal{l}\\t%0\";
	  else
	    return \"sal{b}\\t%0\";
	}
      else
	{
	  if (get_attr_mode (insn) == MODE_SI)
	    return \"sal{l}\\t{%2, %k0|%k0, %2}\";
	  else
	    return \"sal{b}\\t{%2, %0|%0, %2}\";
	}
    }
}"
  [(set (attr "type")
     (cond [(eq_attr "alternative" "2")
	      (const_string "lea")
            (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,SI,SI")])

(define_insn "*ashlqi3_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,r")
	(ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		   (match_operand:QI 2 "nonmemory_operand" "cI,cI")))
   (clobber (reg:CC 17))]
  "TARGET_PARTIAL_REG_STALL
   && ix86_binary_operator_ok (ASHIFT, QImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      if (NON_QI_REG_P (operands[1]))
        return \"add{l}\\t{%k0, %k0|%k0, %k0}\";
      else
        return \"add{b}\\t{%0, %0|%0, %0}\";

    default:
      if (REG_P (operands[2]))
	{
          if (NON_QI_REG_P (operands[1]))
	    return \"sal{l}\\t{%b2, %k0|%k0, %b2}\";
	  else
	    return \"sal{b}\\t{%b2, %0|%0, %b2}\";
	}
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	{
          if (NON_QI_REG_P (operands[1]))
	    return \"sal{l}\\t%0\";
	  else
	    return \"sal{b}\\t%0\";
	}
      else
	{
          if (NON_QI_REG_P (operands[1]))
	    return \"sal{l}\\t{%2, %k0|%k0, %2}\";
	  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,SI")])

;; 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.
(define_insn "*ashlqi3_cmpno"
  [(set (reg 17)
	(compare
	  (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(ashift:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (ASHIFT, QImode, operands)"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU:
      if (operands[2] != const1_rtx)
	abort ();
      return \"add{b}\\t{%0, %0|%0, %0}\";

    default:
      if (REG_P (operands[2]))
	return \"sal{b}\\t{%b2, %0|%0, %b2}\";
      else if (GET_CODE (operands[2]) == CONST_INT
	       && INTVAL (operands[2]) == 1
	       && (TARGET_PENTIUM || TARGET_PENTIUMPRO))
	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")])

;; See comment above `ashldi3' about how this works.

(define_expand "ashrdi3"
  [(parallel [(set (match_operand:DI 0 "register_operand" "=r")
		   (ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
				(match_operand:QI 2 "nonmemory_operand" "Jc")))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_CMOVE && ! immediate_operand (operands[2], QImode))
    {
      emit_insn (gen_ashrdi3_1 (operands[0], operands[1], operands[2]));
      DONE;
    }
}")

(define_insn "ashrdi3_1"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "Jc")))
   (clobber (match_scratch:SI 3 "=&r"))
   (clobber (reg:CC 17))]
  "TARGET_CMOVE"
  "#"
  [(set_attr "type" "multi")])

(define_insn "*ashrdi3_2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(ashiftrt:DI (match_operand:DI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "Jc")))
   (clobber (reg:CC 17))]
  ""
  "#"
  [(set_attr "type" "multi")])

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_CMOVE && reload_completed"
  [(const_int 0)]
  "ix86_split_ashrdi (operands, operands[3]); DONE;")

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(ashiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(const_int 0)]
  "ix86_split_ashrdi (operands, NULL_RTX); DONE;")

(define_insn "x86_shrd_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "+r*m,r*m")
        (ior:SI (ashiftrt:SI (match_dup 0)
		  (match_operand:QI 2 "nonmemory_operand" "I,c"))
		(ashift:SI (match_operand:SI 1 "register_operand" "r,r")
		  (minus:QI (const_int 32) (match_dup 2)))))
   (clobber (reg:CC 17))]
  ""
  "@
   shrd{l}\\t{%2, %1, %0|%0, %1, %2}
   shrd{l}\\t{%s2%1, %0|%0, %1, %2}"
  [(set_attr "type" "ishift")
   (set_attr "prefix_0f" "1")
   (set_attr "pent_pair" "np")
   (set_attr "ppro_uops" "few")
   (set_attr "mode" "SI")])

(define_expand "x86_shift_adj_3"
  [(use (match_operand:SI 0 "register_operand" ""))
   (use (match_operand:SI 1 "register_operand" ""))
   (use (match_operand:QI 2 "register_operand" ""))]
  ""
  "
{
  rtx label = gen_label_rtx ();
  rtx tmp;

  emit_insn (gen_testqi_ccz_1 (operands[2], GEN_INT (32)));

  tmp = gen_rtx_REG (CCZmode, FLAGS_REG);
  tmp = gen_rtx_EQ (VOIDmode, tmp, const0_rtx);
  tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
			      gen_rtx_LABEL_REF (VOIDmode, label),
			      pc_rtx);
  tmp = emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
  JUMP_LABEL (tmp) = label;

  emit_move_insn (operands[0], operands[1]);
  emit_insn (gen_ashrsi3_31 (operands[1], operands[1], GEN_INT (31)));

  emit_label (label);
  LABEL_NUSES (label) = 1;

  DONE;
}")

(define_insn "ashrsi3_31"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=*d,rm")
	(ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "*a,0")
		     (match_operand:SI 2 "const_int_operand" "i,i")))
   (clobber (reg:CC 17))]
  "INTVAL (operands[2]) == 31 && (TARGET_USE_CLTD || optimize_size)
   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)"
  "@
   {cltd|cdq}
   sar{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "imovx,ishift")
   (set_attr "prefix_0f" "0,*")
   (set_attr "length_immediate" "0,*")
   (set_attr "modrm" "0,1")
   (set_attr "mode" "SI")])

(define_expand "ashrsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (ASHIFTRT, SImode, operands); DONE;")

(define_insn "*ashrsi3_1_one_bit"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ASHIFTRT, SImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "sar{l}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*ashrsi3_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ASHIFTRT, SImode, operands)"
  "@
   sar{l}\\t{%2, %0|%0, %2}
   sar{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "SI")])

;; 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.
(define_insn "*ashrsi3_one_bit_cmpno"
  [(set (reg 17)
	(compare
	  (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "const_int_1_operand" ""))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)
   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)"
  "sar{l}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

;; 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.
(define_insn "*ashrsi3_cmpno"
  [(set (reg 17)
	(compare
	  (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (ASHIFTRT, SImode, operands)"
  "@
   sar{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "SI")])

(define_expand "ashrhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (ASHIFTRT, HImode, operands); DONE;")

(define_insn "*ashrhi3_1_one_bit"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ASHIFTRT, HImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "sar{w}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*ashrhi3_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ASHIFTRT, HImode, operands)"
  "@
   sar{w}\\t{%2, %0|%0, %2}
   sar{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "HI")])

;; 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.
(define_insn "*ashrhi3_one_bit_cmpno"
  [(set (reg 17)
	(compare
	  (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "const_int_1_operand" ""))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)
   && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)"
  "sar{w}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

;; 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.
(define_insn "*ashrhi3_cmpno"
  [(set (reg 17)
	(compare
	  (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (ASHIFTRT, HImode, operands)"
  "@
   sar{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "HI")])

(define_expand "ashrqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (ASHIFTRT, QImode, operands); DONE;")

(define_insn "*ashrqi3_1_one_bit"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ASHIFTRT, QImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "sar{b}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*ashrqi3_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
	(ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ASHIFTRT, QImode, operands)"
  "@
   sar{b}\\t{%2, %0|%0, %2}
   sar{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "QI")])

;; 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.
(define_insn "*ashrqi3_cmpno_one_bit"
  [(set (reg 17)
	(compare
	  (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "const_int_1_operand" "I"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)
   && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)"
  "sar{b}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

;; 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.
(define_insn "*ashrqi3_cmpno"
  [(set (reg 17)
	(compare
	  (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=rm")
	(ashiftrt:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (ASHIFTRT, QImode, operands)"
  "@
   sar{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "QI")])

;; Logical shift instructions

;; See comment above `ashldi3' about how this works.

(define_expand "lshrdi3"
  [(parallel [(set (match_operand:DI 0 "register_operand" "=r")
		   (lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
			        (match_operand:QI 2 "nonmemory_operand" "Jc")))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_CMOVE && ! immediate_operand (operands[2], QImode))
    {
      emit_insn (gen_lshrdi3_1 (operands[0], operands[1], operands[2]));
      DONE;
    }
}")

(define_insn "lshrdi3_1"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "Jc")))
   (clobber (match_scratch:SI 3 "=&r"))
   (clobber (reg:CC 17))]
  "TARGET_CMOVE"
  "#"
  [(set_attr "type" "multi")])

(define_insn "*lshrdi3_2"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "Jc")))
   (clobber (reg:CC 17))]
  ""
  "#"
  [(set_attr "type" "multi")])

(define_split 
  [(set (match_operand:DI 0 "register_operand" "")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_CMOVE && reload_completed"
  [(const_int 0)]
  "ix86_split_lshrdi (operands, operands[3]); DONE;")

(define_split 
  [(set (match_operand:DI 0 "register_operand" "")
	(lshiftrt:DI (match_operand:DI 1 "register_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(const_int 0)]
  "ix86_split_lshrdi (operands, NULL_RTX); DONE;")

(define_expand "lshrsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (LSHIFTRT, SImode, operands); DONE;")

(define_insn "*lshrsi3_1_one_bit"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "shr{l}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*lshrsi3_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
  "@
   shr{l}\\t{%2, %0|%0, %2}
   shr{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "SI")])

;; 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.
(define_insn "*lshrsi3_cmpno_one_bit"
  [(set (reg 17)
	(compare
	  (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "const_int_1_operand" ""))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(lshiftrt:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)
   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
  "shr{l}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

;; 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.
(define_insn "*lshrsi3_cmpno"
  [(set (reg 17)
	(compare
	  (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(lshiftrt:SI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
  "@
   shr{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "SI")])

(define_expand "lshrhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (LSHIFTRT, HImode, operands); DONE;")

(define_insn "*lshrhi3_1_one_bit"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "shr{w}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*lshrhi3_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
  "@
   shr{w}\\t{%2, %0|%0, %2}
   shr{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "HI")])

;; 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.
(define_insn "*lshrhi3_cmpno_one_bit"
  [(set (reg 17)
	(compare
	  (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "const_int_1_operand" ""))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(lshiftrt:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)
   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
  "shr{w}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

;; 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.
(define_insn "*lshrhi3_cmpno"
  [(set (reg 17)
	(compare
	  (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(lshiftrt:HI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (LSHIFTRT, HImode, operands)"
  "@
   shr{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "HI")])

(define_expand "lshrqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (LSHIFTRT, QImode, operands); DONE;")

(define_insn "*lshrqi3_1_one_bit"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (LSHIFTRT, QImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "shr{b}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*lshrqi3_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
	(lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (LSHIFTRT, QImode, operands)"
  "@
   shr{b}\\t{%2, %0|%0, %2}
   shr{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "QI")])

;; 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.
(define_insn "*lshrqi2_cmpno_one_bit"
  [(set (reg 17)
	(compare
	  (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "const_int_1_operand" ""))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(lshiftrt:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)
   && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)"
  "shr{b}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

;; 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.
(define_insn "*lshrqi2_cmpno"
  [(set (reg 17)
	(compare
	  (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		       (match_operand:QI 2 "immediate_operand" "I"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(lshiftrt:QI (match_dup 1) (match_dup 2)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && ix86_binary_operator_ok (LSHIFTRT, QImode, operands)"
  "shr{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "QI")])

;; Rotate instructions

(define_expand "rotlsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(rotate:SI (match_operand:SI 1 "nonimmediate_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (ROTATE, SImode, operands); DONE;")

(define_insn "*rotlsi3_1_one_bit"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		   (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATE, SImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "rol{l}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*rotlsi3_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		   (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATE, SImode, operands)"
  "@
   rol{l}\\t{%2, %0|%0, %2}
   rol{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "SI")])

(define_expand "rotlhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(rotate:HI (match_operand:HI 1 "nonimmediate_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (ROTATE, HImode, operands); DONE;")

(define_insn "*rotlhi3_1_one_bit"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		   (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATE, HImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "rol{w}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*rotlhi3_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		   (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATE, HImode, operands)"
  "@
   rol{w}\\t{%2, %0|%0, %2}
   rol{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "HI")])

(define_expand "rotlqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(rotate:QI (match_operand:QI 1 "nonimmediate_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (ROTATE, QImode, operands); DONE;")

(define_insn "*rotlqi3_1_one_bit"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		   (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATE, QImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "rol{b}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*rotlqi3_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
	(rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		   (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATE, QImode, operands)"
  "@
   rol{b}\\t{%2, %0|%0, %2}
   rol{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "QI")])

(define_expand "rotrsi3"
  [(set (match_operand:SI 0 "nonimmediate_operand" "")
	(rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  ""
  "ix86_expand_binary_operator (ROTATERT, SImode, operands); DONE;")

(define_insn "*rotrsi3_1_one_bit"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATERT, SImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "ror{l}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*rotrsi3_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATERT, SImode, operands)"
  "@
   ror{l}\\t{%2, %0|%0, %2}
   ror{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "SI")])

(define_expand "rotrhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "")
	(rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_HIMODE_MATH"
  "ix86_expand_binary_operator (ROTATERT, HImode, operands); DONE;")

(define_insn "*rotrhi3_one_bit"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATERT, HImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "ror{w}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*rotrhi3"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATERT, HImode, operands)"
  "@
   ror{w}\\t{%2, %0|%0, %2}
   ror{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "HI")])

(define_expand "rotrqi3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "")
	(rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "")
		     (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "TARGET_QIMODE_MATH"
  "ix86_expand_binary_operator (ROTATERT, QImode, operands); DONE;")

(define_insn "*rotrqi3_1_one_bit"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "const_int_1_operand" "")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATERT, QImode, operands)
   && (TARGET_PENTIUM || TARGET_PENTIUMPRO)"
  "ror{b}\\t%0"
  [(set_attr "type" "ishift")
   (set (attr "length") 
     (if_then_else (match_operand:SI 0 "register_operand" "") 
	(const_string "2")
	(const_string "*")))])

(define_insn "*rotrqi3_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,qm")
	(rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c")))
   (clobber (reg:CC 17))]
  "ix86_binary_operator_ok (ROTATERT, QImode, operands)"
  "@
   ror{b}\\t{%2, %0|%0, %2}
   ror{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")
   (set_attr "mode" "QI")])

;; Bit set / bit test instructions

(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" "")))]
  ""
  "
{
  /* Handle extractions from %ah et al.  */
  if (INTVAL (operands[2]) != 8 || INTVAL (operands[3]) != 8)
    FAIL;

  /* From mips.md: extract_bit_field doesn't verify that our source
     matches the predicate, so check it again here.  */
  if (! register_operand (operands[1], VOIDmode))
    FAIL;
}")

(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" "")))]
  ""
  "
{
  /* Handle extractions from %ah et al.  */
  if (INTVAL (operands[2]) != 8 || INTVAL (operands[3]) != 8)
    FAIL;

  /* From mips.md: extract_bit_field doesn't verify that our source
     matches the predicate, so check it again here.  */
  if (! register_operand (operands[1], VOIDmode))
    FAIL;
}")

(define_expand "insv"
  [(set (zero_extract:SI (match_operand 0 "ext_register_operand" "")
			 (match_operand:SI 1 "immediate_operand" "")
			 (match_operand:SI 2 "immediate_operand" ""))
        (match_operand:SI 3 "register_operand" ""))]
  ""
  "
{
  /* Handle extractions from %ah et al.  */
  if (INTVAL (operands[1]) != 8 || INTVAL (operands[2]) != 8)
    FAIL;

  /* From mips.md: insert_bit_field doesn't verify that our source
     matches the predicate, so check it again here.  */
  if (! register_operand (operands[0], VOIDmode))
    FAIL;
}")

;; %%% bts, btr, btc, bt.

;; Store-flag instructions.

;; For all sCOND expanders, also expand the compare or test insn that
;; generates cc0.  Generate an equality comparison if `seq' or `sne'.

;; %%% Do the expansion to SImode.  If PII, do things the xor+setcc way
;; to avoid partial register stalls.  Otherwise do things the setcc+movzx
;; way, which can later delete the movzx if only QImode is needed.

(define_expand "seq"
  [(set (match_operand:SI 0 "register_operand" "")
        (eq:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (EQ, operands[0])) DONE; else FAIL;")

(define_expand "sne"
  [(set (match_operand:SI 0 "register_operand" "")
        (ne:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (NE, operands[0])) DONE; else FAIL;")

(define_expand "sgt"
  [(set (match_operand:SI 0 "register_operand" "")
        (gt:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (GT, operands[0])) DONE; else FAIL;")

(define_expand "sgtu"
  [(set (match_operand:SI 0 "register_operand" "")
        (gtu:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (GTU, operands[0])) DONE; else FAIL;")

(define_expand "slt"
  [(set (match_operand:SI 0 "register_operand" "")
        (lt:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (LT, operands[0])) DONE; else FAIL;")

(define_expand "sltu"
  [(set (match_operand:SI 0 "register_operand" "")
        (ltu:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (LTU, operands[0])) DONE; else FAIL;")

(define_expand "sge"
  [(set (match_operand:SI 0 "register_operand" "")
        (ge:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (GE, operands[0])) DONE; else FAIL;")

(define_expand "sgeu"
  [(set (match_operand:SI 0 "register_operand" "")
        (geu:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (GEU, operands[0])) DONE; else FAIL;")

(define_expand "sle"
  [(set (match_operand:SI 0 "register_operand" "")
        (le:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (LE, operands[0])) DONE; else FAIL;")

(define_expand "sleu"
  [(set (match_operand:SI 0 "register_operand" "")
        (leu:SI (reg:CC 17) (const_int 0)))]
  ""
  "if (ix86_expand_setcc (LEU, operands[0])) DONE; else FAIL;")

(define_expand "sunordered"
  [(set (match_operand:SI 0 "register_operand" "")
        (unordered:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (UNORDERED, operands[0])) DONE; else FAIL;")

(define_expand "sordered"
  [(set (match_operand:SI 0 "register_operand" "")
        (ordered:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (ORDERED, operands[0])) DONE; else FAIL;")

(define_expand "suneq"
  [(set (match_operand:SI 0 "register_operand" "")
        (uneq:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (UNEQ, operands[0])) DONE; else FAIL;")

(define_expand "sunge"
  [(set (match_operand:SI 0 "register_operand" "")
        (unge:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (UNGE, operands[0])) DONE; else FAIL;")

(define_expand "sungt"
  [(set (match_operand:SI 0 "register_operand" "")
        (ungt:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (UNGT, operands[0])) DONE; else FAIL;")

(define_expand "sunle"
  [(set (match_operand:SI 0 "register_operand" "")
        (unle:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (UNLE, operands[0])) DONE; else FAIL;")

(define_expand "sunlt"
  [(set (match_operand:SI 0 "register_operand" "")
        (unlt:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (UNLT, operands[0])) DONE; else FAIL;")

(define_expand "sltgt"
  [(set (match_operand:SI 0 "register_operand" "")
        (ltgt:SI (reg:CC 17) (const_int 0)))]
  "TARGET_80387"
  "if (ix86_expand_setcc (LTGT, operands[0])) DONE; else FAIL;")

(define_insn "*setcc_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(match_operator:QI 1 "no_comparison_operator"
	  [(reg 17) (const_int 0)]))]
  ""
  "set%C1\\t%0"
  [(set_attr "type" "setcc")
   (set_attr "mode" "QI")])

(define_insn "*setcc_2"
  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
	(match_operator:QI 1 "no_comparison_operator"
	  [(reg 17) (const_int 0)]))]
  ""
  "set%C1\\t%0"
  [(set_attr "type" "setcc")
   (set_attr "mode" "QI")])

(define_insn "*setcc_3"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(match_operator:QI 1 "uno_comparison_operator"
	  [(reg:CC 17) (const_int 0)]))]
  ""
  "set%C1\\t%0"
  [(set_attr "type" "setcc")
   (set_attr "mode" "QI")])

(define_insn "*setcc_4"
  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
	(match_operator:QI 1 "uno_comparison_operator"
	  [(reg:CC 17) (const_int 0)]))]
  ""
  "set%C1\\t%0"
  [(set_attr "type" "setcc")
   (set_attr "mode" "QI")])

;; Basic conditional jump instructions.
;; We ignore the overflow flag for signed branch instructions.

;; For all bCOND expanders, also expand the compare or test insn that
;; generates reg 17.  Generate an equality comparison if `beq' or `bne'.

(define_expand "beq"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (EQ, operands[0]); DONE;")

(define_expand "bne"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (NE, operands[0]); DONE;")

(define_expand "bgt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (GT, operands[0]); DONE;")

(define_expand "bgtu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (GTU, operands[0]); DONE;")

(define_expand "blt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (LT, operands[0]); DONE;")

(define_expand "bltu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (LTU, operands[0]); DONE;")

(define_expand "bge"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (GE, operands[0]); DONE;")

(define_expand "bgeu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (GEU, operands[0]); DONE;")

(define_expand "ble"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (LE, operands[0]); DONE;")

(define_expand "bleu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "ix86_expand_branch (LEU, operands[0]); DONE;")

(define_expand "bunordered"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (UNORDERED, operands[0]); DONE;")

(define_expand "bordered"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (ORDERED, operands[0]); DONE;")

(define_expand "buneq"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (UNEQ, operands[0]); DONE;")

(define_expand "bunge"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (UNGE, operands[0]); DONE;")

(define_expand "bungt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (UNGT, operands[0]); DONE;")

(define_expand "bunle"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (UNLE, operands[0]); DONE;")

(define_expand "bunlt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (UNLT, operands[0]); DONE;")

(define_expand "bltgt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  "TARGET_80387"
  "ix86_expand_branch (LTGT, operands[0]); DONE;")

(define_insn "*jcc_1"
  [(set (pc)
	(if_then_else (match_operator 1 "no_comparison_operator"
				      [(reg 17) (const_int 0)])
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "j%C1\\t%l0"
  [(set_attr "type" "ibr")
   (set (attr "prefix_0f")
	   (if_then_else (and (ge (minus (match_dup 0) (pc))
				  (const_int -128))
			      (lt (minus (match_dup 0) (pc))
				  (const_int 124)))
	     (const_int 0)
	     (const_int 1)))])

(define_insn "*jcc_2"
  [(set (pc)
	(if_then_else (match_operator 1 "no_comparison_operator"
				      [(reg 17) (const_int 0)])
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "j%c1\\t%l0"
  [(set_attr "type" "ibr")
   (set (attr "prefix_0f")
	   (if_then_else (and (ge (minus (match_dup 0) (pc))
				  (const_int -128))
			      (lt (minus (match_dup 0) (pc))
				  (const_int 124)))
	     (const_int 0)
	     (const_int 1)))])

(define_insn "*jcc_3"
  [(set (pc)
	(if_then_else (match_operator 1 "uno_comparison_operator"
				      [(reg:CC 17) (const_int 0)])
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "j%C1\\t%l0"
  [(set_attr "type" "ibr")
   (set (attr "prefix_0f")
	   (if_then_else (and (ge (minus (match_dup 0) (pc))
				  (const_int -128))
			      (lt (minus (match_dup 0) (pc))
				  (const_int 124)))
	     (const_int 0)
	     (const_int 1)))])

(define_insn "*jcc_4"
  [(set (pc)
	(if_then_else (match_operator 1 "uno_comparison_operator"
				      [(reg:CC 17) (const_int 0)])
		      (pc)
		      (label_ref (match_operand 0 "" ""))))]
  ""
  "j%c1\\t%l0"
  [(set_attr "type" "ibr")
   (set (attr "prefix_0f")
	   (if_then_else (and (ge (minus (match_dup 0) (pc))
				  (const_int -128))
			      (lt (minus (match_dup 0) (pc))
				  (const_int 124)))
	     (const_int 0)
	     (const_int 1)))])

;; Define combination compare-and-branch fp compare instructions to use
;; during early optimization.  Splitting the operation apart early makes
;; for bad code when we want to reverse the operation.

(define_insn "*fp_jcc_1"
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
			[(match_operand 1 "register_operand" "f")
			 (match_operand 2 "register_operand" "f")])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))]
  "TARGET_CMOVE && TARGET_80387
   && FLOAT_MODE_P (GET_MODE (operands[1]))
   && GET_MODE (operands[1]) == GET_MODE (operands[2])"
  "#")

(define_insn "*fp_jcc_2"
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
			[(match_operand 1 "register_operand" "f")
			 (match_operand 2 "register_operand" "f")])
	  (pc)
	  (label_ref (match_operand 3 "" ""))))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))]
  "TARGET_CMOVE && TARGET_80387
   && FLOAT_MODE_P (GET_MODE (operands[1]))
   && GET_MODE (operands[1]) == GET_MODE (operands[2])"
  "#")

(define_insn "*fp_jcc_3"
  [(set (pc)
	(if_then_else (match_operator:CCFP 0 "comparison_operator"
			[(match_operand 1 "register_operand" "f")
			 (match_operand 2 "nonimmediate_operand" "fm")])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))
   (clobber (match_scratch:HI 4 "=a"))]
  "TARGET_80387
   && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode)
   && GET_MODE (operands[1]) == GET_MODE (operands[2])
   && !ix86_use_fcomi_compare (GET_CODE (operands[0]))"
  "#")

(define_insn "*fp_jcc_4"
  [(set (pc)
	(if_then_else (match_operator:CCFP 0 "comparison_operator"
			[(match_operand 1 "register_operand" "f")
			 (match_operand 2 "nonimmediate_operand" "fm")])
	  (pc)
	  (label_ref (match_operand 3 "" ""))))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))
   (clobber (match_scratch:HI 4 "=a"))]
  "TARGET_80387
   && (GET_MODE (operands[1]) == SFmode || GET_MODE (operands[1]) == DFmode)
   && GET_MODE (operands[1]) == GET_MODE (operands[2])
   && !ix86_use_fcomi_compare (GET_CODE (operands[0]))"
  "#")

(define_insn "*fp_jcc_5"
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
			[(match_operand 1 "register_operand" "f")
			 (match_operand 2 "register_operand" "f")])
	  (label_ref (match_operand 3 "" ""))
	  (pc)))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))
   (clobber (match_scratch:HI 4 "=a"))]
  "TARGET_80387
   && FLOAT_MODE_P (GET_MODE (operands[1]))
   && GET_MODE (operands[1]) == GET_MODE (operands[2])"
  "#")

(define_insn "*fp_jcc_6"
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
			[(match_operand 1 "register_operand" "f")
			 (match_operand 2 "register_operand" "f")])
	  (pc)
	  (label_ref (match_operand 3 "" ""))))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))
   (clobber (match_scratch:HI 4 "=a"))]
  "TARGET_80387
   && FLOAT_MODE_P (GET_MODE (operands[1]))
   && GET_MODE (operands[1]) == GET_MODE (operands[2])"
  "#")

(define_split
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
			[(match_operand 1 "register_operand" "")
			 (match_operand 2 "nonimmediate_operand" "")])
	  (match_operand 3 "" "")
	  (match_operand 4 "" "")))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))]
  "reload_completed"
  [(set (pc)
	(if_then_else (match_dup 5)
	  (match_dup 3)
	  (match_dup 4)))]
  "
{
  operands[5] = ix86_expand_fp_compare (GET_CODE (operands[0]), operands[1],
					operands[2], NULL_RTX);
}")

(define_split
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
			[(match_operand 1 "register_operand" "")
			 (match_operand 2 "nonimmediate_operand" "")])
	  (match_operand 3 "" "")
	  (match_operand 4 "" "")))
   (clobber (reg:CCFP 18))
   (clobber (reg:CCFP 17))
   (clobber (match_scratch:HI 5 "=a"))]
  "reload_completed"
  [(set (pc)
	(if_then_else (match_dup 6)
	  (match_dup 3)
	  (match_dup 4)))]
  "
{
  operands[6] = ix86_expand_fp_compare (GET_CODE (operands[0]), operands[1],
					operands[2], operands[5]);
}")

;; Unconditional and other jump instructions

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
  "jmp\\t%l0"
  [(set_attr "type" "ibr")])

(define_insn "indirect_jump"
  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))]
  ""
  "jmp\\t%*%0"
  [(set_attr "type" "ibr")
   (set_attr "length_immediate" "0")])

(define_insn "tablejump"
  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
   (use (label_ref (match_operand 1 "" "")))]
  "! flag_pic"
  "jmp\\t%*%0"
  [(set_attr "type" "ibr")
   (set_attr "length_immediate" "0")])

;; Implement switch statements when generating PIC code.  Switches are
;; implemented by `tablejump' when not using -fpic.
;;
;; Emit code here to do the range checking and make the index zero based.
;;
;; Each entry in the "addr_diff_vec" looks like this as the result of the
;; two rules below:
;; 
;; 	.long _GLOBAL_OFFSET_TABLE_+[.-.L2]
;; 
;; 1. An expression involving an external reference may only use the
;;    addition operator, and only with an assembly-time constant.
;;    The example above satisfies this because ".-.L2" is a constant.
;; 
;; 2. The symbol _GLOBAL_OFFSET_TABLE_ is magic, and at link time is
;;    given the value of "GOT - .", where GOT is the actual address of
;;    the Global Offset Table.  Therefore, the .long above actually
;;    stores the value "( GOT - . ) + [ . - .L2 ]", or "GOT - .L2".  The
;;    expression "GOT - .L2" by itself would generate an error from as(1).
;; 
;; The pattern below emits code that looks like this:
;; 
;; 	movl %ebx,reg
;; 	subl TABLE@GOTOFF(%ebx,index,4),reg
;; 	jmp reg
;; 
;; The addr_diff_vec contents may be directly referenced with @GOTOFF, since
;; the addr_diff_vec is known to be part of this module.
;; 
;; The subl above calculates "GOT - (( GOT - . ) + [ . - .L2 ])", which
;; evaluates to just ".L2".

(define_expand "casesi"
  [(set (match_dup 5)
	(match_operand:SI 0 "general_operand" ""))
   (parallel [(set (match_dup 6)
		   (minus:SI (match_dup 5)
			     (match_operand:SI 1 "general_operand" "")))
	      (clobber (reg:CC 17))])
   (set (reg:CC 17)
	(compare:CC (match_dup 6)
		    (match_operand:SI 2 "general_operand" "")))
   (set (pc)
	(if_then_else (gtu (reg:CC 17)
			   (const_int 0))
		      (label_ref (match_operand 4 "" ""))
		      (pc)))
   (parallel
     [(set (match_dup 7)
	   (minus:SI (match_dup 8)
	     (mem:SI (plus:SI (plus:SI (mult:SI (match_dup 6) (const_int 4))
			      (match_dup 8))
		     (const (unspec [(label_ref (match_operand 3 "" ""))] 7))))))
      (clobber (reg:CC 17))])
   (parallel [(set (pc) (match_dup 7))
	      (use (label_ref (match_dup 3)))])]
  "flag_pic"
  "
{
  operands[5] = gen_reg_rtx (SImode);
  operands[6] = gen_reg_rtx (SImode);
  operands[7] = gen_reg_rtx (SImode);
  operands[8] = pic_offset_table_rtx;
  current_function_uses_pic_offset_table = 1;
}")

(define_insn "*tablejump_pic"
  [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "rm"))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  "jmp\\t%*%0"
  [(set_attr "type" "ibr")
   (set_attr "length_immediate" "0")])

;; Loop instruction
;;
;; This is all complicated by the fact that since this is a jump insn
;; we must handle our own reloads.

(define_expand "doloop_end"
  [(use (match_operand 0 "" ""))        ; loop pseudo
   (use (match_operand 1 "" ""))        ; iterations; zero if unknown
   (use (match_operand 2 "" ""))        ; max iterations
   (use (match_operand 3 "" ""))        ; loop level 
   (use (match_operand 4 "" ""))]       ; label
  "TARGET_USE_LOOP"
  "                                 
{
  /* Only use cloop on innermost loops.  */
  if (INTVAL (operands[3]) > 1)
    FAIL;
  if (GET_MODE (operands[0]) != SImode)
    FAIL;
  emit_jump_insn (gen_doloop_end_internal (operands[4], operands[0],
					   operands[0]));
  DONE;
}")

(define_insn "doloop_end_internal"
  [(set (pc)
	(if_then_else (ne (match_operand:SI 1 "register_operand" "c,?*r,?*r")
			  (const_int 1))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
   (set (match_operand:SI 2 "register_operand" "=1,1,*m*r")
	(plus:SI (match_dup 1)
		 (const_int -1)))
   (clobber (match_scratch:SI 3 "=X,X,r"))
   (clobber (reg:CC 17))]
  "TARGET_USE_LOOP"
  "*
{
  if (which_alternative != 0)
    return \"#\";
  if (get_attr_length (insn) == 2)
    return \"loop\\t%l0\";
  else
    return \"dec{l}\\t%1\;jne\\t%l0\";
}"
  [(set_attr "ppro_uops" "many")
   (set (attr "type")
	(if_then_else (and (eq_attr "alternative" "0")
			   (and (ge (minus (match_dup 0) (pc))
			            (const_int -128))
			        (lt (minus (match_dup 0) (pc))
			            (const_int 124))))
		      (const_string "ibr")
		      (const_string "multi")))])

(define_split
  [(set (pc)
	(if_then_else (ne (match_operand:SI 1 "register_operand" "")
			  (const_int 1))
		      (match_operand 0 "" "")
		      (pc)))
   (set (match_dup 1)
	(plus:SI (match_dup 1)
		 (const_int -1)))
   (clobber (match_scratch:SI 2 ""))
   (clobber (reg:CC 17))]
  "TARGET_USE_LOOP
   && reload_completed
   && REGNO (operands[1]) != 2"
  [(parallel [(set (reg:CCZ 17)
		   (compare:CCZ (plus:SI (match_dup 1) (const_int -1))
				 (const_int 0)))
	      (set (match_dup 1) (plus:SI (match_dup 1) (const_int -1)))])
   (set (pc) (if_then_else (ne (reg:CCZ 17) (const_int 0))
			   (match_dup 0)
			   (pc)))]
  "")
  
(define_split
  [(set (pc)
	(if_then_else (ne (match_operand:SI 1 "register_operand" "")
			  (const_int 1))
		      (match_operand 0 "" "")
		      (pc)))
   (set (match_operand:SI 2 "nonimmediate_operand" "")
	(plus:SI (match_dup 1)
		 (const_int -1)))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_USE_LOOP
   && reload_completed
   && (! REG_P (operands[2])
       || ! rtx_equal_p (operands[1], operands[2]))"
  [(set (match_dup 3) (match_dup 1))
   (parallel [(set (reg:CCZ 17)
		   (compare:CCZ (plus:SI (match_dup 3) (const_int -1))
				(const_int 0)))
	      (set (match_dup 3) (plus:SI (match_dup 3) (const_int -1)))])
   (set (match_dup 2) (match_dup 3))
   (set (pc) (if_then_else (ne (reg:CCZ 17) (const_int 0))
			   (match_dup 0)
			   (pc)))]
  "")

;; Call instructions.

;; The predicates normally associated with named expanders are not properly
;; checked for calls.  This is a bug in the generic code, but it isn't that
;; easy to fix.  Ignore it for now and be prepared to fix things up.

;; Call subroutine returning no value.

(define_expand "call_pop"
  [(parallel [(call (match_operand:QI 0 "" "")
		    (match_operand:SI 1 "" ""))
	      (set (reg:SI 7)
		   (plus:SI (reg:SI 7)
			    (match_operand:SI 3 "" "")))])]
  ""
  "
{
  if (operands[3] == const0_rtx)
    {
      emit_insn (gen_call (operands[0], operands[1]));
      DONE;
    }
  /* Static functions and indirect calls don't need
     current_function_uses_pic_offset_table.  */
  if (flag_pic
      && constant_call_address_operand (operands[0], SImode)
      && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF
	  || !SYMBOL_REF_FLAG (XEXP (operands[0], 0))))
    current_function_uses_pic_offset_table = 1;
  if (! call_insn_operand (operands[0], QImode))
    XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
}")

(define_insn "*call_pop_0"
  [(call (match_operand:QI 0 "constant_call_address_operand" "")
	 (match_operand:SI 1 "" ""))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
			    (match_operand:SI 3 "immediate_operand" "")))]
  ""
  "*
{
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%P0\";
  else
    return \"call\\t%P0\";
}"
  [(set_attr "type" "call")])
  
(define_insn "*call_pop_1"
  [(call (match_operand:QI 0 "call_insn_operand" "m")
	 (match_operand:SI 1 "" ""))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
			    (match_operand:SI 3 "immediate_operand" "i")))]
  ""
  "*
{
  if (constant_call_address_operand (operands[0], QImode))
    {
      if (SIBLING_CALL_P (insn))
	return \"jmp\\t%P0\";
      else
	return \"call\\t%P0\";
    }
  operands[0] = XEXP (operands[0], 0);
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%*%0\";
  else
    return \"call\\t%*%0\";
}"
  [(set_attr "type" "call")])

(define_expand "call"
  [(call (match_operand:QI 0 "" "")
	 (match_operand:SI 1 "" ""))]
  ;; Operand 1 not used on the i386.
  ""
  "
{
  /* Static functions and indirect calls don't need
     current_function_uses_pic_offset_table.  */
  if (flag_pic
      && constant_call_address_operand (operands[0], SImode)
      && (GET_CODE (XEXP (operands[0], 0)) != SYMBOL_REF
	  || !SYMBOL_REF_FLAG (XEXP (operands[0], 0))))
    current_function_uses_pic_offset_table = 1;
  if (! call_insn_operand (operands[0], QImode))
    XEXP (operands[0], 0) = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
}")

(define_insn "*call_0"
  [(call (match_operand:QI 0 "constant_call_address_operand" "")
	 (match_operand:SI 1 "" ""))]
  ""
  "*
{
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%P0\";
  else
    return \"call\\t%P0\";
}"
  [(set_attr "type" "call")])

(define_insn "*call_1"
  [(call (match_operand:QI 0 "call_insn_operand" "m")
	 (match_operand:SI 1 "" ""))]
  ""
  "*
{
  if (constant_call_address_operand (operands[0], QImode))
    {
      if (SIBLING_CALL_P (insn))
	return \"jmp\\t%P0\";
      else
	return \"call\\t%P0\";
    }
  operands[0] = XEXP (operands[0], 0);
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%*%0\";
  else
    return \"call\\t%*%0\";
}"
  [(set_attr "type" "call")])

;; Call subroutine, returning value in operand 0
;; (which must be a hard register).

(define_expand "call_value_pop"
  [(parallel [(set (match_operand 0 "" "")
		   (call (match_operand:QI 1 "" "")
			 (match_operand:SI 2 "" "")))
	      (set (reg:SI 7)
		   (plus:SI (reg:SI 7)
			    (match_operand:SI 4 "" "")))])]
  ""
  "
{
  if (operands[4] == const0_rtx)
    {
      emit_insn (gen_call_value (operands[0], operands[1], operands[2]));
      DONE;
    }
  /* Static functions and indirect calls don't need
     current_function_uses_pic_offset_table.  */
  if (flag_pic
      && constant_call_address_operand (operands[1], SImode)
      && (GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF
	  || !SYMBOL_REF_FLAG (XEXP (operands[1], 0))))
    current_function_uses_pic_offset_table = 1;
  if (! call_insn_operand (operands[1], QImode))
    XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
}")

(define_expand "call_value"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "" "")
	      (match_operand:SI 2 "" "")))]
  ;; Operand 2 not used on the i386.
  ""
  "
{
  /* Static functions and indirect calls don't need
     current_function_uses_pic_offset_table.  */
  if (flag_pic
      && constant_call_address_operand (operands[1], SImode)
      && (GET_CODE (XEXP (operands[1], 0)) != SYMBOL_REF
	  || !SYMBOL_REF_FLAG (XEXP (operands[1], 0))))
    current_function_uses_pic_offset_table = 1;
  if (! call_insn_operand (operands[1], QImode))
    XEXP (operands[1], 0) = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
}")

;; Call subroutine returning any type.

(define_expand "untyped_call"
  [(parallel [(call (match_operand 0 "" "")
		    (const_int 0))
	      (match_operand 1 "" "")
	      (match_operand 2 "" "")])]
  ""
  "
{
  int i;

  /* In order to give reg-stack an easier job in validating two
     coprocessor registers as containing a possible return value,
     simply pretend the untyped call returns a complex long double
     value.  */

  emit_call_insn (TARGET_80387
                  ? gen_call_value (gen_rtx_REG (XCmode, FIRST_FLOAT_REG),
				    operands[0], const0_rtx)
                  : gen_call (operands[0], const0_rtx));

  for (i = 0; i < XVECLEN (operands[2], 0); i++)
    {
      rtx set = XVECEXP (operands[2], 0, i);
      emit_move_insn (SET_DEST (set), SET_SRC (set));
    }

  /* The optimizer does not know that the call sets the function value
     registers we stored in the result block.  We avoid problems by
     claiming that all hard registers are used and clobbered at this
     point.  */
  emit_insn (gen_blockage ());

  DONE;
}")

;; Prologue and epilogue instructions

;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
;; all of memory.  This blocks insns from being moved across this point.

(define_insn "blockage"
  [(unspec_volatile [(const_int 0)] 0)]
  ""
  ""
  [(set_attr "length" "0")])

;; Insn emitted into the body of a function to return from a function.
;; This is only done if the function's epilogue is known to be simple.
;; See comments for simple_386_epilogue in i386.c.

(define_expand "return"
  [(return)]
  "ix86_can_use_return_insn_p ()"
  "
{
  if (current_function_pops_args)
    {
      rtx popc = GEN_INT (current_function_pops_args);
      emit_jump_insn (gen_return_pop_internal (popc));
      DONE;
    }
}")

(define_insn "return_internal"
  [(return)]
  "reload_completed"
  "ret"
  [(set_attr "length" "1")
   (set_attr "length_immediate" "0")
   (set_attr "modrm" "0")])

(define_insn "return_pop_internal"
  [(return)
   (use (match_operand:SI 0 "const_int_operand" ""))]
  "reload_completed"
  "ret\\t%0"
  [(set_attr "length" "3")
   (set_attr "length_immediate" "2")
   (set_attr "modrm" "0")])

(define_insn "return_indirect_internal"
  [(return)
   (use (match_operand:SI 0 "register_operand" "r"))]
  "reload_completed"
  "jmp\\t%*%0"
  [(set_attr "type" "ibr")
   (set_attr "length_immediate" "0")])

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop"
  [(set_attr "length" "1")
   (set_attr "length_immediate" "0")
   (set_attr "modrm" "0")
   (set_attr "ppro_uops" "one")])

(define_expand "prologue"
  [(const_int 1)]
  ""
  "ix86_expand_prologue (); DONE;")

(define_insn "prologue_set_got"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(unspec_volatile:SI
	 [(plus:SI (match_dup 0)
		   (plus:SI (match_operand:SI 1 "symbolic_operand" "")
			    (minus:SI (pc) (match_operand 2 "" ""))))] 1))
   (clobber (reg:CC 17))]
  ""
  "*
{
  if (GET_CODE (operands[2]) == LABEL_REF)
     operands[2] = XEXP (operands[2], 0);
  if (TARGET_DEEP_BRANCH_PREDICTION) 
    return \"add{l}\\t{%1, %0|%0, %1}\";
  else  
    return \"add{l}\\t{%1+[.-%X2], %0|%0, %a1+(.-%X2)}\";
}"
  [(set_attr "type" "alu")
   ; Since this insn may have two constant operands, we must set the
   ; length manually.
   (set_attr "length_immediate" "4")
   (set_attr "mode" "SI")])

(define_insn "prologue_get_pc"
  [(set (match_operand:SI 0 "register_operand" "=r")
    (unspec_volatile:SI [(plus:SI (pc) (match_operand 1 "" ""))] 2))]
  ""
  "*
{
  if (GET_CODE (operands[1]) == LABEL_REF)
    operands[1] = XEXP (operands[1], 0);
  output_asm_insn (\"call\\t%X1\", operands);
  if (! TARGET_DEEP_BRANCH_PREDICTION)
    {
      ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, \"L\",
				 CODE_LABEL_NUMBER (operands[1]));
    }
  RET;
}"
  [(set_attr "type" "multi")])

(define_expand "epilogue"
  [(const_int 1)]
  ""
  "ix86_expand_epilogue (1); DONE;")

(define_expand "sibcall_epilogue"
  [(const_int 1)]
  ""
  "ix86_expand_epilogue (0); DONE;")

(define_insn "leave"
  [(set (reg:SI 7) (reg:SI 6))
   (set (reg:SI 6) (mem:SI (pre_dec:SI (reg:SI 7))))]
  ""
  "leave"
  [(set_attr "length_immediate" "0")
   (set_attr "length" "1")
   (set_attr "modrm" "0")
   (set_attr "modrm" "0")
   (set_attr "athlon_decode" "vector")
   (set_attr "ppro_uops" "few")])

(define_expand "ffssi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "") 
	(ffs:SI (match_operand:SI 1 "general_operand" "")))]
  ""
  "
{
  rtx out = gen_reg_rtx (SImode), tmp = gen_reg_rtx (SImode);
  rtx in = operands[1];

  if (TARGET_CMOVE)
    {
      emit_move_insn (tmp, constm1_rtx);
      emit_insn (gen_ffssi_1 (out, in));
      emit_insn (gen_rtx_SET (VOIDmode, out,
		  gen_rtx_IF_THEN_ELSE (SImode, 
		    gen_rtx_EQ (VOIDmode, gen_rtx_REG (CCZmode, FLAGS_REG),
				const0_rtx),
		    tmp,
		    out)));
      emit_insn (gen_addsi3 (out, out, const1_rtx));
      emit_move_insn (operands[0], out);
    }

  /* Pentium bsf instruction is extremly slow.  The following code is
     recommended by the Intel Optimizing Manual as a reasonable replacement:
           TEST    EAX,EAX
	   JZ      SHORT BS2
	   XOR     ECX,ECX
	   MOV     DWORD PTR [TEMP+4],ECX
	   SUB     ECX,EAX
	   AND     EAX,ECX
	   MOV     DWORD PTR [TEMP],EAX
	   FILD    QWORD PTR [TEMP]
	   FSTP    QWORD PTR [TEMP]
	   WAIT    ; WAIT only needed for compatibility with
	           ; earlier processors
	   MOV     ECX, DWORD PTR [TEMP+4]
	   SHR     ECX,20
	   SUB     ECX,3FFH
	   TEST    EAX,EAX       ; clear zero flag
       BS2:
     Following piece of code expand ffs to similar beast.
       */

  else if (TARGET_PENTIUM && !optimize_size && TARGET_80387)
    {
      rtx label = gen_label_rtx ();
      rtx lo, hi;
      rtx mem = assign_386_stack_local (DImode, 0);
      rtx fptmp = gen_reg_rtx (DFmode);
      split_di (&mem, 1, &lo, &hi);

      emit_move_insn (out, const0_rtx);

      emit_cmp_and_jump_insns (in, const0_rtx, EQ, 0, SImode, 1, 0, label);

      emit_move_insn (hi, out);
      emit_insn (gen_subsi3 (out, out, in));
      emit_insn (gen_andsi3 (out, out, in));
      emit_move_insn (lo, out);
      emit_insn (gen_floatdidf2 (fptmp,mem));
      emit_move_insn (gen_rtx_MEM (DFmode, XEXP (mem, 0)), fptmp);
      emit_move_insn (out, hi);
      emit_insn (gen_lshrsi3 (out, out, GEN_INT (20)));
      emit_insn (gen_subsi3 (out, out, GEN_INT (0x3ff - 1)));

      emit_label (label);
      LABEL_NUSES (label) = 1;

      emit_move_insn (operands[0], out);
    }
  else
    {
      emit_move_insn (tmp, const0_rtx);
      emit_insn (gen_ffssi_1 (out, in));
      emit_insn (gen_rtx_SET (VOIDmode, 
		  gen_rtx_STRICT_LOW_PART (VOIDmode, gen_lowpart (QImode, tmp)),
		  gen_rtx_EQ (QImode, gen_rtx_REG (CCZmode, FLAGS_REG),
			      const0_rtx)));
      emit_insn (gen_negsi2 (tmp, tmp));
      emit_insn (gen_iorsi3 (out, out, tmp));
      emit_insn (gen_addsi3 (out, out, const1_rtx));
      emit_move_insn (operands[0], out);
    }
  DONE;  
}")

(define_insn "ffssi_1"
  [(set (reg:CCZ 17)
        (compare:CCZ (match_operand:SI 1 "nonimmediate_operand" "rm")
		     (const_int 0)))
   (set (match_operand:SI 0 "register_operand" "=r")
	(unspec:SI [(match_dup 1)] 5))]
  ""
  "bsf{l}\\t{%1, %0|%0, %1}"
  [(set_attr "prefix_0f" "1")
   (set_attr "ppro_uops" "few")])

;; ffshi2 is not useful -- 4 word prefix ops are needed, which is larger
;; and slower than the two-byte movzx insn needed to do the work in SImode.

;; These patterns match the binary 387 instructions for addM3, subM3,
;; mulM3 and divM3.  There are three patterns for each of DFmode and
;; SFmode.  The first is the normal insn, the second the same insn but
;; with one operand a conversion, and the third the same insn but with
;; the other operand a conversion.  The conversion may be SFmode or
;; SImode if the target mode DFmode, but only SImode if the target mode
;; is SFmode.

;; Gcc is slightly more smart about handling normal two address instructions
;; so use special patterns for add and mull.
(define_insn "*fop_sf_comm"
  [(set (match_operand:SF 0 "register_operand" "=f")
	(match_operator:SF 3 "binary_fp_operator"
			[(match_operand:SF 1 "register_operand" "%0")
			 (match_operand:SF 2 "nonimmediate_operand" "fm")]))]
  "TARGET_80387 && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (if_then_else (match_operand:SF 3 "mult_operator" "") 
           (const_string "fmul")
           (const_string "fop")))
   (set_attr "mode" "SF")])

(define_insn "*fop_df_comm"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(match_operator:DF 3 "binary_fp_operator"
			[(match_operand:DF 1 "register_operand" "%0")
			 (match_operand:DF 2 "nonimmediate_operand" "fm")]))]
  "TARGET_80387 && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (if_then_else (match_operand:DF 3 "mult_operator" "") 
           (const_string "fmul")
           (const_string "fop")))
   (set_attr "mode" "DF")])

(define_insn "*fop_xf_comm"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(match_operator:XF 3 "binary_fp_operator"
			[(match_operand:XF 1 "register_operand" "%0")
			 (match_operand:XF 2 "register_operand" "f")]))]
  "TARGET_80387 && GET_RTX_CLASS (GET_CODE (operands[3])) == 'c'"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (if_then_else (match_operand:XF 3 "mult_operator" "") 
           (const_string "fmul")
           (const_string "fop")))
   (set_attr "mode" "XF")])

(define_insn "*fop_sf_1"
  [(set (match_operand:SF 0 "register_operand" "=f,f")
	(match_operator:SF 3 "binary_fp_operator"
			[(match_operand:SF 1 "nonimmediate_operand" "0,fm")
			 (match_operand:SF 2 "nonimmediate_operand" "fm,0")]))]
  "TARGET_80387
   && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'
   && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:SF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:SF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "SF")])

(define_insn "*fop_sf_2"
  [(set (match_operand:SF 0 "register_operand" "=f,f")
	(match_operator:SF 3 "binary_fp_operator"
	  [(float:SF (match_operand:SI 1 "nonimmediate_operand" "m,?r"))
	   (match_operand:SF 2 "register_operand" "0,0")]))]
  "TARGET_80387 && TARGET_USE_FIOP"
  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:SF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:SF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "fp_int_src" "true")
   (set_attr "ppro_uops" "many")
   (set_attr "mode" "SI")])

(define_insn "*fop_sf_3"
  [(set (match_operand:SF 0 "register_operand" "=f,f")
	(match_operator:SF 3 "binary_fp_operator"
	  [(match_operand:SF 1 "register_operand" "0,0")
	   (float:SF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))]
  "TARGET_80387 && TARGET_USE_FIOP"
  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:SF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:SF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "fp_int_src" "true")
   (set_attr "ppro_uops" "many")
   (set_attr "mode" "SI")])

(define_insn "*fop_df_1"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(match_operator:DF 3 "binary_fp_operator"
			[(match_operand:DF 1 "nonimmediate_operand" "0,fm")
			 (match_operand:DF 2 "nonimmediate_operand" "fm,0")]))]
  "TARGET_80387
   && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'
   && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:DF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:DF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "DF")])

(define_insn "*fop_df_2"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(match_operator:DF 3 "binary_fp_operator"
	   [(float:DF (match_operand:SI 1 "nonimmediate_operand" "m,?r"))
	    (match_operand:DF 2 "register_operand" "0,0")]))]
  "TARGET_80387 && TARGET_USE_FIOP"
  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:DF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:DF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "fp_int_src" "true")
   (set_attr "ppro_uops" "many")
   (set_attr "mode" "SI")])

(define_insn "*fop_df_3"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(match_operator:DF 3 "binary_fp_operator"
	   [(match_operand:DF 1 "register_operand" "0,0")
	    (float:DF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))]
  "TARGET_80387 && TARGET_USE_FIOP"
  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:DF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:DF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "fp_int_src" "true")
   (set_attr "ppro_uops" "many")
   (set_attr "mode" "SI")])

(define_insn "*fop_df_4"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(match_operator:DF 3 "binary_fp_operator"
	   [(float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,0"))
	    (match_operand:DF 2 "register_operand" "0,f")]))]
  "TARGET_80387
   && (GET_CODE (operands[1]) != MEM || GET_CODE (operands[2]) != MEM)"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:DF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:DF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "SF")])

(define_insn "*fop_df_5"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(match_operator:DF 3 "binary_fp_operator"
	  [(match_operand:DF 1 "register_operand" "0,f")
	   (float_extend:DF
	    (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
  "TARGET_80387"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:DF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:DF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "SF")])

(define_insn "*fop_xf_1"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(match_operator:XF 3 "binary_fp_operator"
			[(match_operand:XF 1 "register_operand" "0,f")
			 (match_operand:XF 2 "register_operand" "f,0")]))]
  "TARGET_80387
   && GET_RTX_CLASS (GET_CODE (operands[3])) != 'c'"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:XF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:XF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "XF")])

(define_insn "*fop_xf_2"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(match_operator:XF 3 "binary_fp_operator"
	   [(float:XF (match_operand:SI 1 "nonimmediate_operand" "m,?r"))
	    (match_operand:XF 2 "register_operand" "0,0")]))]
  "TARGET_80387 && TARGET_USE_FIOP"
  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:XF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:XF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "fp_int_src" "true")
   (set_attr "mode" "SI")
   (set_attr "ppro_uops" "many")])

(define_insn "*fop_xf_3"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(match_operator:XF 3 "binary_fp_operator"
	  [(match_operand:XF 1 "register_operand" "0,0")
	   (float:XF (match_operand:SI 2 "nonimmediate_operand" "m,?r"))]))]
  "TARGET_80387 && TARGET_USE_FIOP"
  "* return which_alternative ? \"#\" : output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:XF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:XF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "fp_int_src" "true")
   (set_attr "mode" "SI")
   (set_attr "ppro_uops" "many")])

(define_insn "*fop_xf_4"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(match_operator:XF 3 "binary_fp_operator"
	   [(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);"
  [(set (attr "type") 
        (cond [(match_operand:XF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:XF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "SF")])

(define_insn "*fop_xf_5"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(match_operator:XF 3 "binary_fp_operator"
	  [(match_operand:XF 1 "register_operand" "0,f")
	   (float_extend:XF
	    (match_operand:SF 2 "nonimmediate_operand" "fm,0"))]))]
  "TARGET_80387"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:XF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:XF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "SF")])

(define_insn "*fop_xf_6"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(match_operator:XF 3 "binary_fp_operator"
	   [(float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,0"))
	    (match_operand:XF 2 "register_operand" "0,f")]))]
  "TARGET_80387"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:XF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:XF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "DF")])

(define_insn "*fop_xf_7"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(match_operator:XF 3 "binary_fp_operator"
	  [(match_operand:XF 1 "register_operand" "0,f")
	   (float_extend:XF
	    (match_operand:DF 2 "nonimmediate_operand" "fm,0"))]))]
  "TARGET_80387"
  "* return output_387_binary_op (insn, operands);"
  [(set (attr "type") 
        (cond [(match_operand:XF 3 "mult_operator" "") 
                 (const_string "fmul")
               (match_operand:XF 3 "div_operator" "") 
                 (const_string "fdiv")
              ]
              (const_string "fop")))
   (set_attr "mode" "DF")])

(define_split
  [(set (match_operand 0 "register_operand" "")
	(match_operator 3 "binary_fp_operator"
	   [(float (match_operand:SI 1 "register_operand" ""))
	    (match_operand 2 "register_operand" "")]))]
  "TARGET_80387 && reload_completed
   && FLOAT_MODE_P (GET_MODE (operands[0]))"
  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
   (set (match_dup 0)
	(match_op_dup 3 [(match_dup 4) (match_dup 2)]))
   (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
              (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "operands[4] = gen_rtx_FLOAT (GET_MODE (operands[0]),
			       	gen_rtx_MEM (SImode, stack_pointer_rtx));")

(define_split
  [(set (match_operand 0 "register_operand" "")
	(match_operator 3 "binary_fp_operator"
	   [(match_operand 1 "register_operand" "")
	    (float (match_operand:SI 2 "register_operand" ""))]))]
  "TARGET_80387 && reload_completed
   && FLOAT_MODE_P (GET_MODE (operands[0]))"
  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))
   (set (match_dup 0)
	(match_op_dup 3 [(match_dup 1) (match_dup 4)]))
   (parallel [(set (match_dup 2) (mem:SI (reg:SI 7)))
              (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "operands[4] = gen_rtx_FLOAT (GET_MODE (operands[0]),
			       	gen_rtx_MEM (SImode, stack_pointer_rtx));")

;; FPU special functions.

(define_insn "sqrtsf2"
  [(set (match_operand:SF 0 "register_operand" "=f")
	(sqrt:SF (match_operand:SF 1 "register_operand" "0")))]
  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
  "fsqrt"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "SF")
   (set_attr "athlon_decode" "direct")])

(define_insn "sqrtdf2"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(sqrt:DF (match_operand:DF 1 "register_operand" "0")))]
  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
   && (TARGET_IEEE_FP || flag_fast_math) "
  "fsqrt"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "DF")
   (set_attr "athlon_decode" "direct")])

(define_insn "*sqrtextendsfdf2"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(sqrt:DF (float_extend:DF
		  (match_operand:SF 1 "register_operand" "0"))))]
  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
  "fsqrt"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "DF")
   (set_attr "athlon_decode" "direct")])

(define_insn "sqrtxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(sqrt:XF (match_operand:XF 1 "register_operand" "0")))]
  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387 
   && (TARGET_IEEE_FP || flag_fast_math) "
  "fsqrt"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "XF")
   (set_attr "athlon_decode" "direct")])

(define_insn "*sqrtextenddfxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(sqrt:XF (float_extend:XF
		  (match_operand:DF 1 "register_operand" "0"))))]
  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
  "fsqrt"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "XF")
   (set_attr "athlon_decode" "direct")])

(define_insn "*sqrtextendsfxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(sqrt:XF (float_extend:XF
		  (match_operand:SF 1 "register_operand" "0"))))]
  "! TARGET_NO_FANCY_MATH_387 && TARGET_80387"
  "fsqrt"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "XF")
   (set_attr "athlon_decode" "direct")])

(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 && flag_fast_math"
  "fsin"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "DF")])

(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 && flag_fast_math"
  "fsin"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "SF")])

(define_insn "*sinextendsfdf2"
  [(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 && flag_fast_math"
  "fsin"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "DF")])

(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 && flag_fast_math"
  "fsin"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "XF")])

(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 && flag_fast_math"
  "fcos"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "DF")])

(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 && flag_fast_math"
  "fcos"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "SF")])

(define_insn "*cosextendsfdf2"
  [(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 && flag_fast_math"
  "fcos"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "DF")])

(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 && flag_fast_math"
  "fcos"
  [(set_attr "type" "fpspc")
   (set_attr "mode" "XF")])

;; Block operation instructions

(define_insn "cld"
 [(set (reg:SI 19) (const_int 0))]
 ""
 "cld"
  [(set_attr "type" "cld")])

(define_expand "movstrsi"
  [(use (match_operand:BLK 0 "memory_operand" ""))
   (use (match_operand:BLK 1 "memory_operand" ""))
   (use (match_operand:SI 2 "nonmemory_operand" ""))
   (use (match_operand:SI 3 "const_int_operand" ""))]
  ""
  "
{
  rtx srcreg, destreg, countreg;
  int align = 0;
  int count = -1;

  if (GET_CODE (operands[3]) == CONST_INT)
    align = INTVAL (operands[3]);

  /* This simple hack avoids all inlining code and simplifies code bellow.  */
  if (!TARGET_ALIGN_STRINGOPS)
    align = 32;

  if (GET_CODE (operands[2]) == CONST_INT)
    count = INTVAL (operands[2]);

  destreg = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
  srcreg = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));

  emit_insn (gen_cld());

  /* When optimizing for size emit simple rep ; movsb instruction for
     counts not divisible by 4.  */

  if ((!optimize || optimize_size) 
      && (count < 0 || (count & 0x03)))
    {
      countreg = copy_to_mode_reg (SImode, operands[2]);
      emit_insn (gen_rep_movqi (destreg, srcreg, countreg,
      				destreg, srcreg, countreg));
    }

  /* For constant aligned (or small unaligned) copies use rep movsl
     followed by code copying the rest.  For PentiumPro ensure 8 byte
     alignment to allow rep movsl acceleration.  */

  else if (count >= 0 
	   && (align >= 8
	       || (!TARGET_PENTIUMPRO && align >= 4)
	       || optimize_size || count < 64))
    {
      if (count & ~0x03)
	{
	  countreg = copy_to_mode_reg (SImode,
	  			       GEN_INT ((count >> 2)
						& 0x3fffffff));
	  emit_insn (gen_rep_movsi (destreg, srcreg, countreg,
				    destreg, srcreg, countreg));
	}
      if (count & 0x02)
	emit_insn (gen_strmovhi (destreg, srcreg));
      if (count & 0x01)
	emit_insn (gen_strmovqi (destreg, srcreg));
    }
  /* The generic code based on the glibc implementation:
     - align destination to 4 bytes (8 byte alignment is used for PentiumPro
       allowing accelerated copying there)
     - copy the data using rep movsl
     - copy the rest.  */
  else
    {
      rtx countreg2;
      rtx label = NULL;

      /* In case we don't know anything about the alignment, default to
         library version, since it is usually equally fast and result in
	 shorter code.  */
      if (!TARGET_INLINE_ALL_STRINGOPS && align < 4)
	FAIL;

      if (TARGET_SINGLE_STRINGOP)
	emit_insn (gen_cld());

      countreg2 = gen_reg_rtx (SImode);
      countreg = copy_to_mode_reg (SImode, operands[2]);

      /* We don't use loops to align destination and to copy parts smaller
	 than 4 bytes, because gcc is able to optimize such code better (in
	 the case the destination or the count really is aligned, gcc is often
	 able to predict the branches) and also it is friendlier to the
	 hardware branch prediction.  

	 Using loops is benefical for generic case, because we can
	 handle small counts using the loops.  Many CPUs (such as Athlon)
	 have large REP prefix setup costs.

	 This is quite costy.  Maybe we can revisit this decision later or
	 add some customizability to this code.  */

      if (count < 0
	  && align < (TARGET_PENTIUMPRO && (count < 0 || count >= 260) ? 8 : 4))
	{
	  label = gen_label_rtx ();
	  emit_cmp_and_jump_insns (countreg, GEN_INT (3),
				   LEU, 0, SImode, 1, 0, label);
	}
      if (align <= 1)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, destreg, GEN_INT (1)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strmovqi (destreg, srcreg));
	  emit_insn (gen_addsi3 (countreg, countreg, constm1_rtx));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align <= 2)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, destreg, GEN_INT (2)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strmovhi (destreg, srcreg));
	  emit_insn (gen_addsi3 (countreg, countreg, GEN_INT (-2)));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align <= 4 && TARGET_PENTIUMPRO && (count < 1 || count >= 260))
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, destreg, GEN_INT (4)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strmovsi (destreg, srcreg));
	  emit_insn (gen_addsi3 (countreg, countreg, GEN_INT (-4)));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}

      if (!TARGET_SINGLE_STRINGOP)
	emit_insn (gen_cld());
      emit_insn (gen_lshrsi3 (countreg2, countreg, GEN_INT (2)));
      emit_insn (gen_rep_movsi (destreg, srcreg, countreg2,
				destreg, srcreg, countreg2));

      if (label)
	{
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align > 2 && count > 0 && (count & 2))
	emit_insn (gen_strmovhi (destreg, srcreg));
      if (align <= 2 || count < 0)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, countreg, GEN_INT (2)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strmovhi (destreg, srcreg));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align > 1 && count > 0 && (count & 1))
	emit_insn (gen_strmovsi (destreg, srcreg));
      if (align <= 1 || count < 0)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, countreg, GEN_INT (1)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strmovqi (destreg, srcreg));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
    }
  DONE;
}")

;; Most CPUs don't like single string operations
;; Handle this case here to simplify previous expander.

(define_expand "strmovsi"
  [(set (match_dup 2)
  	(mem:SI (match_operand:SI 1 "register_operand" "")))
   (set (mem:SI (match_operand:SI 0 "register_operand" ""))
        (match_dup 2))
   (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 4)))
	      (clobber (reg:CC 17))])
   (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 4)))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_SINGLE_STRINGOP || optimize_size)
    {
      emit_insn (gen_strmovsi_1 (operands[0], operands[1], operands[0],
				operands[1]));
      DONE;
    }
  else 
    operands[2] = gen_reg_rtx (SImode);
}")

(define_expand "strmovhi"
  [(set (match_dup 2)
  	(mem:HI (match_operand:SI 1 "register_operand" "")))
   (set (mem:HI (match_operand:SI 0 "register_operand" ""))
        (match_dup 2))
   (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 2)))
	      (clobber (reg:CC 17))])
   (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 2)))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_SINGLE_STRINGOP || optimize_size)
    {
      emit_insn (gen_strmovhi_1 (operands[0], operands[1], operands[0],
				operands[1]));
      DONE;
    }
  else 
    operands[2] = gen_reg_rtx (HImode);
}")

(define_expand "strmovqi"
  [(set (match_dup 2)
  	(mem:QI (match_operand:SI 1 "register_operand" "")))
   (set (mem:QI (match_operand:SI 0 "register_operand" ""))
        (match_dup 2))
   (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1)))
	      (clobber (reg:CC 17))])
   (parallel [(set (match_dup 1) (plus:SI (match_dup 1) (const_int 1)))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_SINGLE_STRINGOP || optimize_size)
    {
      emit_insn (gen_strmovqi_1 (operands[0], operands[1], operands[0],
				operands[1]));
      DONE;
    }
  else 
    operands[2] = gen_reg_rtx (QImode);
}")

(define_insn "strmovsi_1"
  [(set (mem:SI (match_operand:SI 2 "register_operand" "0"))
	(mem:SI (match_operand:SI 3 "register_operand" "1")))
   (set (match_operand:SI 0 "register_operand" "=D")
	(plus:SI (match_dup 0)
		 (const_int 4)))
   (set (match_operand:SI 1 "register_operand" "=S")
	(plus:SI (match_dup 1)
		 (const_int 4)))
   (use (reg:SI 19))]
  "TARGET_SINGLE_STRINGOP || optimize_size"
  "movsl"
  [(set_attr "type" "str")
   (set_attr "mode" "SI")
   (set_attr "memory" "both")])

(define_insn "strmovhi_1"
  [(set (mem:HI (match_operand:SI 2 "register_operand" "0"))
	(mem:HI (match_operand:SI 3 "register_operand" "1")))
   (set (match_operand:SI 0 "register_operand" "=D")
	(plus:SI (match_dup 0)
		 (const_int 2)))
   (set (match_operand:SI 1 "register_operand" "=S")
	(plus:SI (match_dup 1)
		 (const_int 2)))
   (use (reg:SI 19))]
  "TARGET_SINGLE_STRINGOP || optimize_size"
  "movsw"
  [(set_attr "type" "str")
   (set_attr "memory" "both")
   (set_attr "mode" "HI")])

(define_insn "strmovqi_1"
  [(set (mem:QI (match_operand:SI 2 "register_operand" "0"))
	(mem:QI (match_operand:SI 3 "register_operand" "1")))
   (set (match_operand:SI 0 "register_operand" "=D")
	(plus:SI (match_dup 0)
		 (const_int 1)))
   (set (match_operand:SI 1 "register_operand" "=S")
	(plus:SI (match_dup 1)
		 (const_int 1)))
   (use (reg:SI 19))]
  "TARGET_SINGLE_STRINGOP || optimize_size"
  "movsb"
  [(set_attr "type" "str")
   (set_attr "memory" "both")
   (set_attr "mode" "QI")])

;; It might seem that operands 3 & 4 could use predicate register_operand.
;; But strength reduction might offset the MEM expression.  So we let
;; reload put the address into %edi & %esi.

(define_insn "rep_movsi"
  [(set (match_operand:SI 2 "register_operand" "=c") (const_int 0))
   (use (match_operand:SI 5 "register_operand" "2"))
   (set (match_operand:SI 0 "register_operand" "=D") 
        (plus:SI (match_operand:SI 3 "address_operand" "0")
	         (ashift:SI (match_dup 5) (const_int 2))))
   (set (match_operand:SI 1 "register_operand" "=S") 
        (plus:SI (match_operand:SI 4 "address_operand" "1")
	         (ashift:SI (match_dup 5) (const_int 2))))
   (set (mem:BLK (match_dup 3))
	(mem:BLK (match_dup 4)))
   (use (reg:SI 19))]
  ""
  "rep\;movsl|rep movsd"
  [(set_attr "type" "str")
   (set_attr "prefix_rep" "1")
   (set_attr "memory" "both")
   (set_attr "mode" "SI")])

(define_insn "rep_movqi"
  [(set (match_operand:SI 2 "register_operand" "=c") (const_int 0))
   (use (match_operand:SI 5 "register_operand" "2"))
   (set (match_operand:SI 0 "register_operand" "=D") 
        (plus:SI (match_operand:SI 3 "address_operand" "0") (match_dup 5)))
   (set (match_operand:SI 1 "register_operand" "=S") 
        (plus:SI (match_operand:SI 4 "address_operand" "1") (match_dup 5)))
   (set (mem:BLK (match_dup 3))
	(mem:BLK (match_dup 4)))
   (use (reg:SI 19))]
  ""
  "rep\;movsb|rep movsb"
  [(set_attr "type" "str")
   (set_attr "prefix_rep" "1")
   (set_attr "memory" "both")
   (set_attr "mode" "SI")])

(define_expand "clrstrsi"
   [(use (match_operand:BLK 0 "memory_operand" ""))
    (use (match_operand:SI 1 "nonmemory_operand" ""))
    (use (match_operand:SI 2 "const_int_operand" ""))]
  ""
  "
{
  /* See comments in movstr expanders.  The code is mostly identical.  */

  rtx destreg, zeroreg, countreg;
  int align = 0;
  int count = -1;

  if (GET_CODE (operands[2]) == CONST_INT)
    align = INTVAL (operands[2]);

  /* This simple hack avoids all inlining code and simplifies code bellow.  */
  if (!TARGET_ALIGN_STRINGOPS)
    align = 32;

  if (GET_CODE (operands[1]) == CONST_INT)
    count = INTVAL (operands[1]);

  destreg = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));

  emit_insn (gen_cld());

  /* When optimizing for size emit simple rep ; movsb instruction for
     counts not divisible by 4.  */

  if ((!optimize || optimize_size) 
      && (count < 0 || (count & 0x03)))
    {
      countreg = copy_to_mode_reg (SImode, operands[1]);
      zeroreg = copy_to_mode_reg (QImode, const0_rtx);
      emit_insn (gen_rep_stosqi (destreg, countreg, zeroreg,
				 destreg, countreg));
    }
  else if (count >= 0 
	   && (align >= 8
	       || (!TARGET_PENTIUMPRO && align >= 4)
	       || optimize_size || count < 64))
    {
      zeroreg = copy_to_mode_reg (SImode, const0_rtx);
      if (INTVAL (operands[1]) & ~0x03)
	{
	  countreg = copy_to_mode_reg (SImode,
	  			       GEN_INT ((INTVAL (operands[1]) >> 2)
						& 0x3fffffff));
	  emit_insn (gen_rep_stossi (destreg, countreg, zeroreg,
				     destreg, countreg));
	}
      if (INTVAL (operands[1]) & 0x02)
	emit_insn (gen_strsethi (destreg,
				 gen_rtx_SUBREG (HImode, zeroreg, 0)));
      if (INTVAL (operands[1]) & 0x01)
	emit_insn (gen_strsetqi (destreg,
				 gen_rtx_SUBREG (QImode, zeroreg, 0)));
    }
  else
    {
      rtx countreg2;
      rtx label = NULL;

      /* In case we don't know anything about the alignment, default to
         library version, since it is usually equally fast and result in
	 shorter code.  */
      if (!TARGET_INLINE_ALL_STRINGOPS && align < 4)
	FAIL;

      if (TARGET_SINGLE_STRINGOP)
	emit_insn (gen_cld());

      countreg2 = gen_reg_rtx (SImode);
      countreg = copy_to_mode_reg (SImode, operands[1]);
      zeroreg = copy_to_mode_reg (SImode, const0_rtx);

      if (count < 0
	  && align < (TARGET_PENTIUMPRO && (count < 0 || count >= 260) ? 8 : 4))
	{
	  label = gen_label_rtx ();
	  emit_cmp_and_jump_insns (countreg, GEN_INT (3),
				   LEU, 0, SImode, 1, 0, label);
	}
      if (align <= 1)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, destreg, GEN_INT (1)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strsetqi (destreg,
				   gen_rtx_SUBREG (QImode, zeroreg, 0)));
	  emit_insn (gen_addsi3 (countreg, countreg, constm1_rtx));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align <= 2)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, destreg, GEN_INT (2)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strsethi (destreg,
				   gen_rtx_SUBREG (HImode, zeroreg, 0)));
	  emit_insn (gen_addsi3 (countreg, countreg, GEN_INT (-2)));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align <= 4 && TARGET_PENTIUMPRO && (count < 1 || count >= 260))
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, destreg, GEN_INT (4)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strsetsi (destreg, zeroreg));
	  emit_insn (gen_addsi3 (countreg, countreg, GEN_INT (-4)));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}

      if (!TARGET_SINGLE_STRINGOP)
	emit_insn (gen_cld());
      emit_insn (gen_lshrsi3 (countreg2, countreg, GEN_INT (2)));
      emit_insn (gen_rep_stossi (destreg, countreg2, zeroreg,
				 destreg, countreg2));

      if (label)
	{
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align > 2 && count > 0 && (count & 2))
	emit_insn (gen_strsethi (destreg,
				 gen_rtx_SUBREG (HImode, zeroreg, 0)));
      if (align <= 2 || count < 0)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, countreg, GEN_INT (2)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strsethi (destreg,
				   gen_rtx_SUBREG (HImode, zeroreg, 0)));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
      if (align > 1 && count > 0 && (count & 1))
	emit_insn (gen_strsetqi (destreg,
				 gen_rtx_SUBREG (QImode, zeroreg, 0)));
      if (align <= 1 || count < 0)
	{
	  rtx label = gen_label_rtx ();
	  rtx tmpcount = gen_reg_rtx (SImode);
	  emit_insn (gen_andsi3 (tmpcount, countreg, GEN_INT (1)));
	  emit_cmp_and_jump_insns (tmpcount, GEN_INT (0), EQ, 0,
				   SImode, 1, 0, label);
	  emit_insn (gen_strsetqi (destreg,
				   gen_rtx_SUBREG (QImode, zeroreg, 0)));
	  emit_label (label);
	  LABEL_NUSES (label) = 1;
	}
    }
  DONE;
}")

;; Most CPUs don't like single string operations
;; Handle this case here to simplify previous expander.

(define_expand "strsetsi"
  [(set (mem:SI (match_operand:SI 0 "register_operand" ""))
	(match_operand:SI 1 "register_operand" ""))
   (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 4)))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_SINGLE_STRINGOP || optimize_size)
    {
      emit_insn (gen_strsetsi_1 (operands[0], operands[0], operands[1]));
      DONE;
    }
}")

(define_expand "strsethi"
  [(set (mem:HI (match_operand:SI 0 "register_operand" ""))
	(match_operand:HI 1 "register_operand" ""))
   (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 2)))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_SINGLE_STRINGOP || optimize_size)
    {
      emit_insn (gen_strsethi_1 (operands[0], operands[0], operands[1]));
      DONE;
    }
}")

(define_expand "strsetqi"
  [(set (mem:QI (match_operand:SI 0 "register_operand" ""))
	(match_operand:QI 1 "register_operand" ""))
   (parallel [(set (match_dup 0) (plus:SI (match_dup 0) (const_int 1)))
	      (clobber (reg:CC 17))])]
  ""
  "
{
  if (TARGET_SINGLE_STRINGOP || optimize_size)
    {
      emit_insn (gen_strsetqi_1 (operands[0], operands[0], operands[1]));
      DONE;
    }
}")

(define_insn "strsetsi_1"
  [(set (mem:SI (match_operand:SI 1 "register_operand" "0"))
	(match_operand:SI 2 "register_operand" "a"))
   (set (match_operand:SI 0 "register_operand" "=D")
	(plus:SI (match_dup 0)
		 (const_int 4)))
   (use (reg:SI 19))]
  "TARGET_SINGLE_STRINGOP || optimize_size"
  "stosl"
  [(set_attr "type" "str")
   (set_attr "memory" "store")
   (set_attr "mode" "SI")])

(define_insn "strsethi_1"
  [(set (mem:HI (match_operand:SI 1 "register_operand" "0"))
	(match_operand:HI 2 "register_operand" "a"))
   (set (match_operand:SI 0 "register_operand" "=D")
	(plus:SI (match_dup 0)
		 (const_int 2)))
   (use (reg:SI 19))]
  "TARGET_SINGLE_STRINGOP || optimize_size"
  "stosw"
  [(set_attr "type" "str")
   (set_attr "memory" "store")
   (set_attr "mode" "HI")])

(define_insn "strsetqi_1"
  [(set (mem:QI (match_operand:SI 1 "register_operand" "0"))
	(match_operand:QI 2 "register_operand" "a"))
   (set (match_operand:SI 0 "register_operand" "=D")
	(plus:SI (match_dup 0)
		 (const_int 1)))
   (use (reg:SI 19))]
  "TARGET_SINGLE_STRINGOP || optimize_size"
  "stosb"
  [(set_attr "type" "str")
   (set_attr "memory" "store")
   (set_attr "mode" "QI")])

;; It might seem that operand 0 could use predicate register_operand.
;; But strength reduction might offset the MEM expression.  So we let
;; reload put the address into %edi.

(define_insn "rep_stossi"
  [(set (match_operand:SI 1 "register_operand" "=c") (const_int 0))
   (use (match_operand:SI 2 "register_operand" "a"))
   (use (match_operand:SI 4 "register_operand" "1"))
   (set (match_operand:SI 0 "register_operand" "=D") 
        (plus:SI (match_operand:SI 3 "address_operand" "0")
	         (ashift:SI (match_dup 3) (const_int 2))))
   (set (mem:BLK (match_dup 3))
	(const_int 0))
   (use (reg:SI 19))]
  ""
  "rep\;stosl|rep stosd"
  [(set_attr "type" "str")
   (set_attr "prefix_rep" "1")
   (set_attr "memory" "store")
   (set_attr "mode" "SI")])

(define_insn "rep_stosqi"
  [(set (match_operand:SI 1 "register_operand" "=c") (const_int 0))
   (use (match_operand:QI 2 "register_operand" "a"))
   (use (match_operand:SI 4 "register_operand" "1"))
   (set (match_operand:SI 0 "register_operand" "=D") 
        (plus:SI (match_operand:SI 3 "address_operand" "0") (match_dup 3)))
   (set (mem:BLK (match_dup 3))
	(const_int 0))
   (use (reg:SI 19))]
  ""
  "rep\;stosb|rep stosb"
  [(set_attr "type" "str")
   (set_attr "prefix_rep" "1")
   (set_attr "memory" "store")
   (set_attr "mode" "QI")])

(define_expand "cmpstrsi"
  [(set (match_operand:SI 0 "register_operand" "")
	(compare:SI (match_operand:BLK 1 "general_operand" "")
		    (match_operand:BLK 2 "general_operand" "")))
   (use (match_operand:SI 3 "general_operand" ""))
   (use (match_operand:SI 4 "immediate_operand" ""))]
  ""
  "
{
  rtx addr1, addr2, out, outlow, count, countreg, align;

  out = operands[0];
  if (GET_CODE (out) != REG)
    out = gen_reg_rtx (SImode);

  addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));
  addr2 = copy_to_mode_reg (Pmode, XEXP (operands[2], 0));
  
  count = operands[3];
  countreg = copy_to_mode_reg (SImode, count);

  /* %%% Iff we are testing strict equality, we can use known alignment
     to good advantage.  This may be possible with combine, particularly
     once cc0 is dead.  */
  align = operands[4];

  emit_insn (gen_cld ());
  if (GET_CODE (count) == CONST_INT)
    {
      if (INTVAL (count) == 0)
	{
	  emit_move_insn (operands[0], const0_rtx);
	  DONE;
	}
      emit_insn (gen_cmpstrsi_nz_1 (addr1, addr2, countreg, align));
    }
  else
    {
      emit_insn (gen_cmpsi_1 (countreg, countreg));
      emit_insn (gen_cmpstrsi_1 (addr1, addr2, countreg, align));
    }

  outlow = gen_lowpart (QImode, out);
  emit_insn (gen_cmpintqi (outlow));
  emit_move_insn (out, gen_rtx_SIGN_EXTEND (SImode, outlow));

  if (operands[0] != out)
    emit_move_insn (operands[0], out);

  DONE;
}")

;; Produce a tri-state integer (-1, 0, 1) from condition codes.

(define_expand "cmpintqi"
  [(set (match_dup 1)
	(gtu:QI (reg:CC 17) (const_int 0)))
   (set (match_dup 2)
	(ltu:QI (reg:CC 17) (const_int 0)))
   (parallel [(set (match_operand:QI 0 "register_operand" "")
		   (minus:QI (match_dup 1)
			     (match_dup 2)))
	      (clobber (reg:CC 17))])]
  ""
  "operands[1] = gen_reg_rtx (QImode);
   operands[2] = gen_reg_rtx (QImode);")

;; memcmp recognizers.  The `cmpsb' opcode does nothing if the count is
;; zero.  Emit extra code to make sure that a zero-length compare is EQ.
;;
;; It might seem that operands 0 & 1 could use predicate register_operand.
;; But strength reduction might offset the MEM expression.  So we let
;; reload put the address into %edi & %esi.

(define_insn "cmpstrsi_nz_1"
  [(set (reg:CC 17)
	(compare:CC (mem:BLK (match_operand:SI 0 "address_operand" "S"))
		    (mem:BLK (match_operand:SI 1 "address_operand" "D"))))
   (use (match_operand:SI 2 "register_operand" "c"))
   (use (match_operand:SI 3 "immediate_operand" "i"))
   (use (reg:SI 19))
   (clobber (match_dup 0))
   (clobber (match_dup 1))
   (clobber (match_dup 2))]
  ""
  "repz{\;| }cmpsb"
  [(set_attr "type" "str")
   (set_attr "mode" "QI")
   (set_attr "prefix_rep" "1")])

;; The same, but the count is not known to not be zero.

(define_insn "cmpstrsi_1"
  [(set (reg:CC 17)
	(if_then_else:CC (ne (match_operand:SI 2 "register_operand" "c")
			     (const_int 0))
	  (compare:SI (mem:BLK (match_operand:SI 0 "address_operand" "S"))
		      (mem:BLK (match_operand:SI 1 "address_operand" "D")))
	  (const_int 0)))
   (use (match_operand:SI 3 "immediate_operand" "i"))
   (use (reg:CC 17))
   (use (reg:SI 19))
   (clobber (match_dup 0))
   (clobber (match_dup 1))
   (clobber (match_dup 2))]
  ""
  "repz{\;| }cmpsb"
  [(set_attr "type" "str")
   (set_attr "mode" "QI")
   (set_attr "prefix_rep" "1")])

(define_expand "strlensi"
  [(set (match_operand:SI 0 "register_operand" "")
	(unspec:SI [(match_operand:BLK 1 "general_operand" "")
		    (match_operand:QI 2 "immediate_operand" "")
		    (match_operand:SI 3 "immediate_operand" "")] 0))]
  ""
  "
{
  rtx out, addr, scratch1, scratch2, scratch3;
  rtx eoschar = operands[2];
  rtx align = operands[3];

  /* The generic case of strlen expander is long.  Avoid it's
     expanding unless TARGET_INLINE_ALL_STRINGOPS.  */

  if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1
      && !TARGET_INLINE_ALL_STRINGOPS
      && !optimize_size
      && (GET_CODE (align) != CONST_INT || INTVAL (align) < 4))
    FAIL;

  out = operands[0];
  addr = force_reg (Pmode, XEXP (operands[1], 0));
  scratch1 = gen_reg_rtx (SImode);

  if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1
      && !optimize_size)
    {
      /* Well it seems that some optimizer does not combine a call like
	     foo(strlen(bar), strlen(bar));
	 when the move and the subtraction is done here.  It does calculate
	 the length just once when these instructions are done inside of
	 output_strlen_unroll().  But I think since &bar[strlen(bar)] is
	 often used and I use one fewer register for the lifetime of
	 output_strlen_unroll() this is better.  */

      if (GET_CODE (align) != CONST_INT || INTVAL (align) < 4)
	emit_move_insn (scratch1, addr);

      emit_move_insn (out, addr);

      ix86_expand_strlensi_unroll_1 (out, align, scratch1);

      /* strlensi_unroll_1 returns the address of the zero at the end of
	 the string, like memchr(), so compute the length by subtracting
	 the start address.  */
      emit_insn (gen_subsi3 (out, out, addr));
    }
  else
    {
      scratch2 = gen_reg_rtx (SImode);
      scratch3 = gen_reg_rtx (SImode);

      emit_move_insn (scratch3, addr);

      emit_insn (gen_cld ());
      emit_insn (gen_strlensi_1 (scratch1, scratch3, eoschar,
				 align, constm1_rtx));
      emit_insn (gen_one_cmplsi2 (scratch2, scratch1));
      emit_insn (gen_addsi3 (out, scratch2, constm1_rtx));
    }
  DONE;
}")

;; It might seem that operands 0 & 1 could use predicate register_operand.
;; But strength reduction might offset the MEM expression.  So we let
;; reload put the address into %edi.

(define_insn "strlensi_1"
  [(set (match_operand:SI 0 "register_operand" "=&c")
	(unspec:SI [(mem:BLK (match_operand:SI 1 "address_operand" "D"))
		    (match_operand:QI 2 "general_operand" "a")
		    (match_operand:SI 3 "immediate_operand" "i")
		    (match_operand:SI 4 "immediate_operand" "0")] 0))
   (use (reg:SI 19))
   (clobber (match_dup 1))
   (clobber (reg:CC 17))]
  ""
  "repnz{\;| }scasb"
  [(set_attr "type" "str")
   (set_attr "mode" "QI")
   (set_attr "prefix_rep" "1")])

;; Conditional move instructions.

(define_expand "movsicc"
  [(set (match_operand:SI 0 "register_operand" "")
	(if_then_else:SI (match_operand 1 "comparison_operator" "")
			 (match_operand:SI 2 "general_operand" "")
			 (match_operand:SI 3 "general_operand" "")))]
  ""
  "if (!ix86_expand_int_movcc (operands)) FAIL; DONE;")

;; Data flow gets confused by our desire for `sbbl reg,reg', and clearing
;; the register first winds up with `sbbl $0,reg', which is also weird.
;; So just document what we're doing explicitly.

(define_insn "x86_movsicc_0_m1"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(if_then_else:SI (ltu (reg:CC 17) (const_int 0))
	  (const_int -1)
	  (const_int 0)))
   (clobber (reg:CC 17))]
  ""
  "sbb{l}\\t%0, %0"
  ; Since we don't have the proper number of operands for an alu insn,
  ; fill in all the blanks.
  [(set_attr "type" "alu")
   (set_attr "memory" "none")
   (set_attr "imm_disp" "false")
   (set_attr "mode" "SI")
   (set_attr "length_immediate" "0")])

(define_insn "*movsicc_noc"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(if_then_else:SI (match_operator 1 "no_comparison_operator" 
				[(reg 17) (const_int 0)])
		      (match_operand:SI 2 "nonimmediate_operand" "rm,0")
		      (match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
  "TARGET_CMOVE
   && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")
   (set_attr "mode" "SI")])

(define_insn "*movsicc_c"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(if_then_else:SI (match_operator 1 "uno_comparison_operator" 
				[(reg:CC 17) (const_int 0)])
		      (match_operand:SI 2 "nonimmediate_operand" "rm,0")
		      (match_operand:SI 3 "nonimmediate_operand" "0,rm")))]
  "TARGET_CMOVE
   && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")
   (set_attr "mode" "SI")])

(define_expand "movhicc"
  [(set (match_operand:HI 0 "register_operand" "")
	(if_then_else:HI (match_operand 1 "comparison_operator" "")
			 (match_operand:HI 2 "nonimmediate_operand" "")
			 (match_operand:HI 3 "nonimmediate_operand" "")))]
  "TARGET_CMOVE && TARGET_HIMODE_MATH"
  "if (!ix86_expand_int_movcc (operands)) FAIL; DONE;")

(define_insn "*movhicc_noc"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(if_then_else:HI (match_operator 1 "no_comparison_operator" 
				[(reg 17) (const_int 0)])
		      (match_operand:HI 2 "nonimmediate_operand" "rm,0")
		      (match_operand:HI 3 "nonimmediate_operand" "0,rm")))]
  "TARGET_CMOVE
   && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")
   (set_attr "mode" "HI")])

(define_insn "*movhicc_c"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(if_then_else:HI (match_operator 1 "uno_comparison_operator" 
				[(reg:CC 17) (const_int 0)])
		      (match_operand:HI 2 "nonimmediate_operand" "rm,0")
		      (match_operand:HI 3 "nonimmediate_operand" "0,rm")))]
  "TARGET_CMOVE
   && (GET_CODE (operands[2]) != MEM || GET_CODE (operands[3]) != MEM)"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")
   (set_attr "mode" "HI")])

(define_expand "movsfcc"
  [(set (match_operand:SF 0 "register_operand" "")
	(if_then_else:SF (match_operand 1 "comparison_operator" "")
			 (match_operand:SF 2 "register_operand" "")
			 (match_operand:SF 3 "register_operand" "")))]
  "TARGET_CMOVE"
  "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")

(define_insn "*movsfcc_1"
  [(set (match_operand:SF 0 "register_operand" "=f,f")
	(if_then_else:SF (match_operator 1 "fcmov_comparison_operator" 
				[(reg 17) (const_int 0)])
		      (match_operand:SF 2 "register_operand" "f,0")
		      (match_operand:SF 3 "register_operand" "0,f")))]
  "TARGET_CMOVE"
  "@
   fcmov%F1\\t{%2, %0|%0, %2}
   fcmov%f1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "fcmov")
   (set_attr "mode" "SF")])

(define_expand "movdfcc"
  [(set (match_operand:DF 0 "register_operand" "")
	(if_then_else:DF (match_operand 1 "comparison_operator" "")
			 (match_operand:DF 2 "register_operand" "")
			 (match_operand:DF 3 "register_operand" "")))]
  "TARGET_CMOVE"
  "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")

(define_insn "*movdfcc_1"
  [(set (match_operand:DF 0 "register_operand" "=f,f")
	(if_then_else:DF (match_operator 1 "fcmov_comparison_operator" 
				[(reg 17) (const_int 0)])
		      (match_operand:DF 2 "register_operand" "f,0")
		      (match_operand:DF 3 "register_operand" "0,f")))]
  "TARGET_CMOVE"
  "@
   fcmov%F1\\t{%2, %0|%0, %2}
   fcmov%f1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "fcmov")
   (set_attr "mode" "DF")])

(define_expand "movxfcc"
  [(set (match_operand:XF 0 "register_operand" "")
	(if_then_else:XF (match_operand 1 "comparison_operator" "")
			 (match_operand:XF 2 "register_operand" "")
			 (match_operand:XF 3 "register_operand" "")))]
  "TARGET_CMOVE"
  "if (! ix86_expand_fp_movcc (operands)) FAIL; DONE;")

(define_insn "*movxfcc_1"
  [(set (match_operand:XF 0 "register_operand" "=f,f")
	(if_then_else:XF (match_operator 1 "fcmov_comparison_operator" 
				[(reg 17) (const_int 0)])
		      (match_operand:XF 2 "register_operand" "f,0")
		      (match_operand:XF 3 "register_operand" "0,f")))]
  "TARGET_CMOVE"
  "@
   fcmov%F1\\t{%2, %0|%0, %2}
   fcmov%f1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "fcmov")
   (set_attr "mode" "XF")])

;; Misc patterns (?)

;; This pattern exists to put a dependancy on all ebp-based memory accesses.
;; Otherwise there will be nothing to keep
;; 
;; [(set (reg ebp) (reg esp))]
;; [(set (reg esp) (plus (reg esp) (const_int -160000)))
;;  (clobber (eflags)]
;; [(set (mem (plus (reg ebp) (const_int -160000))) (const_int 0))]
;;
;; in proper program order.

(define_insn "pro_epilogue_adjust_stack"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(plus:SI (match_operand:SI 1 "register_operand" "0,r")
	         (match_operand:SI 2 "immediate_operand" "i,i")))
   (set (match_operand:SI 3 "register_operand" "+r,r")
	(match_dup 3))
   (clobber (reg:CC 17))]
  ""
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_IMOV:
      return \"mov{l}\\t{%1, %0|%0, %1}\";

    case TYPE_ALU:
      if (GET_CODE (operands[2]) == CONST_INT
          && (INTVAL (operands[2]) == 128
	      || (INTVAL (operands[2]) < 0
	          && INTVAL (operands[2]) != -128)))
	{
	  operands[2] = GEN_INT (-INTVAL (operands[2]));
	  return \"sub{l}\\t{%2, %0|%0, %2}\";
	}
      return \"add{l}\\t{%2, %0|%0, %2}\";

    case TYPE_LEA:
      operands[2] = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
      return \"lea{l}\\t{%a2, %0|%0, %a2}\";

    default:
      abort ();
    }
}"
  [(set (attr "type")
	(cond [(eq_attr "alternative" "0")
		 (const_string "alu")
	       (match_operand:SI 2 "const0_operand" "")
		 (const_string "imov")
	      ]
	      (const_string "lea")))
   (set_attr "mode" "SI")])

(define_insn "allocate_stack_worker"
  [(unspec:SI [(match_operand:SI 0 "register_operand" "a")] 3)
   (set (reg:SI 7) (minus:SI (reg:SI 7) (match_dup 0)))
   (clobber (match_dup 0))
   (clobber (reg:CC 17))]
  "TARGET_STACK_PROBE"
  "call\\t__alloca"
  [(set_attr "type" "multi")
   (set_attr "length" "5")])

(define_expand "allocate_stack"
  [(parallel [(set (match_operand:SI 0 "register_operand" "=r")
		   (minus:SI (reg:SI 7)
			     (match_operand:SI 1 "general_operand" "")))
	      (clobber (reg:CC 17))])
   (parallel [(set (reg:SI 7)
		   (minus:SI (reg:SI 7) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "TARGET_STACK_PROBE"
  "
{
#ifdef CHECK_STACK_LIMIT
  if (GET_CODE (operands[1]) == CONST_INT
      && INTVAL (operands[1]) < CHECK_STACK_LIMIT)
    emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx,
			   operands[1]));
  else 
#endif
    emit_insn (gen_allocate_stack_worker (copy_to_mode_reg (SImode,
							    operands[1])));

  emit_move_insn (operands[0], virtual_stack_dynamic_rtx);
  DONE;
}")

(define_expand "exception_receiver"
  [(const_int 0)]
  "flag_pic"
  "
{
  load_pic_register ();
  DONE;
}")

(define_expand "builtin_setjmp_receiver"
  [(label_ref (match_operand 0 "" ""))]
  "flag_pic"
  "
{
  load_pic_register ();
  DONE;
}")

;; Avoid redundant prefixes by splitting HImode arithmetic to SImode.

(define_split
  [(set (match_operand 0 "register_operand" "")
	(match_operator 3 "promotable_binary_operator"
	   [(match_operand 1 "register_operand" "")
	    (match_operand 2 "aligned_operand" "")]))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed
   && ((GET_MODE (operands[0]) == HImode 
	&& (!optimize_size || GET_CODE (operands[2]) != CONST_INT
	    || CONST_OK_FOR_LETTER_P (INTVAL (operands[2]), 'K')))
       || (GET_MODE (operands[0]) == QImode 
	   && (TARGET_PROMOTE_QImode || optimize_size)))"
  [(parallel [(set (match_dup 0)
		   (match_op_dup 3 [(match_dup 1) (match_dup 2)]))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
   if (GET_CODE (operands[3]) != ASHIFT)
     operands[2] = gen_lowpart (SImode, operands[2]);
   GET_MODE (operands[3]) = SImode;")

(define_split
  [(set (reg 17)
	(compare (and (match_operand 1 "aligned_operand" "")
		      (match_operand 2 "const_int_operand" ""))
		 (const_int 0)))
   (set (match_operand 0 "register_operand" "")
	(and (match_dup 1) (match_dup 2)))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed
   && ix86_match_ccmode (insn, CCNOmode)
   && (GET_MODE (operands[0]) == HImode
       || (GET_MODE (operands[0]) == QImode 
	   && (TARGET_PROMOTE_QImode || optimize_size)))"
  [(parallel [(set (reg:CCNO 17)
		   (compare:CCNO (and:SI (match_dup 1) (match_dup 2))
			         (const_int 0)))
	      (set (match_dup 0)
		   (and:SI (match_dup 1) (match_dup 2)))])]
  "operands[2]
     = GEN_INT (INTVAL (operands[2]) & GET_MODE_MASK (GET_MODE (operands[0])));
   operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);")

(define_split
  [(set (reg 17)
	(compare (and (match_operand 0 "aligned_operand" "")
		      (match_operand 1 "const_int_operand" ""))
		 (const_int 0)))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed
   && ix86_match_ccmode (insn, CCNOmode)
   && (GET_MODE (operands[0]) == HImode
       || (GET_MODE (operands[0]) == QImode 
	   && (TARGET_PROMOTE_QImode || optimize_size)))"
  [(set (reg:CCNO 17)
	(compare:CCNO (and:SI (match_dup 0) (match_dup 1))
		      (const_int 0)))]
  "operands[1]
     = GEN_INT (INTVAL (operands[1]) & GET_MODE_MASK (GET_MODE (operands[0])));
   operands[0] = gen_lowpart (SImode, operands[0]);")

(define_split
  [(set (match_operand 0 "register_operand" "")
	(neg (match_operand 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed
   && (GET_MODE (operands[0]) == HImode
       || (GET_MODE (operands[0]) == QImode 
	   && (TARGET_PROMOTE_QImode || optimize_size)))"
  [(parallel [(set (match_dup 0)
		   (neg:SI (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);")

(define_split
  [(set (match_operand 0 "register_operand" "")
	(not (match_operand 1 "register_operand" "")))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed
   && (GET_MODE (operands[0]) == HImode
       || (GET_MODE (operands[0]) == QImode 
	   && (TARGET_PROMOTE_QImode || optimize_size)))"
  [(set (match_dup 0)
	(not:SI (match_dup 1)))]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);")

(define_split 
  [(set (match_operand 0 "register_operand" "")
	(if_then_else (match_operator 1 "comparison_operator" 
				[(reg 17) (const_int 0)])
		      (match_operand 2 "register_operand" "")
		      (match_operand 3 "register_operand" "")))]
  "! TARGET_PARTIAL_REG_STALL && TARGET_CMOVE
   && (GET_MODE (operands[0]) == HImode
       || (GET_MODE (operands[0]) == QImode 
	   && (TARGET_PROMOTE_QImode || optimize_size)))"
  [(set (match_dup 0)
	(if_then_else:SI (match_dup 1) (match_dup 2) (match_dup 3)))]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[2] = gen_lowpart (SImode, operands[2]);
   operands[3] = gen_lowpart (SImode, operands[3]);")
			

;; RTL Peephole optimizations, run before sched2.  These primarily look to
;; transform a complex memory operation into two memory to register operations.

;; Don't push memory operands
(define_peephole2
  [(set (match_operand:SI 0 "push_operand" "")
	(match_operand:SI 1 "memory_operand" ""))
   (match_scratch:SI 2 "r")]
  "! optimize_size && ! TARGET_PUSH_MEMORY"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

;; We need to handle SFmode only, because DFmode and XFmode is split to
;; SImode pushes.
(define_peephole2
  [(set (match_operand:SF 0 "push_operand" "")
	(match_operand:SF 1 "memory_operand" ""))
   (match_scratch:SF 2 "r")]
  "! optimize_size && ! TARGET_PUSH_MEMORY"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

(define_peephole2
  [(set (match_operand:HI 0 "push_operand" "")
	(match_operand:HI 1 "memory_operand" ""))
   (match_scratch:HI 2 "r")]
  "! optimize_size && ! TARGET_PUSH_MEMORY"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

(define_peephole2
  [(set (match_operand:QI 0 "push_operand" "")
	(match_operand:QI 1 "memory_operand" ""))
   (match_scratch:QI 2 "q")]
  "! optimize_size && ! TARGET_PUSH_MEMORY"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

;; Don't move an immediate directly to memory when the instruction
;; gets too big.
(define_peephole2
  [(match_scratch:SI 1 "r")
   (set (match_operand:SI 0 "memory_operand" "")
        (const_int 0))]
  "! optimize_size
   && ! TARGET_USE_MOV0
   && TARGET_SPLIT_LONG_MOVES
   && get_attr_length (insn) >= ix86_cost->large_insn
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 1) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (match_dup 0) (match_dup 1))]
  "")

(define_peephole2
  [(match_scratch:HI 1 "r")
   (set (match_operand:HI 0 "memory_operand" "")
        (const_int 0))]
  "! optimize_size
   && ! TARGET_USE_MOV0
   && TARGET_SPLIT_LONG_MOVES
   && get_attr_length (insn) >= ix86_cost->large_insn
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 2) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (match_dup 0) (match_dup 1))]
  "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));")

(define_peephole2
  [(match_scratch:QI 1 "q")
   (set (match_operand:QI 0 "memory_operand" "")
        (const_int 0))]
  "! optimize_size
   && ! TARGET_USE_MOV0
   && TARGET_SPLIT_LONG_MOVES
   && get_attr_length (insn) >= ix86_cost->large_insn
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 2) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (match_dup 0) (match_dup 1))]
  "operands[2] = gen_rtx_REG (SImode, true_regnum (operands[1]));")

(define_peephole2
  [(match_scratch:SI 2 "r")
   (set (match_operand:SI 0 "memory_operand" "")
        (match_operand:SI 1 "immediate_operand" ""))]
  "! optimize_size
   && get_attr_length (insn) >= ix86_cost->large_insn
   && TARGET_SPLIT_LONG_MOVES"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

(define_peephole2
  [(match_scratch:HI 2 "r")
   (set (match_operand:HI 0 "memory_operand" "")
        (match_operand:HI 1 "immediate_operand" ""))]
  "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
  && TARGET_SPLIT_LONG_MOVES"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

(define_peephole2
  [(match_scratch:QI 2 "q")
   (set (match_operand:QI 0 "memory_operand" "")
        (match_operand:QI 1 "immediate_operand" ""))]
  "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
  && TARGET_SPLIT_LONG_MOVES"
  [(set (match_dup 2) (match_dup 1))
   (set (match_dup 0) (match_dup 2))]
  "")

;; Don't compare memory with zero, load and use a test instead.
(define_peephole2
  [(set (reg 17)
	(compare (match_operand:SI 0 "memory_operand" "")
	         (const_int 0)))
   (match_scratch:SI 3 "r")]
  "ix86_match_ccmode (insn, CCNOmode) && ! optimize_size"
  [(set (match_dup 3) (match_dup 0))
   (set (reg:CCNO 17) (compare:CCNO (match_dup 3) (const_int 0)))]
  "")

;; NOT is not pairable on Pentium, while XOR is, but one byte longer. 
;; Don't split NOTs with a displacement operand, because resulting XOR
;; will not be pariable anyway.
;;
;; On AMD K6, NOT is vector decoded with memory operand that can not be
;; represented using a modRM byte.  The XOR replacement is long decoded,
;; so this split helps here as well.
;;
;; Note: Can't do this as a regular split because we can't get proper
;; lifetime information then.

(define_peephole2
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
  "!optimize_size
   && peep2_regno_dead_p (0, FLAGS_REG)
   && ((TARGET_PENTIUM 
        && (GET_CODE (operands[0]) != MEM
            || !memory_displacement_operand (operands[0], SImode)))
       || (TARGET_K6 && long_memory_operand (operands[0], SImode)))"
  [(parallel [(set (match_dup 0)
		   (xor:SI (match_dup 1) (const_int -1)))
	      (clobber (reg:CC 17))])]
  "")

(define_peephole2
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
  "!optimize_size
   && peep2_regno_dead_p (0, FLAGS_REG)
   && ((TARGET_PENTIUM 
        && (GET_CODE (operands[0]) != MEM
            || !memory_displacement_operand (operands[0], HImode)))
       || (TARGET_K6 && long_memory_operand (operands[0], HImode)))"
  [(parallel [(set (match_dup 0)
		   (xor:HI (match_dup 1) (const_int -1)))
	      (clobber (reg:CC 17))])]
  "")

(define_peephole2
  [(set (match_operand:QI 0 "nonimmediate_operand" "=rm")
	(not:QI (match_operand:QI 1 "nonimmediate_operand" "0")))]
  "!optimize_size
   && peep2_regno_dead_p (0, FLAGS_REG)
   && ((TARGET_PENTIUM 
        && (GET_CODE (operands[0]) != MEM
            || !memory_displacement_operand (operands[0], QImode)))
       || (TARGET_K6 && long_memory_operand (operands[0], QImode)))"
  [(parallel [(set (match_dup 0)
		   (xor:QI (match_dup 1) (const_int -1)))
	      (clobber (reg:CC 17))])]
  "")

;; Non pairable "test imm, reg" instructions can be translated to
;; "and imm, reg" if reg dies.  The "and" form is also shorter (one
;; byte opcode instead of two, have a short form for byte operands),
;; so do it for other CPUs as well.  Given that the value was dead,
;; this should not create any new dependancies.  Pass on the sub-word
;; versions if we're concerned about partial register stalls.

(define_peephole2
  [(set (reg 17)
	(compare (and:SI (match_operand:SI 0 "register_operand" "")
			 (match_operand:SI 1 "immediate_operand" ""))
		 (const_int 0)))]
  "ix86_match_ccmode (insn, CCNOmode)
   && (true_regnum (operands[0]) != 0
       || CONST_OK_FOR_LETTER_P (INTVAL (operands[1]), 'K'))
   && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))"
  [(parallel
     [(set (reg:CCNO 17)
	   (compare:CCNO (and:SI (match_dup 0)
			         (match_dup 1))
		         (const_int 0)))
      (set (match_dup 0)
	   (and:SI (match_dup 0) (match_dup 1)))])]
  "")

;; We don't need to handle HImode case, because it will be promoted to SImode
;; on ! TARGET_PARTIAL_REG_STALL

(define_peephole2
  [(set (reg 17)
	(compare (and:QI (match_operand:QI 0 "register_operand" "")
			 (match_operand:QI 1 "immediate_operand" ""))
		 (const_int 0)))]
  "! TARGET_PARTIAL_REG_STALL
   && ix86_match_ccmode (insn, CCNOmode)
   && true_regnum (operands[0]) != 0
   && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))"
  [(parallel
     [(set (reg:CCNO 17)
	   (compare:CCNO (and:QI (match_dup 0)
 			         (match_dup 1))
		         (const_int 0)))
      (set (match_dup 0)
	   (and:QI (match_dup 0) (match_dup 1)))])]
  "")

(define_peephole2
  [(set (reg 17)
	(compare
	  (and:SI
	    (zero_extract:SI
	      (match_operand 0 "ext_register_operand" "q")
	      (const_int 8)
	      (const_int 8))
	    (match_operand 1 "const_int_operand" "n"))
	  (const_int 0)))]
  "! TARGET_PARTIAL_REG_STALL
   && ix86_match_ccmode (insn, CCNOmode)
   && true_regnum (operands[0]) != 0
   && find_regno_note (insn, REG_DEAD, true_regnum (operands[0]))"
  [(parallel [(set (reg:CCNO 17)
		   (compare:CCNO
		       (and:SI
			 (zero_extract:SI
			 (match_dup 0)
			 (const_int 8)
			 (const_int 8))
			(match_dup 1))
		   (const_int 0)))
	      (set (zero_extract:SI (match_dup 0)
				    (const_int 8)
				    (const_int 8))
		   (and:SI 
		     (zero_extract:SI
		       (match_dup 0)
		       (const_int 8)
		       (const_int 8))
		     (match_dup 1)))])]
  "")

;; Don't do logical operations with memory inputs.
(define_peephole2
  [(match_scratch:SI 2 "r")
   (parallel [(set (match_operand:SI 0 "register_operand" "")
                   (match_operator:SI 3 "arith_or_logical_operator"
                     [(match_dup 0)
                      (match_operand:SI 1 "memory_operand" "")]))
              (clobber (reg:CC 17))])]
  "! optimize_size && ! TARGET_READ_MODIFY"
  [(set (match_dup 2) (match_dup 1))
   (parallel [(set (match_dup 0)
                   (match_op_dup 3 [(match_dup 0) (match_dup 2)]))
              (clobber (reg:CC 17))])]
  "")

(define_peephole2
  [(match_scratch:SI 2 "r")
   (parallel [(set (match_operand:SI 0 "register_operand" "")
                   (match_operator:SI 3 "arith_or_logical_operator"
                     [(match_operand:SI 1 "memory_operand" "")
                      (match_dup 0)]))
              (clobber (reg:CC 17))])]
  "! optimize_size && ! TARGET_READ_MODIFY"
  [(set (match_dup 2) (match_dup 1))
   (parallel [(set (match_dup 0)
                   (match_op_dup 3 [(match_dup 2) (match_dup 0)]))
              (clobber (reg:CC 17))])]
  "")

; Don't do logical operations with memory outputs
;
; These two don't make sense for PPro/PII -- we're expanding a 4-uop
; instruction into two 1-uop insns plus a 2-uop insn.  That last has
; the same decoder scheduling characteristics as the original.

(define_peephole2
  [(match_scratch:SI 2 "r")
   (parallel [(set (match_operand:SI 0 "memory_operand" "")
                   (match_operator:SI 3 "arith_or_logical_operator"
                     [(match_dup 0)
                      (match_operand:SI 1 "nonmemory_operand" "")]))
              (clobber (reg:CC 17))])]
  "! optimize_size && ! TARGET_READ_MODIFY_WRITE"
  [(set (match_dup 2) (match_dup 0))
   (parallel [(set (match_dup 2)
                   (match_op_dup 3 [(match_dup 2) (match_dup 1)]))
              (clobber (reg:CC 17))])
   (set (match_dup 0) (match_dup 2))]
  "")

(define_peephole2
  [(match_scratch:SI 2 "r")
   (parallel [(set (match_operand:SI 0 "memory_operand" "")
                   (match_operator:SI 3 "arith_or_logical_operator"
                     [(match_operand:SI 1 "nonmemory_operand" "")
                      (match_dup 0)]))
              (clobber (reg:CC 17))])]
  "! optimize_size && ! TARGET_READ_MODIFY_WRITE"
  [(set (match_dup 2) (match_dup 0))
   (parallel [(set (match_dup 2)
                   (match_op_dup 3 [(match_dup 1) (match_dup 2)]))
              (clobber (reg:CC 17))])
   (set (match_dup 0) (match_dup 2))]
  "")

;; Attempt to always use XOR for zeroing registers.
(define_peephole2
  [(set (match_operand 0 "register_operand" "")
	(const_int 0))]
  "(GET_MODE (operands[0]) == QImode
    || GET_MODE (operands[0]) == HImode
    || GET_MODE (operands[0]) == SImode)
   && (! TARGET_USE_MOV0 || optimize_size)
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 0) (const_int 0))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]));")

(define_peephole2
  [(set (strict_low_part (match_operand 0 "register_operand" ""))
	(const_int 0))]
  "(GET_MODE (operands[0]) == QImode
    || GET_MODE (operands[0]) == HImode)
   && (! TARGET_USE_MOV0 || optimize_size)
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (strict_low_part (match_dup 0)) (const_int 0))
	      (clobber (reg:CC 17))])])

;; For HI and SI modes, or $-1,reg is smaller than mov $-1,reg.
(define_peephole2
  [(set (match_operand 0 "register_operand" "")
	(const_int -1))]
  "(GET_MODE (operands[0]) == HImode
    || GET_MODE (operands[0]) == SImode)
   && (optimize_size || TARGET_PENTIUM)
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 0) (const_int -1))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_rtx_REG (SImode, true_regnum (operands[0]));")

;; Attempt to convert simple leas to adds. These can be created by
;; move expanders.
(define_peephole2
  [(set (match_operand:SI 0 "register_operand" "")
  	(plus:SI (match_dup 0)
		 (match_operand:SI 1 "nonmemory_operand" "")))]
  "peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 0) (plus:SI (match_dup 0) (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "")

(define_peephole2
  [(set (match_operand:SI 0 "register_operand" "")
  	(mult:SI (match_dup 0)
		 (match_operand:SI 1 "immediate_operand" "")))]
  "exact_log2 (INTVAL (operands[1])) >= 0
   && peep2_regno_dead_p (0, FLAGS_REG)"
  [(parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 2)))
	      (clobber (reg:CC 17))])]
  "operands[2] = GEN_INT (exact_log2 (INTVAL (operands[1])));")

;; The ESP adjustments can be done by the push and pop instructions.  Resulting
;; code is shorter, since push is only 1 byte, while add imm, %esp 3 bytes.  On
;; many CPUs it is also faster, since special hardware to avoid esp
;; dependancies is present.

;; While some of these converisons may be done using splitters, we use peepholes
;; in order to allow combine_stack_adjustments pass to see nonobfuscated RTL.

;; Convert prologue esp substractions to push.
;; We need register to push.  In order to keep verify_flow_info happy we have
;; two choices
;; - use scratch and clobber it in order to avoid dependencies
;; - use already live register
;; We can't use the second way right now, since there is no reliable way how to
;; verify that given register is live.  First choice will also most likely in
;; fewer dependencies.  On the place of esp adjustments it is very likely that
;; call clobbered registers are dead.  We may want to use base pointer as an
;; alternative when no register is available later.

(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4)))
	      (set (reg:SI 6) (reg:SI 6))
	      (clobber (reg:CC 17))])]
  "optimize_size || !TARGET_SUB_ESP_4"
  [(clobber (match_dup 0))
   (parallel [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))
	      (set (reg:SI 6) (reg:SI 6))])])

(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8)))
	      (set (reg:SI 6) (reg:SI 6))
	      (clobber (reg:CC 17))])]
  "optimize_size || !TARGET_SUB_ESP_8"
  [(clobber (match_dup 0))
   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))
   (parallel [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))
	      (set (reg:SI 6) (reg:SI 6))])])

;; Convert esp substractions to push.
(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -4)))
	      (clobber (reg:CC 17))])]
  "optimize_size || !TARGET_SUB_ESP_4"
  [(clobber (match_dup 0))
   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))])

(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int -8)))
	      (clobber (reg:CC 17))])]
  "optimize_size || !TARGET_SUB_ESP_8"
  [(clobber (match_dup 0))
   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))
   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))])

;; Convert epilogue deallocator to pop.
(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))
	      (set (reg:SI 6) (reg:SI 6))
	      (clobber (reg:CC 17))])]
  "optimize_size || !TARGET_ADD_ESP_4"
  [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))
	      (set (reg:SI 6) (reg:SI 6))])]
  "")

;; Two pops case is tricky, since pop causes dependency on destination register.
;; We use two registers if available.
(define_peephole2
  [(match_scratch:SI 0 "r")
   (match_scratch:SI 1 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8)))
	      (set (reg:SI 6) (reg:SI 6))
	      (clobber (reg:CC 17))])]
  "optimize_size || !TARGET_ADD_ESP_8"
  [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))
	      (set (reg:SI 6) (reg:SI 6))])
   (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "")

(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8)))
	      (set (reg:SI 6) (reg:SI 6))
	      (clobber (reg:CC 17))])]
  "optimize_size"
  [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))
	      (set (reg:SI 6) (reg:SI 6))])
   (parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "")

;; Convert esp additions to pop.
(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))
	      (clobber (reg:CC 17))])]
  ""
  [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "")

;; Two pops case is tricky, since pop causes dependency on destination register.
;; We use two registers if available.
(define_peephole2
  [(match_scratch:SI 0 "r")
   (match_scratch:SI 1 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8)))
	      (clobber (reg:CC 17))])]
  ""
  [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])
   (parallel [(set (match_dup 1) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "")

(define_peephole2
  [(match_scratch:SI 0 "r")
   (parallel [(set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 8)))
	      (clobber (reg:CC 17))])]
  "optimize_size"
  [(parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])
   (parallel [(set (match_dup 0) (mem:SI (reg:SI 7)))
	      (set (reg:SI 7) (plus:SI (reg:SI 7) (const_int 4)))])]
  "")

;; Call-value patterns last so that the wildcard operand does not
;; disrupt insn-recog's switch tables.

(define_insn "*call_value_pop_0"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "constant_call_address_operand" "")
	      (match_operand:SI 2 "" "")))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
			    (match_operand:SI 4 "immediate_operand" "")))]
  ""
  "*
{
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%P1\";
  else
    return \"call\\t%P1\";
}"
  [(set_attr "type" "callv")])

(define_insn "*call_value_pop_1"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "call_insn_operand" "m")
	      (match_operand:SI 2 "" "")))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
			    (match_operand:SI 4 "immediate_operand" "i")))]
  ""
  "*
{
  if (constant_call_address_operand (operands[1], QImode))
    {
      if (SIBLING_CALL_P (insn))
	return \"jmp\\t%P1\";
      else
	return \"call\\t%P1\";
    }
  operands[1] = XEXP (operands[1], 0);
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%*%1\";
  else
    return \"call\\t%*%1\";
}"
  [(set_attr "type" "callv")])

(define_insn "*call_value_0"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "constant_call_address_operand" "")
	      (match_operand:SI 2 "" "")))]
  ""
  "*
{
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%P1\";
  else
    return \"call\\t%P1\";
}"
  [(set_attr "type" "callv")])

(define_insn "*call_value_1"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "call_insn_operand" "m")
	      (match_operand:SI 2 "" "")))]
  ""
  "*
{
  if (constant_call_address_operand (operands[1], QImode))
    {
      if (SIBLING_CALL_P (insn))
	return \"jmp\\t%P1\";
      else
	return \"call\\t%P1\";
    }
  operands[1] = XEXP (operands[1], 0);
  if (SIBLING_CALL_P (insn))
    return \"jmp\\t%*%1\";
  else
    return \"call\\t%*%1\";
}"
  [(set_attr "type" "callv")])
