diff options
author | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
---|---|---|
committer | upstream source tree <ports@midipix.org> | 2015-03-15 20:14:05 -0400 |
commit | 554fd8c5195424bdbcabf5de30fdc183aba391bd (patch) | |
tree | 976dc5ab7fddf506dadce60ae936f43f58787092 /gcc/config/ia64/ia64.md | |
download | cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.bz2 cbb-gcc-4.6.4-15d2061ac0796199866debe9ac87130894b0cdd3.tar.xz |
obtained gcc-4.6.4.tar.bz2 from upstream website;upstream
verified gcc-4.6.4.tar.bz2.sig;
imported gcc-4.6.4 source tree from verified upstream tarball.
downloading a git-generated archive based on the 'upstream' tag
should provide you with a source tree that is binary identical
to the one extracted from the above tarball.
if you have obtained the source via the command 'git clone',
however, do note that line-endings of files in your working
directory might differ from line-endings of the respective
files in the upstream repository.
Diffstat (limited to 'gcc/config/ia64/ia64.md')
-rw-r--r-- | gcc/config/ia64/ia64.md | 5188 |
1 files changed, 5188 insertions, 0 deletions
diff --git a/gcc/config/ia64/ia64.md b/gcc/config/ia64/ia64.md new file mode 100644 index 000000000..c258ca5b7 --- /dev/null +++ b/gcc/config/ia64/ia64.md @@ -0,0 +1,5188 @@ +;; IA-64 Machine description template +;; Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, +;; 2009, 2010 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 3, 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 COPYING3. If not see +;; <http://www.gnu.org/licenses/>. + +;;- 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) + (UNSPEC_LDA 40) + (UNSPEC_LDS 41) + (UNSPEC_LDS_A 42) + (UNSPEC_LDSA 43) + (UNSPEC_LDCCLR 44) + (UNSPEC_LDCNC 45) + (UNSPEC_CHKACLR 46) + (UNSPEC_CHKANC 47) + (UNSPEC_CHKS 48) + (UNSPEC_FR_RECIP_APPROX_RES 49) + (UNSPEC_FR_SQRT_RECIP_APPROX_RES 50) + ]) + +(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) + (UNSPECV_GOTO_RECEIVER 8) + ]) + +(include "predicates.md") +(include "constraints.md") + +;; :::::::::::::::::::: +;; :: +;; :: Attributes +;; :: +;; :::::::::::::::::::: + +;; Processor type. This attribute must exactly match the processor_type +;; enumeration in ia64.h. +(define_attr "cpu" "itanium,itanium2" + (const (symbol_ref "((enum attr_cpu) 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_i,chk_s_f,chk_a,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_i 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_f,chk_a") (const_string "M") + (eq_attr "itanium_class" "chk_s_i,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")) + +(define_attr "data_speculative" "no,yes" (const_string "no")) + +(define_attr "control_speculative" "no,yes" (const_string "no")) + +(define_attr "check_load" "no,yes" (const_string "no")) + +(define_attr "speculable1" "no,yes" (const_string "no")) + +(define_attr "speculable2" "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 "itanium2.md") + +;; Mode iterators + +; Used for truncations from XFmode. +(define_mode_iterator MODE_SDF [SF DF]) + +(define_mode_attr suffix [ + (SF ".s") + (DF ".d") + (XF "") + ]) + +;; :::::::::::::::::::: +;; :: +;; :: 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 "destination_operand" "=c,c,?c,?*r, c,*r,*m,*r") + (match_operand:CCI 1 "move_operand" " O,n, c, c,*r,*m,*r,*r"))] + "" + "@ + cmp.ne %0, p0 = r0, r0 + cmp.eq %0, p0 = r0, r0 + (%1) cmp.eq.unc %0, p0 = r0, r0 + # + tbit.nz %0, p0 = %1, 0 + ld1%O1 %0 = %1%P1 + st1%Q0 %0 = %1%P0 + mov %0 = %1" + [(set_attr "itanium_class" "icmp,icmp,icmp,unknown,tbit,ld,st,ialu") + (set_attr "predicable" "no")]) + +(define_split + [(set (match_operand:CCI 0 "register_operand" "") + (match_operand:CCI 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]))" + [(set (match_dup 2) (const_int 0)) + (cond_exec (ne (match_dup 3) (const_int 0)) + (set (match_dup 2) (const_int 1)))] + "operands[2] = gen_rtx_REG (BImode, REGNO (operands[0])); + operands[3] = gen_rtx_REG (BImode, REGNO (operands[1]));") + +(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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, no, no, no, no, no, yes,no,no")]) + +(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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, no, yes,no,no, no, no")]) + +(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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, no, yes,no,no, no, no")]) + +(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,r, m, r,*f,*f, r,*d") + (match_operand:SI 1 "move_operand" "rO,J,j,i,m,rO,*f,rO,*f,*d,rK"))] + "ia64_move_ok (operands[0], operands[1])" + "@ + mov %0 = %r1 + addl %0 = %1, r0 + addp4 %0 = %1 - 0x100000000, 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,ialu,long_i,ld,st,frfr,tofr,fmisc,frar_m,toar_m") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, no, no, no, yes,no,no, no, no, no, no")]) + +(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,r, m, r,*f,*f,*f, Q, r,*b, r,*e, r,*d, r,*c") + (match_operand:DI 1 "move_operand" + "rO,JT,j,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", + "%,addp4 %0 = %1 - 0x100000000, 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,ialu,long_i,ld,st,frfr,tofr,fmisc,fld,stf,frbr,tobr,frar_i,toar_i,frar_m,toar_m,frpr,topr") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, no, no, no, yes,no,no, no, no, yes,no, no, no, no, no, no, no, no, no")]) + +(define_mode_iterator MODE [BI QI HI SI DI SF DF XF TI]) +(define_mode_iterator MODE_FOR_CMP [BI SI DI SF DF XF (TF "TARGET_HPUX")]) +(define_mode_iterator MODE_FOR_EXTEND [QI HI SI]) + +(define_mode_attr output_a [ + (BI "ld1.a %0 = %1%P1") + (QI "ld1.a %0 = %1%P1") + (HI "ld2.a %0 = %1%P1") + (SI "ld4.a %0 = %1%P1") + (DI + "@ + ld8.a %0 = %1%P1 + ldf8.a %0 = %1%P1") + (SF + "@ + ldfs.a %0 = %1%P1 + ld4.a %0 = %1%P1") + (DF + "@ + ldfd.a %0 = %1%P1 + ld8.a %0 = %1%P1") + (XF "ldfe.a %0 = %1%P1") + (TI "ldfp8.a %X0 = %1%P1")]) + +(define_mode_attr output_s [ + (BI "ld1.s %0 = %1%P1") + (QI "ld1.s %0 = %1%P1") + (HI "ld2.s %0 = %1%P1") + (SI "ld4.s %0 = %1%P1") + (DI + "@ + ld8.s %0 = %1%P1 + ldf8.s %0 = %1%P1") + (SF + "@ + ldfs.s %0 = %1%P1 + ld4.s %0 = %1%P1") + (DF + "@ + ldfd.s %0 = %1%P1 + ld8.s %0 = %1%P1") + (XF "ldfe.s %0 = %1%P1") + (TI "ldfp8.s %X0 = %1%P1")]) + +(define_mode_attr output_sa [ + (BI "ld1.sa %0 = %1%P1") + (QI "ld1.sa %0 = %1%P1") + (HI "ld2.sa %0 = %1%P1") + (SI "ld4.sa %0 = %1%P1") + (DI + "@ + ld8.sa %0 = %1%P1 + ldf8.sa %0 = %1%P1") + (SF + "@ + ldfs.sa %0 = %1%P1 + ld4.sa %0 = %1%P1") + (DF + "@ + ldfd.sa %0 = %1%P1 + ld8.sa %0 = %1%P1") + (XF "ldfe.sa %0 = %1%P1") + (TI "ldfp8.sa %X0 = %1%P1")]) + +(define_mode_attr output_c_clr [ + (BI "ld1.c.clr%O1 %0 = %1%P1") + (QI "ld1.c.clr%O1 %0 = %1%P1") + (HI "ld2.c.clr%O1 %0 = %1%P1") + (SI "ld4.c.clr%O1 %0 = %1%P1") + (DI + "@ + ld8.c.clr%O1 %0 = %1%P1 + ldf8.c.clr %0 = %1%P1") + (SF + "@ + ldfs.c.clr %0 = %1%P1 + ld4.c.clr%O1 %0 = %1%P1") + (DF + "@ + ldfd.c.clr %0 = %1%P1 + ld8.c.clr%O1 %0 = %1%P1") + (XF "ldfe.c.clr %0 = %1%P1") + (TI "ldfp8.c.clr %X0 = %1%P1")]) + +(define_mode_attr output_c_nc [ + (BI "ld1.c.nc%O1 %0 = %1%P1") + (QI "ld1.c.nc%O1 %0 = %1%P1") + (HI "ld2.c.nc%O1 %0 = %1%P1") + (SI "ld4.c.nc%O1 %0 = %1%P1") + (DI + "@ + ld8.c.nc%O1 %0 = %1%P1 + ldf8.c.nc %0 = %1%P1") + (SF + "@ + ldfs.c.nc %0 = %1%P1 + ld4.c.nc%O1 %0 = %1%P1") + (DF + "@ + ldfd.c.nc %0 = %1%P1 + ld8.c.nc%O1 %0 = %1%P1") + (XF "ldfe.c.nc %0 = %1%P1") + (TI "ldfp8.c.nc %X0 = %1%P1")]) + +(define_mode_attr ld_reg_constr [(BI "=*r") (QI "=r") (HI "=r") (SI "=r") (DI "=r,*f") (SF "=f,*r") (DF "=f,*r") (XF "=f") (TI "=*x")]) +(define_mode_attr ldc_reg_constr [(BI "+*r") (QI "+r") (HI "+r") (SI "+r") (DI "+r,*f") (SF "+f,*r") (DF "+f,*r") (XF "+f") (TI "+*x")]) +(define_mode_attr chk_reg_constr [(BI "*r") (QI "r") (HI "r") (SI "r") (DI "r,*f") (SF "f,*r") (DF "f,*r") (XF "f") (TI "*x")]) + +(define_mode_attr mem_constr [(BI "*m") (QI "m") (HI "m") (SI "m") (DI "m,Q") (SF "Q,m") (DF "Q,m") (XF "m") (TI "Q")]) + +;; Define register predicate prefix. +;; We can generate speculative loads only for general and fp registers - this +;; is constrained in ia64.c: ia64_speculate_insn (). +(define_mode_attr reg_pred_prefix [(BI "gr") (QI "gr") (HI "gr") (SI "gr") (DI "grfr") (SF "grfr") (DF "grfr") (XF "fr") (TI "fr")]) + +(define_mode_attr ld_class [(BI "ld") (QI "ld") (HI "ld") (SI "ld") (DI "ld,fld") (SF "fld,ld") (DF "fld,ld") (XF "fld") (TI "fldp")]) +(define_mode_attr chka_class [(BI "chk_a") (QI "chk_a") (HI "chk_a") (SI "chk_a") (DI "chk_a,chk_a") (SF "chk_a,chk_a") (DF "chk_a,chk_a") (XF "chk_a") (TI "chk_a")]) +(define_mode_attr chks_class [(BI "chk_s_i") (QI "chk_s_i") (HI "chk_s_i") (SI "chk_s_i") (DI "chk_s_i,chk_s_f") (SF "chk_s_f,chk_s_i") (DF "chk_s_f,chk_s_i") (XF "chk_s_f") (TI "chk_s_i")]) + +(define_mode_attr attr_yes [(BI "yes") (QI "yes") (HI "yes") (SI "yes") (DI "yes,yes") (SF "yes,yes") (DF "yes,yes") (XF "yes") (TI "yes")]) + +(define_insn "mov<mode>_advanced" + [(set (match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<ld_reg_constr>") + (unspec:MODE [(match_operand:MODE 1 "memory_operand" "<mem_constr>")] UNSPEC_LDA))] + "ia64_move_ok (operands[0], operands[1])" + "<output_a>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "data_speculative" "<attr_yes>")]) + +(define_insn "zero_extend<mode>di2_advanced" + [(set (match_operand:DI 0 "gr_register_operand" "=r") + (zero_extend:DI (unspec:MODE_FOR_EXTEND [(match_operand:MODE_FOR_EXTEND 1 "memory_operand" "<mem_constr>")] UNSPEC_LDA)))] + "" + "<output_a>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "data_speculative" "<attr_yes>")]) + +(define_insn "mov<mode>_speculative" + [(set (match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<ld_reg_constr>") + (unspec:MODE [(match_operand:MODE 1 "memory_operand" "<mem_constr>")] UNSPEC_LDS))] + "ia64_move_ok (operands[0], operands[1])" + "<output_s>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "control_speculative" "<attr_yes>")]) + +(define_insn "zero_extend<mode>di2_speculative" + [(set (match_operand:DI 0 "gr_register_operand" "=r") + (zero_extend:DI (unspec:MODE_FOR_EXTEND [(match_operand:MODE_FOR_EXTEND 1 "memory_operand" "<mem_constr>")] UNSPEC_LDS)))] + "" + "<output_s>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "control_speculative" "<attr_yes>")]) + +(define_insn "mov<mode>_speculative_advanced" + [(set (match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<ld_reg_constr>") + (unspec:MODE [(match_operand:MODE 1 "memory_operand" "<mem_constr>")] UNSPEC_LDSA))] + "ia64_move_ok (operands[0], operands[1])" + "<output_sa>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "data_speculative" "<attr_yes>") + (set_attr "control_speculative" "<attr_yes>")]) + +(define_insn "mov<mode>_speculative_a" + [(set (match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<ld_reg_constr>") + (unspec:MODE [(match_operand:MODE 1 "memory_operand" "<mem_constr>")] UNSPEC_LDS_A))] + "ia64_move_ok (operands[0], operands[1])" + "<output_sa>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "data_speculative" "<attr_yes>") + (set_attr "control_speculative" "<attr_yes>")]) + +(define_insn "zero_extend<mode>di2_speculative_advanced" + [(set (match_operand:DI 0 "gr_register_operand" "=r") + (zero_extend:DI (unspec:MODE_FOR_EXTEND [(match_operand:MODE_FOR_EXTEND 1 "memory_operand" "<mem_constr>")] UNSPEC_LDSA)))] + "" + "<output_sa>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "data_speculative" "<attr_yes>") + (set_attr "control_speculative" "<attr_yes>")]) + +(define_insn "zero_extend<mode>di2_speculative_a" + [(set (match_operand:DI 0 "gr_register_operand" "=r") + (zero_extend:DI (unspec:MODE_FOR_EXTEND [(match_operand:MODE_FOR_EXTEND 1 "memory_operand" "<mem_constr>")] UNSPEC_LDS_A)))] + "" + "<output_sa>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "data_speculative" "<attr_yes>") + (set_attr "control_speculative" "<attr_yes>")]) + +(define_insn "mov<mode>_clr" + [(set (match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<ldc_reg_constr>") + (if_then_else:MODE (ne (unspec [(match_dup 0)] UNSPEC_LDCCLR) (const_int 0)) + (match_operand:MODE 1 "memory_operand" "<mem_constr>") + (match_dup 0)))] + "ia64_move_ok (operands[0], operands[1])" + "<output_c_clr>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "check_load" "<attr_yes>")]) + +(define_insn "mov<mode>_nc" + [(set (match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<ldc_reg_constr>") + (if_then_else:MODE (ne (unspec [(match_dup 0)] UNSPEC_LDCNC) (const_int 0)) + (match_operand:MODE 1 "memory_operand" "<mem_constr>") + (match_dup 0)))] + "ia64_move_ok (operands[0], operands[1])" + "<output_c_nc>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "check_load" "<attr_yes>")]) + +(define_insn "zero_extend<mode>di2_clr" + [(set (match_operand:DI 0 "gr_register_operand" "+r") + (if_then_else:DI (ne (unspec [(match_dup 0)] UNSPEC_LDCCLR) (const_int 0)) + (zero_extend:DI (match_operand:MODE_FOR_EXTEND 1 "memory_operand" "<mem_constr>")) + (match_dup 0)))] + "" + "<output_c_clr>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "check_load" "<attr_yes>")]) + +(define_insn "zero_extend<mode>di2_nc" + [(set (match_operand:DI 0 "gr_register_operand" "+r") + (if_then_else:DI (ne (unspec [(match_dup 0)] UNSPEC_LDCNC) (const_int 0)) + (zero_extend:DI (match_operand:MODE_FOR_EXTEND 1 "memory_operand" "<mem_constr>")) + (match_dup 0)))] + "" + "<output_c_nc>" + [(set_attr "itanium_class" "<ld_class>") + (set_attr "check_load" "<attr_yes>")]) + +(define_insn "advanced_load_check_clr_<mode>" + [(set (pc) + (if_then_else (ne (unspec [(match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<chk_reg_constr>")] UNSPEC_CHKACLR) (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "chk.a.clr %0, %l1" + [(set_attr "itanium_class" "<chka_class>")]) + +(define_insn "advanced_load_check_nc_<mode>" + [(set (pc) + (if_then_else (ne (unspec [(match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<chk_reg_constr>")] UNSPEC_CHKANC) (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "chk.a.clr %0, %l1" + [(set_attr "itanium_class" "<chka_class>")]) + +(define_insn "speculation_check_<mode>" + [(set (pc) + (if_then_else (ne (unspec [(match_operand:MODE 0 "<reg_pred_prefix>_register_operand" "<chk_reg_constr>")] UNSPEC_CHKS) (const_int 0)) + (pc) + (label_ref (match_operand 1 "" ""))))] + "" + "chk.s %0, %l1" + [(set_attr "itanium_class" "<chks_class>")]) + +(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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, no, yes, no, no")]) + +;; 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,*r") + (match_operand:SF 1 "general_operand" "fG,Q,fG,fG,*r,*r, m,*r, F"))] + "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 + movl %0 = %G1" + [(set_attr "itanium_class" "fmisc,fld,stf,frfr,tofr,ialu,ld,st,long_i") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, yes,no, no, no, no, yes,no,no")]) + +(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,*r") + (match_operand:DF 1 "general_operand" "fG,Q,fG,fG,*r,*r, m,*r, F"))] + "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 + movl %0 = %G1" + [(set_attr "itanium_class" "fmisc,fld,stf,frfr,tofr,ialu,ld,st,long_i") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, yes,no, no, no, no, yes,no,no")]) + +;; 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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, yes,no")]) + +;; 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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, yes")]) + +(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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, yes")]) + +(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") + (set_attr "speculable1" "yes") + (set_attr "speculable2" "no, yes,no")]) + +;; 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_reg_or_fp01_operand" "fG")))] + "" + "fnorm.d %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fnorm %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fnorm %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fnorm.s %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fnorm.s %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fnorm.d %0 = %F1" + [(set_attr "itanium_class" "fmac")]) + +;; Convert between signed integer types and floating point. + +(define_insn "floatdirf2" + [(set (match_operand:RF 0 "fr_register_operand" "=f") + (float:RF (match_operand:DI 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fcvt.xf %0 = %F1" + [(set_attr "itanium_class" "fcvtfx")]) + +(define_insn "floatdixf2" + [(set (match_operand:XF 0 "fr_register_operand" "=f") + (float:XF (match_operand:DI 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fcvt.xf %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fx.trunc %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fx.trunc %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fx.trunc %0 = %F1" + [(set_attr "itanium_class" "fcvtfx")]) + +(define_insn "fix_truncrfdi2" + [(set (match_operand:DI 0 "fr_register_operand" "=f") + (fix:DI (match_operand:RF 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fx.trunc %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.xuf.s %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.xuf.d %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.xuf %0 = %F1" + [(set_attr "itanium_class" "fcvtfx")]) + +(define_insn "floatunsdirf2" + [(set (match_operand:RF 0 "fr_register_operand" "=f") + (unsigned_float:RF (match_operand:DI 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fcvt.xuf %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fxu.trunc %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fxu.trunc %0 = %F1" + [(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_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fxu.trunc %0 = %F1" + [(set_attr "itanium_class" "fcvtfx")]) + +(define_insn "fixuns_truncrfdi2" + [(set (match_operand:DI 0 "fr_register_operand" "=f") + (unsigned_fix:DI (match_operand:RF 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fcvt.fxu.trunc %0 = %F1" + [(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" "M")) + (match_operand:DI 3 "const_int_operand" "n")))] + "satisfies_constraint_M (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); }) + +;; :::::::::::::::::::: +;; :: +;; :: 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_reg_or_fp01_operand" "fG")) + (sign_extend:TI + (match_operand:DI 2 "fr_reg_or_fp01_operand" "fG"))) + (const_int 64))))] + "" + "xmpy.h %0 = %F1, %F2" + [(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_reg_or_fp01_operand" "fG")) + (zero_extend:TI + (match_operand:DI 2 "fr_reg_or_fp01_operand" "fG"))) + (const_int 64))))] + "" + "xmpy.hu %0 = %F1, %F2" + [(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_reg_or_fp01_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 "bswapdi2" + [(set (match_operand:DI 0 "gr_register_operand" "=r") + (bswap:DI (match_operand:DI 1 "gr_register_operand" "r")))] + "" + "mux1 %0 = %1, @rev" + [(set_attr "itanium_class" "mmshf")]) + +(define_insn "*getf_exp_xf" + [(set (match_operand:DI 0 "gr_register_operand" "=r") + (unspec:DI [(match_operand:XF 1 "fr_reg_or_fp01_operand" "fG")] + UNSPEC_GETF_EXP))] + "" + "getf.exp %0 = %F1" + [(set_attr "itanium_class" "frfr")]) + +;; :::::::::::::::::::: +;; :: +;; :: 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 && satisfies_constraint_K (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_reg_or_fp01_operand" "")) + (sign_extend:TI + (match_operand:DI 2 "fr_reg_or_fp01_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_reg_or_fp01_operand" "fG")) + (sign_extend:TI + (match_operand:DI 2 "fr_reg_or_fp01_operand" "fG"))))] + "" + "#" + "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_reg_or_fp01_operand" "")) + (zero_extend:TI + (match_operand:DI 2 "fr_reg_or_fp01_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_reg_or_fp01_operand" "fG")) + (zero_extend:TI + (match_operand:DI 2 "fr_reg_or_fp01_operand" "fG"))))] + "" + "#" + "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_reg_or_fp01_operand" "%fG") + (match_operand:SF 2 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fadd.s %0 = %F1, %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_signed_fp01_operand" "fZ")))] + "" + "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_reg_or_fp01_operand" "fG") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")))] + "" + "fmpy.s %0 = %F1, %F2" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "abssf2" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (abs:SF (match_operand:SF 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fabs %0 = %F1" + [(set_attr "itanium_class" "fmisc")]) + +(define_insn "negsf2" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (neg:SF (match_operand:SF 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fneg %0 = %F1" + [(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_reg_or_fp01_operand" "fG"))))] + "" + "fnegabs %0 = %F1" + [(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_reg_or_fp01_operand" "fG") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")))] + "" + "fmin %0 = %F1, %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_reg_or_fp01_operand" "fG") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG")))] + "" + "fmax %0 = %F1, %F2" + [(set_attr "itanium_class" "fmisc")]) + +(define_insn "*nmulsf3" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (neg:SF (mult:SF (match_operand:SF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG"))))] + "" + "fnmpy.s %0 = %F1, %F2" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fmasf4" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (fma:SF (match_operand:SF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:SF 3 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fma.s %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fmssf4" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (fma:SF (match_operand:SF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG") + (neg:SF + (match_operand:SF 3 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fms.s %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fnmasf4" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (fma:SF (neg:SF (match_operand:SF 1 "fr_reg_or_fp01_operand" "fG")) + (match_operand:SF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:SF 3 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fnma.s %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +;; :::::::::::::::::::: +;; :: +;; :: 64-bit floating point arithmetic +;; :: +;; :::::::::::::::::::: + +(define_insn "adddf3" + [(set (match_operand:DF 0 "fr_register_operand" "=f") + (plus:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "%fG") + (match_operand:DF 2 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fadd.d %0 = %F1, %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_reg_or_fp01_operand" "%fG") + (match_operand:DF 2 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fadd.s %0 = %F1, %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_signed_fp01_operand" "fZ")))] + "" + "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_signed_fp01_operand" "fZ"))))] + "" + "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_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))] + "" + "fmpy.d %0 = %F1, %F2" + [(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_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG"))))] + "" + "fmpy.s %0 = %F1, %F2" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "absdf2" + [(set (match_operand:DF 0 "fr_register_operand" "=f") + (abs:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fabs %0 = %F1" + [(set_attr "itanium_class" "fmisc")]) + +(define_insn "negdf2" + [(set (match_operand:DF 0 "fr_register_operand" "=f") + (neg:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")))] + "" + "fneg %0 = %F1" + [(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_reg_or_fp01_operand" "fG"))))] + "" + "fnegabs %0 = %F1" + [(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_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))] + "" + "fmin %0 = %F1, %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_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))] + "" + "fmax %0 = %F1, %F2" + [(set_attr "itanium_class" "fmisc")]) + +(define_insn "*nmuldf3" + [(set (match_operand:DF 0 "fr_register_operand" "=f") + (neg:DF (mult:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG"))))] + "" + "fnmpy.d %0 = %F1, %F2" + [(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_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG")))))] + "" + "fnmpy.s %0 = %F1, %F2" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fmadf4" + [(set (match_operand:DF 0 "fr_register_operand" "=f") + (fma:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 3 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fma.d %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "*fmadf_trunc_sf" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (float_truncate:SF + (fma:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 3 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fma.s %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fmsdf4" + [(set (match_operand:DF 0 "fr_register_operand" "=f") + (fma:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG") + (neg:DF + (match_operand:DF 3 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fms.d %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "*fmsdf_trunc_sf" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (float_truncate:SF + (fma:DF + (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG") + (neg:DF + (match_operand:DF 3 "fr_reg_or_signed_fp01_operand" "fZ")))))] + "" + "fms.s %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fnmadf4" + [(set (match_operand:DF 0 "fr_register_operand" "=f") + (fma:DF (neg:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")) + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 3 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fnma.d %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "*fnmadf_trunc_sf" + [(set (match_operand:SF 0 "fr_register_operand" "=f") + (float_truncate:SF + (fma:DF + (neg:DF (match_operand:DF 1 "fr_reg_or_fp01_operand" "fG")) + (match_operand:DF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:DF 3 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fnma.s %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +;; :::::::::::::::::::: +;; :: +;; :: 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_signed_fp01_operand" "fZ")))] + "" + "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_signed_fp01_operand" "fZ"))))] + "" + "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_signed_fp01_operand" "fZ"))))] + "" + "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_signed_fp01_operand" "fZ")))] + "" + "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_signed_fp01_operand" "fZ"))))] + "" + "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_signed_fp01_operand" "fZ"))))] + "" + "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 "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 "*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 "fmaxf4" + [(set (match_operand:XF 0 "fr_register_operand" "=f") + (fma:XF (match_operand:XF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 3 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fma %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "*fmaxf_trunc_<mode>" + [(set (match_operand:MODE_SDF 0 "fr_register_operand" "=f") + (float_truncate:MODE_SDF + (fma:XF + (match_operand:XF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 3 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fma<suffix> %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fmsxf4" + [(set (match_operand:XF 0 "fr_register_operand" "=f") + (fma:XF (match_operand:XF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG") + (neg:XF + (match_operand:XF 3 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fms %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "*fmsxf_trunc_<mode>" + [(set (match_operand:MODE_SDF 0 "fr_register_operand" "=f") + (float_truncate:MODE_SDF + (fma:XF + (match_operand:XF 1 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG") + (neg:XF + (match_operand:XF 3 "fr_reg_or_signed_fp01_operand" "fZ")))))] + "" + "fms<suffix> %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "fnmaxf4" + [(set (match_operand:XF 0 "fr_register_operand" "=f") + (fma:XF (neg:XF (match_operand:XF 1 "fr_reg_or_fp01_operand" "fG")) + (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 3 "fr_reg_or_signed_fp01_operand" "fZ")))] + "" + "fnma %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +(define_insn "*fnmaxf_trunc_<mode>" + [(set (match_operand:MODE_SDF 0 "fr_register_operand" "=f") + (float_truncate:MODE_SDF + (fma:XF + (neg:XF (match_operand:XF 1 "fr_reg_or_fp01_operand" "fG")) + (match_operand:XF 2 "fr_reg_or_fp01_operand" "fG") + (match_operand:XF 3 "fr_reg_or_signed_fp01_operand" "fZ"))))] + "" + "fnma<suffix> %0 = %F1, %F2, %F3" + [(set_attr "itanium_class" "fmac")]) + +;; :::::::::::::::::::: +;; :: +;; :: 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")))] + "" + "mux2 %0 = %1, 0xe1" + "reload_completed && INTVAL (operands[2]) != 16" + [(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])); +} + [(set_attr "itanium_class" "mmshf")]) + +;; :::::::::::::::::::: +;; :: +;; :: 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 "cbranchbi4" + [(set (pc) + (if_then_else (match_operator 0 "ia64_cbranch_operator" + [(match_operand:BI 1 "register_operand" "") + (match_operand:BI 2 "const_int_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "cbranchsi4" + [(set (pc) + (if_then_else (match_operator 0 "ia64_cbranch_operator" + [(match_operand:SI 1 "gr_register_operand" "") + (match_operand:SI 2 "gr_reg_or_8bit_and_adjusted_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "cbranchdi4" + [(set (pc) + (if_then_else (match_operator 0 "ia64_cbranch_operator" + [(match_operand:DI 1 "gr_register_operand" "") + (match_operand:DI 2 "gr_reg_or_8bit_and_adjusted_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "cbranchsf4" + [(set (pc) + (if_then_else (match_operator 0 "ia64_cbranch_operator" + [(match_operand:SF 1 "fr_reg_or_fp01_operand" "") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "cbranchdf4" + [(set (pc) + (if_then_else (match_operator 0 "ia64_cbranch_operator" + [(match_operand:DF 1 "fr_reg_or_fp01_operand" "") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "cbranchxf4" + [(set (pc) + (if_then_else (match_operator 0 "ia64_cbranch_operator" + [(match_operand:XF 1 "xfreg_or_fp01_operand" "") + (match_operand:XF 2 "xfreg_or_fp01_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "cbranchtf4" + [(set (pc) + (if_then_else (match_operator 0 "ia64_cbranch_operator" + [(match_operand:TF 1 "gr_register_operand" "") + (match_operand:TF 2 "gr_register_operand" "")]) + (label_ref (match_operand 3 "" "")) + (pc)))] + "TARGET_HPUX" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + + +(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_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 "cstorebi4" + [(set (match_operand:DI 0 "gr_register_operand" "") + (match_operator:DI 1 "ia64_cbranch_operator" + [(match_operand:BI 2 "register_operand" "") + (match_operand:BI 3 "const_int_operand" "")]))] + "" + "ia64_expand_compare (&operands[1], &operands[2], &operands[3]);") + +(define_expand "cstoresi4" + [(set (match_operand:DI 0 "gr_register_operand" "") + (match_operator:DI 1 "ia64_cbranch_operator" + [(match_operand:SI 2 "gr_register_operand" "") + (match_operand:SI 3 "gr_reg_or_8bit_and_adjusted_operand" "")]))] + "" + "ia64_expand_compare (&operands[1], &operands[2], &operands[3]);") + +(define_expand "cstoredi4" + [(set (match_operand:DI 0 "gr_register_operand" "") + (match_operator:DI 1 "ia64_cbranch_operator" + [(match_operand:DI 2 "gr_register_operand" "") + (match_operand:DI 3 "gr_reg_or_8bit_and_adjusted_operand" "")]))] + "" + "ia64_expand_compare (&operands[1], &operands[2], &operands[3]);") + +(define_expand "cstoresf4" + [(set (match_operand:DI 0 "gr_register_operand" "") + (match_operator:DI 1 "ia64_cbranch_operator" + [(match_operand:SF 2 "fr_reg_or_fp01_operand" "") + (match_operand:SF 3 "fr_reg_or_fp01_operand" "")]))] + "" + "ia64_expand_compare (&operands[1], &operands[2], &operands[3]);") + +(define_expand "cstoredf4" + [(set (match_operand:DI 0 "gr_register_operand" "") + (match_operator:DI 1 "ia64_cbranch_operator" + [(match_operand:DF 2 "fr_reg_or_fp01_operand" "") + (match_operand:DF 3 "fr_reg_or_fp01_operand" "")]))] + "" + "ia64_expand_compare (&operands[1], &operands[2], &operands[3]);") + +(define_expand "cstorexf4" + [(set (match_operand:DI 0 "gr_register_operand" "") + (match_operator:DI 1 "ia64_cbranch_operator" + [(match_operand:XF 2 "xfreg_or_fp01_operand" "") + (match_operand:XF 3 "xfreg_or_fp01_operand" "")]))] + "" + "ia64_expand_compare (&operands[1], &operands[2], &operands[3]);") + +(define_expand "cstoretf4" + [(set (match_operand:DI 0 "gr_register_operand" "") + (match_operator:DI 1 "ia64_cbranch_operator" + [(match_operand:TF 2 "gr_register_operand" "") + (match_operand:TF 3 "gr_register_operand" "")]))] + "TARGET_HPUX" + "ia64_expand_compare (&operands[1], &operands[2], &operands[3]);") + +;; 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 "not_postinc_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 "not_postinc_move_operand" + "rim, *f, *b,*d*e,rim,rim, rim,*f,*b,*d*e,rO,*f,rOQ,rO, rK") + (match_operand:DI 3 "not_postinc_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 "not_postinc_destination_operand" "") + (if_then_else + (match_operator 4 "predicate_operator" + [(match_operand:BI 1 "register_operand" "") + (const_int 0)]) + (match_operand 2 "not_postinc_move_operand" "") + (match_operand 3 "not_postinc_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 "not_postinc_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 "not_postinc_move_operand" + "0,0,0,rim*f,rO,rO,rim*f,rO,rO") + (match_operand:SI 3 "not_postinc_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,s")) + (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,s")) + (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,s")) + (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,s")) + (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,s")) + (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,s")) + (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_i")]) + +(define_expand "ctrapbi4" + [(trap_if (match_operator 0 "ia64_cbranch_operator" + [(match_operand:BI 1 "register_operand" "") + (match_operand:BI 2 "const_int_operand" "")]) + (match_operand 3 "" ""))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "ctrapsi4" + [(trap_if (match_operator 0 "ia64_cbranch_operator" + [(match_operand:SI 1 "gr_register_operand" "") + (match_operand:SI 2 "gr_reg_or_8bit_and_adjusted_operand" "")]) + (match_operand 3 "" ""))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "ctrapdi4" + [(trap_if (match_operator 0 "ia64_cbranch_operator" + [(match_operand:DI 1 "gr_register_operand" "") + (match_operand:DI 2 "gr_reg_or_8bit_and_adjusted_operand" "")]) + (match_operand 3 "" ""))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "ctrapsf4" + [(trap_if (match_operator 0 "ia64_cbranch_operator" + [(match_operand:SF 1 "fr_reg_or_fp01_operand" "") + (match_operand:SF 2 "fr_reg_or_fp01_operand" "")]) + (match_operand 3 "" ""))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "ctrapdf4" + [(trap_if (match_operator 0 "ia64_cbranch_operator" + [(match_operand:DF 1 "fr_reg_or_fp01_operand" "") + (match_operand:DF 2 "fr_reg_or_fp01_operand" "")]) + (match_operand 3 "" ""))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "ctrapxf4" + [(trap_if (match_operator 0 "ia64_cbranch_operator" + [(match_operand:XF 1 "xfreg_or_fp01_operand" "") + (match_operand:XF 2 "xfreg_or_fp01_operand" "")]) + (match_operand 3 "" ""))] + "" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + +(define_expand "ctraptf4" + [(trap_if (match_operator 0 "ia64_cbranch_operator" + [(match_operand:TF 1 "gr_register_operand" "") + (match_operand:TF 2 "gr_register_operand" "")]) + (match_operand 3 "" ""))] + "TARGET_HPUX" + "ia64_expand_compare (&operands[0], &operands[1], &operands[2]);") + + +(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_i") + (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\"), + LCT_NORMAL, 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 "nonlocal_goto_receiver" + [(unspec_volatile [(const_int 0)] UNSPECV_GOTO_RECEIVER)] + "" + "#" + "reload_completed" + [(const_int 0)] +{ + ia64_reload_gp (); + 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_use (sp); + emit_use (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"), + LCT_NORMAL, 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" "frbr")]) + +;; Vector operations +(include "vect.md") +;; Atomic operations +(include "sync.md") +;; New division operations +(include "div.md") |