;; IA-64 Machine description template
;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005
;; Free Software Foundation, Inc.
;; Contributed by James E. Wilson <wilson@cygnus.com> and
;;		  David Mosberger <davidm@hpl.hp.com>.

;; This file is part of GCC.

;; GCC 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.

;; GCC 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 GCC; see the file COPYING.  If not, write to
;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.

;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.

;; ??? register_operand accepts (subreg:DI (mem:SI X)) which forces later
;; reload.  This will be fixed once scheduling support is turned on.

;; ??? Optimize for post-increment addressing modes.

;; ??? fselect is not supported, because there is no integer register
;; equivalent.

;; ??? fp abs/min/max instructions may also work for integer values.

;; ??? Would a predicate_reg_operand predicate be useful?  The HP one is buggy,
;; it assumes the operand is a register and takes REGNO of it without checking.

;; ??? Would a branch_reg_operand predicate be useful?  The HP one is buggy,
;; it assumes the operand is a register and takes REGNO of it without checking.

;; ??? Go through list of documented named patterns and look for more to
;; implement.

;; ??? Go through instruction manual and look for more instructions that
;; can be emitted.

;; ??? Add function unit scheduling info for Itanium (TM) processor.

;; ??? Need a better way to describe alternate fp status registers.

(define_constants
  [; Relocations
   (UNSPEC_LTOFF_DTPMOD		0)
   (UNSPEC_LTOFF_DTPREL		1)
   (UNSPEC_DTPREL		2)
   (UNSPEC_LTOFF_TPREL		3)
   (UNSPEC_TPREL		4)
   (UNSPEC_DTPMOD		5)

   (UNSPEC_LD_BASE		9)
   (UNSPEC_GR_SPILL		10)
   (UNSPEC_GR_RESTORE		11)
   (UNSPEC_FR_SPILL		12)
   (UNSPEC_FR_RESTORE		13)
   (UNSPEC_FR_RECIP_APPROX	14)
   (UNSPEC_PRED_REL_MUTEX	15)
   (UNSPEC_GETF_EXP		16)
   (UNSPEC_PIC_CALL		17)
   (UNSPEC_MF			18)
   (UNSPEC_CMPXCHG_ACQ		19)
   (UNSPEC_FETCHADD_ACQ		20)
   (UNSPEC_BSP_VALUE		21)
   (UNSPEC_FLUSHRS		22)
   (UNSPEC_BUNDLE_SELECTOR	23)
   (UNSPEC_ADDP4		24)
   (UNSPEC_PROLOGUE_USE		25)
   (UNSPEC_RET_ADDR		26)
   (UNSPEC_SETF_EXP             27)
   (UNSPEC_FR_SQRT_RECIP_APPROX 28)
   (UNSPEC_SHRP			29)
   (UNSPEC_COPYSIGN		30)
   (UNSPEC_VECT_EXTR		31)
  ])

(define_constants
  [(UNSPECV_ALLOC		0)
   (UNSPECV_BLOCKAGE		1)
   (UNSPECV_INSN_GROUP_BARRIER	2)
   (UNSPECV_BREAK		3)
   (UNSPECV_SET_BSP		4)
   (UNSPECV_PSAC_ALL		5)	; pred.safe_across_calls
   (UNSPECV_PSAC_NORMAL		6)
   (UNSPECV_SETJMP_RECEIVER	7)
  ])

(include "predicates.md")

;; ::::::::::::::::::::
;; ::
;; :: Attributes
;; ::
;; ::::::::::::::::::::

;; Processor type.  This attribute must exactly match the processor_type
;; enumeration in ia64.h.
(define_attr "cpu" "itanium,itanium2" (const (symbol_ref "ia64_tune")))

;; Instruction type.  This primarily determines how instructions can be
;; packed in bundles, and secondarily affects scheduling to function units.

;; A alu, can go in I or M syllable of a bundle
;; I integer
;; M memory
;; F floating-point
;; B branch
;; L long immediate, takes two syllables
;; S stop bit

;; ??? Should not have any pattern with type unknown.  Perhaps add code to
;; check this in md_reorg?  Currently use unknown for patterns which emit
;; multiple instructions, patterns which emit 0 instructions, and patterns
;; which emit instruction that can go in any slot (e.g. nop).

(define_attr "itanium_class" "unknown,ignore,stop_bit,br,fcmp,fcvtfx,fld,
	fldp,fmac,fmisc,frar_i,frar_m,frbr,frfr,frpr,ialu,icmp,ilog,ishf,
	ld,chk_s,long_i,mmalua,mmmul,mmshf,mmshfi,rse_m,scall,sem,stf,
        st,syst_m0, syst_m,tbit,toar_i,toar_m,tobr,tofr,topr,xmpy,xtd,nop,
        nop_b,nop_f,nop_i,nop_m,nop_x,lfetch,pre_cycle"
  (const_string "unknown"))

;; chk_s has an I and an M form; use type A for convenience.
(define_attr "type" "unknown,A,I,M,F,B,L,X,S"
  (cond [(eq_attr "itanium_class" "ld,st,fld,fldp,stf,sem,nop_m") (const_string "M")
	 (eq_attr "itanium_class" "rse_m,syst_m,syst_m0") (const_string "M")
	 (eq_attr "itanium_class" "frar_m,toar_m,frfr,tofr") (const_string "M")
	 (eq_attr "itanium_class" "lfetch") (const_string "M")
	 (eq_attr "itanium_class" "chk_s,ialu,icmp,ilog,mmalua")
	   (const_string "A")
	 (eq_attr "itanium_class" "fmisc,fmac,fcmp,xmpy") (const_string "F")
	 (eq_attr "itanium_class" "fcvtfx,nop_f") (const_string "F")
	 (eq_attr "itanium_class" "frar_i,toar_i,frbr,tobr") (const_string "I")
	 (eq_attr "itanium_class" "frpr,topr,ishf,xtd,tbit") (const_string "I")
	 (eq_attr "itanium_class" "mmmul,mmshf,mmshfi,nop_i") (const_string "I")
	 (eq_attr "itanium_class" "br,scall,nop_b") (const_string "B")
	 (eq_attr "itanium_class" "stop_bit") (const_string "S")
	 (eq_attr "itanium_class" "nop_x") (const_string "X")
	 (eq_attr "itanium_class" "long_i") (const_string "L")]
	(const_string "unknown")))

(define_attr "itanium_requires_unit0" "no,yes"
  (cond [(eq_attr "itanium_class" "syst_m0,sem,frfr,rse_m") (const_string "yes")
	 (eq_attr "itanium_class" "toar_m,frar_m") (const_string "yes")
	 (eq_attr "itanium_class" "frbr,tobr,mmmul") (const_string "yes")
	 (eq_attr "itanium_class" "tbit,ishf,topr,frpr") (const_string "yes")
	 (eq_attr "itanium_class" "toar_i,frar_i") (const_string "yes")
	 (eq_attr "itanium_class" "fmisc,fcmp") (const_string "yes")]
	(const_string "no")))

;; Predication.  True iff this instruction can be predicated.

(define_attr "predicable" "no,yes" (const_string "yes"))

;; Empty.  True iff this insn does not generate any code.

(define_attr "empty" "no,yes" (const_string "no"))

;; True iff this insn must be the first insn of an instruction group.
;; This is true for the alloc instruction, and will also be true of others
;; when we have full intrinsics support.

(define_attr "first_insn" "no,yes" (const_string "no"))

;; DFA descriptions of ia64 processors used for insn scheduling and
;; bundling.

(automata_option "ndfa")

;; Uncomment the following line to output automata for debugging.
;; (automata_option "v")

(automata_option "w")

(include "itanium1.md")
(include "itanium2.md")


;; ::::::::::::::::::::
;; ::
;; :: Moves
;; ::
;; ::::::::::::::::::::

;; Set of a single predicate register.  This is only used to implement
;; pr-to-pr move and complement.

(define_insn "*movcci"
  [(set (match_operand:CCI 0 "register_operand" "=c,c,c")
	(match_operand:CCI 1 "nonmemory_operand" "O,n,c"))]
  ""
  "@
   cmp.ne %0, p0 = r0, r0
   cmp.eq %0, p0 = r0, r0
   (%1) cmp.eq.unc %0, p0 = r0, r0"
  [(set_attr "itanium_class" "icmp")
   (set_attr "predicable" "no")])

(define_insn "movbi"
  [(set (match_operand:BI 0 "destination_operand" "=c,c,?c,?*r, c,*r,*r,*m,*r")
	(match_operand:BI 1 "move_operand"        " O,n, c,  c,*r, n,*m,*r,*r"))]
  ""
  "@
   cmp.ne %0, %I0 = r0, r0
   cmp.eq %0, %I0 = r0, r0
   #
   #
   tbit.nz %0, %I0 = %1, 0
   adds %0 = %1, r0
   ld1%O1 %0 = %1%P1
   st1%Q0 %0 = %1%P0
   mov %0 = %1"
  [(set_attr "itanium_class" "icmp,icmp,unknown,unknown,tbit,ialu,ld,st,ialu")])

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(match_operand:BI 1 "register_operand" ""))]
  "reload_completed
   && GET_CODE (operands[0]) == REG && GR_REGNO_P (REGNO (operands[0]))
   && GET_CODE (operands[1]) == REG && PR_REGNO_P (REGNO (operands[1]))"
  [(cond_exec (ne (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 1)))
   (cond_exec (eq (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 0)))]
  "")

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(match_operand:BI 1 "register_operand" ""))]
  "reload_completed
   && GET_CODE (operands[0]) == REG && PR_REGNO_P (REGNO (operands[0]))
   && GET_CODE (operands[1]) == REG && PR_REGNO_P (REGNO (operands[1]))"
  [(set (match_dup 2) (match_dup 4))
   (set (match_dup 3) (match_dup 5))
   (set (match_dup 0) (unspec:BI [(match_dup 0)] UNSPEC_PRED_REL_MUTEX))]
  "operands[2] = gen_rtx_REG (CCImode, REGNO (operands[0]));
   operands[3] = gen_rtx_REG (CCImode, REGNO (operands[0]) + 1);
   operands[4] = gen_rtx_REG (CCImode, REGNO (operands[1]));
   operands[5] = gen_rtx_REG (CCImode, REGNO (operands[1]) + 1);")

(define_expand "movqi"
  [(set (match_operand:QI 0 "general_operand" "")
	(match_operand:QI 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn "*movqi_internal"
  [(set (match_operand:QI 0 "destination_operand" "=r,r,r, m, r,*f,*f")
	(match_operand:QI 1 "move_operand"        "rO,J,m,rO,*f,rO,*f"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
   mov %0 = %r1
   addl %0 = %1, r0
   ld1%O1 %0 = %1%P1
   st1%Q0 %0 = %r1%P0
   getf.sig %0 = %1
   setf.sig %0 = %r1
   mov %0 = %1"
  [(set_attr "itanium_class" "ialu,ialu,ld,st,frfr,tofr,fmisc")])

(define_expand "movhi"
  [(set (match_operand:HI 0 "general_operand" "")
	(match_operand:HI 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn "*movhi_internal"
  [(set (match_operand:HI 0 "destination_operand" "=r,r,r, m, r,*f,*f")
	(match_operand:HI 1 "move_operand"        "rO,J,m,rO,*f,rO,*f"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
   mov %0 = %r1
   addl %0 = %1, r0
   ld2%O1 %0 = %1%P1
   st2%Q0 %0 = %r1%P0
   getf.sig %0 = %1
   setf.sig %0 = %r1
   mov %0 = %1"
  [(set_attr "itanium_class" "ialu,ialu,ld,st,frfr,tofr,fmisc")])

(define_expand "movsi"
  [(set (match_operand:SI 0 "general_operand" "")
	(match_operand:SI 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn "*movsi_internal"
  [(set (match_operand:SI 0 "destination_operand" "=r,r,r,r, m, r,*f,*f, r,*d")
	(match_operand:SI 1 "move_operand"        "rO,J,i,m,rO,*f,rO,*f,*d,rK"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
  mov %0 = %r1
  addl %0 = %1, r0
  movl %0 = %1
  ld4%O1 %0 = %1%P1
  st4%Q0 %0 = %r1%P0
  getf.sig %0 = %1
  setf.sig %0 = %r1
  mov %0 = %1
  mov %0 = %1
  mov %0 = %r1"
  ;; frar_m, toar_m ??? why not frar_i and toar_i
  [(set_attr "itanium_class" "ialu,ialu,long_i,ld,st,frfr,tofr,fmisc,frar_m,toar_m")])

(define_expand "movdi"
  [(set (match_operand:DI 0 "general_operand" "")
	(match_operand:DI 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn "*movdi_internal"
  [(set (match_operand:DI 0 "destination_operand"
		    "=r,r,r,r, m, r,*f,*f,*f, Q, r,*b, r,*e, r,*d, r,*c")
	(match_operand:DI 1 "move_operand"
		    "rO,JT,i,m,rO,*f,rO,*f, Q,*f,*b,rO,*e,rK,*d,rK,*c,rO"))]
  "ia64_move_ok (operands[0], operands[1])"
{
  static const char * const alt[] = {
    "%,mov %0 = %r1",
    "%,addl %0 = %1, r0",
    "%,movl %0 = %1",
    "%,ld8%O1 %0 = %1%P1",
    "%,st8%Q0 %0 = %r1%P0",
    "%,getf.sig %0 = %1",
    "%,setf.sig %0 = %r1",
    "%,mov %0 = %1",
    "%,ldf8 %0 = %1%P1",
    "%,stf8 %0 = %1%P0",
    "%,mov %0 = %1",
    "%,mov %0 = %r1",
    "%,mov %0 = %1",
    "%,mov %0 = %1",
    "%,mov %0 = %1",
    "%,mov %0 = %1",
    "mov %0 = pr",
    "mov pr = %1, -1"
  };

  gcc_assert (which_alternative != 2 || TARGET_NO_PIC
              || !symbolic_operand (operands[1], VOIDmode));

  return alt[which_alternative];
}
  [(set_attr "itanium_class" "ialu,ialu,long_i,ld,st,frfr,tofr,fmisc,fld,stf,frbr,tobr,frar_i,toar_i,frar_m,toar_m,frpr,topr")])

(define_split
  [(set (match_operand 0 "register_operand" "")
	(match_operand 1 "symbolic_operand" ""))]
  "reload_completed"
  [(const_int 0)]
{
  if (ia64_expand_load_address (operands[0], operands[1]))
    DONE;
  else
    FAIL;
})

(define_expand "load_fptr"
  [(set (match_operand:DI 0 "register_operand" "")
	(plus:DI (match_dup 2) (match_operand 1 "function_operand" "")))
   (set (match_dup 0) (match_dup 3))]
  "reload_completed"
{
  operands[2] = pic_offset_table_rtx;
  operands[3] = gen_const_mem (DImode, operands[0]);
})

(define_insn "*load_fptr_internal1"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (reg:DI 1) (match_operand 1 "function_operand" "s")))]
  "reload_completed"
  "addl %0 = @ltoff(@fptr(%1)), gp"
  [(set_attr "itanium_class" "ialu")])

(define_insn "load_gprel"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (reg:DI 1) (match_operand 1 "sdata_symbolic_operand" "s")))]
  "reload_completed"
  "addl %0 = @gprel(%1), gp"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*gprel64_offset"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(minus:DI (match_operand:DI 1 "symbolic_operand" "") (reg:DI 1)))]
  "reload_completed"
  "movl %0 = @gprel(%1)"
  [(set_attr "itanium_class" "long_i")])

(define_expand "load_gprel64"
  [(set (match_operand:DI 0 "register_operand" "")
	(minus:DI (match_operand:DI 1 "symbolic_operand" "") (match_dup 2)))
   (set (match_dup 0)
	(plus:DI (match_dup 2) (match_dup 0)))]
  "reload_completed"
{
  operands[2] = pic_offset_table_rtx;
})

;; This is used as a placeholder for the return address during early
;; compilation.  We won't know where we've placed this until during
;; reload, at which point it can wind up in b0, a general register,
;; or memory.  The only safe destination under these conditions is a
;; general register.

(define_insn_and_split "*movdi_ret_addr"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(const_int 0)] UNSPEC_RET_ADDR))]
  ""
  "#"
  "reload_completed"
  [(const_int 0)]
{
  ia64_split_return_addr_rtx (operands[0]);
  DONE;
}
  [(set_attr "itanium_class" "ialu")])

(define_insn "*load_symptr_high"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (high:DI (match_operand 1 "got_symbolic_operand" "s"))
		 (match_operand:DI 2 "register_operand" "a")))]
  "reload_completed"
{
  if (HAVE_AS_LTOFFX_LDXMOV_RELOCS)
    return "%,addl %0 = @ltoffx(%1), %2";
  else
    return "%,addl %0 = @ltoff(%1), %2";
}
  [(set_attr "itanium_class" "ialu")])

(define_insn "*load_symptr_low"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(lo_sum:DI (match_operand:DI 1 "register_operand" "r")
		   (match_operand 2 "got_symbolic_operand" "s")))]
  "reload_completed"
{
  if (HAVE_AS_LTOFFX_LDXMOV_RELOCS)
    return "%,ld8.mov %0 = [%1], %2";
  else
    return "%,ld8 %0 = [%1]";
}
  [(set_attr "itanium_class" "ld")])

(define_insn_and_split "load_dtpmod"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand 1 "tls_symbolic_operand" "")]
		   UNSPEC_DTPMOD))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 0)
	(plus:DI (unspec:DI [(match_dup 1)] UNSPEC_LTOFF_DTPMOD)
		 (match_dup 2)))
   (set (match_dup 0) (match_dup 3))]
{
  operands[2] = pic_offset_table_rtx;
  operands[3] = gen_const_mem (DImode, operands[0]);
})

(define_insn "*load_ltoff_dtpmod"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (unspec:DI [(match_operand 1 "tls_symbolic_operand" "")]
			    UNSPEC_LTOFF_DTPMOD)
		 (match_operand:DI 2 "register_operand" "a")))]
  "reload_completed"
  "addl %0 = @ltoff(@dtpmod(%1)), %2"
  [(set_attr "itanium_class" "ialu")])

(define_expand "load_dtprel"
  [(set (match_operand:DI 0 "register_operand" "")
	(unspec:DI [(match_operand 1 "tls_symbolic_operand" "")]
		   UNSPEC_DTPREL))]
  ""
  "")

(define_insn "*load_dtprel64"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand 1 "ld_tls_symbolic_operand" "")]
		   UNSPEC_DTPREL))]
  "TARGET_TLS64"
  "movl %0 = @dtprel(%1)"
  [(set_attr "itanium_class" "long_i")])

(define_insn "*load_dtprel22"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand 1 "ld_tls_symbolic_operand" "")]
		   UNSPEC_DTPREL))]
  ""
  "addl %0 = @dtprel(%1), r0"
  [(set_attr "itanium_class" "ialu")])

(define_insn_and_split "*load_dtprel_gd"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand 1 "tls_symbolic_operand" "")]
		   UNSPEC_DTPREL))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 0)
	(plus:DI (unspec:DI [(match_dup 1)] UNSPEC_LTOFF_DTPREL)
		 (match_dup 2)))
   (set (match_dup 0) (match_dup 3))]
{
  operands[2] = pic_offset_table_rtx;
  operands[3] = gen_const_mem (DImode, operands[0]);
})

(define_insn "*load_ltoff_dtprel"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (unspec:DI [(match_operand 1 "tls_symbolic_operand" "")]
			    UNSPEC_LTOFF_DTPREL)
		 (match_operand:DI 2 "register_operand" "a")))]
  ""
  "addl %0 = @ltoff(@dtprel(%1)), %2"
  [(set_attr "itanium_class" "ialu")])

(define_expand "add_dtprel"
  [(set (match_operand:DI 0 "register_operand" "")
	(plus:DI (unspec:DI [(match_operand 1 "ld_tls_symbolic_operand" "")]
			    UNSPEC_DTPREL)
		 (match_operand:DI 2 "register_operand" "")))]
  "!TARGET_TLS64"
  "")

(define_insn "*add_dtprel14"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (unspec:DI [(match_operand 1 "ld_tls_symbolic_operand" "")]
			    UNSPEC_DTPREL)
		 (match_operand:DI 2 "register_operand" "r")))]
  "TARGET_TLS14"
  "adds %0 = @dtprel(%1), %2"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*add_dtprel22"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (unspec:DI [(match_operand 1 "ld_tls_symbolic_operand" "")]
			    UNSPEC_DTPREL)
		 (match_operand:DI 2 "register_operand" "a")))]
  "TARGET_TLS22"
  "addl %0 = @dtprel(%1), %2"
  [(set_attr "itanium_class" "ialu")])

(define_expand "load_tprel"
  [(set (match_operand:DI 0 "register_operand" "")
	(unspec:DI [(match_operand 1 "tls_symbolic_operand" "")]
		   UNSPEC_TPREL))]
  ""
  "")

(define_insn "*load_tprel64"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand 1 "le_tls_symbolic_operand" "")]
		   UNSPEC_TPREL))]
  "TARGET_TLS64"
  "movl %0 = @tprel(%1)"
  [(set_attr "itanium_class" "long_i")])

(define_insn "*load_tprel22"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand 1 "le_tls_symbolic_operand" "")]
		   UNSPEC_TPREL))]
  ""
  "addl %0 = @tprel(%1), r0"
  [(set_attr "itanium_class" "ialu")])

(define_insn_and_split "*load_tprel_ie"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand 1 "ie_tls_symbolic_operand" "")]
		   UNSPEC_TPREL))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 0)
	(plus:DI (unspec:DI [(match_dup 1)] UNSPEC_LTOFF_TPREL)
		 (match_dup 2)))
   (set (match_dup 0) (match_dup 3))]
{
  operands[2] = pic_offset_table_rtx;
  operands[3] = gen_const_mem (DImode, operands[0]);
})

(define_insn "*load_ltoff_tprel"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (unspec:DI [(match_operand 1 "ie_tls_symbolic_operand" "")]
			    UNSPEC_LTOFF_TPREL)
		 (match_operand:DI 2 "register_operand" "a")))]
  ""
  "addl %0 = @ltoff(@tprel(%1)), %2"
  [(set_attr "itanium_class" "ialu")])

(define_expand "add_tprel"
  [(set (match_operand:DI 0 "register_operand" "")
	(plus:DI (unspec:DI [(match_operand 1 "le_tls_symbolic_operand" "")]
			    UNSPEC_TPREL)
		 (match_operand:DI 2 "register_operand" "")))]
  "!TARGET_TLS64"
  "")

(define_insn "*add_tprel14"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (unspec:DI [(match_operand 1 "le_tls_symbolic_operand" "")]
			    UNSPEC_TPREL)
		 (match_operand:DI 2 "register_operand" "r")))]
  "TARGET_TLS14"
  "adds %0 = @tprel(%1), %2"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*add_tprel22"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(plus:DI (unspec:DI [(match_operand 1 "le_tls_symbolic_operand" "")]
			    UNSPEC_TPREL)
		 (match_operand:DI 2 "register_operand" "a")))]
  "TARGET_TLS22"
  "addl %0 = @tprel(%1), %2"
  [(set_attr "itanium_class" "ialu")])

;; With no offsettable memory references, we've got to have a scratch
;; around to play with the second word.  However, in order to avoid a
;; reload nightmare we lie, claim we don't need one, and fix it up
;; in ia64_split_tmode_move.
(define_expand "movti"
  [(set (match_operand:TI 0 "general_operand" "")
	(match_operand:TI 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn_and_split "*movti_internal"
  [(set (match_operand:TI 0 "destination_operand" "=r,   *fm,*x,*f,  Q")
	(match_operand:TI 1 "general_operand"     "r*fim,r,  Q, *fOQ,*f"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
   #
   #
   ldfp8 %X0 = %1%P1
   #
   #"
  "reload_completed && !ia64_load_pair_ok(operands[0], operands[1])"
  [(const_int 0)]
{
  ia64_split_tmode_move (operands);
  DONE;
}
  [(set_attr "itanium_class" "unknown,unknown,fldp,unknown,unknown")])

;; Floating Point Moves
;;
;; Note - Patterns for SF mode moves are compulsory, but
;; patterns for DF are optional, as GCC can synthesize them.

(define_expand "movsf"
  [(set (match_operand:SF 0 "general_operand" "")
	(match_operand:SF 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn "*movsf_internal"
  [(set (match_operand:SF 0 "destination_operand" "=f,f, Q,*r, f,*r,*r, m")
	(match_operand:SF 1 "general_operand"     "fG,Q,fG,fG,*r,*r, m,*r"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
   mov %0 = %F1
   ldfs %0 = %1%P1
   stfs %0 = %F1%P0
   getf.s %0 = %F1
   setf.s %0 = %1
   mov %0 = %1
   ld4%O1 %0 = %1%P1
   st4%Q0 %0 = %1%P0"
  [(set_attr "itanium_class" "fmisc,fld,stf,frfr,tofr,ialu,ld,st")])

(define_expand "movdf"
  [(set (match_operand:DF 0 "general_operand" "")
	(match_operand:DF 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn "*movdf_internal"
  [(set (match_operand:DF 0 "destination_operand" "=f,f, Q,*r, f,*r,*r, m")
	(match_operand:DF 1 "general_operand"     "fG,Q,fG,fG,*r,*r, m,*r"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
   mov %0 = %F1
   ldfd %0 = %1%P1
   stfd %0 = %F1%P0
   getf.d %0 = %F1
   setf.d %0 = %1
   mov %0 = %1
   ld8%O1 %0 = %1%P1
   st8%Q0 %0 = %1%P0"
  [(set_attr "itanium_class" "fmisc,fld,stf,frfr,tofr,ialu,ld,st")])

;; With no offsettable memory references, we've got to have a scratch
;; around to play with the second word if the variable winds up in GRs.
(define_expand "movxf"
  [(set (match_operand:XF 0 "general_operand" "")
	(match_operand:XF 1 "general_operand" ""))]
  ""
{
  if (ia64_expand_movxf_movrf (XFmode, operands))
    DONE;
})

;; ??? There's no easy way to mind volatile acquire/release semantics.

(define_insn "*movxf_internal"
  [(set (match_operand:XF 0 "destination_operand" "=f,f, m")
	(match_operand:XF 1 "general_operand"     "fG,m,fG"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
   mov %0 = %F1
   ldfe %0 = %1%P1
   stfe %0 = %F1%P0"
  [(set_attr "itanium_class" "fmisc,fld,stf")])

;; Same as for movxf, but for RFmode.
(define_expand "movrf"
  [(set (match_operand:RF 0 "general_operand" "")
	(match_operand:RF 1 "general_operand" ""))]
  ""
{
  if (ia64_expand_movxf_movrf (RFmode, operands))
    DONE;
})

(define_insn "*movrf_internal"
  [(set (match_operand:RF 0 "destination_operand" "=f,f, m")
	(match_operand:RF 1 "general_operand"     "fG,m,fG"))]
  "ia64_move_ok (operands[0], operands[1])"
  "@
   mov %0 = %F1
   ldf.fill %0 = %1%P1
   stf.spill %0 = %F1%P0"
  [(set_attr "itanium_class" "fmisc,fld,stf")])

;; Better code generation via insns that deal with TFmode register pairs
;; directly.  Same concerns apply as for TImode.
(define_expand "movtf"
  [(set (match_operand:TF 0 "general_operand" "")
	(match_operand:TF 1 "general_operand" ""))]
  ""
{
  rtx op1 = ia64_expand_move (operands[0], operands[1]);
  if (!op1)
    DONE;
  operands[1] = op1;
})

(define_insn_and_split "*movtf_internal"
  [(set (match_operand:TF 0 "destination_operand"  "=r,r,m")
	(match_operand:TF 1 "general_operand"      "ri,m,r"))]
  "ia64_move_ok (operands[0], operands[1])"
  "#"
  "reload_completed"
  [(const_int 0)]
{
  ia64_split_tmode_move (operands);
  DONE;
}
  [(set_attr "itanium_class" "unknown")
   (set_attr "predicable" "no")])


;; ::::::::::::::::::::
;; ::
;; :: Conversions
;; ::
;; ::::::::::::::::::::

;; Signed conversions from a smaller integer to a larger integer

(define_insn "extendqidi2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(sign_extend:DI (match_operand:QI 1 "gr_register_operand" "r")))]
  ""
  "sxt1 %0 = %1"
  [(set_attr "itanium_class" "xtd")])

(define_insn "extendhidi2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(sign_extend:DI (match_operand:HI 1 "gr_register_operand" "r")))]
  ""
  "sxt2 %0 = %1"
  [(set_attr "itanium_class" "xtd")])

(define_insn "extendsidi2"
  [(set (match_operand:DI 0 "grfr_register_operand" "=r,?f")
	(sign_extend:DI (match_operand:SI 1 "grfr_register_operand" "r,f")))]
  ""
  "@
   sxt4 %0 = %1
   fsxt.r %0 = %1, %1"
  [(set_attr "itanium_class" "xtd,fmisc")])

;; Unsigned conversions from a smaller integer to a larger integer

(define_insn "zero_extendqidi2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r,r")
	(zero_extend:DI (match_operand:QI 1 "gr_nonimmediate_operand" "r,m")))]
  ""
  "@
   zxt1 %0 = %1
   ld1%O1 %0 = %1%P1"
  [(set_attr "itanium_class" "xtd,ld")])

(define_insn "zero_extendhidi2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r,r")
	(zero_extend:DI (match_operand:HI 1 "gr_nonimmediate_operand" "r,m")))]
  ""
  "@
   zxt2 %0 = %1
   ld2%O1 %0 = %1%P1"
  [(set_attr "itanium_class" "xtd,ld")])

(define_insn "zero_extendsidi2"
  [(set (match_operand:DI 0 "grfr_register_operand" "=r,r,?f")
	(zero_extend:DI
	  (match_operand:SI 1 "grfr_nonimmediate_operand" "r,m,f")))]
  ""
  "@
   addp4 %0 = %1, r0
   ld4%O1 %0 = %1%P1
   fmix.r %0 = f0, %1"
  [(set_attr "itanium_class" "ialu,ld,fmisc")])

;; Convert between floating point types of different sizes.

;; At first glance, it would appear that emitting fnorm for an extending
;; conversion is unnecessary.  However, the stf and getf instructions work
;; correctly only if the input is properly rounded for its type.  In
;; particular, we get the wrong result for getf.d/stfd if the input is a
;; denorm single.  Since we don't know what the next instruction will be, we
;; have to emit an fnorm.

;; ??? Optimization opportunity here.  Get rid of the insn altogether
;; when we can.  Should probably use a scheme like has been proposed
;; for ia32 in dealing with operands that match unary operators.  This
;; would let combine merge the thing into adjacent insns.  See also how the
;; mips port handles SIGN_EXTEND as operands to integer arithmetic insns via
;; se_register_operand.

(define_insn "extendsfdf2"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_extend:DF (match_operand:SF 1 "fr_register_operand" "f")))]
  ""
  "fnorm.d %0 = %1"
  [(set_attr "itanium_class" "fmac")])

(define_insn "extendsfxf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(float_extend:XF (match_operand:SF 1 "fr_register_operand" "f")))]
  ""
  "fnorm %0 = %1"
  [(set_attr "itanium_class" "fmac")])

(define_insn "extenddfxf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(float_extend:XF (match_operand:DF 1 "fr_register_operand" "f")))]
  ""
  "fnorm %0 = %1"
  [(set_attr "itanium_class" "fmac")])

(define_insn "truncdfsf2"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF (match_operand:DF 1 "fr_register_operand" "f")))]
  ""
  "fnorm.s %0 = %1"
  [(set_attr "itanium_class" "fmac")])

(define_insn "truncxfsf2"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF (match_operand:XF 1 "fr_register_operand" "f")))]
  ""
  "fnorm.s %0 = %1"
  [(set_attr "itanium_class" "fmac")])

(define_insn "truncxfdf2"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF (match_operand:XF 1 "fr_register_operand" "f")))]
  ""
  "fnorm.d %0 = %1"
  [(set_attr "itanium_class" "fmac")])

;; Convert between signed integer types and floating point.

(define_insn "floatdixf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(float:XF (match_operand:DI 1 "fr_register_operand" "f")))]
  ""
  "fcvt.xf %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fix_truncsfdi2"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(fix:DI (match_operand:SF 1 "fr_register_operand" "f")))]
  ""
  "fcvt.fx.trunc %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fix_truncdfdi2"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(fix:DI (match_operand:DF 1 "fr_register_operand" "f")))]
  ""
  "fcvt.fx.trunc %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fix_truncxfdi2"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(fix:DI (match_operand:XF 1 "fr_register_operand" "f")))]
  ""
  "fcvt.fx.trunc %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fix_truncxfdi2_alts"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(fix:DI (match_operand:XF 1 "fr_register_operand" "f")))
   (use (match_operand:SI 2 "const_int_operand" ""))]
  ""
  "fcvt.fx.trunc.s%2 %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

;; Convert between unsigned integer types and floating point.

(define_insn "floatunsdisf2"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(unsigned_float:SF (match_operand:DI 1 "fr_register_operand" "f")))]
  ""
  "fcvt.xuf.s %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "floatunsdidf2"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(unsigned_float:DF (match_operand:DI 1 "fr_register_operand" "f")))]
  ""
  "fcvt.xuf.d %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "floatunsdixf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(unsigned_float:XF (match_operand:DI 1 "fr_register_operand" "f")))]
  ""
  "fcvt.xuf %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fixuns_truncsfdi2"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(unsigned_fix:DI (match_operand:SF 1 "fr_register_operand" "f")))]
  ""
  "fcvt.fxu.trunc %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fixuns_truncdfdi2"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(unsigned_fix:DI (match_operand:DF 1 "fr_register_operand" "f")))]
  ""
  "fcvt.fxu.trunc %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fixuns_truncxfdi2"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(unsigned_fix:DI (match_operand:XF 1 "fr_register_operand" "f")))]
  ""
  "fcvt.fxu.trunc %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

(define_insn "fixuns_truncxfdi2_alts"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(unsigned_fix:DI (match_operand:XF 1 "fr_register_operand" "f")))
   (use (match_operand:SI 2 "const_int_operand" ""))]
  ""
  "fcvt.fxu.trunc.s%2 %0 = %1"
  [(set_attr "itanium_class" "fcvtfx")])

;; ::::::::::::::::::::
;; ::
;; :: Bit field extraction
;; ::
;; ::::::::::::::::::::

(define_insn "extv"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(sign_extract:DI (match_operand:DI 1 "gr_register_operand" "r")
			 (match_operand:DI 2 "extr_len_operand" "n")
			 (match_operand:DI 3 "shift_count_operand" "M")))]
  ""
  "extr %0 = %1, %3, %2"
  [(set_attr "itanium_class" "ishf")])

(define_insn "extzv"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(zero_extract:DI (match_operand:DI 1 "gr_register_operand" "r")
			 (match_operand:DI 2 "extr_len_operand" "n")
			 (match_operand:DI 3 "shift_count_operand" "M")))]
  ""
  "extr.u %0 = %1, %3, %2"
  [(set_attr "itanium_class" "ishf")])

;; Insert a bit field.
;; Can have 3 operands, source1 (inserter), source2 (insertee), dest.
;; Source1 can be 0 or -1.
;; Source2 can be 0.

;; ??? Actual dep instruction is more powerful than what these insv
;; patterns support.  Unfortunately, combine is unable to create patterns
;; where source2 != dest.

(define_expand "insv"
  [(set (zero_extract:DI (match_operand:DI 0 "gr_register_operand" "")
			 (match_operand:DI 1 "const_int_operand" "")
			 (match_operand:DI 2 "const_int_operand" ""))
	(match_operand:DI 3 "nonmemory_operand" ""))]
  ""
{
  int width = INTVAL (operands[1]);
  int shift = INTVAL (operands[2]);

  /* If operand[3] is a constant, and isn't 0 or -1, then load it into a
     pseudo.  */
  if (! register_operand (operands[3], DImode)
      && operands[3] != const0_rtx && operands[3] != constm1_rtx)
    operands[3] = force_reg (DImode, operands[3]);

  /* If this is a single dep instruction, we have nothing to do.  */
  if (! ((register_operand (operands[3], DImode) && width <= 16)
	 || operands[3] == const0_rtx || operands[3] == constm1_rtx))
    {
      /* Check for cases that can be implemented with a mix instruction.  */
      if (width == 32 && shift == 0)
	{
	  /* Directly generating the mix4left instruction confuses
	     optimize_bit_field in function.c.  Since this is performing
	     a useful optimization, we defer generation of the complicated
	     mix4left RTL to the first splitting phase.  */
	  rtx tmp = gen_reg_rtx (DImode);
	  emit_insn (gen_shift_mix4left (operands[0], operands[3], tmp));
	  DONE;
	}
      else if (width == 32 && shift == 32)
	{
	  emit_insn (gen_mix4right (operands[0], operands[3]));
	  DONE;
	}

      /* We could handle remaining cases by emitting multiple dep
	 instructions.

	 If we need more than two dep instructions then we lose.  A 6
	 insn sequence mov mask1,mov mask2,shl;;and,and;;or is better than
	 mov;;dep,shr;;dep,shr;;dep.  The former can be executed in 3 cycles,
	 the latter is 6 cycles on an Itanium (TM) processor, because there is
	 only one function unit that can execute dep and shr immed.

	 If we only need two dep instruction, then we still lose.
	 mov;;dep,shr;;dep is still 4 cycles.  Even if we optimize away
	 the unnecessary mov, this is still undesirable because it will be
	 hard to optimize, and it creates unnecessary pressure on the I0
	 function unit.  */

      FAIL;

#if 0
      /* This code may be useful for other IA-64 processors, so we leave it in
	 for now.  */
      while (width > 16)
	{
	  rtx tmp;

	  emit_insn (gen_insv (operands[0], GEN_INT (16), GEN_INT (shift),
			       operands[3]));
	  shift += 16;
	  width -= 16;
	  tmp = gen_reg_rtx (DImode);
	  emit_insn (gen_lshrdi3 (tmp, operands[3], GEN_INT (16)));
	  operands[3] = tmp;
	}
      operands[1] = GEN_INT (width);
      operands[2] = GEN_INT (shift);
#endif
    }
})

(define_insn "*insv_internal"
  [(set (zero_extract:DI (match_operand:DI 0 "gr_register_operand" "+r")
			 (match_operand:DI 1 "const_int_operand" "n")
			 (match_operand:DI 2 "const_int_operand" "n"))
	(match_operand:DI 3 "nonmemory_operand" "rP"))]
  "(gr_register_operand (operands[3], DImode) && INTVAL (operands[1]) <= 16)
   || operands[3] == const0_rtx || operands[3] == constm1_rtx"
  "dep %0 = %3, %0, %2, %1"
  [(set_attr "itanium_class" "ishf")])

;; Combine doesn't like to create bit-field insertions into zero.
(define_insn "*shladdp4_internal"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(and:DI (ashift:DI (match_operand:DI 1 "gr_register_operand" "r")
			   (match_operand:DI 2 "shladd_log2_operand" "n"))
		(match_operand:DI 3 "const_int_operand" "n")))]
  "ia64_depz_field_mask (operands[3], operands[2]) + INTVAL (operands[2]) == 32"
  "shladdp4 %0 = %1, %2, r0"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*depz_internal"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(and:DI (ashift:DI (match_operand:DI 1 "gr_register_operand" "r")
			   (match_operand:DI 2 "const_int_operand" "n"))
		(match_operand:DI 3 "const_int_operand" "n")))]
  "CONST_OK_FOR_M (INTVAL (operands[2]))
   && ia64_depz_field_mask (operands[3], operands[2]) > 0"
{
  operands[3] = GEN_INT (ia64_depz_field_mask (operands[3], operands[2]));
  return "%,dep.z %0 = %1, %2, %3";
}
  [(set_attr "itanium_class" "ishf")])

(define_insn "shift_mix4left"
  [(set (zero_extract:DI (match_operand:DI 0 "gr_register_operand" "+r")
			 (const_int 32) (const_int 0))
	(match_operand:DI 1 "gr_register_operand" "r"))
   (clobber (match_operand:DI 2 "gr_register_operand" "=r"))]
  ""
  "#"
  [(set_attr "itanium_class" "unknown")])

(define_split
  [(set (zero_extract:DI (match_operand:DI 0 "register_operand" "")
			 (const_int 32) (const_int 0))
	(match_operand:DI 1 "register_operand" ""))
   (clobber (match_operand:DI 2 "register_operand" ""))]
  ""
  [(set (match_dup 3) (ashift:DI (match_dup 1) (const_int 32)))
   (set (zero_extract:DI (match_dup 0) (const_int 32) (const_int 0))
	(lshiftrt:DI (match_dup 3) (const_int 32)))]
  "operands[3] = operands[2];")

(define_insn "*mix4left"
  [(set (zero_extract:DI (match_operand:DI 0 "gr_register_operand" "+r")
			 (const_int 32) (const_int 0))
	(lshiftrt:DI (match_operand:DI 1 "gr_register_operand" "r")
		     (const_int 32)))]
  ""
  "mix4.l %0 = %0, %r1"
  [(set_attr "itanium_class" "mmshf")])

(define_insn "mix4right"
  [(set (zero_extract:DI (match_operand:DI 0 "gr_register_operand" "+r")
			 (const_int 32) (const_int 32))
	(match_operand:DI 1 "gr_reg_or_0_operand" "rO"))]
  ""
  "mix4.r %0 = %r1, %0"
  [(set_attr "itanium_class" "mmshf")])

;; This is used by the rotrsi3 pattern.

(define_insn "*mix4right_3op"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(ior:DI (zero_extend:DI (match_operand:SI 1 "gr_register_operand" "r"))
		(ashift:DI (zero_extend:DI
			     (match_operand:SI 2 "gr_register_operand" "r"))
			   (const_int 32))))]
  ""
  "mix4.r %0 = %2, %1"
  [(set_attr "itanium_class" "mmshf")])


;; ::::::::::::::::::::
;; ::
;; :: 1 bit Integer arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn_and_split "andbi3"
  [(set (match_operand:BI 0 "register_operand" "=c,c,r")
	(and:BI (match_operand:BI 1 "register_operand" "%0,0,r")
		(match_operand:BI 2 "register_operand" "c,r,r")))]
  ""
  "@
   #
   tbit.nz.and.orcm %0, %I0 = %2, 0
   and %0 = %2, %1"
  "reload_completed
   && GET_CODE (operands[0]) == REG && PR_REGNO_P (REGNO (operands[0]))
   && GET_CODE (operands[2]) == REG && PR_REGNO_P (REGNO (operands[2]))"
  [(cond_exec (eq (match_dup 2) (const_int 0))
     (set (match_dup 0) (and:BI (ne:BI (const_int 0) (const_int 0))
				(match_dup 0))))]
  ""
  [(set_attr "itanium_class" "unknown,tbit,ilog")])

(define_insn_and_split "*andcmbi3"
  [(set (match_operand:BI 0 "register_operand" "=c,c,r")
	(and:BI (not:BI (match_operand:BI 1 "register_operand" "c,r,r"))
		(match_operand:BI 2 "register_operand" "0,0,r")))]
  ""
  "@
   #
   tbit.z.and.orcm %0, %I0 = %1, 0
   andcm %0 = %2, %1"
  "reload_completed
   && GET_CODE (operands[0]) == REG && PR_REGNO_P (REGNO (operands[0]))
   && GET_CODE (operands[1]) == REG && PR_REGNO_P (REGNO (operands[1]))"
  [(cond_exec (ne (match_dup 1) (const_int 0))
     (set (match_dup 0) (and:BI (ne:BI (const_int 0) (const_int 0))
				(match_dup 0))))]
  ""
  [(set_attr "itanium_class" "unknown,tbit,ilog")])

(define_insn_and_split "iorbi3"
  [(set (match_operand:BI 0 "register_operand" "=c,c,r")
	(ior:BI (match_operand:BI 1 "register_operand" "%0,0,r")
		(match_operand:BI 2 "register_operand" "c,r,r")))]
  ""
  "@
   #
   tbit.nz.or.andcm %0, %I0 = %2, 0
   or %0 = %2, %1"
  "reload_completed
   && GET_CODE (operands[0]) == REG && PR_REGNO_P (REGNO (operands[0]))
   && GET_CODE (operands[2]) == REG && PR_REGNO_P (REGNO (operands[2]))"
  [(cond_exec (ne (match_dup 2) (const_int 0))
     (set (match_dup 0) (ior:BI (eq:BI (const_int 0) (const_int 0))
				(match_dup 0))))]
  ""
  [(set_attr "itanium_class" "unknown,tbit,ilog")])

(define_insn_and_split "*iorcmbi3"
  [(set (match_operand:BI 0 "register_operand" "=c,c")
	(ior:BI (not:BI (match_operand:BI 1 "register_operand" "c,r"))
		(match_operand:BI 2 "register_operand" "0,0")))]
  ""
  "@
   #
   tbit.z.or.andcm %0, %I0 = %1, 0"
  "reload_completed
   && GET_CODE (operands[0]) == REG && PR_REGNO_P (REGNO (operands[0]))
   && GET_CODE (operands[1]) == REG && PR_REGNO_P (REGNO (operands[1]))"
  [(cond_exec (eq (match_dup 1) (const_int 0))
     (set (match_dup 0) (ior:BI (eq:BI (const_int 0) (const_int 0))
				(match_dup 0))))]
  ""
  [(set_attr "itanium_class" "unknown,tbit")])

(define_insn "one_cmplbi2"
  [(set (match_operand:BI 0 "register_operand" "=c,r,c,&c")
	(not:BI (match_operand:BI 1 "register_operand" "r,r,0,c")))
   (clobber (match_scratch:BI 2 "=X,X,c,X"))]
  ""
  "@
   tbit.z %0, %I0 = %1, 0
   xor %0 = 1, %1
   #
   #"
  [(set_attr "itanium_class" "tbit,ilog,unknown,unknown")])

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(not:BI (match_operand:BI 1 "register_operand" "")))
   (clobber (match_scratch:BI 2 ""))]
  "reload_completed
   && GET_CODE (operands[0]) == REG && PR_REGNO_P (REGNO (operands[0]))
   && rtx_equal_p (operands[0], operands[1])"
  [(set (match_dup 4) (match_dup 3))
   (set (match_dup 0) (const_int 1))
   (cond_exec (ne (match_dup 2) (const_int 0))
     (set (match_dup 0) (const_int 0)))
   (set (match_dup 0) (unspec:BI [(match_dup 0)] UNSPEC_PRED_REL_MUTEX))]
  "operands[3] = gen_rtx_REG (CCImode, REGNO (operands[1]));
   operands[4] = gen_rtx_REG (CCImode, REGNO (operands[2]));")

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(not:BI (match_operand:BI 1 "register_operand" "")))
   (clobber (match_scratch:BI 2 ""))]
  "reload_completed
   && GET_CODE (operands[0]) == REG && PR_REGNO_P (REGNO (operands[0]))
   && GET_CODE (operands[1]) == REG && PR_REGNO_P (REGNO (operands[1]))
   && ! rtx_equal_p (operands[0], operands[1])"
  [(cond_exec (ne (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 0)))
   (cond_exec (eq (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 1)))
   (set (match_dup 0) (unspec:BI [(match_dup 0)] UNSPEC_PRED_REL_MUTEX))]
  "")

(define_insn "*cmpsi_and_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (match_operator:BI 4 "predicate_operator"
		  [(match_operand:SI 2 "gr_reg_or_0_operand" "rO")
		   (match_operand:SI 3 "gr_reg_or_8bit_operand" "rK")])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C4.and.orcm %0, %I0 = %3, %r2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpsi_and_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (match_operator:BI 3 "signed_inequality_operator"
		  [(match_operand:SI 2 "gr_register_operand" "r")
		   (const_int 0)])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C3.and.orcm %0, %I0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpsi_andnot_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (not:BI (match_operator:BI 4 "predicate_operator"
			 [(match_operand:SI 2 "gr_reg_or_0_operand" "rO")
			  (match_operand:SI 3 "gr_reg_or_8bit_operand" "rK")]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C4.or.andcm %I0, %0 = %3, %r2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpsi_andnot_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (not:BI (match_operator:BI 3 "signed_inequality_operator"
			  [(match_operand:SI 2 "gr_register_operand" "r")
			   (const_int 0)]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C3.or.andcm %I0, %0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_and_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (match_operator:BI 4 "predicate_operator"
		  [(match_operand:DI 2 "gr_register_operand" "r")
		   (match_operand:DI 3 "gr_reg_or_8bit_operand" "rK")])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C4.and.orcm %0, %I0 = %3, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_and_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (match_operator:BI 3 "signed_inequality_operator"
		  [(match_operand:DI 2 "gr_register_operand" "r")
		   (const_int 0)])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C3.and.orcm %0, %I0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_andnot_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (not:BI (match_operator:BI 4 "predicate_operator"
			 [(match_operand:DI 2 "gr_register_operand" "r")
			  (match_operand:DI 3 "gr_reg_or_8bit_operand" "rK")]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C4.or.andcm %I0, %0 = %3, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_andnot_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (not:BI (match_operator:BI 3 "signed_inequality_operator"
			  [(match_operand:DI 2 "gr_register_operand" "r")
			   (const_int 0)]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C3.or.andcm %I0, %0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*tbit_and_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (ne:BI (and:DI (match_operand:DI 1 "gr_register_operand" "r")
			       (const_int 1))
		       (const_int 0))
		(match_operand:BI 2 "register_operand" "0")))]
  ""
  "tbit.nz.and.orcm %0, %I0 = %1, 0"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*tbit_and_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (eq:BI (and:DI (match_operand:DI 1 "gr_register_operand" "r")
			       (const_int 1))
		       (const_int 0))
		(match_operand:BI 2 "register_operand" "0")))]
  ""
  "tbit.z.and.orcm %0, %I0 = %1, 0"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*tbit_and_2"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (ne:BI (zero_extract:DI
			 (match_operand:DI 1 "gr_register_operand" "r")
			 (const_int 1)
			 (match_operand:DI 2 "shift_count_operand" "M"))
		       (const_int 0))
		(match_operand:BI 3 "register_operand" "0")))]
  ""
  "tbit.nz.and.orcm %0, %I0 = %1, %2"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*tbit_and_3"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(and:BI (eq:BI (zero_extract:DI
			 (match_operand:DI 1 "gr_register_operand" "r")
			 (const_int 1)
			 (match_operand:DI 2 "shift_count_operand" "M"))
		       (const_int 0))
		(match_operand:BI 3 "register_operand" "0")))]
  ""
  "tbit.z.and.orcm %0, %I0 = %1, %2"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*cmpsi_or_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (match_operator:BI 4 "predicate_operator"
		  [(match_operand:SI 2 "gr_reg_or_0_operand" "rO")
		   (match_operand:SI 3 "gr_reg_or_8bit_operand" "rK")])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C4.or.andcm %0, %I0 = %3, %r2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpsi_or_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (match_operator:BI 3 "signed_inequality_operator"
		  [(match_operand:SI 2 "gr_register_operand" "r")
		   (const_int 0)])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C3.or.andcm %0, %I0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpsi_orcm_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (not:BI (match_operator:BI 4 "predicate_operator"
			 [(match_operand:SI 2 "gr_reg_or_0_operand" "rO")
			  (match_operand:SI 3 "gr_reg_or_8bit_operand" "rK")]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C4.and.orcm %I0, %0 = %3, %r2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpsi_orcm_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (not:BI (match_operator:BI 3 "signed_inequality_operator"
			  [(match_operand:SI 2 "gr_register_operand" "r")
			   (const_int 0)]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp4.%C3.and.orcm %I0, %0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_or_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (match_operator:BI 4 "predicate_operator"
		  [(match_operand:DI 2 "gr_register_operand" "r")
		   (match_operand:DI 3 "gr_reg_or_8bit_operand" "rK")])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C4.or.andcm %0, %I0 = %3, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_or_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (match_operator:BI 3 "signed_inequality_operator"
		  [(match_operand:DI 2 "gr_register_operand" "r")
		   (const_int 0)])
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C3.or.andcm %0, %I0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_orcm_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (not:BI (match_operator:BI 4 "predicate_operator"
			 [(match_operand:DI 2 "gr_register_operand" "r")
			  (match_operand:DI 3 "gr_reg_or_8bit_operand" "rK")]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C4.and.orcm %I0, %0 = %3, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_orcm_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (not:BI (match_operator:BI 3 "signed_inequality_operator"
			  [(match_operand:DI 2 "gr_register_operand" "r")
			   (const_int 0)]))
		(match_operand:BI 1 "register_operand" "0")))]
  ""
  "cmp.%C3.and.orcm %I0, %0 = r0, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*tbit_or_0"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (ne:BI (and:DI (match_operand:DI 1 "gr_register_operand" "r")
			       (const_int 1))
		       (const_int 0))
		(match_operand:BI 2 "register_operand" "0")))]
  ""
  "tbit.nz.or.andcm %0, %I0 = %1, 0"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*tbit_or_1"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (eq:BI (and:DI (match_operand:DI 1 "gr_register_operand" "r")
			       (const_int 1))
		       (const_int 0))
		(match_operand:BI 2 "register_operand" "0")))]
  ""
  "tbit.z.or.andcm %0, %I0 = %1, 0"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*tbit_or_2"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (ne:BI (zero_extract:DI
			 (match_operand:DI 1 "gr_register_operand" "r")
			 (const_int 1)
			 (match_operand:DI 2 "shift_count_operand" "M"))
		       (const_int 0))
		(match_operand:BI 3 "register_operand" "0")))]
  ""
  "tbit.nz.or.andcm %0, %I0 = %1, %2"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*tbit_or_3"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ior:BI (eq:BI (zero_extract:DI
			 (match_operand:DI 1 "gr_register_operand" "r")
			 (const_int 1)
			 (match_operand:DI 2 "shift_count_operand" "M"))
		       (const_int 0))
		(match_operand:BI 3 "register_operand" "0")))]
  ""
  "tbit.z.or.andcm %0, %I0 = %1, %2"
  [(set_attr "itanium_class" "tbit")])

;; Transform test of and/or of setcc into parallel comparisons.

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(ne:BI (and:DI (ne:DI (match_operand:BI 2 "register_operand" "")
			      (const_int 0))
		       (match_operand:DI 3 "register_operand" ""))
	       (const_int 0)))]
  ""
  [(set (match_dup 0)
	(and:BI (ne:BI (and:DI (match_dup 3) (const_int 1)) (const_int 0))
		(match_dup 2)))]
  "")

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(eq:BI (and:DI (ne:DI (match_operand:BI 2 "register_operand" "")
			      (const_int 0))
		       (match_operand:DI 3 "register_operand" ""))
	       (const_int 0)))]
  ""
  [(set (match_dup 0)
	(and:BI (ne:BI (and:DI (match_dup 3) (const_int 1)) (const_int 0))
		(match_dup 2)))
   (parallel [(set (match_dup 0) (not:BI (match_dup 0)))
	      (clobber (scratch))])]
  "")

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(ne:BI (ior:DI (ne:DI (match_operand:BI 2 "register_operand" "")
			      (const_int 0))
		       (match_operand:DI 3 "register_operand" ""))
	       (const_int 0)))]
  ""
  [(set (match_dup 0) 
	(ior:BI (ne:BI (match_dup 3) (const_int 0))
		(match_dup 2)))]
  "")

(define_split
  [(set (match_operand:BI 0 "register_operand" "")
	(eq:BI (ior:DI (ne:DI (match_operand:BI 2 "register_operand" "")
			      (const_int 0))
		       (match_operand:DI 3 "register_operand" ""))
	       (const_int 0)))]
  ""
  [(set (match_dup 0) 
	(ior:BI (ne:BI (match_dup 3) (const_int 0))
		(match_dup 2)))
   (parallel [(set (match_dup 0) (not:BI (match_dup 0)))
	      (clobber (scratch))])]
  "")

;; ??? Incredibly hackish.  Either need four proper patterns with all
;; the alternatives, or rely on sched1 to split the insn and hope that
;; nothing bad happens to the comparisons in the meantime.
;;
;; Alternately, adjust combine to allow 2->2 and 3->3 splits, assuming
;; that we're doing height reduction.
;
;(define_insn_and_split ""
;  [(set (match_operand:BI 0 "register_operand" "=c")
;	(and:BI (and:BI (match_operator:BI 1 "comparison_operator"
;			  [(match_operand 2 "" "")
;			   (match_operand 3 "" "")])
;			(match_operator:BI 4 "comparison_operator"
;			  [(match_operand 5 "" "")
;			   (match_operand 6 "" "")]))
;		(match_dup 0)))]
;  "flag_schedule_insns"
;  "#"
;  ""
;  [(set (match_dup 0) (and:BI (match_dup 1) (match_dup 0)))
;   (set (match_dup 0) (and:BI (match_dup 4) (match_dup 0)))]
;  "")
;
;(define_insn_and_split ""
;  [(set (match_operand:BI 0 "register_operand" "=c")
;	(ior:BI (ior:BI (match_operator:BI 1 "comparison_operator"
;			  [(match_operand 2 "" "")
;			   (match_operand 3 "" "")])
;			(match_operator:BI 4 "comparison_operator"
;			  [(match_operand 5 "" "")
;			   (match_operand 6 "" "")]))
;		(match_dup 0)))]
;  "flag_schedule_insns"
;  "#"
;  ""
;  [(set (match_dup 0) (ior:BI (match_dup 1) (match_dup 0)))
;   (set (match_dup 0) (ior:BI (match_dup 4) (match_dup 0)))]
;  "")
;
;(define_split
;  [(set (match_operand:BI 0 "register_operand" "")
;	(and:BI (and:BI (match_operator:BI 1 "comparison_operator"
;			  [(match_operand 2 "" "")
;			   (match_operand 3 "" "")])
;			(match_operand:BI 7 "register_operand" ""))
;		(and:BI (match_operator:BI 4 "comparison_operator"
;			  [(match_operand 5 "" "")
;			   (match_operand 6 "" "")])
;			(match_operand:BI 8 "register_operand" ""))))]
;  ""
;  [(set (match_dup 0) (and:BI (match_dup 7) (match_dup 8)))
;   (set (match_dup 0) (and:BI (and:BI (match_dup 1) (match_dup 4))
;			      (match_dup 0)))]
;  "")
;
;(define_split
;  [(set (match_operand:BI 0 "register_operand" "")
;	(ior:BI (ior:BI (match_operator:BI 1 "comparison_operator"
;			  [(match_operand 2 "" "")
;			   (match_operand 3 "" "")])
;			(match_operand:BI 7 "register_operand" ""))
;		(ior:BI (match_operator:BI 4 "comparison_operator"
;			  [(match_operand 5 "" "")
;			   (match_operand 6 "" "")])
;			(match_operand:BI 8 "register_operand" ""))))]
;  ""
;  [(set (match_dup 0) (ior:BI (match_dup 7) (match_dup 8)))
;   (set (match_dup 0) (ior:BI (ior:BI (match_dup 1) (match_dup 4))
;			      (match_dup 0)))]
;  "")

;; Try harder to avoid predicate copies by duplicating compares.
;; Note that we'll have already split the predicate copy, which
;; is kind of a pain, but oh well.

(define_peephole2
  [(set (match_operand:BI 0 "register_operand" "")
	(match_operand:BI 1 "comparison_operator" ""))
   (set (match_operand:CCI 2 "register_operand" "")
	(match_operand:CCI 3 "register_operand" ""))
   (set (match_operand:CCI 4 "register_operand" "")
	(match_operand:CCI 5 "register_operand" ""))
   (set (match_operand:BI 6 "register_operand" "")
	(unspec:BI [(match_dup 6)] UNSPEC_PRED_REL_MUTEX))]
  "REGNO (operands[3]) == REGNO (operands[0])
   && REGNO (operands[4]) == REGNO (operands[0]) + 1
   && REGNO (operands[4]) == REGNO (operands[2]) + 1
   && REGNO (operands[6]) == REGNO (operands[2])"
  [(set (match_dup 0) (match_dup 1))
   (set (match_dup 6) (match_dup 7))]
  "operands[7] = copy_rtx (operands[1]);")

;; ::::::::::::::::::::
;; ::
;; :: 16 bit Integer arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn "mulhi3"
  [(set (match_operand:HI 0 "gr_register_operand" "=r")
	(mult:HI (match_operand:HI 1 "gr_register_operand" "r")
		 (match_operand:HI 2 "gr_register_operand" "r")))]
  ""
  "pmpy2.r %0 = %1, %2"
  [(set_attr "itanium_class" "mmmul")])


;; ::::::::::::::::::::
;; ::
;; :: 32 bit Integer arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn "addsi3"
  [(set (match_operand:SI 0 "gr_register_operand" "=r,r,r")
	(plus:SI (match_operand:SI 1 "gr_register_operand" "%r,r,a")
		 (match_operand:SI 2 "gr_reg_or_22bit_operand" "r,I,J")))]
  ""
  "@
   add %0 = %1, %2
   adds %0 = %2, %1
   addl %0 = %2, %1"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*addsi3_plus1"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(plus:SI (plus:SI (match_operand:SI 1 "gr_register_operand" "r")
			  (match_operand:SI 2 "gr_register_operand" "r"))
		 (const_int 1)))]
  ""
  "add %0 = %1, %2, 1"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*addsi3_plus1_alt"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(plus:SI (mult:SI (match_operand:SI 1 "gr_register_operand" "r")
			  (const_int 2))
		 (const_int 1)))]
  ""
  "add %0 = %1, %1, 1"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*addsi3_shladd"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(plus:SI (mult:SI (match_operand:SI 1 "gr_register_operand" "r")
			  (match_operand:SI 2 "shladd_operand" "n"))
		 (match_operand:SI 3 "gr_register_operand" "r")))]
  ""
  "shladd %0 = %1, %S2, %3"
  [(set_attr "itanium_class" "ialu")])

(define_insn "subsi3"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(minus:SI (match_operand:SI 1 "gr_reg_or_8bit_operand" "rK")
		  (match_operand:SI 2 "gr_register_operand" "r")))]
  ""
  "sub %0 = %1, %2"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*subsi3_minus1"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(plus:SI (not:SI (match_operand:SI 1 "gr_register_operand" "r"))
		 (match_operand:SI 2 "gr_register_operand" "r")))]
  ""
  "sub %0 = %2, %1, 1"
  [(set_attr "itanium_class" "ialu")])

;; ??? Could add maddsi3 patterns patterned after the madddi3 patterns.

(define_insn "mulsi3"
  [(set (match_operand:SI 0 "fr_register_operand" "=f")
	(mult:SI (match_operand:SI 1 "grfr_register_operand" "f")
		 (match_operand:SI 2 "grfr_register_operand" "f")))]
  ""
  "xmpy.l %0 = %1, %2"
  [(set_attr "itanium_class" "xmpy")])

(define_insn "maddsi4"
  [(set (match_operand:SI 0 "fr_register_operand" "=f")
	(plus:SI (mult:SI (match_operand:SI 1 "grfr_register_operand" "f")
			  (match_operand:SI 2 "grfr_register_operand" "f"))
		 (match_operand:SI 3 "grfr_register_operand" "f")))]
  ""
  "xma.l %0 = %1, %2, %3"
  [(set_attr "itanium_class" "xmpy")])

(define_insn "negsi2"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(neg:SI (match_operand:SI 1 "gr_register_operand" "r")))]
  ""
  "sub %0 = r0, %1"
  [(set_attr "itanium_class" "ialu")])

(define_expand "abssi2"
  [(set (match_dup 2)
	(ge:BI (match_operand:SI 1 "gr_register_operand" "") (const_int 0)))
   (set (match_operand:SI 0 "gr_register_operand" "")
	(if_then_else:SI (eq (match_dup 2) (const_int 0))
			 (neg:SI (match_dup 1))
			 (match_dup 1)))]
  ""
  { operands[2] = gen_reg_rtx (BImode); })

(define_expand "sminsi3"
  [(set (match_dup 3)
	(ge:BI (match_operand:SI 1 "gr_register_operand" "")
	       (match_operand:SI 2 "gr_register_operand" "")))
   (set (match_operand:SI 0 "gr_register_operand" "")
	(if_then_else:SI (ne (match_dup 3) (const_int 0))
			 (match_dup 2) (match_dup 1)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "smaxsi3"
  [(set (match_dup 3)
	(ge:BI (match_operand:SI 1 "gr_register_operand" "")
	       (match_operand:SI 2 "gr_register_operand" "")))
   (set (match_operand:SI 0 "gr_register_operand" "")
	(if_then_else:SI (ne (match_dup 3) (const_int 0))
			 (match_dup 1) (match_dup 2)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "uminsi3"
  [(set (match_dup 3)
	(geu:BI (match_operand:SI 1 "gr_register_operand" "")
		(match_operand:SI 2 "gr_register_operand" "")))
   (set (match_operand:SI 0 "gr_register_operand" "")
	(if_then_else:SI (ne (match_dup 3) (const_int 0))
			 (match_dup 2) (match_dup 1)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "umaxsi3"
  [(set (match_dup 3)
	(geu:BI (match_operand:SI 1 "gr_register_operand" "")
		(match_operand:SI 2 "gr_register_operand" "")))
   (set (match_operand:SI 0 "gr_register_operand" "")
	(if_then_else:SI (ne (match_dup 3) (const_int 0))
			 (match_dup 1) (match_dup 2)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "divsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(div:SI (match_operand:SI 1 "general_operand" "")
		(match_operand:SI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op1_xf, op2_xf, op0_xf, op0_di, twon34, twon34_exp;

  op0_xf = gen_reg_rtx (XFmode);
  op0_di = gen_reg_rtx (DImode);

  if (CONSTANT_P (operands[1]))
    operands[1] = force_reg (SImode, operands[1]);
  op1_xf = gen_reg_rtx (XFmode);
  expand_float (op1_xf, operands[1], 0);

  if (CONSTANT_P (operands[2]))
    operands[2] = force_reg (SImode, operands[2]);
  op2_xf = gen_reg_rtx (XFmode);
  expand_float (op2_xf, operands[2], 0);

  /* 2^-34 */
  twon34_exp = gen_reg_rtx (DImode);
  emit_move_insn (twon34_exp, GEN_INT (65501));
  twon34 = gen_reg_rtx (XFmode);
  emit_insn (gen_setf_exp_xf (twon34, twon34_exp));

  emit_insn (gen_cond_trap (EQ, operands[2], CONST0_RTX (SImode),
			    CONST1_RTX (SImode)));
  
  emit_insn (gen_divsi3_internal (op0_xf, op1_xf, op2_xf, twon34));

  emit_insn (gen_fix_truncxfdi2_alts (op0_di, op0_xf, const1_rtx));
  emit_move_insn (operands[0], gen_lowpart (SImode, op0_di));
  DONE;
})

(define_expand "modsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(mod:SI (match_operand:SI 1 "general_operand" "")
		(match_operand:SI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op2_neg, op1_di, div;

  div = gen_reg_rtx (SImode);
  emit_insn (gen_divsi3 (div, operands[1], operands[2]));

  op2_neg = expand_unop (SImode, neg_optab, operands[2], NULL_RTX, 0);

  /* This is a trick to get us to reuse the value that we're sure to
     have already copied to the FP regs.  */
  op1_di = gen_reg_rtx (DImode);
  convert_move (op1_di, operands[1], 0);

  emit_insn (gen_maddsi4 (operands[0], div, op2_neg,
			  gen_lowpart (SImode, op1_di)));
  DONE;
})

(define_expand "udivsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(udiv:SI (match_operand:SI 1 "general_operand" "")
		 (match_operand:SI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op1_xf, op2_xf, op0_xf, op0_di, twon34, twon34_exp;

  op0_xf = gen_reg_rtx (XFmode);
  op0_di = gen_reg_rtx (DImode);

  if (CONSTANT_P (operands[1]))
    operands[1] = force_reg (SImode, operands[1]);
  op1_xf = gen_reg_rtx (XFmode);
  expand_float (op1_xf, operands[1], 1);

  if (CONSTANT_P (operands[2]))
    operands[2] = force_reg (SImode, operands[2]);
  op2_xf = gen_reg_rtx (XFmode);
  expand_float (op2_xf, operands[2], 1);

  /* 2^-34 */
  twon34_exp = gen_reg_rtx (DImode);
  emit_move_insn (twon34_exp, GEN_INT (65501));
  twon34 = gen_reg_rtx (XFmode);
  emit_insn (gen_setf_exp_xf (twon34, twon34_exp));

  emit_insn (gen_cond_trap (EQ, operands[2], CONST0_RTX (SImode),
			    CONST1_RTX (SImode)));
  
  emit_insn (gen_divsi3_internal (op0_xf, op1_xf, op2_xf, twon34));

  emit_insn (gen_fixuns_truncxfdi2_alts (op0_di, op0_xf, const1_rtx));
  emit_move_insn (operands[0], gen_lowpart (SImode, op0_di));
  DONE;
})

(define_expand "umodsi3"
  [(set (match_operand:SI 0 "register_operand" "")
	(umod:SI (match_operand:SI 1 "general_operand" "")
		 (match_operand:SI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op2_neg, op1_di, div;

  div = gen_reg_rtx (SImode);
  emit_insn (gen_udivsi3 (div, operands[1], operands[2]));

  op2_neg = expand_unop (SImode, neg_optab, operands[2], NULL_RTX, 0);

  /* This is a trick to get us to reuse the value that we're sure to
     have already copied to the FP regs.  */
  op1_di = gen_reg_rtx (DImode);
  convert_move (op1_di, operands[1], 1);

  emit_insn (gen_maddsi4 (operands[0], div, op2_neg,
			  gen_lowpart (SImode, op1_di)));
  DONE;
})

(define_insn_and_split "divsi3_internal"
  [(set (match_operand:XF 0 "fr_register_operand" "=&f")
	(float:XF (div:SI (match_operand:XF 1 "fr_register_operand" "f")
			  (match_operand:XF 2 "fr_register_operand" "f"))))
   (clobber (match_scratch:XF 4 "=&f"))
   (clobber (match_scratch:XF 5 "=&f"))
   (clobber (match_scratch:BI 6 "=c"))
   (use (match_operand:XF 3 "fr_register_operand" "f"))]
  "TARGET_INLINE_INT_DIV"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0) (div:XF (const_int 1) (match_dup 2)))
	      (set (match_dup 6) (unspec:BI [(match_dup 1) (match_dup 2)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 1))])
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 4) (mult:XF (match_dup 1) (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 5)
		     (minus:XF (match_dup 7)
			       (mult:XF (match_dup 2) (match_dup 0))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 4)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 4))
			      (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 5)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 5))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 4))
			      (match_dup 4)))
		(use (const_int 1))]))
  ] 
  "operands[7] = CONST1_RTX (XFmode);"
  [(set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: 64 bit Integer arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn "adddi3"
  [(set (match_operand:DI 0 "gr_register_operand" "=r,r,r")
	(plus:DI (match_operand:DI 1 "gr_register_operand" "%r,r,a")
		 (match_operand:DI 2 "gr_reg_or_22bit_operand" "r,I,J")))]
  ""
  "@
   add %0 = %1, %2
   adds %0 = %2, %1
   addl %0 = %2, %1"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*adddi3_plus1"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(plus:DI (plus:DI (match_operand:DI 1 "gr_register_operand" "r")
			  (match_operand:DI 2 "gr_register_operand" "r"))
		 (const_int 1)))]
  ""
  "add %0 = %1, %2, 1"
  [(set_attr "itanium_class" "ialu")])

;; This has some of the same problems as shladd.  We let the shladd
;; eliminator hack handle it, which results in the 1 being forced into
;; a register, but not more ugliness here.
(define_insn "*adddi3_plus1_alt"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(plus:DI (mult:DI (match_operand:DI 1 "gr_register_operand" "r")
			  (const_int 2))
		 (const_int 1)))]
  ""
  "add %0 = %1, %1, 1"
  [(set_attr "itanium_class" "ialu")])

(define_insn "subdi3"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(minus:DI (match_operand:DI 1 "gr_reg_or_8bit_operand" "rK")
		  (match_operand:DI 2 "gr_register_operand" "r")))]
  ""
  "sub %0 = %1, %2"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*subdi3_minus1"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(plus:DI (not:DI (match_operand:DI 1 "gr_register_operand" "r"))
		 (match_operand:DI 2 "gr_register_operand" "r")))]
  ""
  "sub %0 = %2, %1, 1"
  [(set_attr "itanium_class" "ialu")])

;; ??? Use grfr instead of fr because of virtual register elimination
;; and silly test cases multiplying by the frame pointer.
(define_insn "muldi3"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(mult:DI (match_operand:DI 1 "grfr_register_operand" "f")
		 (match_operand:DI 2 "grfr_register_operand" "f")))]
  ""
  "xmpy.l %0 = %1, %2"
  [(set_attr "itanium_class" "xmpy")])

;; ??? If operand 3 is an eliminable reg, then register elimination causes the
;; same problem that we have with shladd below.  Unfortunately, this case is
;; much harder to fix because the multiply puts the result in an FP register,
;; but the add needs inputs from a general register.  We add a spurious clobber
;; here so that it will be present just in case register elimination gives us
;; the funny result.

;; ??? Maybe validate_changes should try adding match_scratch clobbers?

;; ??? Maybe we should change how adds are canonicalized.

(define_insn "madddi4"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(plus:DI (mult:DI (match_operand:DI 1 "grfr_register_operand" "f")
			  (match_operand:DI 2 "grfr_register_operand" "f"))
		 (match_operand:DI 3 "grfr_register_operand" "f")))
   (clobber (match_scratch:DI 4 "=X"))]
  ""
  "xma.l %0 = %1, %2, %3"
  [(set_attr "itanium_class" "xmpy")])

;; This can be created by register elimination if operand3 of shladd is an
;; eliminable register or has reg_equiv_constant set.

;; We have to use nonmemory_operand for operand 4, to ensure that the
;; validate_changes call inside eliminate_regs will always succeed.  If it
;; doesn't succeed, then this remain a madddi4 pattern, and will be reloaded
;; incorrectly.

(define_insn "*madddi4_elim"
  [(set (match_operand:DI 0 "register_operand" "=&r")
	(plus:DI (plus:DI (mult:DI (match_operand:DI 1 "register_operand" "f")
				   (match_operand:DI 2 "register_operand" "f"))
			  (match_operand:DI 3 "register_operand" "f"))
		 (match_operand:DI 4 "nonmemory_operand" "rI")))
   (clobber (match_scratch:DI 5 "=f"))]
  "reload_in_progress"
  "#"
  [(set_attr "itanium_class" "unknown")])

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(plus:DI (plus:DI (mult:DI (match_operand:DI 1 "register_operand" "")
				   (match_operand:DI 2 "register_operand" ""))
			  (match_operand:DI 3 "register_operand" ""))
		 (match_operand:DI 4 "gr_reg_or_14bit_operand" "")))
   (clobber (match_scratch:DI 5 ""))]
  "reload_completed"
  [(parallel [(set (match_dup 5) (plus:DI (mult:DI (match_dup 1) (match_dup 2))
					  (match_dup 3)))
	      (clobber (match_dup 0))])
   (set (match_dup 0) (match_dup 5))
   (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
  "")

(define_insn "smuldi3_highpart"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(truncate:DI
	 (lshiftrt:TI
	  (mult:TI (sign_extend:TI
		     (match_operand:DI 1 "fr_register_operand" "f"))
		   (sign_extend:TI
		     (match_operand:DI 2 "fr_register_operand" "f")))
	  (const_int 64))))]
  ""
  "xmpy.h %0 = %1, %2"
  [(set_attr "itanium_class" "xmpy")])

(define_insn "umuldi3_highpart"
  [(set (match_operand:DI 0 "fr_register_operand" "=f")
	(truncate:DI
	 (lshiftrt:TI
	  (mult:TI (zero_extend:TI
		     (match_operand:DI 1 "fr_register_operand" "f"))
		   (zero_extend:TI
		     (match_operand:DI 2 "fr_register_operand" "f")))
	  (const_int 64))))]
  ""
  "xmpy.hu %0 = %1, %2"
  [(set_attr "itanium_class" "xmpy")])

(define_insn "negdi2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(neg:DI (match_operand:DI 1 "gr_register_operand" "r")))]
  ""
  "sub %0 = r0, %1"
  [(set_attr "itanium_class" "ialu")])

(define_expand "absdi2"
  [(set (match_dup 2)
	(ge:BI (match_operand:DI 1 "gr_register_operand" "") (const_int 0)))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(if_then_else:DI (eq (match_dup 2) (const_int 0))
			 (neg:DI (match_dup 1))
			 (match_dup 1)))]
  ""
  { operands[2] = gen_reg_rtx (BImode); })

(define_expand "smindi3"
  [(set (match_dup 3)
	(ge:BI (match_operand:DI 1 "gr_register_operand" "")
	       (match_operand:DI 2 "gr_register_operand" "")))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(if_then_else:DI (ne (match_dup 3) (const_int 0))
			 (match_dup 2) (match_dup 1)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "smaxdi3"
  [(set (match_dup 3)
	(ge:BI (match_operand:DI 1 "gr_register_operand" "")
	       (match_operand:DI 2 "gr_register_operand" "")))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(if_then_else:DI (ne (match_dup 3) (const_int 0))
			 (match_dup 1) (match_dup 2)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "umindi3"
  [(set (match_dup 3)
	(geu:BI (match_operand:DI 1 "gr_register_operand" "")
		(match_operand:DI 2 "gr_register_operand" "")))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(if_then_else:DI (ne (match_dup 3) (const_int 0))
			 (match_dup 2) (match_dup 1)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "umaxdi3"
  [(set (match_dup 3)
	(geu:BI (match_operand:DI 1 "gr_register_operand" "")
		(match_operand:DI 2 "gr_register_operand" "")))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(if_then_else:DI (ne (match_dup 3) (const_int 0))
			 (match_dup 1) (match_dup 2)))]
  ""
  { operands[3] = gen_reg_rtx (BImode); })

(define_expand "ffsdi2"
  [(set (match_dup 6)
	(eq:BI (match_operand:DI 1 "gr_register_operand" "") (const_int 0)))
   (set (match_dup 2) (plus:DI (match_dup 1) (const_int -1)))
   (set (match_dup 5) (const_int 0))
   (set (match_dup 3) (xor:DI (match_dup 1) (match_dup 2)))
   (set (match_dup 4) (popcount:DI (match_dup 3)))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(if_then_else:DI (ne (match_dup 6) (const_int 0))
			 (match_dup 5) (match_dup 4)))]
  ""
{
  operands[2] = gen_reg_rtx (DImode);
  operands[3] = gen_reg_rtx (DImode);
  operands[4] = gen_reg_rtx (DImode);
  operands[5] = gen_reg_rtx (DImode);
  operands[6] = gen_reg_rtx (BImode);
})

(define_expand "ctzdi2"
  [(set (match_dup 2) (plus:DI (match_operand:DI 1 "gr_register_operand" "")
			       (const_int -1)))
   (set (match_dup 3) (not:DI (match_dup 1)))
   (set (match_dup 4) (and:DI (match_dup 2) (match_dup 3)))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(popcount:DI (match_dup 4)))]
  ""
{
  operands[2] = gen_reg_rtx (DImode);
  operands[3] = gen_reg_rtx (DImode);
  operands[4] = gen_reg_rtx (DImode);
})

;; Note the computation here is op0 = 63 - (exp - 0xffff).
(define_expand "clzdi2"
  [(set (match_dup 2)
	(unsigned_float:XF (match_operand:DI 1 "fr_register_operand" "")))
   (set (match_dup 3)
	(unspec:DI [(match_dup 2)] UNSPEC_GETF_EXP))
   (set (match_dup 4) (const_int 65598))
   (set (match_operand:DI 0 "gr_register_operand" "")
	(minus:DI (match_dup 4) (match_dup 3)))]
  ""
{
  operands[2] = gen_reg_rtx (XFmode);
  operands[3] = gen_reg_rtx (DImode);
  operands[4] = gen_reg_rtx (DImode);
})

(define_insn "popcountdi2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(popcount:DI (match_operand:DI 1 "gr_register_operand" "r")))]
  ""
  "popcnt %0 = %1"
  [(set_attr "itanium_class" "mmmul")])

(define_insn "*getf_exp_xf"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(unspec:DI [(match_operand:XF 1 "fr_register_operand" "f")]
		   UNSPEC_GETF_EXP))]
  ""
  "getf.exp %0 = %1"
  [(set_attr "itanium_class" "frfr")])

(define_expand "divdi3"
  [(set (match_operand:DI 0 "register_operand" "")
	(div:DI (match_operand:DI 1 "general_operand" "")
		(match_operand:DI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op1_xf, op2_xf, op0_xf;

  op0_xf = gen_reg_rtx (XFmode);

  if (CONSTANT_P (operands[1]))
    operands[1] = force_reg (DImode, operands[1]);
  op1_xf = gen_reg_rtx (XFmode);
  expand_float (op1_xf, operands[1], 0);

  if (CONSTANT_P (operands[2]))
    operands[2] = force_reg (DImode, operands[2]);
  op2_xf = gen_reg_rtx (XFmode);
  expand_float (op2_xf, operands[2], 0);

  emit_insn (gen_cond_trap (EQ, operands[2], CONST0_RTX (DImode),
			    CONST1_RTX (DImode)));

  if (TARGET_INLINE_INT_DIV == INL_MIN_LAT)
    emit_insn (gen_divdi3_internal_lat (op0_xf, op1_xf, op2_xf));
  else
    emit_insn (gen_divdi3_internal_thr (op0_xf, op1_xf, op2_xf));

  emit_insn (gen_fix_truncxfdi2_alts (operands[0], op0_xf, const1_rtx));
  DONE;
})

(define_expand "moddi3"
  [(set (match_operand:DI 0 "register_operand" "")
	(mod:SI (match_operand:DI 1 "general_operand" "")
		(match_operand:DI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op2_neg, div;

  div = gen_reg_rtx (DImode);
  emit_insn (gen_divdi3 (div, operands[1], operands[2]));

  op2_neg = expand_unop (DImode, neg_optab, operands[2], NULL_RTX, 0);

  emit_insn (gen_madddi4 (operands[0], div, op2_neg, operands[1]));
  DONE;
})

(define_expand "udivdi3"
  [(set (match_operand:DI 0 "register_operand" "")
	(udiv:DI (match_operand:DI 1 "general_operand" "")
		 (match_operand:DI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op1_xf, op2_xf, op0_xf;

  op0_xf = gen_reg_rtx (XFmode);

  if (CONSTANT_P (operands[1]))
    operands[1] = force_reg (DImode, operands[1]);
  op1_xf = gen_reg_rtx (XFmode);
  expand_float (op1_xf, operands[1], 1);

  if (CONSTANT_P (operands[2]))
    operands[2] = force_reg (DImode, operands[2]);
  op2_xf = gen_reg_rtx (XFmode);
  expand_float (op2_xf, operands[2], 1);

  emit_insn (gen_cond_trap (EQ, operands[2], CONST0_RTX (DImode),
			    CONST1_RTX (DImode)));

  if (TARGET_INLINE_INT_DIV == INL_MIN_LAT)
    emit_insn (gen_divdi3_internal_lat (op0_xf, op1_xf, op2_xf));
  else
    emit_insn (gen_divdi3_internal_thr (op0_xf, op1_xf, op2_xf));

  emit_insn (gen_fixuns_truncxfdi2_alts (operands[0], op0_xf, const1_rtx));
  DONE;
})

(define_expand "umoddi3"
  [(set (match_operand:DI 0 "register_operand" "")
	(umod:DI (match_operand:DI 1 "general_operand" "")
		 (match_operand:DI 2 "general_operand" "")))]
  "TARGET_INLINE_INT_DIV"
{
  rtx op2_neg, div;

  div = gen_reg_rtx (DImode);
  emit_insn (gen_udivdi3 (div, operands[1], operands[2]));

  op2_neg = expand_unop (DImode, neg_optab, operands[2], NULL_RTX, 0);

  emit_insn (gen_madddi4 (operands[0], div, op2_neg, operands[1]));
  DONE;
})

(define_insn_and_split "divdi3_internal_lat"
  [(set (match_operand:XF 0 "fr_register_operand" "=&f")
	(float:XF (div:SI (match_operand:XF 1 "fr_register_operand" "f")
			  (match_operand:XF 2 "fr_register_operand" "f"))))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:XF 4 "=&f"))
   (clobber (match_scratch:XF 5 "=&f"))
   (clobber (match_scratch:BI 6 "=c"))]
  "TARGET_INLINE_INT_DIV == INL_MIN_LAT"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0) (div:XF (const_int 1) (match_dup 2)))
	      (set (match_dup 6) (unspec:BI [(match_dup 1) (match_dup 2)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 1))])
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 3)
		     (minus:XF (match_dup 7)
			       (mult:XF (match_dup 2) (match_dup 0))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 4) (mult:XF (match_dup 1) (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 5) (mult:XF (match_dup 3) (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 4)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 4))
			      (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 4))
			      (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 1)
			       (mult:XF (match_dup 2) (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 0))
			      (match_dup 3)))
		(use (const_int 1))]))
  ] 
  "operands[7] = CONST1_RTX (XFmode);"
  [(set_attr "predicable" "no")])

(define_insn_and_split "divdi3_internal_thr"
  [(set (match_operand:XF 0 "fr_register_operand" "=&f")
	(float:XF (div:SI (match_operand:XF 1 "fr_register_operand" "f")
			  (match_operand:XF 2 "fr_register_operand" "f"))))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:XF 4 "=f"))
   (clobber (match_scratch:BI 5 "=c"))]
  "TARGET_INLINE_INT_DIV == INL_MAX_THR"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0) (div:XF (const_int 1) (match_dup 2)))
	      (set (match_dup 5) (unspec:BI [(match_dup 1) (match_dup 2)] 
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 1))])
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (minus:XF (match_dup 6)
			       (mult:XF (match_dup 2) (match_dup 0))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3) (mult:XF (match_dup 3) (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3) (mult:XF (match_dup 0) (match_dup 1)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 1)
			       (mult:XF (match_dup 2) (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 0))
			      (match_dup 3)))
		(use (const_int 1))]))
  ] 
  "operands[6] = CONST1_RTX (XFmode);"
  [(set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: 128 bit Integer arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn "addti3"
  [(set (match_operand:TI 0 "gr_register_operand" "=&r")
	(plus:TI (match_operand:TI 1 "gr_register_operand" "%r")
		 (match_operand:TI 2 "gr_reg_or_14bit_operand" "rI")))
   (clobber (match_scratch:BI 3 "=&c"))]
  ""
  "#"
  [(set_attr "itanium_class" "unknown")])

(define_split
  [(set (match_operand:TI 0 "register_operand" "")
	(plus:TI (match_operand:TI 1 "register_operand" "")
		 (match_operand:TI 2 "register_operand" "")))
   (clobber (match_scratch:BI 3 ""))]
  "reload_completed"
  [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))
   (set (match_dup 3) (ltu:BI (match_dup 0) (match_dup 1)))
   (cond_exec (eq (match_dup 3) (const_int 0))
	      (set (match_dup 4) (plus:DI (match_dup 5) (match_dup 6))))
   (cond_exec (ne (match_dup 3) (const_int 0))
	      (set (match_dup 4)
		   (plus:DI (plus:DI (match_dup 5) (match_dup 6))
			    (const_int 1))))]
{
  operands[4] = gen_highpart (DImode, operands[0]);
  operands[0] = gen_lowpart (DImode, operands[0]);
  operands[5] = gen_highpart (DImode, operands[1]);
  operands[1] = gen_lowpart (DImode, operands[1]);
  operands[6] = gen_highpart (DImode, operands[2]);
  operands[2] = gen_lowpart (DImode, operands[2]);
})

(define_split
  [(set (match_operand:TI 0 "register_operand" "")
	(plus:TI (match_operand:TI 1 "register_operand" "")
		 (match_operand:TI 2 "immediate_operand" "")))
   (clobber (match_scratch:BI 3 ""))]
  "reload_completed"
  [(set (match_dup 0) (plus:DI (match_dup 1) (match_dup 2)))
   (set (match_dup 3) (ltu:BI (match_dup 0) (match_dup 1)))
   (cond_exec (eq (match_dup 3) (const_int 0))
	      (set (match_dup 4)
		   (plus:DI (match_dup 5) (match_dup 6))))
   (cond_exec (ne (match_dup 3) (const_int 0))
	      (set (match_dup 4)
		   (plus:DI (match_dup 5) (match_dup 7))))]
{
  operands[4] = gen_highpart (DImode, operands[0]);
  operands[0] = gen_lowpart (DImode, operands[0]);
  operands[5] = gen_highpart (DImode, operands[1]);
  operands[1] = gen_lowpart (DImode, operands[1]);
  operands[6] = INTVAL (operands[2]) < 0 ? constm1_rtx : const0_rtx;
  operands[7] = INTVAL (operands[2]) < 0 ? const0_rtx : const1_rtx;
})

(define_insn "subti3"
  [(set (match_operand:TI 0 "gr_register_operand" "=&r")
	(minus:TI (match_operand:TI 1 "gr_reg_or_8bit_operand" "rK")
		  (match_operand:TI 2 "gr_register_operand" "r")))
   (clobber (match_scratch:BI 3 "=&c"))]
  ""
  "#"
  [(set_attr "itanium_class" "unknown")])

(define_split
  [(set (match_operand:TI 0 "register_operand" "")
	(minus:TI (match_operand:TI 1 "register_operand" "")
		  (match_operand:TI 2 "register_operand" "")))
   (clobber (match_scratch:BI 3 "=&c"))]
  "reload_completed"
  [(set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2)))
   (set (match_dup 3) (ltu:BI (match_dup 1) (match_dup 0)))
   (cond_exec (eq (match_dup 3) (const_int 0))
	      (set (match_dup 4) (minus:DI (match_dup 5) (match_dup 6))))
   (cond_exec (ne (match_dup 3) (const_int 0))
	      (set (match_dup 4)
		   (plus:DI (not:DI (match_dup 6)) (match_dup 5))))]
{
  operands[4] = gen_highpart (DImode, operands[0]);
  operands[0] = gen_lowpart (DImode, operands[0]);
  operands[5] = gen_highpart (DImode, operands[1]);
  operands[1] = gen_lowpart (DImode, operands[1]);
  operands[6] = gen_highpart (DImode, operands[2]);
  operands[2] = gen_lowpart (DImode, operands[2]);
})

(define_split
  [(set (match_operand:TI 0 "register_operand" "")
	(minus:TI (match_operand:TI 1 "immediate_operand" "")
		  (match_operand:TI 2 "register_operand" "")))
   (clobber (match_scratch:BI 3 "=&c"))]
  "reload_completed && CONST_OK_FOR_K (INTVAL (operands[1]))"
  [(set (match_dup 0) (minus:DI (match_dup 1) (match_dup 2)))
   (set (match_dup 3) (gtu:BI (match_dup 0) (match_dup 1)))
   (cond_exec (ne (match_dup 3) (const_int 0))
	      (set (match_dup 4) (minus:DI (match_dup 6) (match_dup 5))))
   (cond_exec (eq (match_dup 3) (const_int 0))
	      (set (match_dup 4) (minus:DI (match_dup 7) (match_dup 5))))]
{
  operands[4] = gen_highpart (DImode, operands[0]);
  operands[0] = gen_lowpart (DImode, operands[0]);
  operands[5] = gen_highpart (DImode, operands[2]);
  operands[2] = gen_lowpart (DImode, operands[2]);
  operands[6] = INTVAL (operands[1]) < 0 ? GEN_INT (-2) : constm1_rtx;
  operands[7] = INTVAL (operands[1]) < 0 ? constm1_rtx : const0_rtx;
})

(define_expand "mulditi3"
  [(set (match_operand:TI 0 "fr_register_operand" "")
	(mult:TI (sign_extend:TI
		   (match_operand:DI 1 "fr_register_operand" ""))
		 (sign_extend:TI
		   (match_operand:DI 2 "fr_register_operand" ""))))]
  ""
  "")

(define_insn_and_split "*mulditi3_internal"
  [(set (match_operand:TI 0 "fr_register_operand" "=&f")
	(mult:TI (sign_extend:TI
		   (match_operand:DI 1 "fr_register_operand" "%f"))
		 (sign_extend:TI
		   (match_operand:DI 2 "fr_register_operand" "f"))))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 0) (mult:DI (match_dup 1) (match_dup 2)))
   (set (match_dup 3) (truncate:DI
			(lshiftrt:TI
			  (mult:TI (sign_extend:TI (match_dup 1))
				   (sign_extend:TI (match_dup 2)))
			  (const_int 64))))]
{
  operands[3] = gen_highpart (DImode, operands[0]);
  operands[0] = gen_lowpart (DImode, operands[0]);
}
  [(set_attr "itanium_class" "unknown")])

(define_expand "umulditi3"
  [(set (match_operand:TI 0 "fr_register_operand" "")
	(mult:TI (zero_extend:TI
		   (match_operand:DI 1 "fr_register_operand" ""))
		 (zero_extend:TI
		   (match_operand:DI 2 "fr_register_operand" ""))))]
  ""
  "")

(define_insn_and_split "*umulditi3_internal"
  [(set (match_operand:TI 0 "fr_register_operand" "=&f")
	(mult:TI (zero_extend:TI
		   (match_operand:DI 1 "fr_register_operand" "%f"))
		 (zero_extend:TI
		   (match_operand:DI 2 "fr_register_operand" "f"))))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 0) (mult:DI (match_dup 1) (match_dup 2)))
   (set (match_dup 3) (truncate:DI
			(lshiftrt:TI
			  (mult:TI (zero_extend:TI (match_dup 1))
				   (zero_extend:TI (match_dup 2)))
			  (const_int 64))))]
{
  operands[3] = gen_highpart (DImode, operands[0]);
  operands[0] = gen_lowpart (DImode, operands[0]);
}
  [(set_attr "itanium_class" "unknown")])

(define_insn_and_split "negti2"
  [(set (match_operand:TI 0 "gr_register_operand" "=&r")
	(neg:TI (match_operand:TI 1 "gr_register_operand" "r")))
   (clobber (match_scratch:BI 2 "=&c"))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 2) (eq:BI (match_dup 1) (const_int 0)))
   (set (match_dup 0) (minus:DI (const_int 0) (match_dup 1)))
   (cond_exec (eq (match_dup 2) (const_int 0))
	      (set (match_dup 3) (minus:DI (const_int -1) (match_dup 4))))
   (cond_exec (ne (match_dup 2) (const_int 0))
	      (set (match_dup 3) (minus:DI (const_int 0) (match_dup 4))))]
{
  operands[3] = gen_highpart (DImode, operands[0]);
  operands[0] = gen_lowpart (DImode, operands[0]);
  operands[4] = gen_highpart (DImode, operands[1]);
  operands[1] = gen_lowpart (DImode, operands[1]);
}
  [(set_attr "itanium_class" "unknown")])

;; ::::::::::::::::::::
;; ::
;; :: 32 bit floating point arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn "addsf3"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(plus:SF (match_operand:SF 1 "fr_register_operand" "%f")
		 (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fadd.s %0 = %1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "subsf3"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(minus:SF (match_operand:SF 1 "fr_reg_or_fp01_operand" "fG")
		  (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fsub.s %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "mulsf3"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(mult:SF (match_operand:SF 1 "fr_register_operand" "%f")
		 (match_operand:SF 2 "fr_register_operand" "f")))]
  ""
  "fmpy.s %0 = %1, %2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "abssf2"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(abs:SF (match_operand:SF 1 "fr_register_operand" "f")))]
  ""
  "fabs %0 = %1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "negsf2"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(neg:SF (match_operand:SF 1 "fr_register_operand" "f")))]
  ""
  "fneg %0 = %1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*nabssf2"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(neg:SF (abs:SF (match_operand:SF 1 "fr_register_operand" "f"))))]
  ""
  "fnegabs %0 = %1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "copysignsf3"
  [(set (match_operand:SF 0 "register_operand" "=f")
	(unspec:SF [(match_operand:SF 1 "fr_reg_or_fp01_operand" "fG")
		    (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")]
		   UNSPEC_COPYSIGN))]
  ""
  "fmerge.s %0 = %F2, %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*ncopysignsf3"
  [(set (match_operand:SF 0 "register_operand" "=f")
	(neg:SF (unspec:SF [(match_operand:SF 1 "fr_reg_or_fp01_operand" "fG")
			    (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")]
			   UNSPEC_COPYSIGN)))]
  ""
  "fmerge.ns %0 = %F2, %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "sminsf3"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(smin:SF (match_operand:SF 1 "fr_register_operand" "f")
		 (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fmin %0 = %1, %F2"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "smaxsf3"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(smax:SF (match_operand:SF 1 "fr_register_operand" "f")
		 (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fmax %0 = %1, %F2"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*maddsf4"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(plus:SF (mult:SF (match_operand:SF 1 "fr_register_operand" "f")
			  (match_operand:SF 2 "fr_register_operand" "f"))
		 (match_operand:SF 3 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fma.s %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*msubsf4"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(minus:SF (mult:SF (match_operand:SF 1 "fr_register_operand" "f")
			   (match_operand:SF 2 "fr_register_operand" "f"))
		  (match_operand:SF 3 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fms.s %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmulsf3"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(neg:SF (mult:SF (match_operand:SF 1 "fr_register_operand" "f")
			 (match_operand:SF 2 "fr_register_operand" "f"))))]
  ""
  "fnmpy.s %0 = %1, %2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddsf4"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(minus:SF (match_operand:SF 3 "fr_reg_or_fp01_operand" "fG") 
		  (mult:SF (match_operand:SF 1 "fr_register_operand" "f")
			   (match_operand:SF 2 "fr_register_operand" "f"))))]
  ""
  "fnma.s %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddsf4_alts"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(minus:SF (match_operand:SF 3 "fr_reg_or_fp01_operand" "fG") 
		  (mult:SF (match_operand:SF 1 "fr_register_operand" "f")
			   (match_operand:SF 2 "fr_register_operand" "f"))))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fnma.s.s%4 %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_expand "divsf3"
  [(set (match_operand:SF 0 "fr_register_operand" "")
	(div:SF (match_operand:SF 1 "fr_register_operand" "")
		(match_operand:SF 2 "fr_register_operand" "")))]
  "TARGET_INLINE_FLOAT_DIV"
{
  rtx insn;
  if (TARGET_INLINE_FLOAT_DIV == INL_MIN_LAT)
    insn = gen_divsf3_internal_lat (operands[0], operands[1], operands[2]);
  else
    insn = gen_divsf3_internal_thr (operands[0], operands[1], operands[2]);
  emit_insn (insn);
  DONE;
})

(define_insn_and_split "divsf3_internal_lat"
  [(set (match_operand:SF 0 "fr_register_operand" "=&f")
	(div:SF (match_operand:SF 1 "fr_register_operand" "f")
		(match_operand:SF 2 "fr_register_operand" "f")))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:XF 4 "=f"))
   (clobber (match_scratch:BI 5 "=c"))]
  "TARGET_INLINE_FLOAT_DIV == INL_MIN_LAT"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 6) (div:XF (const_int 1) (match_dup 8)))
	      (set (match_dup 5) (unspec:BI [(match_dup 7) (match_dup 8)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 0))])
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3) (mult:XF (match_dup 7) (match_dup 6)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 10)
			       (mult:XF (match_dup 8) (match_dup 6))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 3))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4) (mult:XF (match_dup 4) (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 3))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4) (mult:XF (match_dup 4) (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 9)
		     (float_truncate:DF
		       (plus:XF (mult:XF (match_dup 4) (match_dup 3))
			      (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (set (match_dup 0)
	  (float_truncate:SF (match_dup 6))))
  ] 
{
  operands[6] = gen_rtx_REG (XFmode, REGNO (operands[0]));
  operands[7] = gen_rtx_REG (XFmode, REGNO (operands[1]));
  operands[8] = gen_rtx_REG (XFmode, REGNO (operands[2]));
  operands[9] = gen_rtx_REG (DFmode, REGNO (operands[0]));
  operands[10] = CONST1_RTX (XFmode);
}
  [(set_attr "predicable" "no")])

(define_insn_and_split "divsf3_internal_thr"
  [(set (match_operand:SF 0 "fr_register_operand" "=&f")
	(div:SF (match_operand:SF 1 "fr_register_operand" "f")
		(match_operand:SF 2 "fr_register_operand" "f")))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:XF 4 "=f"))
   (clobber (match_scratch:BI 5 "=c"))]
  "TARGET_INLINE_FLOAT_DIV == INL_MAX_THR"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 6) (div:XF (const_int 1) (match_dup 8)))
	      (set (match_dup 5) (unspec:BI [(match_dup 7) (match_dup 8)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 0))])
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (minus:XF (match_dup 10)
			       (mult:XF (match_dup 8) (match_dup 6))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 3))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 6)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 6))
			      (match_dup 6)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 9)
		     (float_truncate:SF
		       (mult:XF (match_dup 7) (match_dup 6))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 7)
			       (mult:XF (match_dup 8) (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (set (match_dup 0)
	  (float_truncate:SF
	    (plus:XF (mult:XF (match_dup 4) (match_dup 6))
			      (match_dup 3)))))
  ] 
{
  operands[6] = gen_rtx_REG (XFmode, REGNO (operands[0]));
  operands[7] = gen_rtx_REG (XFmode, REGNO (operands[1]));
  operands[8] = gen_rtx_REG (XFmode, REGNO (operands[2]));
  operands[9] = gen_rtx_REG (SFmode, REGNO (operands[3]));
  operands[10] = CONST1_RTX (XFmode);
}
  [(set_attr "predicable" "no")])

;; Inline square root.

(define_insn "*sqrt_approx"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
        (div:XF (const_int 1)
                (sqrt:XF (match_operand:XF 2 "fr_register_operand" "f"))))
   (set (match_operand:BI 1 "register_operand" "=c")
        (unspec:BI [(match_dup 2)] UNSPEC_FR_SQRT_RECIP_APPROX))
   (use (match_operand:SI 3 "const_int_operand" "")) ]
  ""
  "frsqrta.s%3 %0, %1 = %2"
  [(set_attr "itanium_class" "fmisc")
   (set_attr "predicable" "no")])

(define_insn "setf_exp_xf"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
        (unspec:XF [(match_operand:DI 1 "register_operand" "r")]
                  UNSPEC_SETF_EXP))]
  ""
  "setf.exp %0 = %1"
  [(set_attr "itanium_class" "frfr")])

(define_expand "sqrtsf2"
  [(set (match_operand:SF 0 "fr_register_operand" "=&f")
	(sqrt:SF (match_operand:SF 1 "fr_register_operand" "f")))]
  "TARGET_INLINE_SQRT"
{
  rtx insn;
#if 0
  if (TARGET_INLINE_SQRT == INL_MIN_LAT)
    insn = gen_sqrtsf2_internal_lat (operands[0], operands[1]);
  else
#else
  gcc_assert (TARGET_INLINE_SQRT != INL_MIN_LAT);
#endif
  insn = gen_sqrtsf2_internal_thr (operands[0], operands[1]);
  emit_insn (insn);
  DONE;
})

;; Latency-optimized square root.
;; FIXME: Implement.

;; Throughput-optimized square root.

(define_insn_and_split "sqrtsf2_internal_thr"
  [(set (match_operand:SF 0 "fr_register_operand" "=&f")
	(sqrt:SF (match_operand:SF 1 "fr_register_operand" "f")))
   ;; Register r2 in optimization guide.
   (clobber (match_scratch:DI 2 "=r"))
   ;; Register f8 in optimization guide
   (clobber (match_scratch:XF 3 "=&f"))
   ;; Register f9 in optimization guide
   (clobber (match_scratch:XF 4 "=&f"))
   ;; Register f10 in optimization guide
   (clobber (match_scratch:XF 5 "=&f"))
   ;; Register p6 in optimization guide.
   (clobber (match_scratch:BI 6 "=c"))]
  "TARGET_INLINE_SQRT == INL_MAX_THR"
  "#"
  "&& reload_completed"
  [ ;; exponent of +1/2 in r2
    (set (match_dup 2) (const_int 65534))
    ;; +1/2 in f8
    (set (match_dup 3) 
         (unspec:XF [(match_dup 2)] UNSPEC_SETF_EXP))
    ;; Step 1
    ;; y0 = 1/sqrt(a) in f7
    (parallel [(set (match_dup 7)
                    (div:XF (const_int 1)
                            (sqrt:XF (match_dup 8))))
               (set (match_dup 6)
                    (unspec:BI [(match_dup 8)]
                                 UNSPEC_FR_SQRT_RECIP_APPROX))
               (use (const_int 0))])
    ;; Step 2
    ;; H0 = 1/2 * y0 in f9
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 4)
                      (plus:XF (mult:XF (match_dup 3) (match_dup 7))
                               (match_dup 9)))
                 (use (const_int 1))]))
    ;; Step 3
    ;; S0 = a * y0 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 7)
                      (plus:XF (mult:XF (match_dup 8) (match_dup 7))
                               (match_dup 9)))
                 (use (const_int 1))]))
    ;; Step 4
    ;; d = 1/2 - S0 * H0 in f10
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 5)
                      (minus:XF (match_dup 3)
				(mult:XF (match_dup 7) (match_dup 4))))
                 (use (const_int 1))]))
    ;; Step 5
    ;; d' = d + 1/2 * d in f8
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 3)
                       (plus:XF (mult:XF (match_dup 3) (match_dup 5))
                                (match_dup 5)))
                  (use (const_int 1))]))
    ;; Step 6
    ;; e = d + d * d' in f8
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 3)
                       (plus:XF (mult:XF (match_dup 5) (match_dup 3))
                                (match_dup 5)))
                  (use (const_int 1))]))
    ;; Step 7
    ;; S1 = S0 + e * S0 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 0)
		      (float_truncate:SF
                        (plus:XF (mult:XF (match_dup 3) (match_dup 7))
                                 (match_dup 7))))
                 (use (const_int 1))]))
    ;; Step 8
    ;; H1 = H0 + e * H0 in f8
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 3)
                       (plus:XF (mult:XF (match_dup 3) (match_dup 4))
                                (match_dup 4)))
                  (use (const_int 1))]))
    ;; Step 9 
    ;; d1 = a - S1 * S1 in f9
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 4)
                       (minus:XF (match_dup 8)
				 (mult:XF (match_dup 7) (match_dup 7))))
                  (use (const_int 1))]))
    ;; Step 10
    ;; S = S1 + d1 * H1 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 0)
                       (float_truncate:SF
                         (plus:XF (mult:XF (match_dup 4) (match_dup 3))
                                  (match_dup 7))))
                  (use (const_int 0))]))]
{
  /* Generate 82-bit versions of the input and output operands.  */
  operands[7] = gen_rtx_REG (XFmode, REGNO (operands[0]));
  operands[8] = gen_rtx_REG (XFmode, REGNO (operands[1]));
  /* Generate required floating-point constants.  */
  operands[9] = CONST0_RTX (XFmode);
}
  [(set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: 64 bit floating point arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn "adddf3"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(plus:DF (match_operand:DF 1 "fr_register_operand" "%f")
		 (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fadd.d %0 = %1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*adddf3_trunc"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (plus:DF (match_operand:DF 1 "fr_register_operand" "%f")
		   (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG"))))]
  ""
  "fadd.s %0 = %1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "subdf3"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(minus:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")
		  (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fsub.d %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*subdf3_trunc"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (minus:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")
		    (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG"))))]
  ""
  "fsub.s %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "muldf3"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(mult:DF (match_operand:DF 1 "fr_register_operand" "f")
		 (match_operand:DF 2 "fr_register_operand" "f")))]
  ""
  "fmpy.d %0 = %1, %2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*muldf3_trunc"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
		   (match_operand:DF 2 "fr_register_operand" "f"))))]
  ""
  "fmpy.s %0 = %1, %2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "absdf2"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(abs:DF (match_operand:DF 1 "fr_register_operand" "f")))]
  ""
  "fabs %0 = %1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "negdf2"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(neg:DF (match_operand:DF 1 "fr_register_operand" "f")))]
  ""
  "fneg %0 = %1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*nabsdf2"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(neg:DF (abs:DF (match_operand:DF 1 "fr_register_operand" "f"))))]
  ""
  "fnegabs %0 = %1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "copysigndf3"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(unspec:DF [(match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")
		    (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")]
		   UNSPEC_COPYSIGN))]
  ""
  "fmerge.s %0 = %F2, %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*ncopysigndf3"
  [(set (match_operand:DF 0 "register_operand" "=f")
	(neg:DF (unspec:DF [(match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")
			    (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")]
			   UNSPEC_COPYSIGN)))]
  ""
  "fmerge.ns %0 = %F2, %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "smindf3"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(smin:DF (match_operand:DF 1 "fr_register_operand" "f")
		 (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fmin %0 = %1, %F2"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "smaxdf3"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(smax:DF (match_operand:DF 1 "fr_register_operand" "f")
		 (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fmax %0 = %1, %F2"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*madddf4"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(plus:DF (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			  (match_operand:DF 2 "fr_register_operand" "f"))
		 (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fma.d %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*madddf4_trunc"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (plus:DF (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			    (match_operand:DF 2 "fr_register_operand" "f"))
		   (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG"))))]
  ""
  "fma.s %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*msubdf4"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(minus:DF (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			   (match_operand:DF 2 "fr_register_operand" "f"))
		  (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG")))]
  ""
  "fms.d %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*msubdf4_trunc"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (minus:DF (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			     (match_operand:DF 2 "fr_register_operand" "f"))
		    (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG"))))]
  ""
  "fms.s %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmuldf3"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(neg:DF (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			 (match_operand:DF 2 "fr_register_operand" "f"))))]
  ""
  "fnmpy.d %0 = %1, %2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmuldf3_trunc"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (neg:DF (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			   (match_operand:DF 2 "fr_register_operand" "f")))))]
  ""
  "fnmpy.s %0 = %1, %2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmadddf4"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(minus:DF (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG")
		  (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			   (match_operand:DF 2 "fr_register_operand" "f"))))]
  ""
  "fnma.d %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmadddf4_alts"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(minus:DF (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG")
		  (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			   (match_operand:DF 2 "fr_register_operand" "f"))))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fnma.d.s%4 %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmadddf4_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	(minus:DF (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG")
		  (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			   (match_operand:DF 2 "fr_register_operand" "f")))))]
  ""
  "fnma.s %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmadddf4_truncsf_alts"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	(minus:DF (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG")
		  (mult:DF (match_operand:DF 1 "fr_register_operand" "f")
			   (match_operand:DF 2 "fr_register_operand" "f")))))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fnma.s.s%4 %0 = %1, %2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_expand "divdf3"
  [(set (match_operand:DF 0 "fr_register_operand" "")
	(div:DF (match_operand:DF 1 "fr_register_operand" "")
		(match_operand:DF 2 "fr_register_operand" "")))]
  "TARGET_INLINE_FLOAT_DIV"
{
  rtx insn;
  if (TARGET_INLINE_FLOAT_DIV == INL_MIN_LAT)
    insn = gen_divdf3_internal_lat (operands[0], operands[1], operands[2]);
  else
    insn = gen_divdf3_internal_thr (operands[0], operands[1], operands[2]);
  emit_insn (insn);
  DONE;
})

(define_insn_and_split "divdf3_internal_lat"
  [(set (match_operand:DF 0 "fr_register_operand" "=&f")
	(div:DF (match_operand:DF 1 "fr_register_operand" "f")
		(match_operand:DF 2 "fr_register_operand" "f")))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:XF 4 "=&f"))
   (clobber (match_scratch:XF 5 "=&f"))
   (clobber (match_scratch:BI 6 "=c"))]
  "TARGET_INLINE_FLOAT_DIV == INL_MIN_LAT"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 7) (div:XF (const_int 1) (match_dup 9)))
	      (set (match_dup 6) (unspec:BI [(match_dup 8) (match_dup 9)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 0))])
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 3) (mult:XF (match_dup 8) (match_dup 7)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 12)
			       (mult:XF (match_dup 9) (match_dup 7))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 3))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 5) (mult:XF (match_dup 4) (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 7)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 7))
			      (match_dup 7)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 3))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 4) (mult:XF (match_dup 5) (match_dup 5)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 7)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 7))
			      (match_dup 7)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 10)
		     (float_truncate:DF
		       (plus:XF (mult:XF (match_dup 4) (match_dup 3))
			      (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 7)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 7))
			      (match_dup 7)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (parallel [(set (match_dup 11)
		     (float_truncate:DF
		       (minus:XF (match_dup 8)
				 (mult:XF (match_dup 9) (match_dup 3)))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 6) (const_int 0))
     (set (match_dup 0)
	  (float_truncate:DF (plus:XF (mult:XF (match_dup 5) (match_dup 7))
			      (match_dup 3)))))
  ] 
{
  operands[7] = gen_rtx_REG (XFmode, REGNO (operands[0]));
  operands[8] = gen_rtx_REG (XFmode, REGNO (operands[1]));
  operands[9] = gen_rtx_REG (XFmode, REGNO (operands[2]));
  operands[10] = gen_rtx_REG (DFmode, REGNO (operands[3]));
  operands[11] = gen_rtx_REG (DFmode, REGNO (operands[5]));
  operands[12] = CONST1_RTX (XFmode);
}
  [(set_attr "predicable" "no")])

(define_insn_and_split "divdf3_internal_thr"
  [(set (match_operand:DF 0 "fr_register_operand" "=&f")
	(div:DF (match_operand:DF 1 "fr_register_operand" "f")
		(match_operand:DF 2 "fr_register_operand" "f")))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:DF 4 "=f"))
   (clobber (match_scratch:BI 5 "=c"))]
  "TARGET_INLINE_FLOAT_DIV == INL_MAX_THR"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 6) (div:XF (const_int 1) (match_dup 8)))
	      (set (match_dup 5) (unspec:BI [(match_dup 7) (match_dup 8)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 0))])
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (minus:XF (match_dup 10)
			       (mult:XF (match_dup 8) (match_dup 6))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 6)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 6))
			      (match_dup 6)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (mult:XF (match_dup 3) (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 6)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 6))
			      (match_dup 6)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (mult:XF (match_dup 3) (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 6)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 6))
			      (match_dup 6)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 9)
		     (float_truncate:DF
		       (mult:XF (match_dup 7) (match_dup 6))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:DF (match_dup 1)
			       (mult:DF (match_dup 2) (match_dup 9))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (set (match_dup 0)
	  (plus:DF (mult:DF (match_dup 4) (match_dup 0))
			    (match_dup 9))))
  ] 
{
  operands[6] = gen_rtx_REG (XFmode, REGNO (operands[0]));
  operands[7] = gen_rtx_REG (XFmode, REGNO (operands[1]));
  operands[8] = gen_rtx_REG (XFmode, REGNO (operands[2]));
  operands[9] = gen_rtx_REG (DFmode, REGNO (operands[3]));
  operands[10] = CONST1_RTX (XFmode);
}
  [(set_attr "predicable" "no")])

;; Inline square root.

(define_expand "sqrtdf2"
  [(set (match_operand:DF 0 "fr_register_operand" "=&f")
	(sqrt:DF (match_operand:DF 1 "fr_register_operand" "f")))]
  "TARGET_INLINE_SQRT"
{
  rtx insn;
#if 0
  if (TARGET_INLINE_SQRT == INL_MIN_LAT)
    insn = gen_sqrtdf2_internal_lat (operands[0], operands[1]);
  else
#else
  gcc_assert (TARGET_INLINE_SQRT != INL_MIN_LAT);
#endif
  insn = gen_sqrtdf2_internal_thr (operands[0], operands[1]);
  emit_insn (insn);
  DONE;
})

;; Latency-optimized square root.
;; FIXME: Implement.

;; Throughput-optimized square root.

(define_insn_and_split "sqrtdf2_internal_thr"
  [(set (match_operand:DF 0 "fr_register_operand" "=&f")
	(sqrt:DF (match_operand:DF 1 "fr_register_operand" "f")))
   ;; Register r2 in optimization guide.
   (clobber (match_scratch:DI 2 "=r"))
   ;; Register f8 in optimization guide
   (clobber (match_scratch:XF 3 "=&f"))
   ;; Register f9 in optimization guide
   (clobber (match_scratch:XF 4 "=&f"))
   ;; Register f10 in optimization guide
   (clobber (match_scratch:XF 5 "=&f"))
   ;; Register p6 in optimization guide.
   (clobber (match_scratch:BI 6 "=c"))]
  "TARGET_INLINE_SQRT == INL_MAX_THR"
  "#"
  "&& reload_completed"
  [ ;; exponent of +1/2 in r2
    (set (match_dup 2) (const_int 65534))
    ;; +1/2 in f10
    (set (match_dup 5) 
         (unspec:XF [(match_dup 2)] UNSPEC_SETF_EXP))
    ;; Step 1
    ;; y0 = 1/sqrt(a) in f7
    (parallel [(set (match_dup 7)
                    (div:XF (const_int 1)
                            (sqrt:XF (match_dup 8))))
               (set (match_dup 6)
                    (unspec:BI [(match_dup 8)]
                                 UNSPEC_FR_SQRT_RECIP_APPROX))
               (use (const_int 0))])
    ;; Step 2
    ;; H0 = 1/2 * y0 in f8
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 3)
                      (plus:XF (mult:XF (match_dup 5) (match_dup 7))
                               (match_dup 9)))
                 (use (const_int 1))]))
    ;; Step 3
    ;; G0 = a * y0 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 7)
                      (plus:XF (mult:XF (match_dup 8) (match_dup 7))
                               (match_dup 9)))
                 (use (const_int 1))]))
    ;; Step 4
    ;; r0 = 1/2 - G0 * H0 in f9
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 4)
                      (minus:XF (match_dup 5)
				(mult:XF (match_dup 7) (match_dup 3))))
                 (use (const_int 1))]))
    ;; Step 5
    ;; H1 = H0 + r0 * H0 in f8
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 3)
                       (plus:XF (mult:XF (match_dup 4) (match_dup 3))
                                (match_dup 3)))
                  (use (const_int 1))]))
    ;; Step 6
    ;; G1 = G0 + r0 * G0 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 7)
                       (plus:XF (mult:XF (match_dup 4) (match_dup 7))
                                (match_dup 7)))
                  (use (const_int 1))]))
    ;; Step 7
    ;; r1 = 1/2 - G1 * H1 in f9
    (cond_exec (ne (match_dup 6) (const_int 0))
      (parallel [(set (match_dup 4)
                      (minus:XF (match_dup 5)
				(mult:XF (match_dup 7) (match_dup 3))))
                 (use (const_int 1))]))
    ;; Step 8
    ;; H2 = H1 + r1 * H1 in f8
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 3)
                       (plus:XF (mult:XF (match_dup 4) (match_dup 3))
                                (match_dup 3)))
                  (use (const_int 1))]))
    ;; Step 9 
    ;; G2 = G1 + r1 * G1 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 7)
                       (plus:XF (mult:XF (match_dup 4) (match_dup 7))
                                (match_dup 7)))
                  (use (const_int 1))]))
    ;; Step 10
    ;; d2 = a - G2 * G2 in f9
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 4)
                       (minus:XF (match_dup 8)
				 (mult:XF (match_dup 7) (match_dup 7))))
                  (use (const_int 1))]))
    ;; Step 11
    ;; G3 = G2 + d2 * H2 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 7)
                       (plus:XF (mult:XF (match_dup 4) (match_dup 3))
                                (match_dup 7)))
                  (use (const_int 1))]))
    ;; Step 12
    ;; d3 = a - G3 * G3 in f9
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 4)
                       (minus:XF (match_dup 8)
				 (mult:XF (match_dup 7) (match_dup 7))))
                  (use (const_int 1))]))
    ;; Step 13
    ;; S = G3 + d3 * H2 in f7
    (cond_exec (ne (match_dup 6) (const_int 0))
       (parallel [(set (match_dup 0)
                       (float_truncate:DF
                         (plus:XF (mult:XF (match_dup 4) (match_dup 3))
                                  (match_dup 7))))
                  (use (const_int 0))]))]
{
  /* Generate 82-bit versions of the input and output operands.  */
  operands[7] = gen_rtx_REG (XFmode, REGNO (operands[0]));
  operands[8] = gen_rtx_REG (XFmode, REGNO (operands[1]));
  /* Generate required floating-point constants.  */
  operands[9] = CONST0_RTX (XFmode);
}
  [(set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: 80 bit floating point arithmetic
;; ::
;; ::::::::::::::::::::

(define_insn "addxf3"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(plus:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		 (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fadd %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*addxf3_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (plus:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fadd.s %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*addxf3_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (plus:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fadd.d %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "subxf3"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(minus:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		  (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fsub %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*subxf3_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (minus:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fsub.s %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*subxf3_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (minus:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fsub.d %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "mulxf3"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		 (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fmpy %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*mulxf3_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fmpy.s %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*mulxf3_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fmpy.d %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*mulxf3_alts"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		 (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))
   (use (match_operand:SI 3 "const_int_operand" ""))]
  ""
  "fmpy.s%3 %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*mulxf3_truncsf_alts"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))
   (use (match_operand:SI 3 "const_int_operand" ""))]
  ""
  "fmpy.s.s%3 %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*mulxf3_truncdf_alts"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))
   (use (match_operand:SI 3 "const_int_operand" ""))]
  ""
  "fmpy.d.s%3 %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "absxf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(abs:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fabs %0 = %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "negxf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(neg:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fneg %0 = %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*nabsxf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(neg:XF (abs:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fnegabs %0 = %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "copysignxf3"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(unspec:XF [(match_operand:XF 1 "fr_reg_or_fp01_operand" "fG")
		    (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG")]
		   UNSPEC_COPYSIGN))]
  ""
  "fmerge.s %0 = %F2, %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*ncopysignxf3"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(neg:XF (unspec:XF [(match_operand:XF 1 "fr_reg_or_fp01_operand" "fG")
			    (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG")]
			   UNSPEC_COPYSIGN)))]
  ""
  "fmerge.ns %0 = %F2, %F1"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "sminxf3"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(smin:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		 (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fmin %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "smaxxf3"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(smax:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		 (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fmax %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmisc")])

(define_insn "*maddxf4"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(plus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			  (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		 (match_operand:XF 3 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fma %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*maddxf4_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (plus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		   (match_operand:XF 3 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fma.s %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*maddxf4_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (plus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		   (match_operand:XF 3 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fma.d %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*maddxf4_alts"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(plus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			  (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		 (match_operand:XF 3 "xfreg_or_fp01_operand" "fG")))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fma.s%4 %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*maddxf4_alts_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (plus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		   (match_operand:XF 3 "xfreg_or_fp01_operand" "fG"))))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fma.s.s%4 %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*maddxf4_alts_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (plus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		   (match_operand:XF 3 "xfreg_or_fp01_operand" "fG"))))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fma.d.s%4 %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*msubxf4"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(minus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		  (match_operand:XF 3 "xfreg_or_fp01_operand" "fG")))]
  ""
  "fms %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*msubxf4_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (minus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			     (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		    (match_operand:XF 3 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fms.s %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*msubxf4_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (minus:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			     (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))
		    (match_operand:XF 3 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fms.d %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmulxf3"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(neg:XF (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			 (match_operand:XF 2 "xfreg_or_fp01_operand" "fG"))))]
  ""
  "fnmpy %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmulxf3_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (neg:XF (mult:XF
		    (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))))]
  ""
  "fnmpy.s %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmulxf3_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (neg:XF (mult:XF
		    (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
		    (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")))))]
  ""
  "fnmpy.d %0 = %F1, %F2"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddxf4"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(minus:XF (match_operand:XF 3 "xfreg_or_fp01_operand" "fG")
		  (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")
   )))]
  ""
  "fnma %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddxf4_truncsf"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (minus:XF (match_operand:XF 3 "xfreg_or_fp01_operand" "fG") 
		    (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			     (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")
   ))))]
  ""
  "fnma.s %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddxf4_truncdf"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (minus:XF (match_operand:XF 3 "xfreg_or_fp01_operand" "fG") 
		    (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			     (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")
   ))))]
  ""
  "fnma.d %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddxf4_alts"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(minus:XF (match_operand:XF 3 "xfreg_or_fp01_operand" "fG")
		  (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			   (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")
   )))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fnma.s%4 %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddxf4_truncsf_alts"
  [(set (match_operand:SF 0 "fr_register_operand" "=f")
	(float_truncate:SF
	  (minus:XF (match_operand:XF 3 "xfreg_or_fp01_operand" "fG") 
		    (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			     (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")
   ))))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fnma.s.s%4 %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_insn "*nmaddxf4_truncdf_alts"
  [(set (match_operand:DF 0 "fr_register_operand" "=f")
	(float_truncate:DF
	  (minus:XF (match_operand:XF 3 "xfreg_or_fp01_operand" "fG") 
		    (mult:XF (match_operand:XF 1 "xfreg_or_fp01_operand" "fG")
			     (match_operand:XF 2 "xfreg_or_fp01_operand" "fG")
   ))))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "fnma.d.s%4 %0 = %F1, %F2, %F3"
  [(set_attr "itanium_class" "fmac")])

(define_expand "divxf3"
  [(set (match_operand:XF 0 "fr_register_operand" "")
	(div:XF (match_operand:XF 1 "fr_register_operand" "")
		(match_operand:XF 2 "fr_register_operand" "")))]
  "TARGET_INLINE_FLOAT_DIV"
{
  rtx insn;
  if (TARGET_INLINE_FLOAT_DIV == INL_MIN_LAT)
    insn = gen_divxf3_internal_lat (operands[0], operands[1], operands[2]);
  else
    insn = gen_divxf3_internal_thr (operands[0], operands[1], operands[2]);
  emit_insn (insn);
  DONE;
})

(define_insn_and_split "divxf3_internal_lat"
  [(set (match_operand:XF 0 "fr_register_operand" "=&f")
	(div:XF (match_operand:XF 1 "fr_register_operand" "f")
		(match_operand:XF 2 "fr_register_operand" "f")))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:XF 4 "=&f"))
   (clobber (match_scratch:XF 5 "=&f"))
   (clobber (match_scratch:XF 6 "=&f"))
   (clobber (match_scratch:BI 7 "=c"))]
  "TARGET_INLINE_FLOAT_DIV == INL_MIN_LAT"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0) (div:XF (const_int 1) (match_dup 2)))
	      (set (match_dup 7) (unspec:BI [(match_dup 1) (match_dup 2)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 0))])
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 3)
		     (minus:XF (match_dup 8)
			       (mult:XF (match_dup 2) (match_dup 0))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 4) (mult:XF (match_dup 1) (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 5) (mult:XF (match_dup 3) (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 6)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 3))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 5))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 5)
		     (plus:XF (mult:XF (match_dup 6) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 5) (match_dup 3))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 1)
			       (mult:XF (match_dup 2) (match_dup 4))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 0))
			      (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 5)
		     (minus:XF (match_dup 8)
			       (mult:XF (match_dup 2) (match_dup 0))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 1)
			       (mult:XF (match_dup 2) (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 7) (const_int 0))
     (set (match_dup 0)
	  (plus:XF (mult:XF (match_dup 4) (match_dup 0))
		   (match_dup 3))))
  ] 
  "operands[8] = CONST1_RTX (XFmode);"
  [(set_attr "predicable" "no")])

(define_insn_and_split "divxf3_internal_thr"
  [(set (match_operand:XF 0 "fr_register_operand" "=&f")
	(div:XF (match_operand:XF 1 "fr_register_operand" "f")
		(match_operand:XF 2 "fr_register_operand" "f")))
   (clobber (match_scratch:XF 3 "=&f"))
   (clobber (match_scratch:XF 4 "=&f"))
   (clobber (match_scratch:BI 5 "=c"))]
  "TARGET_INLINE_FLOAT_DIV == INL_MAX_THR"
  "#"
  "&& reload_completed"
  [(parallel [(set (match_dup 0) (div:XF (const_int 1) (match_dup 2)))
	      (set (match_dup 5) (unspec:BI [(match_dup 1) (match_dup 2)]
					    UNSPEC_FR_RECIP_APPROX))
	      (use (const_int 0))])
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (minus:XF (match_dup 6)
			       (mult:XF (match_dup 2) (match_dup 0))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3) (mult:XF (match_dup 3) (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 4))
			      (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4) (mult:XF (match_dup 1) (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 0)
		     (minus:XF (match_dup 6)
			       (mult:XF (match_dup 2) (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 0) (match_dup 3))
			      (match_dup 3)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (minus:XF (match_dup 1)
			       (mult:XF (match_dup 2) (match_dup 4))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 3)
		     (plus:XF (mult:XF (match_dup 3) (match_dup 0))
			      (match_dup 4)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 6)
			       (mult:XF (match_dup 2) (match_dup 0))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 0)
		     (plus:XF (mult:XF (match_dup 4) (match_dup 0))
			      (match_dup 0)))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (parallel [(set (match_dup 4)
		     (minus:XF (match_dup 1)
			       (mult:XF (match_dup 2) (match_dup 3))))
		(use (const_int 1))]))
   (cond_exec (ne (match_dup 5) (const_int 0))
     (set (match_dup 0)
	  (plus:XF (mult:XF (match_dup 4) (match_dup 0))
		   (match_dup 3))))
  ] 
  "operands[6] = CONST1_RTX (XFmode);"
  [(set_attr "predicable" "no")])

;; Inline square root.

(define_expand "sqrtxf2"
  [(set (match_operand:XF 0 "fr_register_operand" "=&f")
	(sqrt:XF (match_operand:XF 1 "fr_register_operand" "f")))]
  "TARGET_INLINE_SQRT"
{
  rtx insn;
#if 0
  if (TARGET_INLINE_SQRT == INL_MIN_LAT)
    insn = gen_sqrtxf2_internal_lat (operands[0], operands[1]);
  else
#else
  gcc_assert (TARGET_INLINE_SQRT != INL_MIN_LAT);
#endif
  insn = gen_sqrtxf2_internal_thr (operands[0], operands[1]);
  emit_insn (insn);
  DONE;
})

;; Latency-optimized square root.
;; FIXME: Implement.

;; Throughput-optimized square root.

(define_insn_and_split "sqrtxf2_internal_thr"
  [(set (match_operand:XF 0 "fr_register_operand" "=&f")
	(sqrt:XF (match_operand:XF 1 "fr_register_operand" "f")))
   ;; Register r2 in optimization guide.
   (clobber (match_scratch:DI 2 "=r"))
   ;; Register f8 in optimization guide
   (clobber (match_scratch:XF 3 "=&f"))
   ;; Register f9 in optimization guide
   (clobber (match_scratch:XF 4 "=&f"))
   ;; Register f10 in optimization guide
   (clobber (match_scratch:XF 5 "=&f"))
   ;; Register f11 in optimization guide
   (clobber (match_scratch:XF 6 "=&f"))
   ;; Register p6 in optimization guide.
   (clobber (match_scratch:BI 7 "=c"))]
  "TARGET_INLINE_SQRT == INL_MAX_THR"
  "#"
  "&& reload_completed"
  [ ;; exponent of +1/2 in r2
    (set (match_dup 2) (const_int 65534))
    ;; +1/2 in f8.  The Intel manual mistakenly specifies f10.
    (set (match_dup 3) 
         (unspec:XF [(match_dup 2)] UNSPEC_SETF_EXP))
    ;; Step 1
    ;; y0 = 1/sqrt(a) in f7
    (parallel [(set (match_dup 8)
                    (div:XF (const_int 1)
                            (sqrt:XF (match_dup 9))))
               (set (match_dup 7)
                    (unspec:BI [(match_dup 9)]
                                 UNSPEC_FR_SQRT_RECIP_APPROX))
               (use (const_int 0))])
    ;; Step 2
    ;; H0 = 1/2 * y0 in f9
    (cond_exec (ne (match_dup 7) (const_int 0))
      (parallel [(set (match_dup 4)
                      (plus:XF (mult:XF (match_dup 3) (match_dup 8))
                               (match_dup 10)))
                 (use (const_int 1))]))
    ;; Step 3
    ;; S0 = a * y0 in f7
    (cond_exec (ne (match_dup 7) (const_int 0))
      (parallel [(set (match_dup 8)
                      (plus:XF (mult:XF (match_dup 9) (match_dup 8))
                               (match_dup 10)))
                 (use (const_int 1))]))
    ;; Step 4
    ;; d0 = 1/2 - S0 * H0 in f10
    (cond_exec (ne (match_dup 7) (const_int 0))
      (parallel [(set (match_dup 5)
                      (minus:XF (match_dup 3)
				(mult:XF (match_dup 8) (match_dup 4))))
                 (use (const_int 1))]))
    ;; Step 5
    ;; H1 = H0 + d0 * H0 in f9
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 4)
                       (plus:XF (mult:XF (match_dup 5) (match_dup 4))
                                (match_dup 4)))
                  (use (const_int 1))]))
    ;; Step 6
    ;; S1 = S0 + d0 * S0 in f7
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 8)
                       (plus:XF (mult:XF (match_dup 5) (match_dup 8))
                                (match_dup 8)))
                  (use (const_int 1))]))
    ;; Step 7
    ;; d1 = 1/2 - S1 * H1 in f10
    (cond_exec (ne (match_dup 7) (const_int 0))
      (parallel [(set (match_dup 5)
                      (minus:XF (match_dup 3)
				(mult:XF (match_dup 8) (match_dup 4))))
                 (use (const_int 1))]))
    ;; Step 8
    ;; H2 = H1 + d1 * H1 in f9
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 4)
                       (plus:XF (mult:XF (match_dup 5) (match_dup 4))
                                (match_dup 4)))
                  (use (const_int 1))]))
    ;; Step 9 
    ;; S2 = S1 + d1 * S1 in f7
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 8)
                       (plus:XF (mult:XF (match_dup 5) (match_dup 8))
                                (match_dup 8)))
                  (use (const_int 1))]))
    ;; Step 10
    ;; d2 = 1/2 - S2 * H2 in f10
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 5)
                       (minus:XF (match_dup 3)
				 (mult:XF (match_dup 8) (match_dup 4))))
                  (use (const_int 1))]))
    ;; Step 11
    ;; e2 = a - S2 * S2 in f8
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 3)
                       (minus:XF (match_dup 9)
				 (mult:XF (match_dup 8) (match_dup 8))))
                  (use (const_int 1))]))
    ;; Step 12
    ;; S3 = S2 + e2 * H2 in f7
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 8)
                       (plus:XF (mult:XF (match_dup 3) (match_dup 4))
                                (match_dup 8)))
                  (use (const_int 1))]))
    ;; Step 13
    ;; H3 = H2 + d2 * H2 in f9
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 4)
                       (plus:XF (mult:XF (match_dup 5) (match_dup 4))
                                (match_dup 4)))
                  (use (const_int 1))]))
    ;; Step 14
    ;; e3 = a - S3 * S3 in f8
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 3)
                       (minus:XF (match_dup 9)
				 (mult:XF (match_dup 8) (match_dup 8))))
                  (use (const_int 1))]))
    ;; Step 15
    ;; S = S3 + e3 * H3 in f7
    (cond_exec (ne (match_dup 7) (const_int 0))
       (parallel [(set (match_dup 0)
                       (plus:XF (mult:XF (match_dup 3) (match_dup 4))
                                (match_dup 8)))
                  (use (const_int 0))]))]
{
  /* Generate 82-bit versions of the input and output operands.  */
  operands[8] = gen_rtx_REG (XFmode, REGNO (operands[0]));
  operands[9] = gen_rtx_REG (XFmode, REGNO (operands[1]));
  /* Generate required floating-point constants.  */
  operands[10] = CONST0_RTX (XFmode);
}
  [(set_attr "predicable" "no")])

;; ??? frcpa works like cmp.foo.unc.

(define_insn "*recip_approx"
  [(set (match_operand:XF 0 "fr_register_operand" "=f")
	(div:XF (const_int 1)
		(match_operand:XF 3 "fr_register_operand" "f")))
   (set (match_operand:BI 1 "register_operand" "=c")
	(unspec:BI [(match_operand:XF 2 "fr_register_operand" "f")
		    (match_dup 3)] UNSPEC_FR_RECIP_APPROX))
   (use (match_operand:SI 4 "const_int_operand" ""))]
  ""
  "frcpa.s%4 %0, %1 = %2, %3"
  [(set_attr "itanium_class" "fmisc")
   (set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: 32 bit Integer Shifts and Rotates
;; ::
;; ::::::::::::::::::::

(define_expand "ashlsi3"
  [(set (match_operand:SI 0 "gr_register_operand" "")
	(ashift:SI (match_operand:SI 1 "gr_register_operand" "")
		   (match_operand:SI 2 "gr_reg_or_5bit_operand" "")))]
  ""
{
  if (GET_CODE (operands[2]) != CONST_INT)
    {
      /* Why oh why didn't Intel arrange for SHIFT_COUNT_TRUNCATED?  Now
	 we've got to get rid of stray bits outside the SImode register.  */
      rtx subshift = gen_reg_rtx (DImode);
      emit_insn (gen_zero_extendsidi2 (subshift, operands[2]));
      operands[2] = subshift;
    }
})

(define_insn "*ashlsi3_internal"
  [(set (match_operand:SI 0 "gr_register_operand" "=r,r,r")
	(ashift:SI (match_operand:SI 1 "gr_register_operand" "r,r,r")
		   (match_operand:DI 2 "gr_reg_or_5bit_operand" "R,n,r")))]
  ""
  "@
   shladd %0 = %1, %2, r0
   dep.z %0 = %1, %2, %E2
   shl %0 = %1, %2"
  [(set_attr "itanium_class" "ialu,ishf,mmshf")])

(define_expand "ashrsi3"
  [(set (match_operand:SI 0 "gr_register_operand" "")
	(ashiftrt:SI (match_operand:SI 1 "gr_register_operand" "")
		     (match_operand:SI 2 "gr_reg_or_5bit_operand" "")))]
  ""
{
  rtx subtarget = gen_reg_rtx (DImode);
  if (GET_CODE (operands[2]) == CONST_INT)
    emit_insn (gen_extv (subtarget, gen_lowpart (DImode, operands[1]),
			 GEN_INT (32 - INTVAL (operands[2])), operands[2]));
  else
    {
      rtx subshift = gen_reg_rtx (DImode);
      emit_insn (gen_extendsidi2 (subtarget, operands[1]));
      emit_insn (gen_zero_extendsidi2 (subshift, operands[2]));
      emit_insn (gen_ashrdi3 (subtarget, subtarget, subshift));
    }
  emit_move_insn (gen_lowpart (DImode, operands[0]), subtarget);
  DONE;
})

(define_expand "lshrsi3"
  [(set (match_operand:SI 0 "gr_register_operand" "")
	(lshiftrt:SI (match_operand:SI 1 "gr_register_operand" "")
		     (match_operand:SI 2 "gr_reg_or_5bit_operand" "")))]
  ""
{
  rtx subtarget = gen_reg_rtx (DImode);
  if (GET_CODE (operands[2]) == CONST_INT)
    emit_insn (gen_extzv (subtarget, gen_lowpart (DImode, operands[1]),
			  GEN_INT (32 - INTVAL (operands[2])), operands[2]));
  else
    {
      rtx subshift = gen_reg_rtx (DImode);
      emit_insn (gen_zero_extendsidi2 (subtarget, operands[1]));
      emit_insn (gen_zero_extendsidi2 (subshift, operands[2]));
      emit_insn (gen_lshrdi3 (subtarget, subtarget, subshift));
    }
  emit_move_insn (gen_lowpart (DImode, operands[0]), subtarget);
  DONE;
})

;; Use mix4.r/shr to implement rotrsi3.  We only get 32 bits of valid result
;; here, instead of 64 like the patterns above.  Keep the pattern together
;; until after combine; otherwise it won't get matched often.

(define_expand "rotrsi3"
  [(set (match_operand:SI 0 "gr_register_operand" "")
	(rotatert:SI (match_operand:SI 1 "gr_register_operand" "")
		     (match_operand:SI 2 "gr_reg_or_5bit_operand" "")))]
  ""
{
  if (GET_MODE (operands[2]) != VOIDmode)
    {
      rtx tmp = gen_reg_rtx (DImode);
      emit_insn (gen_zero_extendsidi2 (tmp, operands[2]));
      operands[2] = tmp;
    }
})

(define_insn_and_split "*rotrsi3_internal"
  [(set (match_operand:SI 0 "gr_register_operand" "=&r")
	(rotatert:SI (match_operand:SI 1 "gr_register_operand" "r")
		     (match_operand:DI 2 "gr_reg_or_5bit_operand" "rM")))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 3)
	(ior:DI (zero_extend:DI (match_dup 1))
		(ashift:DI (zero_extend:DI (match_dup 1)) (const_int 32))))
   (set (match_dup 3)
	(lshiftrt:DI (match_dup 3) (match_dup 2)))]
  "operands[3] = gen_rtx_REG (DImode, REGNO (operands[0]));")

(define_expand "rotlsi3"
  [(set (match_operand:SI 0 "gr_register_operand" "")
	(rotate:SI (match_operand:SI 1 "gr_register_operand" "")
		   (match_operand:SI 2 "gr_reg_or_5bit_operand" "")))]
  ""
{
  if (! shift_32bit_count_operand (operands[2], SImode))
    {
      rtx tmp = gen_reg_rtx (SImode);
      emit_insn (gen_subsi3 (tmp, GEN_INT (32), operands[2]));
      emit_insn (gen_rotrsi3 (operands[0], operands[1], tmp));
      DONE;
    }
})

(define_insn_and_split "*rotlsi3_internal"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(rotate:SI (match_operand:SI 1 "gr_register_operand" "r")
		   (match_operand:SI 2 "shift_32bit_count_operand" "n")))]
  ""
  "#"
  "reload_completed"
  [(set (match_dup 3)
	(ior:DI (zero_extend:DI (match_dup 1))
		(ashift:DI (zero_extend:DI (match_dup 1)) (const_int 32))))
   (set (match_dup 3)
	(lshiftrt:DI (match_dup 3) (match_dup 2)))]
{
  operands[3] = gen_rtx_REG (DImode, REGNO (operands[0]));
  operands[2] = GEN_INT (32 - INTVAL (operands[2]));
})

;; ::::::::::::::::::::
;; ::
;; :: 64 bit Integer Shifts and Rotates
;; ::
;; ::::::::::::::::::::

(define_insn "ashldi3"
  [(set (match_operand:DI 0 "gr_register_operand" "=r,r,r")
	(ashift:DI (match_operand:DI 1 "gr_register_operand" "r,r,r")
		   (match_operand:DI 2 "gr_reg_or_6bit_operand" "R,r,rM")))]
  ""
  "@
   shladd %0 = %1, %2, r0
   shl %0 = %1, %2
   shl %0 = %1, %2"
  [(set_attr "itanium_class" "ialu,mmshf,mmshfi")])

;; ??? Maybe combine this with the multiply and add instruction?

(define_insn "*shladd"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(plus:DI (mult:DI (match_operand:DI 1 "gr_register_operand" "r")
			  (match_operand:DI 2 "shladd_operand" "n"))
		 (match_operand:DI 3 "gr_register_operand" "r")))]
  ""
  "shladd %0 = %1, %S2, %3"
  [(set_attr "itanium_class" "ialu")])

;; This can be created by register elimination if operand3 of shladd is an
;; eliminable register or has reg_equiv_constant set.

;; We have to use nonmemory_operand for operand 4, to ensure that the
;; validate_changes call inside eliminate_regs will always succeed.  If it
;; doesn't succeed, then this remain a shladd pattern, and will be reloaded
;; incorrectly.

(define_insn_and_split "*shladd_elim"
  [(set (match_operand:DI 0 "gr_register_operand" "=&r")
	(plus:DI (plus:DI (mult:DI (match_operand:DI 1 "gr_register_operand" "r")
				   (match_operand:DI 2 "shladd_operand" "n"))
			  (match_operand:DI 3 "nonmemory_operand" "r"))
		 (match_operand:DI 4 "nonmemory_operand" "rI")))]
  "reload_in_progress"
  "* gcc_unreachable ();"
  "reload_completed"
  [(set (match_dup 0) (plus:DI (mult:DI (match_dup 1) (match_dup 2))
			       (match_dup 3)))
   (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 4)))]
  ""
  [(set_attr "itanium_class" "unknown")])

(define_insn "ashrdi3"
  [(set (match_operand:DI 0 "gr_register_operand" "=r,r")
	(ashiftrt:DI (match_operand:DI 1 "gr_register_operand" "r,r")
		     (match_operand:DI 2 "gr_reg_or_6bit_operand" "r,rM")))]
  ""
  "@
   shr %0 = %1, %2
   shr %0 = %1, %2"
  [(set_attr "itanium_class" "mmshf,mmshfi")])

(define_insn "lshrdi3"
  [(set (match_operand:DI 0 "gr_register_operand" "=r,r")
	(lshiftrt:DI (match_operand:DI 1 "gr_register_operand" "r,r")
		     (match_operand:DI 2 "gr_reg_or_6bit_operand" "r,rM")))]
  ""
  "@
   shr.u %0 = %1, %2
   shr.u %0 = %1, %2"
  [(set_attr "itanium_class" "mmshf,mmshfi")])

;; Using a predicate that accepts only constants doesn't work, because optabs
;; will load the operand into a register and call the pattern if the predicate
;; did not accept it on the first try.  So we use nonmemory_operand and then
;; verify that we have an appropriate constant in the expander.

(define_expand "rotrdi3"
  [(set (match_operand:DI 0 "gr_register_operand" "")
	(rotatert:DI (match_operand:DI 1 "gr_register_operand" "")
		     (match_operand:DI 2 "nonmemory_operand" "")))]
  ""
{
  if (! shift_count_operand (operands[2], DImode))
    FAIL;
})

(define_insn "*rotrdi3_internal"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(rotatert:DI (match_operand:DI 1 "gr_register_operand" "r")
		     (match_operand:DI 2 "shift_count_operand" "M")))]
  ""
  "shrp %0 = %1, %1, %2"
  [(set_attr "itanium_class" "ishf")])

(define_expand "rotldi3"
  [(set (match_operand:DI 0 "gr_register_operand" "")
	(rotate:DI (match_operand:DI 1 "gr_register_operand" "")
		   (match_operand:DI 2 "nonmemory_operand" "")))]
  ""
{
  if (! shift_count_operand (operands[2], DImode))
    FAIL;
})

(define_insn "*rotldi3_internal"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(rotate:DI (match_operand:DI 1 "gr_register_operand" "r")
		   (match_operand:DI 2 "shift_count_operand" "M")))]
  ""
  "shrp %0 = %1, %1, %e2"
  [(set_attr "itanium_class" "ishf")])

;; ::::::::::::::::::::
;; ::
;; :: 128 bit Integer Shifts and Rotates
;; ::
;; ::::::::::::::::::::

(define_expand "ashlti3"
  [(set (match_operand:TI 0 "gr_register_operand" "")
	(ashift:TI (match_operand:TI 1 "gr_register_operand" "")
		   (match_operand:DI 2 "nonmemory_operand" "")))]
  ""
{
  if (!dshift_count_operand (operands[2], DImode))
    FAIL;
})

(define_insn_and_split "*ashlti3_internal"
  [(set (match_operand:TI 0 "gr_register_operand" "=&r")
	(ashift:TI (match_operand:TI 1 "gr_register_operand" "r")
		   (match_operand:DI 2 "dshift_count_operand" "n")))]
  ""
  "#"
  "reload_completed"
  [(const_int 0)]
{
  HOST_WIDE_INT shift = INTVAL (operands[2]);
  rtx rl = gen_lowpart (DImode, operands[0]);
  rtx rh = gen_highpart (DImode, operands[0]);
  rtx lo = gen_lowpart (DImode, operands[1]);
  rtx shiftlo = GEN_INT (shift & 63);

  if (shift & 64)
    {
      emit_move_insn (rl, const0_rtx);
      if (shift & 63)
	emit_insn (gen_ashldi3 (rh, lo, shiftlo));
      else
	emit_move_insn (rh, lo);
    }
  else
    {
      rtx hi = gen_highpart (DImode, operands[1]);

      emit_insn (gen_shrp (rh, hi, lo, GEN_INT (-shift & 63)));
      emit_insn (gen_ashldi3 (rl, lo, shiftlo));
    }
  DONE;
})

(define_expand "ashrti3"
  [(set (match_operand:TI 0 "gr_register_operand" "")
	(ashiftrt:TI (match_operand:TI 1 "gr_register_operand" "")
		     (match_operand:DI 2 "nonmemory_operand" "")))]
  ""
{
  if (!dshift_count_operand (operands[2], DImode))
    FAIL;
})

(define_insn_and_split "*ashrti3_internal"
  [(set (match_operand:TI 0 "gr_register_operand" "=&r")
	(ashiftrt:TI (match_operand:TI 1 "gr_register_operand" "r")
		     (match_operand:DI 2 "dshift_count_operand" "n")))]
  ""
  "#"
  "reload_completed"
  [(const_int 0)]
{
  HOST_WIDE_INT shift = INTVAL (operands[2]);
  rtx rl = gen_lowpart (DImode, operands[0]);
  rtx rh = gen_highpart (DImode, operands[0]);
  rtx hi = gen_highpart (DImode, operands[1]);
  rtx shiftlo = GEN_INT (shift & 63);

  if (shift & 64)
    {
      if (shift & 63)
	emit_insn (gen_ashrdi3 (rl, hi, shiftlo));
      else
	emit_move_insn (rl, hi);
      emit_insn (gen_ashrdi3 (rh, hi, GEN_INT (63)));
    }
  else
    {
      rtx lo = gen_lowpart (DImode, operands[1]);

      emit_insn (gen_shrp (rl, hi, lo, shiftlo));
      emit_insn (gen_ashrdi3 (rh, hi, shiftlo));
    }
  DONE;
})

(define_expand "lshrti3"
  [(set (match_operand:TI 0 "gr_register_operand" "")
        (lshiftrt:TI (match_operand:TI 1 "gr_register_operand" "")
                     (match_operand:DI 2 "nonmemory_operand" "")))]
  ""
{ 
  if (!dshift_count_operand (operands[2], DImode))
    FAIL;
}) 

(define_insn_and_split "*lshrti3_internal"
  [(set (match_operand:TI 0 "gr_register_operand" "=&r")
	(lshiftrt:TI (match_operand:TI 1 "gr_register_operand" "r")
		     (match_operand:DI 2 "dshift_count_operand" "n")))]
  ""
  "#"
  "reload_completed"
  [(const_int 0)]
{
  HOST_WIDE_INT shift = INTVAL (operands[2]);
  rtx rl = gen_lowpart (DImode, operands[0]);
  rtx rh = gen_highpart (DImode, operands[0]);
  rtx hi = gen_highpart (DImode, operands[1]);
  rtx shiftlo = GEN_INT (shift & 63);

  if (shift & 64)
    {
      if (shift & 63)
	emit_insn (gen_lshrdi3 (rl, hi, shiftlo));
      else
	emit_move_insn (rl, hi);
      emit_move_insn (rh, const0_rtx);
    }
  else
    {
      rtx lo = gen_lowpart (DImode, operands[1]);

      emit_insn (gen_shrp (rl, hi, lo, shiftlo));
      emit_insn (gen_lshrdi3 (rh, hi, shiftlo));
    }
  DONE;
})

(define_expand "rotlti3"
  [(set (match_operand:TI 0 "gr_register_operand" "")
	(rotate:TI (match_operand:TI 1 "gr_register_operand" "")
		   (match_operand:DI 2 "nonmemory_operand" "")))]
  ""
{
  if (! dshift_count_operand (operands[2], DImode))
    FAIL;
})

(define_insn_and_split "*rotlti3_internal"
  [(set (match_operand:TI 0 "gr_register_operand" "=&r")
	(rotate:TI (match_operand:TI 1 "gr_register_operand" "r")
		   (match_operand:DI 2 "dshift_count_operand" "n")))]
  ""
  "#"
  "reload_completed"
  [(const_int 0)]
{
  HOST_WIDE_INT count = INTVAL (operands[2]);
  rtx rl = gen_lowpart (DImode, operands[0]);
  rtx rh = gen_highpart (DImode, operands[0]);
  rtx lo = gen_lowpart (DImode, operands[1]);
  rtx hi = gen_highpart (DImode, operands[1]);
  rtx countlo = GEN_INT (-count & 63);

  if (count & 64)
    {
      if (count & 63)
	{
	  emit_insn (gen_shrp (rl, hi, lo, countlo));
	  emit_insn (gen_shrp (rh, lo, hi, countlo));
	}
      else
	{
	  emit_move_insn (rl, hi);
	  emit_move_insn (rh, lo);
	}
    }
  else
    {
      emit_insn (gen_shrp (rl, lo, hi, countlo));
      emit_insn (gen_shrp (rh, hi, lo, countlo));
    }
  DONE;
}
  [(set_attr "itanium_class" "unknown")])

(define_insn "shrp"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(unspec:DI [(match_operand:DI 1 "gr_register_operand" "r")
		    (match_operand:DI 2 "gr_register_operand" "r")
		    (match_operand:DI 3 "shift_count_operand" "M")]
		   UNSPEC_SHRP))]
  ""
  "shrp %0 = %1, %2, %3"
  [(set_attr "itanium_class" "ishf")])

;; ::::::::::::::::::::
;; ::
;; :: 32 bit Integer Logical operations
;; ::
;; ::::::::::::::::::::

;; We don't seem to need any other 32-bit logical operations, because gcc
;; generates zero-extend;zero-extend;DImode-op, which combine optimizes to
;; DImode-op;zero-extend, and then we can optimize away the zero-extend.
;; This doesn't work for unary logical operations, because we don't call
;; apply_distributive_law for them.

;; ??? Likewise, this doesn't work for andnot, which isn't handled by
;; apply_distributive_law.  We get inefficient code for
;; int sub4 (int i, int j) { return i & ~j; }
;; We could convert (and (not (sign_extend A)) (sign_extend B)) to
;; (zero_extend (and (not A) B)) in combine.
;; Or maybe fix this by adding andsi3/iorsi3/xorsi3 patterns like the
;; one_cmplsi2 pattern.

(define_insn "one_cmplsi2"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(not:SI (match_operand:SI 1 "gr_register_operand" "r")))]
  ""
  "andcm %0 = -1, %1"
  [(set_attr "itanium_class" "ilog")])

;; ::::::::::::::::::::
;; ::
;; :: 64 bit Integer Logical operations
;; ::
;; ::::::::::::::::::::

(define_insn "anddi3"
  [(set (match_operand:DI 0 "grfr_register_operand" "=r,*f")
	(and:DI (match_operand:DI 1 "grfr_register_operand" "%r,*f")
		(match_operand:DI 2 "grfr_reg_or_8bit_operand" "rK,*f")))]
  ""
  "@
   and %0 = %2, %1
   fand %0 = %2, %1"
  [(set_attr "itanium_class" "ilog,fmisc")])

(define_insn "*andnot"
  [(set (match_operand:DI 0 "grfr_register_operand" "=r,*f")
	(and:DI (not:DI (match_operand:DI 1 "grfr_register_operand" "r,*f"))
		(match_operand:DI 2 "grfr_reg_or_8bit_operand" "rK,*f")))]
  ""
  "@
   andcm %0 = %2, %1
   fandcm %0 = %2, %1"
  [(set_attr "itanium_class" "ilog,fmisc")])

(define_insn "iordi3"
  [(set (match_operand:DI 0 "grfr_register_operand" "=r,*f")
	(ior:DI (match_operand:DI 1 "grfr_register_operand" "%r,*f")
		(match_operand:DI 2 "grfr_reg_or_8bit_operand" "rK,*f")))]
  ""
  "@
   or %0 = %2, %1
   for %0 = %2, %1"
  [(set_attr "itanium_class" "ilog,fmisc")])

(define_insn "xordi3"
  [(set (match_operand:DI 0 "grfr_register_operand" "=r,*f")
	(xor:DI (match_operand:DI 1 "grfr_register_operand" "%r,*f")
		(match_operand:DI 2 "grfr_reg_or_8bit_operand" "rK,*f")))]
  ""
  "@
   xor %0 = %2, %1
   fxor %0 = %2, %1"
  [(set_attr "itanium_class" "ilog,fmisc")])

(define_insn "one_cmpldi2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(not:DI (match_operand:DI 1 "gr_register_operand" "r")))]
  ""
  "andcm %0 = -1, %1"
  [(set_attr "itanium_class" "ilog")])

;; ::::::::::::::::::::
;; ::
;; :: Comparisons
;; ::
;; ::::::::::::::::::::

(define_expand "cmpbi"
  [(set (cc0)
        (compare (match_operand:BI 0 "register_operand" "")
  		 (match_operand:BI 1 "const_int_operand" "")))]
  ""
{
  ia64_compare_op0 = operands[0];
  ia64_compare_op1 = operands[1];
  DONE;
})

(define_expand "cmpsi"
  [(set (cc0)
        (compare (match_operand:SI 0 "gr_register_operand" "")
  		 (match_operand:SI 1 "gr_reg_or_8bit_and_adjusted_operand" "")))]
  ""
{
  ia64_compare_op0 = operands[0];
  ia64_compare_op1 = operands[1];
  DONE;
})

(define_expand "cmpdi"
  [(set (cc0)
        (compare (match_operand:DI 0 "gr_register_operand" "")
  		 (match_operand:DI 1 "gr_reg_or_8bit_and_adjusted_operand" "")))]
  ""
{
  ia64_compare_op0 = operands[0];
  ia64_compare_op1 = operands[1];
  DONE;
})

(define_expand "cmpsf"
  [(set (cc0)
        (compare (match_operand:SF 0 "fr_reg_or_fp01_operand" "")
  		 (match_operand:SF 1 "fr_reg_or_fp01_operand" "")))]
  ""
{
  ia64_compare_op0 = operands[0];
  ia64_compare_op1 = operands[1];
  DONE;
})

(define_expand "cmpdf"
  [(set (cc0)
        (compare (match_operand:DF 0 "fr_reg_or_fp01_operand" "")
  		 (match_operand:DF 1 "fr_reg_or_fp01_operand" "")))]
  ""
{
  ia64_compare_op0 = operands[0];
  ia64_compare_op1 = operands[1];
  DONE;
})

(define_expand "cmpxf"
  [(set (cc0)
        (compare (match_operand:XF 0 "xfreg_or_fp01_operand" "")
  		 (match_operand:XF 1 "xfreg_or_fp01_operand" "")))]
  ""
{
  ia64_compare_op0 = operands[0];
  ia64_compare_op1 = operands[1];
  DONE;
})

(define_expand "cmptf"
  [(set (cc0)
        (compare (match_operand:TF 0 "gr_register_operand" "")
  		 (match_operand:TF 1 "gr_register_operand" "")))]
  "TARGET_HPUX"
{
  ia64_compare_op0 = operands[0];
  ia64_compare_op1 = operands[1];
  DONE;
})

(define_insn "*cmpsi_normal"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(match_operator:BI 1 "normal_comparison_operator"
	   [(match_operand:SI 2 "gr_register_operand" "r")
	    (match_operand:SI 3 "gr_reg_or_8bit_operand" "rK")]))]
  ""
  "cmp4.%C1 %0, %I0 = %3, %2"
  [(set_attr "itanium_class" "icmp")])

;; We use %r3 because it is possible for us to match a 0, and two of the
;; unsigned comparisons don't accept immediate operands of zero.

(define_insn "*cmpsi_adjusted"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(match_operator:BI 1 "adjusted_comparison_operator"
	   [(match_operand:SI 2 "gr_register_operand" "r")
	    (match_operand:SI 3 "gr_reg_or_8bit_adjusted_operand" "rL")]))]
  ""
  "cmp4.%C1 %0, %I0 = %r3, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpdi_normal"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(match_operator:BI 1 "normal_comparison_operator"
	   [(match_operand:DI 2 "gr_reg_or_0_operand" "rO")
	    (match_operand:DI 3 "gr_reg_or_8bit_operand" "rK")]))]
  ""
  "cmp.%C1 %0, %I0 = %3, %r2"
  [(set_attr "itanium_class" "icmp")])

;; We use %r3 because it is possible for us to match a 0, and two of the
;; unsigned comparisons don't accept immediate operands of zero.

(define_insn "*cmpdi_adjusted"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(match_operator:BI 1 "adjusted_comparison_operator"
	   [(match_operand:DI 2 "gr_register_operand" "r")
	    (match_operand:DI 3 "gr_reg_or_8bit_adjusted_operand" "rL")]))]
  ""
  "cmp.%C1 %0, %I0 = %r3, %2"
  [(set_attr "itanium_class" "icmp")])

(define_insn "*cmpsf_internal"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(match_operator:BI 1 "comparison_operator"
	   [(match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")
	    (match_operand:SF 3 "fr_reg_or_fp01_operand" "fG")]))]
  ""
  "fcmp.%D1 %0, %I0 = %F2, %F3"
  [(set_attr "itanium_class" "fcmp")])

(define_insn "*cmpdf_internal"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(match_operator:BI 1 "comparison_operator"
	   [(match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")
	    (match_operand:DF 3 "fr_reg_or_fp01_operand" "fG")]))]
  ""
  "fcmp.%D1 %0, %I0 = %F2, %F3"
  [(set_attr "itanium_class" "fcmp")])

(define_insn "*cmpxf_internal"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(match_operator:BI 1 "comparison_operator"
		   [(match_operand:XF 2 "xfreg_or_fp01_operand" "fG")
		    (match_operand:XF 3 "xfreg_or_fp01_operand" "fG")]))]
  ""
  "fcmp.%D1 %0, %I0 = %F2, %F3"
  [(set_attr "itanium_class" "fcmp")])

;; ??? Can this pattern be generated?

(define_insn "*bit_zero"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(eq:BI (zero_extract:DI (match_operand:DI 1 "gr_register_operand" "r")
				(const_int 1)
				(match_operand:DI 2 "shift_count_operand" "M"))
	       (const_int 0)))]
  ""
  "tbit.z %0, %I0 = %1, %2"
  [(set_attr "itanium_class" "tbit")])

(define_insn "*bit_one"
  [(set (match_operand:BI 0 "register_operand" "=c")
	(ne:BI (zero_extract:DI (match_operand:DI 1 "gr_register_operand" "r")
				(const_int 1)
				(match_operand:DI 2 "shift_count_operand" "M"))
	       (const_int 0)))]
  ""
  "tbit.nz %0, %I0 = %1, %2"
  [(set_attr "itanium_class" "tbit")])

;; ::::::::::::::::::::
;; ::
;; :: Branches
;; ::
;; ::::::::::::::::::::

(define_expand "beq"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (EQ, VOIDmode);")

(define_expand "bne"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (NE, VOIDmode);")

(define_expand "blt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (LT, VOIDmode);")

(define_expand "ble"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (LE, VOIDmode);")

(define_expand "bgt"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (GT, VOIDmode);")

(define_expand "bge"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (GE, VOIDmode);")

(define_expand "bltu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (LTU, VOIDmode);")

(define_expand "bleu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (LEU, VOIDmode);")

(define_expand "bgtu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (GTU, VOIDmode);")

(define_expand "bgeu"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (GEU, VOIDmode);")

(define_expand "bunordered"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (UNORDERED, VOIDmode);")

(define_expand "bordered"
  [(set (pc)
	(if_then_else (match_dup 1)
		      (label_ref (match_operand 0 "" ""))
		      (pc)))]
  ""
  "operands[1] = ia64_expand_compare (ORDERED, VOIDmode);")

(define_insn "*br_true"
  [(set (pc)
	(if_then_else (match_operator 0 "predicate_operator"
			[(match_operand:BI 1 "register_operand" "c")
			 (const_int 0)])
		      (label_ref (match_operand 2 "" ""))
		      (pc)))]
  ""
  "(%J0) br.cond%+ %l2"
  [(set_attr "itanium_class" "br")
   (set_attr "predicable" "no")])

(define_insn "*br_false"
  [(set (pc)
	(if_then_else (match_operator 0 "predicate_operator"
			[(match_operand:BI 1 "register_operand" "c")
			 (const_int 0)])
		      (pc)
		      (label_ref (match_operand 2 "" ""))))]
  ""
  "(%j0) br.cond%+ %l2"
  [(set_attr "itanium_class" "br")
   (set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: Counted loop operations
;; ::
;; ::::::::::::::::::::

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

(define_insn "doloop_end_internal"
  [(set (pc) (if_then_else (ne (match_operand:DI 0 "ar_lc_reg_operand" "")
			       (const_int 0))
		(label_ref (match_operand 1 "" ""))
		(pc)))
   (set (match_dup 0) (if_then_else:DI (ne (match_dup 0) (const_int 0))
			 (plus:DI (match_dup 0) (const_int -1))
			 (match_dup 0)))]
  ""
  "br.cloop.sptk.few %l1"
  [(set_attr "itanium_class" "br")
   (set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: Set flag operations
;; ::
;; ::::::::::::::::::::

(define_expand "seq"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (EQ, DImode);")

(define_expand "sne"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (NE, DImode);")

(define_expand "slt"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (LT, DImode);")

(define_expand "sle"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (LE, DImode);")

(define_expand "sgt"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (GT, DImode);")

(define_expand "sge"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (GE, DImode);")

(define_expand "sltu"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (LTU, DImode);")

(define_expand "sleu"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (LEU, DImode);")

(define_expand "sgtu"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (GTU, DImode);")

(define_expand "sgeu"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (GEU, DImode);")

(define_expand "sunordered"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (UNORDERED, DImode);")

(define_expand "sordered"
  [(set (match_operand:DI 0 "gr_register_operand" "") (match_dup 1))]
  ""
  "operands[1] = ia64_expand_compare (ORDERED, DImode);")

;; Don't allow memory as destination here, because cmov/cmov/st is more
;; efficient than mov/mov/cst/cst.

(define_insn_and_split "*sne_internal"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(ne:DI (match_operand:BI 1 "register_operand" "c")
	       (const_int 0)))]
  ""
  "#"
  "reload_completed"
  [(cond_exec (ne (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 1)))
   (cond_exec (eq (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 0)))]
  ""
  [(set_attr "itanium_class" "unknown")])

(define_insn_and_split "*seq_internal"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
	(eq:DI (match_operand:BI 1 "register_operand" "c")
	       (const_int 0)))]
  ""
  "#"
  "reload_completed"
  [(cond_exec (ne (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 0)))
   (cond_exec (eq (match_dup 1) (const_int 0))
     (set (match_dup 0) (const_int 1)))]
  ""
  [(set_attr "itanium_class" "unknown")])

;; ::::::::::::::::::::
;; ::
;; :: Conditional move instructions.
;; ::
;; ::::::::::::::::::::

;; ??? Add movXXcc patterns?

;;
;; DImode if_then_else patterns.
;;

(define_insn "*cmovdi_internal"
  [(set (match_operand:DI 0 "destination_operand"
	   "= r,  r,  r,   r,  r,  r,   r, r, r,   r, m, Q, *f,*b,*d*e")
	(if_then_else:DI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand"
		"c,c,c,c,c,c,c,c,c,c,c,c,c,c,c")
	     (const_int 0)])
	  (match_operand:DI 2 "move_operand"
	   "rim, *f, *b,*d*e,rim,rim, rim,*f,*b,*d*e,rO,*f,rOQ,rO,  rK")
	  (match_operand:DI 3 "move_operand"
	   "rim,rim,rim, rim, *f, *b,*d*e,*f,*b,*d*e,rO,*f,rOQ,rO,  rK")))]
  "ia64_move_ok (operands[0], operands[2])
   && ia64_move_ok (operands[0], operands[3])"
  { gcc_unreachable (); }
  [(set_attr "predicable" "no")])

(define_split
  [(set (match_operand 0 "destination_operand" "")
	(if_then_else
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "")
	     (const_int 0)])
	  (match_operand 2 "move_operand" "")
	  (match_operand 3 "move_operand" "")))]
  "reload_completed"
  [(const_int 0)]
{
  bool emitted_something = false;
  rtx dest = operands[0];
  rtx srct = operands[2];
  rtx srcf = operands[3];
  rtx cond = operands[4];

  if (! rtx_equal_p (dest, srct))
    {
      ia64_emit_cond_move (dest, srct, cond);
      emitted_something = true;
    }
  if (! rtx_equal_p (dest, srcf))
    {
      cond = gen_rtx_fmt_ee (GET_CODE (cond) == NE ? EQ : NE,
 			     VOIDmode, operands[1], const0_rtx);
      ia64_emit_cond_move (dest, srcf, cond);
      emitted_something = true;
    }
  if (! emitted_something)
    emit_note (NOTE_INSN_DELETED);
  DONE;
})

;; Absolute value pattern.

(define_insn "*absdi2_internal"
  [(set (match_operand:DI 0 "gr_register_operand" "=r,r")
	(if_then_else:DI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "c,c")
	     (const_int 0)])
	  (neg:DI (match_operand:DI 2 "gr_reg_or_22bit_operand" "rI,rI"))
	  (match_operand:DI 3 "gr_reg_or_22bit_operand" "0,rI")))]
  ""
  "#"
  [(set_attr "itanium_class" "ialu,unknown")
   (set_attr "predicable" "no")])

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(if_then_else:DI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "c,c")
	     (const_int 0)])
	  (neg:DI (match_operand:DI 2 "gr_reg_or_22bit_operand" ""))
	  (match_operand:DI 3 "gr_reg_or_22bit_operand" "")))]
  "reload_completed && rtx_equal_p (operands[0], operands[3])"
  [(cond_exec
     (match_dup 4)
     (set (match_dup 0)
	  (neg:DI (match_dup 2))))]
  "")

(define_split
  [(set (match_operand:DI 0 "register_operand" "")
	(if_then_else:DI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "c,c")
	     (const_int 0)])
	  (neg:DI (match_operand:DI 2 "gr_reg_or_22bit_operand" ""))
	  (match_operand:DI 3 "gr_reg_or_22bit_operand" "")))]
  "reload_completed"
  [(cond_exec
     (match_dup 4)
     (set (match_dup 0) (neg:DI (match_dup 2))))
   (cond_exec
     (match_dup 5)
     (set (match_dup 0) (match_dup 3)))]
{
  operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[4]) == NE ? EQ : NE,
				VOIDmode, operands[1], const0_rtx);
})

;;
;; SImode if_then_else patterns.
;;

(define_insn "*cmovsi_internal"
  [(set (match_operand:SI 0 "destination_operand" "=r,m,*f,r,m,*f,r,m,*f")
	(if_then_else:SI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "c,c,c,c,c,c,c,c,c")
	     (const_int 0)])
	  (match_operand:SI 2 "move_operand"
		    "0,0,0,rim*f,rO,rO,rim*f,rO,rO")
	  (match_operand:SI 3 "move_operand"
		    "rim*f,rO,rO,0,0,0,rim*f,rO,rO")))]
  "ia64_move_ok (operands[0], operands[2])
   && ia64_move_ok (operands[0], operands[3])"
  { gcc_unreachable (); }
  [(set_attr "predicable" "no")])

(define_insn "*abssi2_internal"
  [(set (match_operand:SI 0 "gr_register_operand" "=r,r")
	(if_then_else:SI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "c,c")
	     (const_int 0)])
	  (neg:SI (match_operand:SI 3 "gr_reg_or_22bit_operand" "rI,rI"))
	  (match_operand:SI 2 "gr_reg_or_22bit_operand" "0,rI")))]
  ""
  "#"
  [(set_attr "itanium_class" "ialu,unknown")
   (set_attr "predicable" "no")])

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(if_then_else:SI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "c,c")
	     (const_int 0)])
	  (neg:SI (match_operand:SI 2 "gr_reg_or_22bit_operand" ""))
	  (match_operand:SI 3 "gr_reg_or_22bit_operand" "")))]
  "reload_completed && rtx_equal_p (operands[0], operands[3])"
  [(cond_exec
     (match_dup 4)
     (set (match_dup 0)
	  (neg:SI (match_dup 2))))]
  "")

(define_split
  [(set (match_operand:SI 0 "register_operand" "")
	(if_then_else:SI
	  (match_operator 4 "predicate_operator"
	    [(match_operand:BI 1 "register_operand" "c,c")
	     (const_int 0)])
	  (neg:SI (match_operand:SI 2 "gr_reg_or_22bit_operand" ""))
	  (match_operand:SI 3 "gr_reg_or_22bit_operand" "")))]
  "reload_completed"
  [(cond_exec
     (match_dup 4)
     (set (match_dup 0) (neg:SI (match_dup 2))))
   (cond_exec
     (match_dup 5)
     (set (match_dup 0) (match_dup 3)))]
{
  operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[4]) == NE ? EQ : NE,
				VOIDmode, operands[1], const0_rtx);
})

(define_insn_and_split "*cond_opsi2_internal"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(match_operator:SI 5 "condop_operator"
	  [(if_then_else:SI
	     (match_operator 6 "predicate_operator"
	       [(match_operand:BI 1 "register_operand" "c")
	        (const_int 0)])
	     (match_operand:SI 2 "gr_register_operand" "r")
	     (match_operand:SI 3 "gr_register_operand" "r"))
	   (match_operand:SI 4 "gr_register_operand" "r")]))]
  ""
  "#"
  "reload_completed"
  [(cond_exec
     (match_dup 6)
     (set (match_dup 0) (match_op_dup:SI 5 [(match_dup 2) (match_dup 4)])))
   (cond_exec
     (match_dup 7)
     (set (match_dup 0) (match_op_dup:SI 5 [(match_dup 3) (match_dup 4)])))]
{
  operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[6]) == NE ? EQ : NE,
				VOIDmode, operands[1], const0_rtx);
}
  [(set_attr "itanium_class" "ialu")
   (set_attr "predicable" "no")])


(define_insn_and_split "*cond_opsi2_internal_b"
  [(set (match_operand:SI 0 "gr_register_operand" "=r")
	(match_operator:SI 5 "condop_operator"
	  [(match_operand:SI 4 "gr_register_operand" "r")
	   (if_then_else:SI
	     (match_operator 6 "predicate_operator"
	       [(match_operand:BI 1 "register_operand" "c")
	        (const_int 0)])
	     (match_operand:SI 2 "gr_register_operand" "r")
	     (match_operand:SI 3 "gr_register_operand" "r"))]))]
  ""
  "#"
  "reload_completed"
  [(cond_exec
     (match_dup 6)
     (set (match_dup 0) (match_op_dup:SI 5 [(match_dup 4) (match_dup 2)])))
   (cond_exec
     (match_dup 7)
     (set (match_dup 0) (match_op_dup:SI 5 [(match_dup 4) (match_dup 3)])))]
{
  operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[6]) == NE ? EQ : NE,
				VOIDmode, operands[1], const0_rtx);
}
  [(set_attr "itanium_class" "ialu")
   (set_attr "predicable" "no")])


;; ::::::::::::::::::::
;; ::
;; :: Call and branch instructions
;; ::
;; ::::::::::::::::::::

;; Subroutine call instruction returning no value.  Operand 0 is the function
;; to call; operand 1 is the number of bytes of arguments pushed (in mode
;; `SImode', except it is normally a `const_int'); operand 2 is the number of
;; registers used as operands.

;; On most machines, operand 2 is not actually stored into the RTL pattern.  It
;; is supplied for the sake of some RISC machines which need to put this
;; information into the assembler code; they can put it in the RTL instead of
;; operand 1.

(define_expand "call"
  [(use (match_operand:DI 0 "" ""))
   (use (match_operand 1 "" ""))
   (use (match_operand 2 "" ""))
   (use (match_operand 3 "" ""))]
  ""
{
  ia64_expand_call (NULL_RTX, operands[0], operands[2], false);
  DONE;
})

(define_expand "sibcall"
  [(use (match_operand:DI 0 "" ""))
   (use (match_operand 1 "" ""))
   (use (match_operand 2 "" ""))
   (use (match_operand 3 "" ""))]
  ""
{
  ia64_expand_call (NULL_RTX, operands[0], operands[2], true);
  DONE;
})

;; Subroutine call instruction returning a value.  Operand 0 is the hard
;; register in which the value is returned.  There are three more operands,
;; the same as the three operands of the `call' instruction (but with numbers
;; increased by one).
;;
;; Subroutines that return `BLKmode' objects use the `call' insn.

(define_expand "call_value"
  [(use (match_operand 0 "" ""))
   (use (match_operand:DI 1 "" ""))
   (use (match_operand 2 "" ""))
   (use (match_operand 3 "" ""))
   (use (match_operand 4 "" ""))]
  ""
{
  ia64_expand_call (operands[0], operands[1], operands[3], false);
  DONE;
})

(define_expand "sibcall_value"
  [(use (match_operand 0 "" ""))
   (use (match_operand:DI 1 "" ""))
   (use (match_operand 2 "" ""))
   (use (match_operand 3 "" ""))
   (use (match_operand 4 "" ""))]
  ""
{
  ia64_expand_call (operands[0], operands[1], operands[3], true);
  DONE;
})

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

  emit_call_insn (gen_call (operands[0], const0_rtx, NULL, 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;
})

(define_insn "call_nogp"
  [(call (mem:DI (match_operand:DI 0 "call_operand" "?b,i"))
	 (const_int 0))
   (clobber (match_operand:DI 1 "register_operand" "=b,b"))]
  ""
  "br.call%+.many %1 = %0"
  [(set_attr "itanium_class" "br,scall")])

(define_insn "call_value_nogp"
  [(set (match_operand 0 "" "=X,X")
	(call (mem:DI (match_operand:DI 1 "call_operand" "?b,i"))
	      (const_int 0)))
   (clobber (match_operand:DI 2 "register_operand" "=b,b"))]
  ""
  "br.call%+.many %2 = %1"
  [(set_attr "itanium_class" "br,scall")])

(define_insn "sibcall_nogp"
  [(call (mem:DI (match_operand:DI 0 "call_operand" "?b,i"))
	 (const_int 0))]
  ""
  "br%+.many %0"
  [(set_attr "itanium_class" "br,scall")])

(define_insn "call_gp"
  [(call (mem:DI (match_operand:DI 0 "call_operand" "?r,i"))
	 (const_int 1))
   (clobber (match_operand:DI 1 "register_operand" "=b,b"))
   (clobber (match_scratch:DI 2 "=&r,X"))
   (clobber (match_scratch:DI 3 "=b,X"))]
  ""
  "#"
  [(set_attr "itanium_class" "br,scall")])

;; Irritatingly, we don't have access to INSN within the split body.
;; See commentary in ia64_split_call as to why these aren't peep2.
(define_split
  [(call (mem (match_operand 0 "call_operand" ""))
	 (const_int 1))
   (clobber (match_operand:DI 1 "register_operand" ""))
   (clobber (match_scratch:DI 2 ""))
   (clobber (match_scratch:DI 3 ""))]
  "reload_completed && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
  [(const_int 0)]
{
  ia64_split_call (NULL_RTX, operands[0], operands[1], operands[2],
		   operands[3], true, false);
  DONE;
})

(define_split
  [(call (mem (match_operand 0 "call_operand" ""))
	 (const_int 1))
   (clobber (match_operand:DI 1 "register_operand" ""))
   (clobber (match_scratch:DI 2 ""))
   (clobber (match_scratch:DI 3 ""))]
  "reload_completed"
  [(const_int 0)]
{
  ia64_split_call (NULL_RTX, operands[0], operands[1], operands[2],
		   operands[3], false, false);
  DONE;
})

(define_insn "call_value_gp"
  [(set (match_operand 0 "" "=X,X")
	(call (mem:DI (match_operand:DI 1 "call_operand" "?r,i"))
	      (const_int 1)))
   (clobber (match_operand:DI 2 "register_operand" "=b,b"))
   (clobber (match_scratch:DI 3 "=&r,X"))
   (clobber (match_scratch:DI 4 "=b,X"))]
  ""
  "#"
  [(set_attr "itanium_class" "br,scall")])

(define_split
  [(set (match_operand 0 "" "")
	(call (mem:DI (match_operand:DI 1 "call_operand" ""))
	      (const_int 1)))
   (clobber (match_operand:DI 2 "register_operand" ""))
   (clobber (match_scratch:DI 3 ""))
   (clobber (match_scratch:DI 4 ""))]
  "reload_completed && find_reg_note (insn, REG_NORETURN, NULL_RTX)"
  [(const_int 0)]
{
  ia64_split_call (operands[0], operands[1], operands[2], operands[3],
		   operands[4], true, false);
  DONE;
})

(define_split
  [(set (match_operand 0 "" "")
	(call (mem:DI (match_operand:DI 1 "call_operand" ""))
	      (const_int 1)))
   (clobber (match_operand:DI 2 "register_operand" ""))
   (clobber (match_scratch:DI 3 ""))
   (clobber (match_scratch:DI 4 ""))]
  "reload_completed"
  [(const_int 0)]
{
  ia64_split_call (operands[0], operands[1], operands[2], operands[3],
		   operands[4], false, false);
  DONE;
})

(define_insn_and_split "sibcall_gp"
  [(call (mem:DI (match_operand:DI 0 "call_operand" "?r,i"))
	 (const_int 1))
   (clobber (match_scratch:DI 1 "=&r,X"))
   (clobber (match_scratch:DI 2 "=b,X"))]
  ""
  "#"
  "reload_completed"
  [(const_int 0)]
{
  ia64_split_call (NULL_RTX, operands[0], NULL_RTX, operands[1],
		   operands[2], true, true);
  DONE;
}
  [(set_attr "itanium_class" "br")])

(define_insn "return_internal"
  [(return)
   (use (match_operand:DI 0 "register_operand" "b"))]
  ""
  "br.ret.sptk.many %0"
  [(set_attr "itanium_class" "br")])

(define_insn "return"
  [(return)]
  "ia64_direct_return ()"
  "br.ret.sptk.many rp"
  [(set_attr "itanium_class" "br")])

(define_insn "*return_true"
  [(set (pc)
	(if_then_else (match_operator 0 "predicate_operator"
			[(match_operand:BI 1 "register_operand" "c")
			 (const_int 0)])
		      (return)
		      (pc)))]
  "ia64_direct_return ()"
  "(%J0) br.ret%+.many rp"
  [(set_attr "itanium_class" "br")
   (set_attr "predicable" "no")])

(define_insn "*return_false"
  [(set (pc)
	(if_then_else (match_operator 0 "predicate_operator"
			[(match_operand:BI 1 "register_operand" "c")
			 (const_int 0)])
		      (pc)
		      (return)))]
  "ia64_direct_return ()"
  "(%j0) br.ret%+.many rp"
  [(set_attr "itanium_class" "br")
   (set_attr "predicable" "no")])

(define_insn "jump"
  [(set (pc) (label_ref (match_operand 0 "" "")))]
  ""
  "br %l0"
  [(set_attr "itanium_class" "br")])

(define_insn "indirect_jump"
  [(set (pc) (match_operand:DI 0 "register_operand" "b"))]
  ""
  "br %0"
  [(set_attr "itanium_class" "br")])

(define_expand "tablejump"
  [(parallel [(set (pc) (match_operand:DI 0 "memory_operand" ""))
	      (use (label_ref (match_operand 1 "" "")))])]
  ""
{
  rtx op0 = operands[0];
  rtx addr;

  /* ??? Bother -- do_tablejump is "helpful" and pulls the table
     element into a register without bothering to see whether that
     is necessary given the operand predicate.  Check for MEM just
     in case someone fixes this.  */
  if (GET_CODE (op0) == MEM)
    addr = XEXP (op0, 0);
  else
    {
      /* Otherwise, cheat and guess that the previous insn in the
	 stream was the memory load.  Grab the address from that.
	 Note we have to momentarily pop out of the sequence started
	 by the insn-emit wrapper in order to grab the last insn.  */
      rtx last, set;

      end_sequence ();
      last = get_last_insn ();
      start_sequence ();
      set = single_set (last);

      gcc_assert (rtx_equal_p (SET_DEST (set), op0)
		  && GET_CODE (SET_SRC (set)) == MEM);
      addr = XEXP (SET_SRC (set), 0);
      gcc_assert (!rtx_equal_p (addr, op0));
    }

  /* Jump table elements are stored pc-relative.  That is, a displacement
     from the entry to the label.  Thus to convert to an absolute address
     we add the address of the memory from which the value is loaded.  */
  operands[0] = expand_simple_binop (DImode, PLUS, op0, addr,
				     NULL_RTX, 1, OPTAB_DIRECT);
})

(define_insn "*tablejump_internal"
  [(set (pc) (match_operand:DI 0 "register_operand" "b"))
   (use (label_ref (match_operand 1 "" "")))]
  ""
  "br %0"
  [(set_attr "itanium_class" "br")])


;; ::::::::::::::::::::
;; ::
;; :: Prologue and Epilogue instructions
;; ::
;; ::::::::::::::::::::

(define_expand "prologue"
  [(const_int 1)]
  ""
{
  ia64_expand_prologue ();
  DONE;
})

(define_expand "epilogue"
  [(return)]
  ""
{
  ia64_expand_epilogue (0);
  DONE;
})

(define_expand "sibcall_epilogue"
  [(return)]
  ""
{
  ia64_expand_epilogue (1);
  DONE;
})

;; This prevents the scheduler from moving the SP decrement past FP-relative
;; stack accesses.  This is the same as adddi3 plus the extra set.

(define_insn "prologue_allocate_stack"
  [(set (match_operand:DI 0 "register_operand" "=r,r,r")
	(plus:DI (match_operand:DI 1 "register_operand" "%r,r,a")
		 (match_operand:DI 2 "gr_reg_or_22bit_operand" "r,I,J")))
   (set (match_operand:DI 3 "register_operand" "+r,r,r")
	(match_dup 3))]
  ""
  "@
   add %0 = %1, %2
   adds %0 = %2, %1
   addl %0 = %2, %1"
  [(set_attr "itanium_class" "ialu")])

;; This prevents the scheduler from moving the SP restore past FP-relative
;; stack accesses.  This is similar to movdi plus the extra set.

(define_insn "epilogue_deallocate_stack"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(match_operand:DI 1 "register_operand" "+r"))
   (set (match_dup 1) (match_dup 1))]
  ""
  "mov %0 = %1"
  [(set_attr "itanium_class" "ialu")])

;; As USE insns aren't meaningful after reload, this is used instead
;; to prevent deleting instructions setting registers for EH handling
(define_insn "prologue_use"
  [(unspec:DI [(match_operand:DI 0 "register_operand" "")]
	      UNSPEC_PROLOGUE_USE)]
  ""
  ""
  [(set_attr "itanium_class" "ignore")
   (set_attr "predicable" "no")
   (set_attr "empty" "yes")])

;; Allocate a new register frame.

(define_insn "alloc"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec_volatile:DI [(const_int 0)] UNSPECV_ALLOC))
   (use (match_operand:DI 1 "const_int_operand" "i"))
   (use (match_operand:DI 2 "const_int_operand" "i"))
   (use (match_operand:DI 3 "const_int_operand" "i"))
   (use (match_operand:DI 4 "const_int_operand" "i"))]
  ""
  "alloc %0 = ar.pfs, %1, %2, %3, %4"
  [(set_attr "itanium_class" "syst_m0")
   (set_attr "predicable" "no")
   (set_attr "first_insn" "yes")])

;; Modifies ar.unat
(define_expand "gr_spill"
  [(parallel [(set (match_operand:DI 0 "memory_operand" "=m")
		   (unspec:DI [(match_operand:DI 1 "register_operand" "r")
			       (match_operand:DI 2 "const_int_operand" "")]
			      UNSPEC_GR_SPILL))
	      (clobber (match_dup 3))])]
  ""
  "operands[3] = gen_rtx_REG (DImode, AR_UNAT_REGNUM);")

(define_insn "gr_spill_internal"
  [(set (match_operand:DI 0 "destination_operand" "=m")
	(unspec:DI [(match_operand:DI 1 "register_operand" "r")
		    (match_operand:DI 2 "const_int_operand" "")]
		   UNSPEC_GR_SPILL))
   (clobber (match_operand:DI 3 "register_operand" ""))]
  ""
{
  /* Note that we use a C output pattern here to avoid the predicate
     being automatically added before the .mem.offset directive.  */
  return ".mem.offset %2, 0\;%,st8.spill %0 = %1%P0";
}
  [(set_attr "itanium_class" "st")])

;; Reads ar.unat
(define_expand "gr_restore"
  [(parallel [(set (match_operand:DI 0 "register_operand" "=r")
		   (unspec:DI [(match_operand:DI 1 "memory_operand" "m")
			       (match_operand:DI 2 "const_int_operand" "")]
			      UNSPEC_GR_RESTORE))
	      (use (match_dup 3))])]
  ""
  "operands[3] = gen_rtx_REG (DImode, AR_UNAT_REGNUM);")

(define_insn "gr_restore_internal"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(match_operand:DI 1 "memory_operand" "m")
		    (match_operand:DI 2 "const_int_operand" "")]
		   UNSPEC_GR_RESTORE))
   (use (match_operand:DI 3 "register_operand" ""))]
  ""
  { return ".mem.offset %2, 0\;%,ld8.fill %0 = %1%P1"; }
  [(set_attr "itanium_class" "ld")])

(define_insn "fr_spill"
  [(set (match_operand:XF 0 "destination_operand" "=m")
	(unspec:XF [(match_operand:XF 1 "register_operand" "f")]
		   UNSPEC_FR_SPILL))]
  ""
  "stf.spill %0 = %1%P0"
  [(set_attr "itanium_class" "stf")])

(define_insn "fr_restore"
  [(set (match_operand:XF 0 "register_operand" "=f")
	(unspec:XF [(match_operand:XF 1 "memory_operand" "m")]
		   UNSPEC_FR_RESTORE))]
  ""
  "ldf.fill %0 = %1%P1"
  [(set_attr "itanium_class" "fld")])

;; ??? The explicit stop is not ideal.  It would be better if
;; rtx_needs_barrier took care of this, but this is something that can be
;; fixed later.  This avoids an RSE DV.

(define_insn "bsp_value"
  [(set (match_operand:DI 0 "register_operand" "=r")
	(unspec:DI [(const_int 0)] UNSPEC_BSP_VALUE))]
  ""
  "*
{
  return \";;\;%,mov %0 = ar.bsp\";
}"
  [(set_attr "itanium_class" "frar_i")])

(define_insn "set_bsp"
  [(unspec_volatile [(match_operand:DI 0 "register_operand" "r")]
		    UNSPECV_SET_BSP)]
  ""
  "flushrs
	mov r19=ar.rsc
	;;
	and r19=0x1c,r19
	;;
	mov ar.rsc=r19
	;;
	mov ar.bspstore=%0
	;;
	or r19=0x3,r19
	;;
	loadrs
	invala
	;;
	mov ar.rsc=r19"
  [(set_attr "itanium_class" "unknown")
   (set_attr "predicable" "no")])

;; ??? The explicit stops are not ideal.  It would be better if
;; rtx_needs_barrier took care of this, but this is something that can be
;; fixed later.  This avoids an RSE DV.

(define_insn "flushrs"
  [(unspec [(const_int 0)] UNSPEC_FLUSHRS)]
  ""
  ";;\;flushrs\;;;"
  [(set_attr "itanium_class" "rse_m")
   (set_attr "predicable" "no")])

;; ::::::::::::::::::::
;; ::
;; :: Miscellaneous instructions
;; ::
;; ::::::::::::::::::::

;; ??? Emitting a NOP instruction isn't very useful.  This should probably
;; be emitting ";;" to force a break in the instruction packing.

;; No operation, needed in case the user uses -g but not -O.
(define_insn "nop"
  [(const_int 0)]
  ""
  "nop 0"
  [(set_attr "itanium_class" "nop")])

(define_insn "nop_m"
  [(const_int 1)]
  ""
  "nop.m 0"
  [(set_attr "itanium_class" "nop_m")])

(define_insn "nop_i"
  [(const_int 2)]
  ""
  "nop.i 0"
  [(set_attr "itanium_class" "nop_i")])

(define_insn "nop_f"
  [(const_int 3)]
  ""
  "nop.f 0"
  [(set_attr "itanium_class" "nop_f")])

(define_insn "nop_b"
  [(const_int 4)]
  ""
  "nop.b 0"
  [(set_attr "itanium_class" "nop_b")])

(define_insn "nop_x"
  [(const_int 5)]
  ""
  ""
  [(set_attr "itanium_class" "nop_x")
   (set_attr "empty" "yes")])

;; The following insn will be never generated.  It is used only by
;; insn scheduler to change state before advancing cycle.
(define_insn "pre_cycle"
  [(const_int 6)]
  ""
  ""
  [(set_attr "itanium_class" "pre_cycle")])

(define_insn "bundle_selector"
  [(unspec [(match_operand 0 "const_int_operand" "")] UNSPEC_BUNDLE_SELECTOR)]
  ""
  { return get_bundle_name (INTVAL (operands[0])); }
  [(set_attr "itanium_class" "ignore")
   (set_attr "predicable" "no")])

;; Pseudo instruction that prevents the scheduler from moving code above this
;; point.
(define_insn "blockage"
  [(unspec_volatile [(const_int 0)] UNSPECV_BLOCKAGE)]
  ""
  ""
  [(set_attr "itanium_class" "ignore")
   (set_attr "predicable" "no")])

(define_insn "insn_group_barrier"
  [(unspec_volatile [(match_operand 0 "const_int_operand" "")]
		    UNSPECV_INSN_GROUP_BARRIER)]
  ""
  ";;"
  [(set_attr "itanium_class" "stop_bit")
   (set_attr "predicable" "no")
   (set_attr "empty" "yes")])

(define_expand "trap"
  [(trap_if (const_int 1) (const_int 0))]
  ""
  "")

;; ??? We don't have a match-any slot type.  Setting the type to unknown
;; produces worse code that setting the slot type to A.

(define_insn "*trap"
  [(trap_if (const_int 1) (match_operand 0 "const_int_operand" ""))]
  ""
  "break %0"
  [(set_attr "itanium_class" "chk_s")])

(define_expand "conditional_trap"
  [(trap_if (match_operand 0 "" "") (match_operand 1 "" ""))]
  ""
{
  operands[0] = ia64_expand_compare (GET_CODE (operands[0]), VOIDmode);
})

(define_insn "*conditional_trap"
  [(trap_if (match_operator 0 "predicate_operator"
	      [(match_operand:BI 1 "register_operand" "c")
	       (const_int 0)])  
	    (match_operand 2 "const_int_operand" ""))]
  ""
  "(%J0) break %2"
  [(set_attr "itanium_class" "chk_s")
   (set_attr "predicable" "no")])

(define_insn "break_f"
  [(unspec_volatile [(const_int 0)] UNSPECV_BREAK)]
  ""
  "break.f 0"
  [(set_attr "itanium_class" "nop_f")])

(define_insn "prefetch"
  [(prefetch (match_operand:DI 0 "address_operand" "p")
	     (match_operand:DI 1 "const_int_operand" "n")
	     (match_operand:DI 2 "const_int_operand" "n"))]
  ""
{
  static const char * const alt[2][4] = {
    {
      "%,lfetch.nta [%0]",
      "%,lfetch.nt1 [%0]",
      "%,lfetch.nt2 [%0]",
      "%,lfetch [%0]"
    },
    {
      "%,lfetch.excl.nta [%0]",
      "%,lfetch.excl.nt1 [%0]",
      "%,lfetch.excl.nt2 [%0]",
      "%,lfetch.excl [%0]"
    }
  };
  int i = (INTVAL (operands[1]));
  int j = (INTVAL (operands[2]));

  gcc_assert (i == 0 || i == 1);
  gcc_assert (j >= 0 && j <= 3);
  return alt[i][j];
}
  [(set_attr "itanium_class" "lfetch")])

;; Non-local goto support.

(define_expand "save_stack_nonlocal"
  [(use (match_operand:OI 0 "memory_operand" ""))
   (use (match_operand:DI 1 "register_operand" ""))]
  ""
{
  emit_library_call (gen_rtx_SYMBOL_REF (Pmode,
					 \"__ia64_save_stack_nonlocal\"),
		     0, VOIDmode, 2, XEXP (operands[0], 0), Pmode,
		     operands[1], Pmode);
  DONE;
})

(define_expand "nonlocal_goto"
  [(use (match_operand 0 "general_operand" ""))
   (use (match_operand 1 "general_operand" ""))
   (use (match_operand 2 "general_operand" ""))
   (use (match_operand 3 "general_operand" ""))]
  ""
{
  emit_library_call (gen_rtx_SYMBOL_REF (Pmode, \"__ia64_nonlocal_goto\"),
		     LCT_NORETURN, VOIDmode, 3,
		     operands[1], Pmode,
		     copy_to_reg (XEXP (operands[2], 0)), Pmode,
		     operands[3], Pmode);
  emit_barrier ();
  DONE;
})

(define_insn_and_split "builtin_setjmp_receiver"
  [(unspec_volatile [(match_operand:DI 0 "" "")] UNSPECV_SETJMP_RECEIVER)]
  ""
  "#"
  "reload_completed"
  [(const_int 0)]
{
  ia64_reload_gp ();
  DONE;
})

(define_expand "eh_epilogue"
  [(use (match_operand:DI 0 "register_operand" "r"))
   (use (match_operand:DI 1 "register_operand" "r"))
   (use (match_operand:DI 2 "register_operand" "r"))]
  ""
{
  rtx bsp = gen_rtx_REG (Pmode, 10);
  rtx sp = gen_rtx_REG (Pmode, 9);

  if (GET_CODE (operands[0]) != REG || REGNO (operands[0]) != 10)
    {
      emit_move_insn (bsp, operands[0]);
      operands[0] = bsp;
    }
  if (GET_CODE (operands[2]) != REG || REGNO (operands[2]) != 9)
    {
      emit_move_insn (sp, operands[2]);
      operands[2] = sp;
    }
  emit_insn (gen_rtx_USE (VOIDmode, sp));
  emit_insn (gen_rtx_USE (VOIDmode, bsp));

  cfun->machine->ia64_eh_epilogue_sp = sp;
  cfun->machine->ia64_eh_epilogue_bsp = bsp;
})

;; Builtin apply support.

(define_expand "restore_stack_nonlocal"
  [(use (match_operand:DI 0 "register_operand" ""))
   (use (match_operand:OI 1 "memory_operand" ""))]
  ""
{
  emit_library_call (gen_rtx_SYMBOL_REF (Pmode,
					 "__ia64_restore_stack_nonlocal"),
		     0, VOIDmode, 1,
		     copy_to_reg (XEXP (operands[1], 0)), Pmode);
  DONE;
})


;; Predication.

(define_cond_exec
  [(match_operator 0 "predicate_operator"
     [(match_operand:BI 1 "register_operand" "c")
      (const_int 0)])]
  ""
  "(%J0)")

(define_insn "pred_rel_mutex"
  [(set (match_operand:BI 0 "register_operand" "+c")
       (unspec:BI [(match_dup 0)] UNSPEC_PRED_REL_MUTEX))]
  ""
  ".pred.rel.mutex %0, %I0"
  [(set_attr "itanium_class" "ignore")
   (set_attr "predicable" "no")])

(define_insn "safe_across_calls_all"
  [(unspec_volatile [(const_int 0)] UNSPECV_PSAC_ALL)]
  ""
  ".pred.safe_across_calls p1-p63"
  [(set_attr "itanium_class" "ignore")
   (set_attr "predicable" "no")])

(define_insn "safe_across_calls_normal"
  [(unspec_volatile [(const_int 0)] UNSPECV_PSAC_NORMAL)]
  ""
{
  emit_safe_across_calls ();
  return "";
}
  [(set_attr "itanium_class" "ignore")
   (set_attr "predicable" "no")])

;; UNSPEC instruction definition to "swizzle" 32 bit pointer into 64 bit
;; pointer.  This is used by the HP-UX 32 bit mode.

(define_insn "ptr_extend"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
        (unspec:DI [(match_operand:SI 1 "gr_register_operand" "r")]
		   UNSPEC_ADDP4))]
  ""
  "addp4 %0 = 0,%1"
  [(set_attr "itanium_class" "ialu")])

;;
;; Optimizations for ptr_extend

(define_insn "ptr_extend_plus_imm"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
        (unspec:DI
         [(plus:SI (match_operand:SI 1 "basereg_operand" "r")
                   (match_operand:SI 2 "gr_reg_or_14bit_operand" "rI"))]
         UNSPEC_ADDP4))]
  "addp4_optimize_ok (operands[1], operands[2])"
  "addp4 %0 = %2, %1"
  [(set_attr "itanium_class" "ialu")])

(define_insn "*ptr_extend_plus_2"
  [(set (match_operand:DI 0 "gr_register_operand" "=r")
        (unspec:DI
         [(plus:SI (match_operand:SI 1 "gr_register_operand" "r")
                   (match_operand:SI 2 "basereg_operand" "r"))]
         UNSPEC_ADDP4))]
  "addp4_optimize_ok (operands[1], operands[2])"
  "addp4 %0 = %1, %2"
  [(set_attr "itanium_class" "ialu")])

;;
;; Get instruction pointer

(define_insn "ip_value"
  [(set (match_operand:DI 0 "register_operand" "=r")
        (pc))]
 ""
 "mov %0 = ip"
  [(set_attr "itanium_class" "ialu")])

;; Vector operations
(include "vect.md")
;; Atomic operations
(include "sync.md")
