;; GCC machine description for IA-32.
;; Copyright (C) 1988, 94-98, 1999 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"
  (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,imov,imovx,lea,incdec,ishift,imul,idiv,ibr,setcc,push,pop,call,callv,icmov,fmov,fop,fop1,fsgn,fmul,fdiv,fpspc,fcmov,fcmp,fxch"
  (const_string "other"))

;; The (bounding maximum) length of an instruction in bytes.
(define_attr "length" ""
  (symbol_ref "ix86_attr_length_default(insn)"))

;; Supporting: number of prefix bytes
(define_attr "length_prefix" ""
  (cond [(and (eq_attr "type" "alu,alu1,negnot,icmp,imovx,incdec,ishift,imul,idiv,imov,pop")
	      (match_operand:HI 0 "general_operand" ""))
	   (const_int 1)
	 (and (eq_attr "type" "push")
	      (match_operand:HI 1 "general_operand" ""))
	   (const_int 1)
	]
	(const_int 0)))

;; Supporting: bytes in the opcode+modrm.
(define_attr "length_opcode" ""
  (cond [(eq_attr "type" "imovx,setcc,icmov")
	   (const_int 3)
         (and (eq_attr "type" "incdec")
	      (ior (match_operand:SI 1 "register_operand" "")
		   (match_operand:HI 1 "register_operand" "")))
	   (const_int 1)
	 (and (eq_attr "type" "push")
	      (not (match_operand 1 "memory_operand" "")))
	   (const_int 1)
	 (and (eq_attr "type" "pop")
	      (not (match_operand 0 "memory_operand" "")))
	   (const_int 1)
	 (and (eq_attr "type" "imov")
	      (and (match_operand 0 "register_operand" "")
	           (match_operand 1 "immediate_operand" "")))
	   (const_int 1)
	 ]
	 (const_int 2)))

;; 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")
	   (const_string "unknown")
	 (eq_attr "type" "lea,fcmov,fpspc")
	   (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")
	   (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,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,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.

;; 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")
	 (eq_attr "type" "alu1,alu,imov,icmp,lea,incdec")
	   (if_then_else (eq_attr "length_prefix" "1")
	     (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" "pop,push")
	      (eq_attr "memory" "!both"))
	   (if_then_else (eq_attr "length_prefix" "1")
	     (const_string "pu")
	     (const_string "uv"))
	 (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)

; ??? 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 "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")
	   (const_string "many")
	 (eq_attr "type" "icmov,fcmov")
	   (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"))
  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"))
  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,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,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)

;; 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")
       (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)

;; 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" "")))]
  ""
  "
{
  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_0"
  [(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" "icmp")])

(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")])

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

(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")])

(define_insn "cmpqi_0"
  [(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" "icmp")])

(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")])

(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")])

(define_insn "*cmpqi_ext_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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")))]
  ""
  "test{b}\\t%h0, %h0"
  [(set_attr "type" "icmp")])

(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")])

(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")])

;; 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")])

;; 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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

;; 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 "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 "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")])

(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")])

;; 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_operand" "ri*m"))]
  ""
  "push{l}\\t%1"
  [(set_attr "type" "push")])

(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")])

(define_insn "*movsi_1"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
	(match_operand:SI 1 "general_operand" "rim,ri"))
   (clobber (reg:CC 17))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU1:
      if (operands[1] != const0_rtx)
	abort();
      return \"xor{l}\\t{%0, %0|%0, %0}\";
    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 (match_operand:SI 1 "const0_operand" "")
		 (and (match_operand:SI 0 "register_operand" "")
		      (eq (symbol_ref "TARGET_USE_MOV0") (const_int 0))))
	      (const_string "alu1")
	    (and (ne (symbol_ref "flag_pic") (const_int 0))
		 (match_operand:SI 1 "symbolic_operand" ""))
	      (const_string "lea")
	   ]
	   (const_string "imov")))])

(define_insn "*movsi_2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=r,m")
	(match_operand:SI 1 "general_operand" "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")))])

(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 "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_operand" "n,r*m"))]
  ""
  "@
   push{w}\\t{|WORD PTR }%1
   push{w}\\t%1"
  [(set_attr "type" "push")])

(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")])

(define_insn "*movhi_1"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m")
	(match_operand:HI 1 "general_operand" "rn,rm,rn"))
   (clobber (reg:CC 17))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU1:
      /* Clear the whole register -- smaller, faster, better.  */
      if (operands[1] != const0_rtx)
	abort();
      return \"xor{l}\\t%k0, %k0\";
    case TYPE_IMOVX:
      return \"movz{wl|x}\\t{%1, %k0|%k0, %1}\";
    default:
      if (get_attr_length_prefix (insn) == 0)
        return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
      else
        return \"mov{w}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(and (match_operand:HI 1 "const0_operand" "")
		 (and (match_operand:HI 0 "register_operand" "")
		      (eq (symbol_ref "TARGET_USE_MOV0") (const_int 0))))
	      (const_string "alu1")
	    (and (ne (symbol_ref "TARGET_MOVX")
		     (const_int 0))
		 (eq_attr "alternative" "1"))
	      (const_string "imovx")
	   ]
	   (const_string "imov")))
    (set (attr "length_prefix")
      (cond [(eq_attr "type" "imovx")
	       (const_string "0")
	     (and (eq_attr "alternative" "0")
		  (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
		      (const_int 0)))
	       (const_string "0")
	    ]
	    (const_string "1")))
    ; There's no place to override just the immediate length
    (set (attr "length")
      (cond [(and (eq_attr "type" "imov")
		  (and (eq_attr "length_prefix" "0")
		       (match_operand:HI 1 "immediate_operand" "")))
	       (const_string "5")
	    ]
	    (const_string "*")))])

(define_insn "*movhi_2"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m")
	(match_operand:HI 1 "general_operand" "rn,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_length_prefix (insn) == 0)
        return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
      else
        return \"mov{w}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(eq_attr "alternative" "0")
	      (const_string "imov")
	    (and (ne (symbol_ref "TARGET_MOVX")
		     (const_int 0))
		 (eq_attr "alternative" "1"))
	      (const_string "imovx")
	   ]
	   (const_string "imov")))
    (set (attr "length_prefix")
      (cond [(eq_attr "type" "imovx")
	       (const_string "0")
	     (and (eq_attr "alternative" "0")
		  (eq (symbol_ref "TARGET_PARTIAL_REG_STALL")
		      (const_int 0)))
	       (const_string "0")
	    ]
	    (const_string "1")))
    ; There's no place to override just the immediate length
    (set (attr "length")
      (cond [(and (eq_attr "type" "imov")
		  (and (eq_attr "length_prefix" "0")
		       (match_operand:HI 1 "immediate_operand" "")))
	       (const_string "5")
	    ]
	    (const_string "*")))])

(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 "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 "length_prefix" "0")
   (set_attr "pent_pair" "np")
   (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")])

(define_expand "movqi"
  [(set (match_operand:QI 0 "general_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_operand" "n,r"))]
  ""
  "@
   push{w}\\t{|word ptr }%1
   push{w}\\t%w1"
  [(set_attr "type" "push")
   (set_attr "length_prefix" "1")
    ; There's no place to override just the immediate length
    (set (attr "length")
      (if_then_else (eq_attr "length_prefix" "0")
	(const_string "4")
	(const_string "*")))])

(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 "length_prefix" "1")])

(define_insn "*movqi_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,*r,*r,m")
	(match_operand:QI 1 "general_operand" "qn,qm,*rn,qm,qn"))
   (clobber (reg:CC 17))]
  "GET_CODE (operands[0]) != MEM || GET_CODE (operands[1]) != MEM"
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU1:
      /* Clear the whole register -- smaller, faster, better.  */
      if (operands[1] != const0_rtx)
	abort();
      return \"xor{l}\\t%k0, %k0\";
    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 (which_alternative == 2)
        return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
      else
        return \"mov{b}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(and (match_operand:QI 1 "const0_operand" "")
		 (and (match_operand:QI 0 "register_operand" "")
		      (eq (symbol_ref "TARGET_USE_MOV0") (const_int 0))))
	      (const_string "alu1")
	    (eq_attr "alternative" "3")
	      (const_string "imovx")
	    (and (ne (symbol_ref "TARGET_MOVX")
		     (const_int 0))
		 (eq_attr "alternative" "1"))
	      (const_string "imovx")
	   ]
	   (const_string "imov")))
    ; There's no place to override just the immediate length
    (set (attr "length")
      (cond [(and (eq_attr "type" "imov")
		  (and (eq_attr "alternative" "2")
		       (match_operand:HI 1 "immediate_operand" "")))
	       (const_string "5")
	    ]
	    (const_string "*")))])

(define_insn "*movqi_2"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=q,q,*r,*r,m")
	(match_operand:QI 1 "general_operand" "qn,qm,*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 (which_alternative == 2)
        return \"mov{l}\\t{%k1, %k0|%k0, %k1}\";
      else
        return \"mov{b}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(eq_attr "alternative" "3")
	      (const_string "imovx")
	    (and (ne (symbol_ref "TARGET_MOVX")
		     (const_int 0))
		 (eq_attr "alternative" "1"))
	      (const_string "imovx")
	   ]
	   (const_string "imov")))
    ; There's no place to override just the immediate length
    (set (attr "length")
      (cond [(and (eq_attr "type" "imov")
		  (and (eq_attr "alternative" "2")
		       (match_operand:HI 1 "immediate_operand" "")))
	       (const_string "5")
	    ]
	    (const_string "*")))])

(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 "ppro_uops" "few")])

(define_expand "movstrictqi"
  [(set (strict_low_part (match_operand:QI 0 "general_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")])

(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")])

(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")])

(define_insn "*movqi_extv_1"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm*r")
        (sign_extract:QI (match_operand:SI 1 "register_operand" "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")))])

(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")])

(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")
				    (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")))])

(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")])

(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")])

(define_expand "movdi"
  [(set (match_operand:DI 0 "general_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 "nonmemory_operand" "riF"))]
  ""
  "#")

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

(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" ""))]
  ""
  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 3))
   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 2))]
  "
{
  split_di (operands+1, 1, operands+2, operands+3);
  /* Compensate for the fact that we're changing stack offsets in
     the middle of this operation.  */
  if (reg_mentioned_p (stack_pointer_rtx, operands[2]))
    operands[2] = adj_offsettable_operand (operands[2], 4);
}")

;; %%% This multiword shite has got to go.
(define_split
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
        (match_operand:DI 1 "general_operand" ""))
   (clobber (reg:CC 17))]
  "reload_completed"
  [(parallel [(set (match_dup 2) (match_dup 4))
	      (clobber (reg:CC 17))])
   (parallel [(set (match_dup 3) (match_dup 5))
	      (clobber (reg:CC 17))])]
  "if (ix86_split_movdi (operands)) DONE;")
  
(define_split
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
        (match_operand:DI 1 "general_operand" ""))]
  "reload_completed"
  [(set (match_dup 2) (match_dup 4))
   (set (match_dup 3) (match_dup 5))]
  "if (ix86_split_movdi (operands)) DONE;")
  
(define_expand "movsf"
  [(set (match_operand:SF 0 "general_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_operand" "f,Ffm*r"))]
  ""
  "*
{
  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")])

;; %%% 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,m,f,*r,m,*r")
	(match_operand:SF 1 "general_operand" "fm,f,G,*rm,*r,G"))]
  ""
  "*
{
  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:
    case 5:
      return \"mov{l}\\t{%1, %0|%0, %1}\";

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

(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")])

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

(define_insn "*pushdf"
  [(set (match_operand:DF 0 "push_operand" "=<,<")
	(match_operand:DF 1 "general_operand" "f,ofF*r"))]
  ""
  "*
{
  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")])

;; %%% 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"
  [(set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 1))
   (set (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]
  "
{
  split_di (operands+1, 1, operands+0, operands+1);
  /* Compensate for the fact that we're changing stack offsets in
     the middle of this operation.  */
  if (reg_mentioned_p (stack_pointer_rtx, operands[0]))
    operands[0] = adj_offsettable_operand (operands[0], 4);
}")

(define_insn "*movdf_1"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m,f,*&r,m,*r")
	(match_operand:DF 1 "general_operand" "fm,f,G,*rm,*r,G"))]
  ""
  "*
{
  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:
    case 5:
      return \"#\";

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

(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 0) (match_dup 2))
   (set (match_dup 1) (match_dup 3))]
  "split_di (operands+1, 1, operands+2, operands+3);
   split_di (operands+0, 1, operands+0, operands+1);")

(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")])

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

(define_insn "*pushxf"
  [(set (match_operand:XF 0 "push_operand" "=<")
	(match_operand:XF 1 "register_operand" "f"))]
  ""
  "*
{
  /* %%% 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\";
}"
  [(set_attr "type" "multi")])

(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))])

(define_split
  [(set (match_operand:DF 0 "push_operand" "")
	(match_operand:DF 1 "memory_operand" ""))]
  "reload_completed"
  [(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 (mem:SI (pre_dec:SI (reg:SI 7))) (match_dup 0))]
  "
{
  operands[0] = change_address (operands[1], SImode, NULL_RTX);
  operands[1] = adj_offsettable_operand (operands[0], 4);
  operands[2] = adj_offsettable_operand (operands[0], 8);
  /* Compensate for the fact that we're changing stack offsets in
     the middle of this operation.  */
  if (reg_mentioned_p (stack_pointer_rtx, operands[1]))
    operands[1] = adj_offsettable_operand (operands[1], 4);
  if (reg_mentioned_p (stack_pointer_rtx, operands[0]))
    operands[0] = adj_offsettable_operand (operands[0], 8);
}")

(define_insn "*movxf_1"
  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m,f,*&r,o")
	(match_operand:XF 1 "general_operand" "fm,f,G,*ro,*r"))]
  ""
  "*
{
  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")])

(define_split
  [(set (match_operand:XF 0 "nonimmediate_operand" "")
	(match_operand:XF 1 "nonimmediate_operand" ""))]
  "(REG_P (operands[0]) && ! FP_REGNO_P (REGNO (operands[0])))
   || (REG_P (operands[1]) && ! FP_REGNO_P (REGNO (operands[1])))"
  [(set (match_dup 0) (match_dup 3))
   (set (match_dup 1) (match_dup 4))
   (set (match_dup 2) (match_dup 5))]
  "split_xf (operands[1], &operands[3]);
   split_xf (operands[0], &operands[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")])

;; Zero extension instructions

(define_insn "zero_extendhisi2"
  [(set (match_operand:SI 0 "register_operand" "=r,?r")
     (zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,rm")))
   (clobber (reg:CC 17))]
  ""
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU1:
      if (!REG_P (operands[1]) || REGNO (operands[0]) != REGNO (operands[1]))
	abort ();
      operands[1] = GEN_INT (0xffff);
      return \"and{l}\\t{%1, %0|%0, %1}\";
    default:
      return \"movz{wl|x}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (if_then_else (and (eq_attr "alternative" "0")
			(ne (symbol_ref "TARGET_ZERO_EXTEND_WITH_AND")
			    (const_int 0)))
       (const_string "alu1")
       (const_string "imovx")))])

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(zero_extend:SI (match_operand:HI 1 "nonimmediate_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && TARGET_ZERO_EXTEND_WITH_AND
   && !reg_overlap_mentioned_p (operands[0], operands[1])"
  [(parallel [(set (match_dup 0) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (strict_low_part (subreg:HI (match_dup 0) 0)) (match_dup 1))]
  "")

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(zero_extend:SI (match_operand:HI 1 "memory_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && TARGET_ZERO_EXTEND_WITH_AND
   && reg_overlap_mentioned_p (operands[0], operands[1])"
  [(set (strict_low_part (subreg:HI (match_dup 0) 0)) (match_dup 1))
   (parallel [(set (match_dup 0) (and:SI (match_dup 0) (const_int 65535)))
	      (clobber (reg:CC 17))])]
  "")

(define_insn "zero_extendqihi2"
  [(set (match_operand:HI 0 "register_operand" "=q,r,r")
     (zero_extend:HI (match_operand:QI 1 "nonimmediate_operand" "0,0,qm")))
   (clobber (reg:CC 17))]
  ""
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU1:
      if (!REG_P (operands[1]) || REGNO (operands[0]) != REGNO (operands[1]))
	abort ();
      operands[1] = GEN_INT (0xff);
      return \"and{l}\\t{%1, %k0|%k0, %1}\";
    default:
      return \"movz{bw|x}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(and (eq_attr "alternative" "0")
		 (ne (symbol_ref "TARGET_ZERO_EXTEND_WITH_AND")
		     (const_int 0)))
	      (const_string "alu1")
	    (eq_attr "alternative" "1")
	      (const_string "alu1")
	   ]
           (const_string "imovx")))])

(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
   && !reg_overlap_mentioned_p (operands[0], operands[1])"
  [(parallel [(set (match_dup 0) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (strict_low_part (subreg:QI (match_dup 0) 0)) (match_dup 1))]
  "")

(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extend:HI (match_operand:QI 1 "memory_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && QI_REG_P (operands[0])
   && TARGET_ZERO_EXTEND_WITH_AND
   && reg_overlap_mentioned_p (operands[0], operands[1])"
  [(set (strict_low_part (subreg:QI (match_dup 0) 0)) (match_dup 1))
   (parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255)))
	      (clobber (reg:CC 17))])]
  "")

(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(zero_extend:HI (match_operand:QI 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && TARGET_ZERO_EXTEND_WITH_AND
   && ! reg_overlap_mentioned_p (operands[0], operands[1])"
  [(set (match_dup 0) (subreg:HI (match_dup 1) 0))
   (parallel [(set (match_dup 0) (and:HI (match_dup 0) (const_int 255)))
	      (clobber (reg:CC 17))])]
  "")

(define_insn "zero_extendqisi2"
  [(set (match_operand:SI 0 "register_operand" "=q,r,r")
     (zero_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,0,qm")))
   (clobber (reg:CC 17))]
  ""
  "*
{
  switch (get_attr_type (insn))
    {
    case TYPE_ALU1:
      if (!REG_P (operands[1]) || REGNO (operands[0]) != REGNO (operands[1]))
	abort ();
      operands[1] = GEN_INT (0xff);
      return \"and{l}\\t{%1, %0|%0, %1}\";
    default:
      return \"movz{bl|x}\\t{%1, %0|%0, %1}\";
    }
}"
  [(set (attr "type")
     (cond [(and (eq_attr "alternative" "0")
		 (ne (symbol_ref "TARGET_ZERO_EXTEND_WITH_AND")
		     (const_int 0)))
	      (const_string "alu1")
	    (eq_attr "alternative" "1")
	      (const_string "alu1")
	   ]
           (const_string "imovx")))])

(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
   && QI_REG_P (operands[0])
   && (GET_CODE (operands[1]) == MEM || QI_REG_P (operands[1]))
   && !reg_overlap_mentioned_p (operands[0], operands[1])"
  [(parallel [(set (match_dup 0) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (strict_low_part (subreg:QI (match_dup 0) 0)) (match_dup 1))]
  "")

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(zero_extend:SI (match_operand:QI 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "reload_completed
   && TARGET_ZERO_EXTEND_WITH_AND
   && ! reg_overlap_mentioned_p (operands[0], operands[1])"
  [(set (match_dup 0) (subreg:SI (match_dup 1) 0))
   (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))]
  ""
  "#")

(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])"
  [(parallel [(set (match_dup 4) (const_int 0))
	      (clobber (reg:CC 17))])]
  "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))
   (parallel [(set (match_dup 4) (const_int 0))
	      (clobber (reg:CC 17))])]
  "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 (match_scratch:SI 2 "=X,X,X,&r"))
   (clobber (reg:CC 17))]
  ""
  "#")

;; 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 (match_operand:SI 2 "register_operand" ""))
   (clobber (reg:CC 17))]
  "(flow2_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 (match_operand:SI 2 "register_operand" ""))
   (clobber (reg:CC 17))]
  "flow2_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 (match_scratch:SI 2 ""))
   (clobber (reg:CC 17))]
  "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_length (insn))
    {
    case 1:
      return \"{cwtl|cwde}\";
    default:
      return \"movs{wl|x}\\t{%1,%0|%0, %1}\";
    }
}"
  [(set_attr "type" "imovx")
    (set (attr "length")
      ;; movsx is short decodable while cwtl is vector decoded.
      (cond [(and (eq_attr "cpu" "!k6")
		  (eq_attr "alternative" "0"))
	       (const_string "1")
	    ]
	    (const_string "*")))])

(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_length (insn))
    {
    case 1:
      return \"{cbtw|cbw}\";
    default:
      return \"movs{bw|x}\\t{%1,%0|%0, %1}\";
    }
}"
  [(set_attr "type" "imovx")
    (set (attr "length")
      ;; movsx is short decodable while cwtl is vector decoded.
      (cond [(and (eq_attr "cpu" "!k6")
		  (eq_attr "alternative" "0"))
	       (const_string "1")
	    ]
	    (const_string "*")))])

(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")])

;; 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_insn "extendsfdf2"
  [(set (match_operand:DF 0 "nonimmediate_operand" "=f,m")
        (float_extend:DF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
  "TARGET_80387"
  "*
{
  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")])

(define_insn "extendsfxf2"
  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
        (float_extend:XF (match_operand:SF 1 "nonimmediate_operand" "fm,f")))]
  "TARGET_80387"
  "*
{
  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")])

(define_insn "extenddfxf2"
  [(set (match_operand:XF 0 "nonimmediate_operand" "=f,m")
        (float_extend:XF (match_operand:DF 1 "nonimmediate_operand" "fm,f")))]
  "TARGET_80387"
  "*
{
  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")])

;; %%% 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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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))]
  "")

;; %% 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_opcode" "2")
   (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_opcode" "2")
   (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 "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 "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 "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 "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 "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 "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 "fp_int_src" "true")])

;; %%% Kill these when reload knows how to do it.
(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 "general_operand" "")
		 (match_operand:DI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "cse_not_expected"
  [(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)))]
  ""
  "add{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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))]
  ""
  "adc{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "pent_pair" "pu")
   (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")])

(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")))])

(define_insn "*addsi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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)"
  "*
{
  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")))])

(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")])

(define_expand "addhi3"
  [(parallel [(set (match_operand:HI 0 "general_operand" "")
		   (plus:HI (match_operand:HI 1 "nonimmediate_operand" "")
			    (match_operand:HI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "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"
  [(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))]
  "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")))])

;; If we know we're not touching memory, promote HImode references to SImode.
(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(plus:HI (match_operand:HI 1 "register_operand" "")
		 (match_operand:HI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed"
  [(parallel [(set (match_dup 0) (plus:SI (match_dup 1) (match_dup 2)))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
   operands[2] = gen_lowpart (SImode, operands[2]);")

(define_insn "*addhi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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)"
  "*
{
  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")))])

(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")])

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

;; %%% Potential partial reg stall on alternative 2.  What to do?
(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))]
  "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")))])

(define_insn "*addqi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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)"
  "*
{
  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")))])

(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")])

(define_insn "*addqi_low_1"
  [(set (strict_low_part (match_operand:QI 0 "register_operand" "+q"))
	(plus:QI (match_operand:QI 1 "register_operand" "0")
		 (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%b0\";
      else if (operands[2] == constm1_rtx
	       || (GET_CODE (operands[2]) == CONST_INT
		   && INTVAL (operands[2]) == 255))
	return \"dec{b}\\t%b0\";
      abort();

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

(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")))])

(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")])

;; 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 "nonimmediate_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 "nonimmediate_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 "general_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 "general_operand" "")
		  (match_operand:DI 2 "general_operand" "")))
   (clobber (reg:CC 17))]
  "cse_not_expected"
  [(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)))]
  ""
  "sub{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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))]
  ""
  "sbb{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")
   (set_attr "pent_pair" "pu")
   (set_attr "ppro_uops" "few")])

(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")])

(define_insn "*subsi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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_binary_operator_ok (MINUS, SImode, operands)"
  "sub{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(define_insn "*subsi_3"
  [(set (reg:CC 17)
	(compare:CC
	  (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_binary_operator_ok (MINUS, SImode, operands)"
  "sub{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(define_expand "subhi3"
  [(parallel [(set (match_operand:HI 0 "general_operand" "")
		   (minus:HI (match_operand:HI 1 "nonimmediate_operand" "")
			     (match_operand:HI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "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")])

(define_insn "*subhi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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_binary_operator_ok (MINUS, HImode, operands)"
  "sub{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(define_insn "*subhi_3"
  [(set (reg:CC 17)
	(compare:CC
	  (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_binary_operator_ok (MINUS, HImode, operands)"
  "sub{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(define_expand "subqi3"
  [(parallel [(set (match_operand:QI 0 "general_operand" "")
		   (minus:QI (match_operand:QI 1 "general_operand" "")
			     (match_operand:QI 2 "general_operand" "")))
	      (clobber (reg:CC 17))])]
  ""
  "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")])

(define_insn "*subqi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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_binary_operator_ok (MINUS, QImode, operands)"
  "sub{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(define_insn "*subqi_3"
  [(set (reg:CC 17)
	(compare:CC
	  (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_binary_operator_ok (MINUS, QImode, operands)"
  "sub{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

;; 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 "nonimmediate_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 "nonimmediate_operand" "")
		  (match_operand:SF 2 "nonimmediate_operand" "")))]
  "TARGET_80387"
  "")

;; Multiply instructions

(define_insn "mulsi3"
  [(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))]
  ""
  ; 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 "length" "2,3,2")])

(define_insn "mulhi3"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(mult:HI (match_operand:HI 1 "nonimmediate_operand" "%rm,0")
		 (match_operand:HI 2 "general_operand" "K,g")))
   (clobber (reg:CC 17))]
  ""
  ; %%% 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, %0|%0, %2}"
  [(set_attr "type" "imul")])

(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))]
  ""
  "mul{b}\\t%2"
  [(set_attr "type" "imul")])

(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))]
  ""
  "imul{b}\\t%2"
  [(set_attr "type" "imul")])

(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")])

(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")])

(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")])

(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")])

;; 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))]
  ""
  "idiv{b}\\t%2"
  [(set_attr "type" "idiv")
   (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))]
  ""
  "div{b}\\t%2"
  [(set_attr "type" "idiv")
   (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_insn "divmodsi4"
  [(set (match_operand:SI 0 "register_operand" "=a")
	(div:SI (match_operand:SI 1 "register_operand" "A")
		(match_operand:SI 2 "nonimmediate_operand" "rm")))
   (set (match_operand:SI 3 "register_operand" "=&d")
	(mod:SI (match_dup 1) (match_dup 2)))
   (clobber (reg:CC 17))]
  ""
  "{cltd|cdq}\;idiv{l}\\t%2"
  [(set_attr "type" "multi")])

(define_insn "*divmodsi_noext"
  [(set (match_operand:SI 0 "register_operand" "=a")
	(div:SI (match_operand:SI 1 "register_operand" "A")
		(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_dup 3))
   (clobber (reg:CC 17))]
  ""
  "idiv{l}\\t%2"
  [(set_attr "type" "idiv")
   (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 (match_dup 1) (match_dup 2)))
	      (set (match_dup 3)
		   (mod:SI (match_dup 1) (match_dup 2)))
	      (use (match_dup 3))
	      (clobber (reg:CC 17))])]
  "
{
  /* Avoid use of cltd in favour of a mov+shift.  */
  if (TARGET_PENTIUM && !optimize_size)
    {
      emit_move_insn (operands[3], operands[1]);
      operands[4] = operands[3];
    }
  else
    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))]
  ""
  "cwtd\;idiv{w}\\t%2"
  [(set_attr "type" "multi")])

(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")])

(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")])

(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"
  [(parallel [(set (match_dup 3) (const_int 0))
	      (clobber (reg:CC 17))])
   (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"
  [(parallel [(set (match_dup 4) (const_int 0))
	      (clobber (reg:CC 17))])
   (parallel [(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_dup 4))
	      (clobber (reg:CC 17))])]
  ""
  "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 "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_1"
  [(set (reg:CCNO 17)
	(compare:CCNO (and:SI (match_operand:SI 0 "nonimmediate_operand" "%*a,r,rm")
			      (match_operand:SI 1 "general_operand" "in,in,rin"))
		      (const_int 0)))]
  ""
  "test{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "icmp")
   (set_attr "pent_pair" "uv,np,uv")])

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

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

;; ??? 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 "testqi_ext_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" "icmp")
   (set_attr "pent_pair" "np")])

(define_insn "*testqi_ext_1"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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)))]
  ""
  "test{b}\\t{%1, %h0|%h0, %1}"
  [(set_attr "type" "icmp")])

(define_insn "*testqi_ext_2"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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)))]
  ""
  "test{b}\\t{%h1, %h0|%h0, %h1}"
  [(set_attr "type" "icmp")])

;; Combine likes to form bit extractions for some tests.  Humor it.
(define_insn "*testqi_ext_3"
  [(set (reg:CCNO 17)
        (compare:CCNO (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)))]
  "GET_MODE (operands[0]) == SImode
   || GET_MODE (operands[0]) == HImode
   || GET_MODE (operands[0]) == QImode"
  "#")

(define_split
  [(set (reg:CCNO 17)
        (compare:CCNO (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)))]
  ""
  [(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 ();

      /* If operands[2] is an immediate, we may be able to use xor.
	 Walk through the cases to figure out which subword we are
	 supposed to clear.  */
      if (REG_P (operands[0])
	  && GET_CODE (operands[2]) == CONST_INT
	  && (optimize_size
	      || ! TARGET_PARTIAL_REG_STALL))
	{
	  if (INTVAL (operands[2]) == (HOST_WIDE_INT) 0xffff0000
	      && optimize_size)
	    return \"xor{w}\\t{%w0, %w0|%w0, %w0}\";
	  if (QI_REG_P (operands[0]))
	    {
	      if (INTVAL (operands[2]) == (HOST_WIDE_INT) 0xffffff00)
	        return \"xor{b}\\t{%b0, %b0|%b0, %b0}\";
	      if (INTVAL (operands[2]) == (HOST_WIDE_INT) 0xffff00ff)
	        return \"xor{b}\\t{%h0, %h0|%h0, %h0}\";
	    }
	}
      return \"and{l}\\t{%2, %0|%0, %2}\";
    }
}"
  [(set_attr "type" "alu,alu,imovx")])

(define_insn "*andsi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_binary_operator_ok (AND, SImode, operands)"
  "and{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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))]
  ""
  "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 ();

      /* If operands[2] is an immediate, we may be able to use xor.
	 Walk through the cases to figure out which subword we are
	 supposed to clear.  */
      /* %%% Do these as splits.  They get length_prefix wrong.  */
      if (GET_CODE (operands[2]) == CONST_INT
	  && QI_REG_P (operands[0])
	  && (optimize_size 
	      || ! TARGET_PARTIAL_REG_STALL))
	{
	  if ((INTVAL (operands[2]) & 0xffff) == 0xff00)
	    return \"xor{b}\\t{%b0, %b0|%b0, %b0}\";
	  if ((INTVAL (operands[2]) & 0xffff) == 0x00ff)
	    return \"xor{b}\\t{%h0, %h0|%h0, %h0}\";
	}

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

(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(and:HI (match_operand:HI 1 "register_operand" "")
		(match_operand:HI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed"
  [(parallel [(set (match_dup 0) (and:SI (match_dup 1) (match_dup 2)))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
   operands[2] = gen_lowpart (SImode, operands[2]);")

(define_insn "*andhi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_binary_operator_ok (AND, HImode, operands)"
  "and{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(define_split
  [(set (reg:CCNO 17)
	(compare:CCNO (and:HI (match_operand:HI 1 "register_operand" "")
			      (match_operand:HI 2 "immediate_operand" ""))
		      (const_int 0)))
   (set (match_operand:HI 0 "register_operand" "")
	(and:HI (match_dup 1) (match_dup 2)))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed"
  [(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[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
   operands[2] = gen_lowpart (SImode, operands[2]);")

(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))]
  ""
  "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")])

(define_insn "*andqi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_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")])

;; ??? 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")])

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

(define_insn "*andqi_ext_0_cc"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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)))]
  "(unsigned HOST_WIDE_INT)INTVAL (operands[2]) <= 0xff"
  "and{b}\\t{%2, %h0|%h0, %2}"
  [(set_attr "type" "alu")])

(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")])

(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")])

;; 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")])

(define_insn "*iorsi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_binary_operator_ok (IOR, SImode, operands)"
  "or{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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))]
  ""
  "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")])

(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(ior:HI (match_operand:HI 1 "register_operand" "")
		(match_operand:HI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed"
  [(parallel [(set (match_dup 0) (ior:SI (match_dup 1) (match_dup 2)))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
   operands[2] = gen_lowpart (SImode, operands[2]);")

(define_insn "*iorhi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_binary_operator_ok (IOR, HImode, operands)"
  "or{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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))]
  ""
  "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")])

(define_insn "*iorqi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_binary_operator_ok (IOR, QImode, operands)"
  "or{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

;; 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")])

(define_insn "*xorsi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_binary_operator_ok (XOR, SImode, operands)"
  "xor{l}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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))]
  ""
  "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")])

(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(xor:HI (match_operand:HI 1 "register_operand" "")
		(match_operand:HI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed"
  [(parallel [(set (match_dup 0) (xor:SI (match_dup 1) (match_dup 2)))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);
   operands[2] = gen_lowpart (SImode, operands[2]);")

(define_insn "*xorhi_2"
  [(set (reg:CCNO 17)
	(compare:CCNO (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_binary_operator_ok (XOR, HImode, operands)"
  "xor{w}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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))]
  ""
  "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")])

(define_insn "*xorqi_cc_1"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (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_binary_operator_ok (XOR, QImode, operands)"
  "xor{b}\\t{%2, %0|%0, %2}"
  [(set_attr "type" "alu")])

(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")])

;; Negation instructions

;; %%% define_expand from the very first?

(define_insn "negdi2"
  [(set (match_operand:DI 0 "nonimmediate_operand" "=ro")
	(neg:DI (match_operand:DI 1 "general_operand" "0")))
   (clobber (reg:CC 17))]
  ""
  "#")

(define_split
  [(set (match_operand:DI 0 "nonimmediate_operand" "")
	(neg:DI (match_operand:DI 1 "general_operand" "")))
   (clobber (reg:CC 17))]
  "cse_not_expected"
  [(parallel
    [(set (reg:CCNO 17)
	  (compare:CCNO (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_insn "negsi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(neg:SI (match_operand:SI 1 "nonimmediate_operand" "0")))
   (clobber (reg:CC 17))]
  ""
  "neg{l}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "*negsi2_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO (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)))]
  ""
  "neg{l}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "*negsi2_cmp"
  [(set (reg:CC 17)
	(compare:CC (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)))]
  ""
  "neg{l}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "neghi2"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(neg:HI (match_operand:HI 1 "nonimmediate_operand" "0")))
   (clobber (reg:CC 17))]
  ""
  "neg{w}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "*neghi2_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO (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)))]
  ""
  "neg{w}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "*neghi2_cmp"
  [(set (reg:CC 17)
	(compare:CC (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)))]
  ""
  "neg{w}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "negqi2"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(neg:QI (match_operand:QI 1 "nonimmediate_operand" "0")))
   (clobber (reg:CC 17))]
  ""
  "neg{b}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "*negqi2_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO (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)))]
  ""
  "neg{b}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "*negqi2_cmp"
  [(set (reg:CC 17)
	(compare:CC (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)))]
  ""
  "neg{b}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "negsf2"
  [(set (match_operand:SF 0 "register_operand" "=f")
	(neg:SF (match_operand:SF 1 "register_operand" "0")))]
  "TARGET_80387"
  "fchs"
  [(set_attr "type" "fsgn")
   (set_attr "ppro_uops" "few")])

(define_insn "negdf2"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(neg:DF (match_operand:DF 1 "register_operand" "0")))]
  "TARGET_80387"
  "fchs"
  [(set_attr "type" "fsgn")
   (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 "ppro_uops" "few")])

(define_insn "negxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(neg:XF (match_operand:XF 1 "register_operand" "0")))]
  "TARGET_80387"
  "fchs"
  [(set_attr "type" "fsgn")
   (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 "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 "ppro_uops" "few")])

;; Absolute value instructions

(define_insn "abssf2"
  [(set (match_operand:SF 0 "register_operand" "=f")
	(abs:SF (match_operand:SF 1 "register_operand" "0")))]
  "TARGET_80387"
  "fabs"
  [(set_attr "type" "fsgn")])

(define_insn "absdf2"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(abs:DF (match_operand:DF 1 "register_operand" "0")))]
  "TARGET_80387"
  "fabs"
  [(set_attr "type" "fsgn")])

(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")])

(define_insn "absxf2"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(abs:XF (match_operand:XF 1 "register_operand" "0")))]
  "TARGET_80387"
  "fabs"
  [(set_attr "type" "fsgn")])

(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")])

(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")])

;; One complement instructions

(define_insn "one_cmplsi2"
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
  ""
  "not{l}\\t%0"
  [(set_attr "type" "negnot")])

(define_insn "*one_cmplsi2_1"
  [(set (reg:CCNO 17)
	(compare:CCNO (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)))]
  ""
  "#"
  [(set_attr "type" "alu1")])

(define_split
  [(set (reg:CCNO 17)
	(compare:CCNO (not:SI (match_operand:SI 1 "nonimmediate_operand" ""))
		      (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "")
	(not:SI (match_dup 1)))]
  ""
  [(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_insn "one_cmplhi2"
  [(set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(not:HI (match_operand:HI 1 "nonimmediate_operand" "0")))]
  ""
  "not{w}\\t%0"
  [(set_attr "type" "negnot")])

(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(not:HI (match_operand:HI 1 "register_operand" "")))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed"
  [(parallel [(set (match_dup 0) (not:SI (match_dup 1)))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);")

(define_insn "*one_cmplhi2_1"
  [(set (reg:CCNO 17)
	(compare:CCNO (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)))]
  ""
  "#"
  [(set_attr "type" "alu1")])

(define_split
  [(set (reg:CCNO 17)
	(compare:CCNO (not:HI (match_operand:HI 1 "nonimmediate_operand" ""))
		      (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "")
	(not:HI (match_dup 1)))]
  ""
  [(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_insn "one_cmplqi2"
  [(set (match_operand:QI 0 "nonimmediate_operand" "=qm,*r")
	(not:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")))]
  ""
  "@
   not{b}\\t%0
   not{l}\\t%k0"
  [(set_attr "type" "negnot")])

(define_insn "*one_cmplqi2_1"
  [(set (reg:CCNO 17)
	(compare:CCNO (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)))]
  ""
  "#"
  [(set_attr "type" "alu1")])

(define_split
  [(set (reg:CCNO 17)
	(compare:CCNO (not:QI (match_operand:QI 1 "nonimmediate_operand" ""))
		      (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "")
	(not:QI (match_dup 1)))]
  ""
  [(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 && cse_not_expected"
  [(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))]
  "cse_not_expected"
  [(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 "length_opcode" "3")
   (set_attr "pent_pair" "np")
   (set_attr "ppro_uops" "few")])

(define_expand "x86_shift_adj_1"
  [(set (reg:CCNO 17)
	(compare:CCNO (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:CCNO 17) (const_int 0))
			 (match_operand:SI 1 "register_operand" "")
			 (match_dup 0)))
   (set (match_dup 1)
	(if_then_else:SI (ne (reg:CCNO 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_1 (operands[2], GEN_INT (32)));

  tmp = gen_rtx_REG (CCNOmode, 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_insn "ashlsi3"
  [(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))]
  ""
  "*
{
  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
	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")))])

(define_insn "*ashlsi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (ashift:SI (match_operand:SI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "cI"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(ashift:SI (match_dup 1) (match_dup 2)))]
  ""
  "*
{
  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
	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")))])

(define_insn "ashlhi3"
  [(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))]
  ""
  "*
{
  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
	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")))])

(define_split
  [(set (match_operand:HI 0 "register_operand" "")
	(ashift:HI (match_operand:HI 1 "register_operand" "")
		   (match_operand:QI 2 "nonmemory_operand" "")))
   (clobber (reg:CC 17))]
  "! TARGET_PARTIAL_REG_STALL && reload_completed"
  [(parallel [(set (match_dup 0) (ashift:SI (match_dup 1) (match_dup 2)))
	      (clobber (reg:CC 17))])]
  "operands[0] = gen_lowpart (SImode, operands[0]);
   operands[1] = gen_lowpart (SImode, operands[1]);")

(define_insn "*ashlhi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (ashift:HI (match_operand:HI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "cI"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm")
	(ashift:HI (match_dup 1) (match_dup 2)))]
  ""
  "*
{
  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
	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")))])

;; %%% Potential partial reg stall on alternative 2.  What to do?
(define_insn "ashlqi3"
  [(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))]
  ""
  "*
{
  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 (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")))])

(define_insn "*ashlqi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (ashift:QI (match_operand:QI 1 "nonimmediate_operand" "0")
		     (match_operand:QI 2 "nonmemory_operand" "cI"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=qm")
	(ashift:QI (match_dup 1) (match_dup 2)))]
  ""
  "*
{
  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
	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")))])

;; 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 && cse_not_expected"
  [(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))]
  "cse_not_expected"
  [(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 "length_opcode" "3")
   (set_attr "pent_pair" "np")
   (set_attr "ppro_uops" "few")])

(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_1 (operands[2], GEN_INT (32)));

  tmp = gen_rtx_REG (CCNOmode, 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"
  "@
   {cltd|cdq}
   sar{l}\\t{%2, %0|%0, %2}"
   [(set_attr "type" "imovx,ishift")
    (set_attr "length" "1,*")])

(define_insn "ashrsi3"
  [(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))]
  ""
  "@
   sar{l}\\t{%2, %0|%0, %2}
   sar{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*ashrsi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (ashiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(ashiftrt:SI (match_dup 1) (match_dup 2)))]
  ""
  "@
   sar{l}\\t{%2, %0|%0, %2}
   sar{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "ashrhi3"
  [(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))]
  ""
  "@
   sar{w}\\t{%2, %0|%0, %2}
   sar{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*ashrhi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (ashiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(ashiftrt:HI (match_dup 1) (match_dup 2)))]
  ""
  "@
   sar{w}\\t{%2, %0|%0, %2}
   sar{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "ashrqi3"
  [(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))]
  ""
  "@
   sar{b}\\t{%2, %0|%0, %2}
   sar{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*ashrqi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (ashiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
	(ashiftrt:QI (match_dup 1) (match_dup 2)))]
  ""
  "@
   sar{b}\\t{%2, %0|%0, %2}
   sar{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

;; 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 && cse_not_expected"
  [(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))]
  "cse_not_expected"
  [(const_int 0)]
  "ix86_split_lshrdi (operands, NULL_RTX); DONE;")

(define_insn "lshrsi3"
  [(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))]
  ""
  "@
   shr{l}\\t{%2, %0|%0, %2}
   shr{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*lshrsi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (lshiftrt:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(lshiftrt:SI (match_dup 1) (match_dup 2)))]
  ""
  "@
   shr{l}\\t{%2, %0|%0, %2}
   shr{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "lshrhi3"
  [(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))]
  ""
  "@
   shr{w}\\t{%2, %0|%0, %2}
   shr{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*lshrhi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (lshiftrt:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(lshiftrt:HI (match_dup 1) (match_dup 2)))]
  ""
  "@
   shr{w}\\t{%2, %0|%0, %2}
   shr{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "lshrqi3"
  [(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))]
  ""
  "@
   shr{b}\\t{%2, %0|%0, %2}
   shr{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*lshrqi2_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (lshiftrt:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
	(lshiftrt:QI (match_dup 1) (match_dup 2)))]
  ""
  "@
   shr{b}\\t{%2, %0|%0, %2}
   shr{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

;; Rotate instructions

(define_insn "rotlsi3"
  [(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))]
  ""
  "@
   rol{l}\\t{%2, %0|%0, %2}
   rol{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*rotlsi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (rotate:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(rotate:SI (match_dup 1) (match_dup 2)))]
  ""
  "@
   rol{l}\\t{%2, %0|%0, %2}
   rol{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "rotlhi3"
  [(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))]
  ""
  "@
   rol{w}\\t{%2, %0|%0, %2}
   rol{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*rotlhi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (rotate:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(rotate:HI (match_dup 1) (match_dup 2)))]
  ""
  "@
   rol{w}\\t{%2, %0|%0, %2}
   rol{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "rotlqi3"
  [(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))]
  ""
  "@
   rol{b}\\t{%2, %0|%0, %2}
   rol{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*rotlqi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (rotate:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		     (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
	(rotate:QI (match_dup 1) (match_dup 2)))]
  ""
  "@
   rol{b}\\t{%2, %0|%0, %2}
   rol{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "rotrsi3"
  [(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))]
  ""
  "@
   ror{l}\\t{%2, %0|%0, %2}
   ror{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*rotrsi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (rotatert:SI (match_operand:SI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:SI 0 "nonimmediate_operand" "=rm,rm")
	(rotatert:SI (match_dup 1) (match_dup 2)))]
  ""
  "@
   ror{l}\\t{%2, %0|%0, %2}
   ror{l}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(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))]
  ""
  "@
   ror{w}\\t{%2, %0|%0, %2}
   ror{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*rotrhi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (rotatert:HI (match_operand:HI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:HI 0 "nonimmediate_operand" "=rm,rm")
	(rotatert:HI (match_dup 1) (match_dup 2)))]
  ""
  "@
   ror{w}\\t{%2, %0|%0, %2}
   ror{w}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "rotrqi3"
  [(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))]
  ""
  "@
   ror{b}\\t{%2, %0|%0, %2}
   ror{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

(define_insn "*rotrqi3_cmpno"
  [(set (reg:CCNO 17)
	(compare:CCNO
	  (rotatert:QI (match_operand:QI 1 "nonimmediate_operand" "0,0")
		       (match_operand:QI 2 "nonmemory_operand" "I,c"))
	  (const_int 0)))
   (set (match_operand:QI 0 "nonimmediate_operand" "=rm,rm")
	(rotatert:QI (match_dup 1) (match_dup 2)))]
  ""
  "@
   ror{b}\\t{%2, %0|%0, %2}
   ror{b}\\t{%b2, %0|%0, %b2}"
  [(set_attr "type" "ishift")])

;; 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, 1, 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, 1, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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, 0, 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")])

(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")])

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

(define_insn "*setcc_4"
  [(set (strict_low_part (match_operand:QI 0 "nonimmediate_operand" "+qm"))
	(match_operator:QI 1 "comparison_operator"
	  [(reg:CC 17) (const_int 0)]))]
  ""
  "set%C1\\t%0"
  [(set_attr "type" "setcc")])

;; 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, 1, operands[0]); DONE;")

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

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

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

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

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

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

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

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

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

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

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

(define_insn "*jcc_3"
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
				      [(reg:CC 17) (const_int 0)])
		      (label_ref (match_operand 1 "" ""))
		      (pc)))]
  ""
  "j%C0\\t%l1"
  [(set_attr "type" "ibr")
   (set (attr "length")
	(if_then_else (and (ge (minus (match_dup 1) (pc))
			       (const_int -128))
			   (lt (minus (match_dup 1) (pc))
			       (const_int 124)))
	  (const_int 2)
	  (const_int 6)))])

(define_insn "*jcc_4"
  [(set (pc)
	(if_then_else (match_operator 0 "comparison_operator"
				      [(reg:CC 17) (const_int 0)])
		      (pc)
		      (label_ref (match_operand 1 "" ""))))]
  ""
  "j%c0\\t%l1"
  [(set_attr "type" "ibr")
   (set (attr "length")
	(if_then_else (and (ge (minus (match_dup 1) (pc))
			       (const_int -128))
			   (lt (minus (match_dup 1) (pc))
			       (const_int 124)))
	  (const_int 2)
	  (const_int 6)))])

;; Unconditional and other jump instructions

(define_insn "jump"
  [(set (pc)
	(label_ref (match_operand 0 "" "")))]
  ""
  "jmp\\t%l0"
  [(set_attr "type" "ibr")
   (set (attr "length")
	(if_then_else (and (ge (minus (match_dup 0) (pc))
			       (const_int -128))
			   (lt (minus (match_dup 0) (pc))
			       (const_int 124)))
	  (const_int 2)
	  (const_int 5)))])

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

(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")])

;; 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")])

;; Loop instruction
;;
;; This is all complicated by the fact that since this is a jump insn
;; we must handle our own reloads.

(define_expand "decrement_and_branch_on_count"
  [(parallel [(set (pc) (if_then_else
			  (ne (match_operand:SI 0 "register_operand" "")
			      (const_int 1))
			  (label_ref (match_operand 1 "" ""))
			  (pc)))
	      (set (match_dup 0)
		   (plus:SI (match_dup 0)
			    (const_int -1)))
	      (clobber (match_scratch:SI 2 ""))
	      (clobber (reg:CC 17))])]
  "TARGET_USE_LOOP"
  "")

(define_insn "*dbra_ne"
  [(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,*r,*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 "type" "ibr")
   (set_attr "ppro_uops" "many")
   (set (attr "length")
	(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_int 2)
		      (const_int 16)))])

(define_insn "*dbra_ge"
  [(set (pc)
	(if_then_else (ge (match_operand:SI 1 "register_operand" "c,*r,*r")
			  (const_int 0))
		      (label_ref (match_operand 0 "" ""))
		      (pc)))
   (set (match_operand:SI 2 "register_operand" "=1,*r,*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 && find_reg_note (insn, REG_NONNEG, 0)"
  "*
{
  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 "type" "ibr")
   (set_attr "ppro_uops" "many")
   (set (attr "length")
	(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_int 2)
		      (const_int 16)))])

(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 "register_operand" "")
	(plus:SI (match_dup 1)
		 (const_int -1)))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_USE_LOOP && reload_completed
   && ! (REGNO (operands[1]) == 2 && rtx_equal_p (operands[1], operands[2]))"
  [(set (match_dup 2) (match_dup 1))
   (parallel [(set (reg:CCNO 17)
		   (compare:CCNO (plus:SI (match_dup 2) (const_int -1))
				 (const_int 0)))
	      (set (match_dup 2) (plus:SI (match_dup 2) (const_int -1)))])
   (set (pc) (if_then_else (ne (reg:CCNO 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 "memory_operand" "")
	(plus:SI (match_dup 1)
		 (const_int -1)))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_USE_LOOP && reload_completed"
  [(set (match_dup 3) (match_dup 1))
   (parallel [(set (reg:CCNO 17)
		   (compare:CCNO (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:CCNO 17) (const_int 0))
			   (match_dup 0)
			   (pc)))]
  "")

(define_split
  [(set (pc)
	(if_then_else (ge (match_operand:SI 1 "register_operand" "")
			  (const_int 0))
		      (match_operand 0 "" "")
		      (pc)))
   (set (match_operand:SI 2 "register_operand" "")
	(plus:SI (match_dup 1)
		 (const_int -1)))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_USE_LOOP && reload_completed
   && ! (REGNO (operands[1]) == 2 && rtx_equal_p (operands[1], operands[2]))"
  [(set (match_dup 2) (match_dup 1))
   (parallel [(set (reg:CCNO 17)
		   (compare:CCNO (plus:SI (match_dup 2) (const_int -1))
				 (const_int 0)))
	      (set (match_dup 2) (plus:SI (match_dup 2) (const_int -1)))])
   (set (pc) (if_then_else (lt (reg:CCNO 17) (const_int 0))
			   (match_dup 0)
			   (pc)))]
  "")
  
(define_split
  [(set (pc)
	(if_then_else (ge (match_operand:SI 1 "register_operand" "")
			  (const_int 0))
		      (match_operand 0 "" "")
		      (pc)))
   (set (match_operand:SI 2 "memory_operand" "")
	(plus:SI (match_dup 1)
		 (const_int -1)))
   (clobber (match_scratch:SI 3 ""))
   (clobber (reg:CC 17))]
  "TARGET_USE_LOOP && reload_completed"
  [(set (match_dup 3) (match_dup 1))
   (parallel [(set (reg:CCNO 17)
		   (compare:CCNO (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 (lt (reg:CCNO 17) (const_int 0))
			   (match_dup 0)
			   (pc)))]
  "")

;; Call instructions.

;; If generating PIC code, the predicate indirect_operand will fail
;; for operands[0] containing symbolic references on all of the named
;; call* patterns.  Each named pattern is followed by an unnamed pattern
;; that matches any call to a symbolic CONST (ie, a symbol_ref).  The
;; unnamed patterns are only used while generating PIC code, because
;; otherwise the named patterns match.

;; Call subroutine returning no value.

(define_expand "call_pop"
  [(parallel [(call (match_operand:QI 0 "indirect_operand" "")
		    (match_operand:SI 1 "general_operand" ""))
	      (set (reg:SI 7)
		   (plus:SI (reg:SI 7)
			    (match_operand:SI 3 "immediate_operand" "")))])]
  ""
  "
{
  rtx addr;

  if (operands[3] == const0_rtx)
    {
      emit_insn (gen_call (operands[0], operands[1]));
      DONE;
    }

  if (flag_pic)
    current_function_uses_pic_offset_table = 1;

  /* With half-pic, force the address into a register.  */
  addr = XEXP (operands[0], 0);
  if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
    XEXP (operands[0], 0) = force_reg (Pmode, addr);

  if (! expander_call_insn_operand (operands[0], QImode))
    operands[0]
      = change_address (operands[0], VOIDmode,
			copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
}")

(define_insn "*call_pop_pic"
  [(call (match_operand:QI 0 "call_insn_operand" "m")
	 (match_operand:SI 1 "general_operand" "g"))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
			    (match_operand:SI 3 "immediate_operand" "i")))]
  ""
  "*
{
  if (constant_call_address_operand (operands[0], GET_MODE (operands[0])))
    return \"call\\t%P0\";
  
  operands[0] = XEXP (operands[0], 0);
  return \"call\\t%*%0\";
}"
  [(set_attr "type" "call")])

(define_insn "*call_pop_pic2"
  [(call (match_operand:QI 0 "constant_call_address_operand" "")
         (match_operand:SI 1 "general_operand" "g"))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
                            (match_operand:SI 3 "immediate_operand" "i")))]
  "!HALF_PIC_P ()"
  "call\\t%P0"
  [(set_attr "type" "call")])

(define_expand "call"
  [(call (match_operand:QI 0 "indirect_operand" "")
	 (match_operand:SI 1 "general_operand" ""))]
  ;; Operand 1 not used on the i386.
  ""
  "
{
  rtx addr;

  if (flag_pic)
    current_function_uses_pic_offset_table = 1;

  /* With half-pic, force the address into a register.  */
  addr = XEXP (operands[0], 0);
  if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
    XEXP (operands[0], 0) = force_reg (Pmode, addr);

  if (! expander_call_insn_operand (operands[0], QImode))
    operands[0]
      = change_address (operands[0], VOIDmode,
			copy_to_mode_reg (Pmode, XEXP (operands[0], 0)));
}")

(define_insn "*call_pic"
  [(call (match_operand:QI 0 "call_insn_operand" "m")
	 (match_operand:SI 1 "general_operand" "g"))]
  ;; Operand 1 not used on the i386.
  ""
  "*
{
  if (constant_call_address_operand (operands[0], GET_MODE (operands[0])))
    return \"call\\t%P0\";
  
  operands[0] = XEXP (operands[0], 0);
  return \"call\\t%*%0\";
}"
  [(set_attr "type" "call")])

(define_insn "*call_pic2"
  [(call (match_operand:QI 0 "constant_call_address_operand" "")
         (match_operand:SI 1 "general_operand" "g"))]
  "!HALF_PIC_P ()"
  "call\\t%P0"
  [(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 "indirect_operand" "")
			 (match_operand:SI 2 "general_operand" "")))
	      (set (reg:SI 7)
		   (plus:SI (reg:SI 7)
			    (match_operand:SI 4 "immediate_operand" "")))])]
  ""
  "
{
  rtx addr;

  if (operands[4] == const0_rtx)
    {
      emit_insn (gen_call_value (operands[0], operands[1], operands[2]));
      DONE;
    }

  if (flag_pic)
    current_function_uses_pic_offset_table = 1;

  /* With half-pic, force the address into a register.  */
  addr = XEXP (operands[1], 0);
  if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
    XEXP (operands[1], 0) = force_reg (Pmode, addr);

  if (! expander_call_insn_operand (operands[1], QImode))
    operands[1]
      = change_address (operands[1], VOIDmode,
			copy_to_mode_reg (Pmode, XEXP (operands[1], 0)));
}")

(define_expand "call_value"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "indirect_operand" "")
	      (match_operand:SI 2 "general_operand" "")))]
  ;; Operand 2 not used on the i386.
  ""
  "
{
  rtx addr;

  if (flag_pic)
    current_function_uses_pic_offset_table = 1;

  /* With half-pic, force the address into a register.  */
  addr = XEXP (operands[1], 0);
  if (GET_CODE (addr) != REG && HALF_PIC_P () && !CONSTANT_ADDRESS_P (addr))
    XEXP (operands[1], 0) = force_reg (Pmode, addr);

  if (! expander_call_insn_operand (operands[1], QImode))
    operands[1]
      = change_address (operands[1], VOIDmode,
			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 ()"
  "")

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

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

(define_insn "nop"
  [(const_int 0)]
  ""
  "nop"
  [(set_attr "length" "1")
   (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")])

(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 (); 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" "1")
   (set_attr "ppro_uops" "few")])

(define_expand "ffssi2"
  [(set (match_operand:SI 0 "general_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 (CCmode, 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.  Following code is recommended by
     the Intel Optimizing Manual as resonable 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 (0x3fe)));

      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 (CCmode, 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;  
}")

;; %%% The CCmode here is not strictly correct -- only Z is defined.
;; But I don't think this can be used except for from above.
(define_insn "ffssi_1"
  [(set (reg:CC 17)
        (compare:CC (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 "length_opcode" "3")
   (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.

(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"
  "* 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")))])

(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")])

(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")])

(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"
  "* 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")))])

(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")])

(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")])

(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"
  "* 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")))])

(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")))])

(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"
  "* 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")))])

(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 "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 "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")))])

(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")))])

(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")))])

(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")))])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

(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")])

;; Block operation instructions

(define_expand "movstrsi"
  [(parallel [(set (match_operand:BLK 0 "memory_operand" "")
		   (match_operand:BLK 1 "memory_operand" ""))
	      (use (match_operand:SI 2 "const_int_operand" ""))
	      (use (match_operand:SI 3 "const_int_operand" ""))
	      (clobber (match_scratch:SI 4 ""))
	      (clobber (match_dup 5))
	      (clobber (match_dup 6))])]
  ""
  "
{
  rtx addr0, addr1;

  if (GET_CODE (operands[2]) != CONST_INT)
    FAIL;

  addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));
  addr1 = copy_to_mode_reg (Pmode, XEXP (operands[1], 0));

  operands[5] = addr0;
  operands[6] = addr1;

  operands[0] = change_address (operands[0], VOIDmode, addr0);
  operands[1] = change_address (operands[1], VOIDmode, addr1);
}")

;; 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 "*movstrsi_1"
  [(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
	(mem:BLK (match_operand:SI 1 "address_operand" "S")))
   (use (match_operand:SI 2 "const_int_operand" "n"))
   (use (match_operand:SI 3 "immediate_operand" "i"))
   (clobber (match_scratch:SI 4 "=&c"))
   (clobber (match_dup 0))
   (clobber (match_dup 1))]
  ""
  "*
{
  rtx xops[2];

  output_asm_insn (\"cld\", operands);
  if (GET_CODE (operands[2]) == CONST_INT)
    {
      if (INTVAL (operands[2]) & ~0x03)
	{
	  xops[0] = GEN_INT ((INTVAL (operands[2]) >> 2) & 0x3fffffff);
	  xops[1] = operands[4];

	  output_asm_insn (\"mov{l}\\t{%0, %1|%1,%0}\", xops);
	  output_asm_insn (\"{rep\;movsl|rep movsd}\", xops);
	}
      if (INTVAL (operands[2]) & 0x02)
	output_asm_insn (\"movsw\", operands);
      if (INTVAL (operands[2]) & 0x01)
	output_asm_insn (\"movsb\", operands);
    }
  else
    abort ();
  RET;
}"
  [(set_attr "type" "multi")])

(define_expand "clrstrsi"
  [(set (match_dup 3) (const_int 0))
   (parallel [(set (match_operand:BLK 0 "memory_operand" "")
		   (const_int 0))
	      (use (match_operand:SI 1 "const_int_operand" ""))
	      (use (match_operand:SI 2 "const_int_operand" ""))
	      (use (match_dup 3))
	      (clobber (match_scratch:SI 4 ""))
	      (clobber (match_dup 5))])]
  ""
  "
{
  rtx addr0;

  if (GET_CODE (operands[1]) != CONST_INT)
    FAIL;

  addr0 = copy_to_mode_reg (Pmode, XEXP (operands[0], 0));

  operands[3] = gen_reg_rtx (SImode);
  operands[5] = addr0;

  operands[0] = gen_rtx_MEM (BLKmode, addr0);
}")

;; 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 "*clrstrsi_1"
  [(set (mem:BLK (match_operand:SI 0 "address_operand" "D"))
	(const_int 0))
   (use (match_operand:SI 1 "const_int_operand" "n"))
   (use (match_operand:SI 2 "immediate_operand" "i"))
   (use (match_operand:SI 3 "register_operand" "a"))
   (clobber (match_scratch:SI 4 "=&c"))
   (clobber (match_dup 0))]
  ""
  "*
{
  rtx xops[2];

  output_asm_insn (\"cld\", operands);
  if (GET_CODE (operands[1]) == CONST_INT)
    {
      unsigned int count = INTVAL (operands[1]) & 0xffffffff;
      if (count & ~0x03)
	{
	  xops[0] = GEN_INT (count / 4);
	  xops[1] = operands[4];

	  /* K6: stos takes 1 cycle, rep stos takes 8 + %ecx cycles.
	     80386: 4/5+5n (+2 for set of ecx)
	     80486: 5/7+5n (+1 for set of ecx)
	     */
	  if (count / 4 < ((int) ix86_cpu < (int)PROCESSOR_PENTIUM ? 4 : 6))
	    {
	      do
		output_asm_insn (\"{stosl|stosd}\", xops);
	      while ((count -= 4) > 3);
	    }
	  else
	    {
	      output_asm_insn (\"mov{l}\\t{%0, %1|%1, %0}\", xops);
	      output_asm_insn (\"{rep\;stosl|rep stosd}\", xops);
	    }
	}
      if (INTVAL (operands[1]) & 0x02)
	output_asm_insn (\"stosw\", operands);
      if (INTVAL (operands[1]) & 0x01)
	output_asm_insn (\"stosb\", operands);
    }
  else
    abort ();
  RET;
}"
  [(set_attr "type" "multi")])

(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];

  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_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"))
   (clobber (match_dup 0))
   (clobber (match_dup 1))
   (clobber (match_dup 2))]
  ""
  "cld\;repz{\;| }cmpsb"
  [(set_attr "type" "multi")
   (set_attr "length" "3")])

;; 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"))
   (clobber (match_dup 0))
   (clobber (match_dup 1))
   (clobber (match_dup 2))]
  ""
  ;; The initial compare sets the zero flag.
  "cmp{l}\\t%2, %2\;cld\;repz{\;| }cmpsb"
  [(set_attr "type" "multi")
   (set_attr "length" "5")])

(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, eoschar, align, scratch1, scratch2, scratch3;

  out = operands[0];
  addr = force_reg (Pmode, XEXP (operands[1], 0));
  eoschar = operands[2];
  align = operands[3];
  scratch1 = gen_reg_rtx (SImode);

  if (TARGET_UNROLL_STRLEN && eoschar == const0_rtx && optimize > 1)
    {
      /* 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_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))
   (clobber (match_dup 1))
   (clobber (reg:CC 17))]
  ""
  "cld\;repnz{\;| }scasb"
  [(set_attr "type" "multi")
   (set_attr "length" "3")])

;; 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 "length" "2")])

(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"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")])

(define_insn "*movsicc_c"
  [(set (match_operand:SI 0 "register_operand" "=r,r")
	(if_then_else:SI (match_operator 1 "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"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")])

(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"
  "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"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")])

(define_insn "*movhicc_c"
  [(set (match_operand:HI 0 "register_operand" "=r,r")
	(if_then_else:HI (match_operator 1 "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"
  "@
   cmov%C1\\t{%2, %0|%0, %2}
   cmov%c1\\t{%3, %0|%0, %3}"
  [(set_attr "type" "icmov")])

(define_split 
  [(set (match_operand:HI 0 "register_operand" "")
	(if_then_else:HI (match_operator 1 "comparison_operator" 
				[(reg 17) (const_int 0)])
		      (match_operand:HI 2 "register_operand" "")
		      (match_operand:HI 3 "register_operand" "")))]
  "! TARGET_PARTIAL_REG_STALL && TARGET_CMOVE"
  [(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]);")
			
(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")])

(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")])

(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")])

;; 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 "prologue_allocate_stack"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(plus:SI (match_operand:SI 1 "register_operand" "0")
		 (match_operand:SI 2 "nonmemory_operand" "ri")))
   (set (match_operand:SI 3 "register_operand" "=r")
	(match_dup 3))
   (clobber (reg:CC 17))]
  ""
  "*
{
  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" "alu")])

(define_insn "epilogue_deallocate_stack"
  [(set (match_operand:SI 0 "register_operand" "=r")
	(match_operand:SI 1 "register_operand" "+r"))
   (set (match_dup 1) (match_dup 1))]
  ""
  "mov{l}\\t{%1, %0|%0, %1}"
  [(set_attr "type" "imov")])

(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;
}")

;; 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))]
  "")

(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 && get_attr_length (insn) >= ix86_cost->large_insn
   && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
   && TARGET_SPLIT_LONG_MOVES"
  [(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 && get_attr_length (insn) >= ix86_cost->large_insn
   && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
   && TARGET_SPLIT_LONG_MOVES"
  [(parallel [(set (match_dup 1) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (match_dup 0) (match_dup 1))]
  "")

(define_peephole2
  [(match_scratch:QI 1 "q")
   (set (match_operand:QI 0 "memory_operand" "")
        (const_int 0))]
  "! optimize_size && get_attr_length (insn) >= ix86_cost->large_insn
   && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))
   && TARGET_SPLIT_LONG_MOVES"
  [(parallel [(set (match_dup 1) (const_int 0))
	      (clobber (reg:CC 17))])
   (set (match_dup 0) (match_dup 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:CCNO 17)
	(compare:CCNO (match_operand:SI 0 "memory_operand" "")
	(const_int 0)))
   (match_scratch:SI 3 "r")]
  "! 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 reg_dead_p assumes
;; resource info is live.

(define_peephole2
  [(set (match_operand:SI 0 "nonimmediate_operand" "=rm")
	(not:SI (match_operand:SI 1 "nonimmediate_operand" "0")))]
  "!optimize_size
   && reg_dead_p (insn, gen_rtx_REG (CCmode, 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
   && reg_dead_p (insn, gen_rtx_REG (CCmode, 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
   && reg_dead_p (insn, gen_rtx_REG (CCmode, 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:CCNO 17)
	(compare:CCNO (and:SI (match_operand:SI 0 "register_operand" "")
			      (match_operand:SI 1 "immediate_operand" ""))
		      (const_int 0)))]
  "(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)))])]
  "")

(define_peephole2
  [(set (reg:CCNO 17)
	(compare:CCNO (and:HI (match_operand:HI 0 "register_operand" "")
			      (match_operand:HI 1 "immediate_operand" ""))
		      (const_int 0)))]
  "! TARGET_PARTIAL_REG_STALL
   && (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:HI (match_dup 0)
			         (match_dup 1))
		         (const_int 0)))
      (set (match_dup 0)
	   (and:HI (match_dup 0) (match_dup 1)))])]
  "")

(define_peephole2
  [(set (reg:CCNO 17)
	(compare:CCNO (and:QI (match_operand:QI 0 "register_operand" "")
			      (match_operand:QI 1 "immediate_operand" ""))
		      (const_int 0)))]
  "! TARGET_PARTIAL_REG_STALL
   && 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: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)))]
  "! TARGET_PARTIAL_REG_STALL
   && 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)
   && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
  [(parallel [(set (match_dup 0) (const_int 0))
	      (clobber (reg:CC 17))])]
  "")

;; ??? Rewrite these to not introduce the false dependancy.  
;; Currently they'll trip update_life_info's sanity checks.

;; For HI and SI modes, or $-1,reg is smaller than mov $-1,reg.
(define_peephole2
  [(set (match_operand:SI 0 "register_operand" "")
	(const_int -1))]
  "0 && (optimize_size || TARGET_PENTIUM)
   && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
  [(parallel [(set (match_dup 0)
		   (ior:SI (match_dup 0) (const_int -1)))
	      (clobber (reg:CC 17))])]
  "")

(define_peephole2
  [(set (match_operand:HI 0 "register_operand" "")
	(const_int -1))]
  "0 && (optimize_size || TARGET_PENTIUM)
   && reg_dead_p (insn, gen_rtx_REG (CCmode, FLAGS_REG))"
  [(parallel [(set (match_dup 0)
		   (ior:HI (match_dup 0) (const_int -1)))
	      (clobber (reg:CC 17))])]
  "")


;; Call-value patterns last so that the wildcard operand does not
;; disrupt insn-recog's switch tables.

(define_insn "*call_value_pop_1"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "call_insn_operand" "m")
	      (match_operand:SI 2 "general_operand" "g")))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
			    (match_operand:SI 4 "immediate_operand" "i")))]
  ""
  "*
{
  if (constant_call_address_operand (operands[1], GET_MODE (operands[1])))
    return \"call\\t%P1\";
  
  operands[1] = XEXP (operands[1], 0);
  return \"call\\t%*%1\";
}"
  [(set_attr "type" "callv")])

(define_insn "*call_value_pop_2"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "constant_call_address_operand" "")
	      (match_operand:SI 2 "general_operand" "g")))
   (set (reg:SI 7) (plus:SI (reg:SI 7)
			    (match_operand:SI 4 "immediate_operand" "i")))]
  "!HALF_PIC_P ()"
  "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 "general_operand" "g")))]
  ;; Operand 2 not used on the i386.
  ""
  "*
{
  if (constant_call_address_operand (operands[1], GET_MODE (operands[1])))
    return \"call\\t%P1\";
  
  operands[1] = XEXP (operands[1], 0);
  return \"call\\t%*%1\";
}"
  [(set_attr "type" "callv")])

(define_insn "*call_value_2"
  [(set (match_operand 0 "" "")
	(call (match_operand:QI 1 "constant_call_address_operand" "")
	      (match_operand:SI 2 "general_operand" "g")))]
  "!HALF_PIC_P ()"
  "call\\t%P1"
  [(set_attr "type" "callv")])
