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/rs6000/rs6000.md | |
download | cbb-gcc-4.6.4-upstream.tar.bz2 cbb-gcc-4.6.4-upstream.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/rs6000/rs6000.md')
-rw-r--r-- | gcc/config/rs6000/rs6000.md | 16361 |
1 files changed, 16361 insertions, 0 deletions
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md new file mode 100644 index 000000000..7befb56a3 --- /dev/null +++ b/gcc/config/rs6000/rs6000.md @@ -0,0 +1,16361 @@ +;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler +;; Copyright (C) 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, +;; 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 +;; Free Software Foundation, Inc. +;; Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) + +;; 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. + +;; +;; REGNOS +;; + +(define_constants + [(MQ_REGNO 64) + (LR_REGNO 65) + (CTR_REGNO 66) + (CR0_REGNO 68) + (CR1_REGNO 69) + (CR2_REGNO 70) + (CR3_REGNO 71) + (CR4_REGNO 72) + (CR5_REGNO 73) + (CR6_REGNO 74) + (CR7_REGNO 75) + (MAX_CR_REGNO 75) + (CA_REGNO 76) + (FIRST_ALTIVEC_REGNO 77) + (LAST_ALTIVEC_REGNO 108) + (VRSAVE_REGNO 109) + (VSCR_REGNO 110) + (SPE_ACC_REGNO 111) + (SPEFSCR_REGNO 112) + (SFP_REGNO 113) + ]) + +;; +;; UNSPEC usage +;; + +(define_constants + [(UNSPEC_FRSP 0) ; frsp for POWER machines + (UNSPEC_PROBE_STACK 4) ; probe stack memory reference + (UNSPEC_TIE 5) ; tie stack contents and stack pointer + (UNSPEC_TOCPTR 6) ; address of a word pointing to the TOC + (UNSPEC_TOC 7) ; address of the TOC (more-or-less) + (UNSPEC_MOVSI_GOT 8) + (UNSPEC_MV_CR_OV 9) ; move_from_CR_ov_bit + (UNSPEC_FCTIWZ 10) + (UNSPEC_FRIM 11) + (UNSPEC_FRIN 12) + (UNSPEC_FRIP 13) + (UNSPEC_FRIZ 14) + (UNSPEC_LD_MPIC 15) ; load_macho_picbase + (UNSPEC_MPIC_CORRECT 16) ; macho_correct_pic + (UNSPEC_TLSGD 17) + (UNSPEC_TLSLD 18) + (UNSPEC_MOVESI_FROM_CR 19) + (UNSPEC_MOVESI_TO_CR 20) + (UNSPEC_TLSDTPREL 21) + (UNSPEC_TLSDTPRELHA 22) + (UNSPEC_TLSDTPRELLO 23) + (UNSPEC_TLSGOTDTPREL 24) + (UNSPEC_TLSTPREL 25) + (UNSPEC_TLSTPRELHA 26) + (UNSPEC_TLSTPRELLO 27) + (UNSPEC_TLSGOTTPREL 28) + (UNSPEC_TLSTLS 29) + (UNSPEC_FIX_TRUNC_TF 30) ; fadd, rounding towards zero + (UNSPEC_MV_CR_GT 31) ; move_from_CR_gt_bit + (UNSPEC_STFIWX 32) + (UNSPEC_POPCNTB 33) + (UNSPEC_FRES 34) + (UNSPEC_SP_SET 35) + (UNSPEC_SP_TEST 36) + (UNSPEC_SYNC 37) + (UNSPEC_LWSYNC 38) + (UNSPEC_ISYNC 39) + (UNSPEC_SYNC_OP 40) + (UNSPEC_ATOMIC 41) + (UNSPEC_CMPXCHG 42) + (UNSPEC_XCHG 43) + (UNSPEC_AND 44) + (UNSPEC_DLMZB 45) + (UNSPEC_DLMZB_CR 46) + (UNSPEC_DLMZB_STRLEN 47) + (UNSPEC_RSQRT 48) + (UNSPEC_TOCREL 49) + (UNSPEC_MACHOPIC_OFFSET 50) + (UNSPEC_BPERM 51) + (UNSPEC_COPYSIGN 52) + (UNSPEC_PARITY 53) + (UNSPEC_FCTIW 54) + (UNSPEC_FCTID 55) + (UNSPEC_LFIWAX 56) + (UNSPEC_LFIWZX 57) + (UNSPEC_FCTIWUZ 58) + ]) + +;; +;; UNSPEC_VOLATILE usage +;; + +(define_constants + [(UNSPECV_BLOCK 0) + (UNSPECV_LL 1) ; load-locked + (UNSPECV_SC 2) ; store-conditional + (UNSPECV_PROBE_STACK_RANGE 3) ; probe range of stack addresses + (UNSPECV_EH_RR 9) ; eh_reg_restore + ]) + +;; Define an insn type attribute. This is used in function unit delay +;; computations. +(define_attr "type" "integer,two,three,load,load_ext,load_ext_u,load_ext_ux,load_ux,load_u,store,store_ux,store_u,fpload,fpload_ux,fpload_u,fpstore,fpstore_ux,fpstore_u,vecload,vecstore,imul,imul2,imul3,lmul,idiv,ldiv,insert_word,branch,cmp,fast_compare,compare,var_delayed_compare,delayed_compare,imul_compare,lmul_compare,fpcompare,cr_logical,delayed_cr,mfcr,mfcrf,mtcr,mfjmpr,mtjmpr,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,jmpreg,brinc,vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,vecfloat,vecfdiv,isync,sync,load_l,store_c,shift,trap,insert_dword,var_shift_rotate,cntlz,exts,mffgpr,mftgpr,isel" + (const_string "integer")) + +;; Define floating point instruction sub-types for use with Xfpu.md +(define_attr "fp_type" "fp_default,fp_addsub_s,fp_addsub_d,fp_mul_s,fp_mul_d,fp_div_s,fp_div_d,fp_maddsub_s,fp_maddsub_d,fp_sqrt_s,fp_sqrt_d" (const_string "fp_default")) + +;; Length (in bytes). +; '(pc)' in the following doesn't include the instruction itself; it is +; calculated as if the instruction had zero size. +(define_attr "length" "" + (if_then_else (eq_attr "type" "branch") + (if_then_else (and (ge (minus (match_dup 0) (pc)) + (const_int -32768)) + (lt (minus (match_dup 0) (pc)) + (const_int 32764))) + (const_int 4) + (const_int 8)) + (const_int 4))) + +;; Processor type -- this attribute must exactly match the processor_type +;; enumeration in rs6000.h. + +(define_attr "cpu" "rios1,rios2,rs64a,mpccore,ppc403,ppc405,ppc440,ppc476,ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,ppc750,ppc7400,ppc7450,ppc8540,ppce300c2,ppce300c3,ppce500mc,ppce500mc64,power4,power5,power6,power7,cell,ppca2,titan" + (const (symbol_ref "rs6000_cpu_attr"))) + + +;; If this instruction is microcoded on the CELL processor +; The default for load extended, the recorded instructions and rotate/shifts by a variable is always microcoded +(define_attr "cell_micro" "not,conditional,always" + (if_then_else (eq_attr "type" "compare,delayed_compare,imul_compare,lmul_compare,load_ext,load_ext_ux,var_shift_rotate,var_delayed_compare") + (const_string "always") + (const_string "not"))) + +(automata_option "ndfa") + +(include "rios1.md") +(include "rios2.md") +(include "rs64.md") +(include "mpc.md") +(include "40x.md") +(include "440.md") +(include "476.md") +(include "603.md") +(include "6xx.md") +(include "7xx.md") +(include "7450.md") +(include "8540.md") +(include "e300c2c3.md") +(include "e500mc.md") +(include "e500mc64.md") +(include "power4.md") +(include "power5.md") +(include "power6.md") +(include "power7.md") +(include "cell.md") +(include "xfpu.md") +(include "a2.md") +(include "titan.md") + +(include "predicates.md") +(include "constraints.md") + +(include "darwin.md") + + +;; Mode iterators + +; This mode iterator allows :GPR to be used to indicate the allowable size +; of whole values in GPRs. +(define_mode_iterator GPR [SI (DI "TARGET_POWERPC64")]) + +; Any supported integer mode. +(define_mode_iterator INT [QI HI SI DI TI]) + +; Any supported integer mode that fits in one register. +(define_mode_iterator INT1 [QI HI SI (DI "TARGET_POWERPC64")]) + +; extend modes for DImode +(define_mode_iterator QHSI [QI HI SI]) + +; SImode or DImode, even if DImode doesn't fit in GPRs. +(define_mode_iterator SDI [SI DI]) + +; The size of a pointer. Also, the size of the value that a record-condition +; (one with a '.') will compare; and the size used for arithmetic carries. +(define_mode_iterator P [(SI "TARGET_32BIT") (DI "TARGET_64BIT")]) + +; Any hardware-supported floating-point mode +(define_mode_iterator FP [ + (SF "TARGET_HARD_FLOAT + && ((TARGET_FPRS && TARGET_SINGLE_FLOAT) || TARGET_E500_SINGLE)") + (DF "TARGET_HARD_FLOAT + && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)") + (TF "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128") + (DD "TARGET_DFP") + (TD "TARGET_DFP")]) + +; Any fma capable floating-point mode. +(define_mode_iterator FMA_F [ + (SF "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT") + (DF "(TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT) + || VECTOR_UNIT_VSX_P (DFmode)") + (V2SF "TARGET_PAIRED_FLOAT") + (V4SF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)") + (V2DF "VECTOR_UNIT_ALTIVEC_OR_VSX_P (V2DFmode)") + ]) + +; These modes do not fit in integer registers in 32-bit mode. +; but on e500v2, the gpr are 64 bit registers +(define_mode_iterator DIFD [DI (DF "!TARGET_E500_DOUBLE") DD]) + +; Iterator for reciprocal estimate instructions +(define_mode_iterator RECIPF [SF DF V4SF V2DF]) + +; Iterator for just SF/DF +(define_mode_iterator SFDF [SF DF]) + +; Various instructions that come in SI and DI forms. +; A generic w/d attribute, for things like cmpw/cmpd. +(define_mode_attr wd [(QI "b") (HI "h") (SI "w") (DI "d")]) + +; DImode bits +(define_mode_attr dbits [(QI "56") (HI "48") (SI "32")]) + +;; ISEL/ISEL64 target selection +(define_mode_attr sel [(SI "") (DI "64")]) + +;; Suffix for reload patterns +(define_mode_attr ptrsize [(SI "32bit") + (DI "64bit")]) + +(define_mode_attr tptrsize [(SI "TARGET_32BIT") + (DI "TARGET_64BIT")]) + +(define_mode_attr mptrsize [(SI "si") + (DI "di")]) + +(define_mode_attr rreg [(SF "f") + (DF "ws") + (V4SF "wf") + (V2DF "wd")]) + +(define_mode_attr rreg2 [(SF "f") + (DF "d")]) + +(define_mode_attr SI_CONVERT_FP [(SF "TARGET_FCFIDS") + (DF "TARGET_FCFID")]) + +(define_mode_attr E500_CONVERT [(SF "!TARGET_FPRS") + (DF "TARGET_E500_DOUBLE")]) + +(define_mode_attr TARGET_FLOAT [(SF "TARGET_SINGLE_FLOAT") + (DF "TARGET_DOUBLE_FLOAT")]) + +;; Start with fixed-point load and store insns. Here we put only the more +;; complex forms. Basic data transfer is done later. + +(define_expand "zero_extend<mode>di2" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (zero_extend:DI (match_operand:QHSI 1 "gpc_reg_operand" "")))] + "TARGET_POWERPC64" + "") + +(define_insn "*zero_extend<mode>di2_internal1" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI (match_operand:QHSI 1 "reg_or_mem_operand" "m,r")))] + "TARGET_POWERPC64" + "@ + l<wd>z%U1%X1 %0,%1 + rldicl %0,%1,0,<dbits>" + [(set_attr "type" "load,*")]) + +(define_insn "*zero_extend<mode>di2_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:DI (match_operand:QHSI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:DI 2 "=r,r"))] + "TARGET_64BIT" + "@ + rldicl. %2,%1,0,<dbits> + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI (match_operand:QHSI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 2 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 2) + (zero_extend:DI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "*zero_extend<mode>di2_internal3" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:DI (match_operand:QHSI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI (match_dup 1)))] + "TARGET_64BIT" + "@ + rldicl. %0,%1,0,<dbits> + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI (match_operand:QHSI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (zero_extend:DI (match_dup 1)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (zero_extend:DI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "extendqidi2" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r")))] + "TARGET_POWERPC64" + "extsb %0,%1" + [(set_attr "type" "exts")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:DI 2 "=r,r"))] + "TARGET_64BIT" + "@ + extsb. %2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 2 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 2) + (sign_extend:DI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (sign_extend:DI (match_dup 1)))] + "TARGET_64BIT" + "@ + extsb. %0,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:DI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (sign_extend:DI (match_dup 1)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (sign_extend:DI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "extendhidi2" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "")))] + "TARGET_POWERPC64" + "") + +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (sign_extend:DI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))] + "TARGET_POWERPC64 && rs6000_gen_cell_microcode" + "@ + lha%U1%X1 %0,%1 + extsh %0,%1" + [(set_attr "type" "load_ext,exts")]) + +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r")))] + "TARGET_POWERPC64 && !rs6000_gen_cell_microcode" + "extsh %0,%1" + [(set_attr "type" "exts")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:DI 2 "=r,r"))] + "TARGET_64BIT" + "@ + extsh. %2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 2 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 2) + (sign_extend:DI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (sign_extend:DI (match_dup 1)))] + "TARGET_64BIT" + "@ + extsh. %0,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:DI (match_operand:HI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (sign_extend:DI (match_dup 1)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (sign_extend:DI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "extendsidi2" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")))] + "TARGET_POWERPC64" + "") + +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (sign_extend:DI (match_operand:SI 1 "lwa_operand" "m,r")))] + "TARGET_POWERPC64 && rs6000_gen_cell_microcode" + "@ + lwa%U1%X1 %0,%1 + extsw %0,%1" + [(set_attr "type" "load_ext,exts")]) + +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r")))] + "TARGET_POWERPC64 && !rs6000_gen_cell_microcode" + "extsw %0,%1" + [(set_attr "type" "exts")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:DI 2 "=r,r"))] + "TARGET_64BIT" + "@ + extsw. %2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 2 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 2) + (sign_extend:DI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (sign_extend:DI (match_dup 1)))] + "TARGET_64BIT" + "@ + extsw. %0,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (sign_extend:DI (match_dup 1)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (sign_extend:DI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "zero_extendqisi2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extend:SI (match_operand:QI 1 "reg_or_mem_operand" "m,r")))] + "" + "@ + lbz%U1%X1 %0,%1 + {rlinm|rlwinm} %0,%1,0,0xff" + [(set_attr "type" "load,*")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 2 "=r,r"))] + "" + "@ + {andil.|andi.} %2,%1,0xff + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 2 ""))] + "reload_completed" + [(set (match_dup 2) + (zero_extend:SI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extend:SI (match_dup 1)))] + "" + "@ + {andil.|andi.} %0,%1,0xff + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (match_dup 1)))] + "reload_completed" + [(set (match_dup 0) + (zero_extend:SI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "extendqisi2" + [(use (match_operand:SI 0 "gpc_reg_operand" "")) + (use (match_operand:QI 1 "gpc_reg_operand" ""))] + "" + " +{ + if (TARGET_POWERPC) + emit_insn (gen_extendqisi2_ppc (operands[0], operands[1])); + else if (TARGET_POWER) + emit_insn (gen_extendqisi2_power (operands[0], operands[1])); + else + emit_insn (gen_extendqisi2_no_power (operands[0], operands[1])); + DONE; +}") + +(define_insn "extendqisi2_ppc" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r")))] + "TARGET_POWERPC" + "extsb %0,%1" + [(set_attr "type" "exts")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 2 "=r,r"))] + "TARGET_POWERPC" + "@ + extsb. %2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 2 ""))] + "TARGET_POWERPC && reload_completed" + [(set (match_dup 2) + (sign_extend:SI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (sign_extend:SI (match_dup 1)))] + "TARGET_POWERPC" + "@ + extsb. %0,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:SI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (sign_extend:SI (match_dup 1)))] + "TARGET_POWERPC && reload_completed" + [(set (match_dup 0) + (sign_extend:SI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "extendqisi2_power" + [(parallel [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "") + (const_int 24))) + (clobber (scratch:SI))]) + (parallel [(set (match_operand:SI 0 "gpc_reg_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24))) + (clobber (scratch:SI))])] + "TARGET_POWER" + " +{ operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }") + +(define_expand "extendqisi2_no_power" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "") + (const_int 24))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "! TARGET_POWER && ! TARGET_POWERPC" + " +{ operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }") + +(define_expand "zero_extendqihi2" + [(set (match_operand:HI 0 "gpc_reg_operand" "") + (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:HI 0 "gpc_reg_operand" "=r,r") + (zero_extend:HI (match_operand:QI 1 "reg_or_mem_operand" "m,r")))] + "" + "@ + lbz%U1%X1 %0,%1 + {rlinm|rlwinm} %0,%1,0,0xff" + [(set_attr "type" "load,*")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:HI 2 "=r,r"))] + "" + "@ + {andil.|andi.} %2,%1,0xff + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:HI 2 ""))] + "reload_completed" + [(set (match_dup 2) + (zero_extend:HI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:HI 0 "gpc_reg_operand" "=r,r") + (zero_extend:HI (match_dup 1)))] + "" + "@ + {andil.|andi.} %0,%1,0xff + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:HI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:HI 0 "gpc_reg_operand" "") + (zero_extend:HI (match_dup 1)))] + "reload_completed" + [(set (match_dup 0) + (zero_extend:HI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "extendqihi2" + [(use (match_operand:HI 0 "gpc_reg_operand" "")) + (use (match_operand:QI 1 "gpc_reg_operand" ""))] + "" + " +{ + if (TARGET_POWERPC) + emit_insn (gen_extendqihi2_ppc (operands[0], operands[1])); + else if (TARGET_POWER) + emit_insn (gen_extendqihi2_power (operands[0], operands[1])); + else + emit_insn (gen_extendqihi2_no_power (operands[0], operands[1])); + DONE; +}") + +(define_insn "extendqihi2_ppc" + [(set (match_operand:HI 0 "gpc_reg_operand" "=r") + (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r")))] + "TARGET_POWERPC" + "extsb %0,%1" + [(set_attr "type" "exts")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:HI 2 "=r,r"))] + "TARGET_POWERPC" + "@ + extsb. %2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:HI 2 ""))] + "TARGET_POWERPC && reload_completed" + [(set (match_dup 2) + (sign_extend:HI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:HI 0 "gpc_reg_operand" "=r,r") + (sign_extend:HI (match_dup 1)))] + "TARGET_POWERPC" + "@ + extsb. %0,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:HI (match_operand:QI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:HI 0 "gpc_reg_operand" "") + (sign_extend:HI (match_dup 1)))] + "TARGET_POWERPC && reload_completed" + [(set (match_dup 0) + (sign_extend:HI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "extendqihi2_power" + [(parallel [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "") + (const_int 24))) + (clobber (scratch:SI))]) + (parallel [(set (match_operand:HI 0 "gpc_reg_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24))) + (clobber (scratch:SI))])] + "TARGET_POWER" + " +{ operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }") + +(define_expand "extendqihi2_no_power" + [(set (match_dup 2) + (ashift:SI (match_operand:QI 1 "gpc_reg_operand" "") + (const_int 24))) + (set (match_operand:HI 0 "gpc_reg_operand" "") + (ashiftrt:SI (match_dup 2) + (const_int 24)))] + "! TARGET_POWER && ! TARGET_POWERPC" + " +{ operands[0] = gen_lowpart (SImode, operands[0]); + operands[1] = gen_lowpart (SImode, operands[1]); + operands[2] = gen_reg_rtx (SImode); }") + +(define_expand "zero_extendhisi2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extend:SI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))] + "" + "@ + lhz%U1%X1 %0,%1 + {rlinm|rlwinm} %0,%1,0,0xffff" + [(set_attr "type" "load,*")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 2 "=r,r"))] + "" + "@ + {andil.|andi.} %2,%1,0xffff + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 2 ""))] + "reload_completed" + [(set (match_dup 2) + (zero_extend:SI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extend:SI (match_dup 1)))] + "" + "@ + {andil.|andi.} %0,%1,0xffff + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (match_dup 1)))] + "reload_completed" + [(set (match_dup 0) + (zero_extend:SI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "extendhisi2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")))] + "" + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (sign_extend:SI (match_operand:HI 1 "reg_or_mem_operand" "m,r")))] + "rs6000_gen_cell_microcode" + "@ + lha%U1%X1 %0,%1 + {exts|extsh} %0,%1" + [(set_attr "type" "load_ext,exts")]) + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r")))] + "!rs6000_gen_cell_microcode" + "{exts|extsh} %0,%1" + [(set_attr "type" "exts")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 2 "=r,r"))] + "" + "@ + {exts.|extsh.} %2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 2 ""))] + "reload_completed" + [(set (match_dup 2) + (sign_extend:SI (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (sign_extend:SI (match_dup 1)))] + "" + "@ + {exts.|extsh.} %0,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +;; IBM 405, 440, 464 and 476 half-word multiplication operations. + +(define_insn "*macchwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (plus:SI (mult:SI (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))) + (match_operand:SI 4 "gpc_reg_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (ashiftrt:SI + (match_dup 2) + (const_int 16)) + (sign_extend:SI + (match_dup 1))) + (match_dup 4)))] + "TARGET_MULHW" + "macchw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*macchw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))) + (match_operand:SI 3 "gpc_reg_operand" "0")))] + "TARGET_MULHW" + "macchw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*macchwuc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (plus:SI (mult:SI (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))) + (match_operand:SI 4 "gpc_reg_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (lshiftrt:SI + (match_dup 2) + (const_int 16)) + (zero_extend:SI + (match_dup 1))) + (match_dup 4)))] + "TARGET_MULHW" + "macchwu. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*macchwu" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))) + (match_operand:SI 3 "gpc_reg_operand" "0")))] + "TARGET_MULHW" + "macchwu %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*machhwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (plus:SI (mult:SI (ashiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))) + (match_operand:SI 4 "gpc_reg_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (ashiftrt:SI + (match_dup 1) + (const_int 16)) + (ashiftrt:SI + (match_dup 2) + (const_int 16))) + (match_dup 4)))] + "TARGET_MULHW" + "machhw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*machhw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (ashiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))) + (match_operand:SI 3 "gpc_reg_operand" "0")))] + "TARGET_MULHW" + "machhw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*machhwuc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (plus:SI (mult:SI (lshiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))) + (match_operand:SI 4 "gpc_reg_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (lshiftrt:SI + (match_dup 1) + (const_int 16)) + (lshiftrt:SI + (match_dup 2) + (const_int 16))) + (match_dup 4)))] + "TARGET_MULHW" + "machhwu. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*machhwu" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (lshiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))) + (match_operand:SI 3 "gpc_reg_operand" "0")))] + "TARGET_MULHW" + "machhwu %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*maclhwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (plus:SI (mult:SI (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (sign_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))) + (match_operand:SI 4 "gpc_reg_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (sign_extend:SI + (match_dup 1)) + (sign_extend:SI + (match_dup 2))) + (match_dup 4)))] + "TARGET_MULHW" + "maclhw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*maclhw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (sign_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))) + (match_operand:SI 3 "gpc_reg_operand" "0")))] + "TARGET_MULHW" + "maclhw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*maclhwuc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (plus:SI (mult:SI (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (zero_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))) + (match_operand:SI 4 "gpc_reg_operand" "0")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (zero_extend:SI + (match_dup 1)) + (zero_extend:SI + (match_dup 2))) + (match_dup 4)))] + "TARGET_MULHW" + "maclhwu. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*maclhwu" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (mult:SI (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (zero_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))) + (match_operand:SI 3 "gpc_reg_operand" "0")))] + "TARGET_MULHW" + "maclhwu %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*nmacchwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (minus:SI (match_operand:SI 4 "gpc_reg_operand" "0") + (mult:SI (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r")))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (minus:SI (match_dup 4) + (mult:SI (ashiftrt:SI + (match_dup 2) + (const_int 16)) + (sign_extend:SI + (match_dup 1)))))] + "TARGET_MULHW" + "nmacchw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*nmacchw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (minus:SI (match_operand:SI 3 "gpc_reg_operand" "0") + (mult:SI (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r")))))] + "TARGET_MULHW" + "nmacchw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*nmachhwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (minus:SI (match_operand:SI 4 "gpc_reg_operand" "0") + (mult:SI (ashiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (minus:SI (match_dup 4) + (mult:SI (ashiftrt:SI + (match_dup 1) + (const_int 16)) + (ashiftrt:SI + (match_dup 2) + (const_int 16)))))] + "TARGET_MULHW" + "nmachhw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*nmachhw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (minus:SI (match_operand:SI 3 "gpc_reg_operand" "0") + (mult:SI (ashiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)))))] + "TARGET_MULHW" + "nmachhw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*nmaclhwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (minus:SI (match_operand:SI 4 "gpc_reg_operand" "0") + (mult:SI (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (sign_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r")))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (minus:SI (match_dup 4) + (mult:SI (sign_extend:SI + (match_dup 1)) + (sign_extend:SI + (match_dup 2)))))] + "TARGET_MULHW" + "nmaclhw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*nmaclhw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (minus:SI (match_operand:SI 3 "gpc_reg_operand" "0") + (mult:SI (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (sign_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r")))))] + "TARGET_MULHW" + "nmaclhw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulchwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (mult:SI (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (ashiftrt:SI + (match_dup 2) + (const_int 16)) + (sign_extend:SI + (match_dup 1))))] + "TARGET_MULHW" + "mulchw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulchw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))))] + "TARGET_MULHW" + "mulchw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulchwuc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (mult:SI (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (lshiftrt:SI + (match_dup 2) + (const_int 16)) + (zero_extend:SI + (match_dup 1))))] + "TARGET_MULHW" + "mulchwu. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulchwu" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16)) + (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "r"))))] + "TARGET_MULHW" + "mulchwu %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulhhwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (mult:SI (ashiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (ashiftrt:SI + (match_dup 1) + (const_int 16)) + (ashiftrt:SI + (match_dup 2) + (const_int 16))))] + "TARGET_MULHW" + "mulhhw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulhhw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (ashiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (ashiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))))] + "TARGET_MULHW" + "mulhhw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulhhwuc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (mult:SI (lshiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (lshiftrt:SI + (match_dup 1) + (const_int 16)) + (lshiftrt:SI + (match_dup 2) + (const_int 16))))] + "TARGET_MULHW" + "mulhhwu. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mulhhwu" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (lshiftrt:SI + (match_operand:SI 1 "gpc_reg_operand" "%r") + (const_int 16)) + (lshiftrt:SI + (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 16))))] + "TARGET_MULHW" + "mulhhwu %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mullhwc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (mult:SI (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (sign_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (sign_extend:SI + (match_dup 1)) + (sign_extend:SI + (match_dup 2))))] + "TARGET_MULHW" + "mullhw. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mullhw" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (sign_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (sign_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))))] + "TARGET_MULHW" + "mullhw %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mullhwuc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (compare:CC (mult:SI (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (zero_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (zero_extend:SI + (match_dup 1)) + (zero_extend:SI + (match_dup 2))))] + "TARGET_MULHW" + "mullhwu. %0, %1, %2" + [(set_attr "type" "imul3")]) + +(define_insn "*mullhwu" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mult:SI (zero_extend:SI + (match_operand:HI 1 "gpc_reg_operand" "%r")) + (zero_extend:SI + (match_operand:HI 2 "gpc_reg_operand" "r"))))] + "TARGET_MULHW" + "mullhwu %0, %1, %2" + [(set_attr "type" "imul3")]) + +;; IBM 405, 440, 464 and 476 string-search dlmzb instruction support. +(define_insn "dlmzb" + [(set (match_operand:CC 3 "cc_reg_operand" "=x") + (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "gpc_reg_operand" "r")] + UNSPEC_DLMZB_CR)) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec:SI [(match_dup 1) + (match_dup 2)] + UNSPEC_DLMZB))] + "TARGET_DLMZB" + "dlmzb. %0, %1, %2") + +(define_expand "strlensi" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (unspec:SI [(match_operand:BLK 1 "general_operand" "") + (match_operand:QI 2 "const_int_operand" "") + (match_operand 3 "const_int_operand" "")] + UNSPEC_DLMZB_STRLEN)) + (clobber (match_scratch:CC 4 "=x"))] + "TARGET_DLMZB && WORDS_BIG_ENDIAN && !optimize_size" +{ + rtx result = operands[0]; + rtx src = operands[1]; + rtx search_char = operands[2]; + rtx align = operands[3]; + rtx addr, scratch_string, word1, word2, scratch_dlmzb; + rtx loop_label, end_label, mem, cr0, cond; + if (search_char != const0_rtx + || GET_CODE (align) != CONST_INT + || INTVAL (align) < 8) + FAIL; + word1 = gen_reg_rtx (SImode); + word2 = gen_reg_rtx (SImode); + scratch_dlmzb = gen_reg_rtx (SImode); + scratch_string = gen_reg_rtx (Pmode); + loop_label = gen_label_rtx (); + end_label = gen_label_rtx (); + addr = force_reg (Pmode, XEXP (src, 0)); + emit_move_insn (scratch_string, addr); + emit_label (loop_label); + mem = change_address (src, SImode, scratch_string); + emit_move_insn (word1, mem); + emit_move_insn (word2, adjust_address (mem, SImode, 4)); + cr0 = gen_rtx_REG (CCmode, CR0_REGNO); + emit_insn (gen_dlmzb (scratch_dlmzb, word1, word2, cr0)); + cond = gen_rtx_NE (VOIDmode, cr0, const0_rtx); + emit_jump_insn (gen_rtx_SET (VOIDmode, + pc_rtx, + gen_rtx_IF_THEN_ELSE (VOIDmode, + cond, + gen_rtx_LABEL_REF + (VOIDmode, + end_label), + pc_rtx))); + emit_insn (gen_addsi3 (scratch_string, scratch_string, GEN_INT (8))); + emit_jump_insn (gen_rtx_SET (VOIDmode, + pc_rtx, + gen_rtx_LABEL_REF (VOIDmode, loop_label))); + emit_barrier (); + emit_label (end_label); + emit_insn (gen_addsi3 (scratch_string, scratch_string, scratch_dlmzb)); + emit_insn (gen_subsi3 (result, scratch_string, addr)); + emit_insn (gen_subsi3 (result, result, const1_rtx)); + DONE; +}) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (sign_extend:SI (match_operand:HI 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (sign_extend:SI (match_dup 1)))] + "reload_completed" + [(set (match_dup 0) + (sign_extend:SI (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Fixed-point arithmetic insns. + +(define_expand "add<mode>3" + [(set (match_operand:SDI 0 "gpc_reg_operand" "") + (plus:SDI (match_operand:SDI 1 "gpc_reg_operand" "") + (match_operand:SDI 2 "reg_or_add_cint_operand" "")))] + "" +{ + if (<MODE>mode == DImode && ! TARGET_POWERPC64) + { + if (non_short_cint_operand (operands[2], DImode)) + FAIL; + } + else if (GET_CODE (operands[2]) == CONST_INT + && ! add_operand (operands[2], <MODE>mode)) + { + rtx tmp = ((!can_create_pseudo_p () + || rtx_equal_p (operands[0], operands[1])) + ? operands[0] : gen_reg_rtx (<MODE>mode)); + + HOST_WIDE_INT val = INTVAL (operands[2]); + HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; + HOST_WIDE_INT rest = trunc_int_for_mode (val - low, <MODE>mode); + + if (<MODE>mode == DImode && !satisfies_constraint_L (GEN_INT (rest))) + FAIL; + + /* The ordering here is important for the prolog expander. + When space is allocated from the stack, adding 'low' first may + produce a temporary deallocation (which would be bad). */ + emit_insn (gen_add<mode>3 (tmp, operands[1], GEN_INT (rest))); + emit_insn (gen_add<mode>3 (operands[0], tmp, GEN_INT (low))); + DONE; + } +}) + +;; Discourage ai/addic because of carry but provide it in an alternative +;; allowing register zero as source. +(define_insn "*add<mode>3_internal1" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,?r,r") + (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,r,b") + (match_operand:GPR 2 "add_operand" "r,I,I,L")))] + "!DECIMAL_FLOAT_MODE_P (GET_MODE (operands[0])) && !DECIMAL_FLOAT_MODE_P (GET_MODE (operands[1]))" + "@ + {cax|add} %0,%1,%2 + {cal %0,%2(%1)|addi %0,%1,%2} + {ai|addic} %0,%1,%2 + {cau|addis} %0,%1,%v2" + [(set_attr "length" "4,4,4,4")]) + +(define_insn "addsi3_high" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b") + (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (high:SI (match_operand 2 "" ""))))] + "TARGET_MACHO && !TARGET_64BIT" + "{cau|addis} %0,%1,ha16(%2)" + [(set_attr "length" "4")]) + +(define_insn "*add<mode>3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (plus:P (match_operand:P 1 "gpc_reg_operand" "%r,r,r,r") + (match_operand:P 2 "reg_or_short_operand" "r,I,r,I")) + (const_int 0))) + (clobber (match_scratch:P 3 "=r,r,r,r"))] + "" + "@ + {cax.|add.} %3,%1,%2 + {ai.|addic.} %3,%1,%2 + # + #" + [(set_attr "type" "fast_compare,compare,compare,compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "reg_or_short_operand" "")) + (const_int 0))) + (clobber (match_scratch:GPR 3 ""))] + "reload_completed" + [(set (match_dup 3) + (plus:GPR (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*add<mode>3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (plus:P (match_operand:P 1 "gpc_reg_operand" "%r,r,r,r") + (match_operand:P 2 "reg_or_short_operand" "r,I,r,I")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r,r,r") + (plus:P (match_dup 1) + (match_dup 2)))] + "" + "@ + {cax.|add.} %0,%1,%2 + {ai.|addic.} %0,%1,%2 + # + #" + [(set_attr "type" "fast_compare,compare,compare,compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (plus:P (match_operand:P 1 "gpc_reg_operand" "") + (match_operand:P 2 "reg_or_short_operand" "")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "") + (plus:P (match_dup 1) (match_dup 2)))] + "reload_completed" + [(set (match_dup 0) + (plus:P (match_dup 1) + (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Split an add that we can't do in one insn into two insns, each of which +;; does one 16-bit part. This is used by combine. Note that the low-order +;; add should be last in case the result gets used in an address. + +(define_split + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "non_add_cint_operand" "")))] + "" + [(set (match_dup 0) (plus:GPR (match_dup 1) (match_dup 3))) + (set (match_dup 0) (plus:GPR (match_dup 0) (match_dup 4)))] +{ + HOST_WIDE_INT val = INTVAL (operands[2]); + HOST_WIDE_INT low = ((val & 0xffff) ^ 0x8000) - 0x8000; + HOST_WIDE_INT rest = trunc_int_for_mode (val - low, <MODE>mode); + + operands[4] = GEN_INT (low); + if (<MODE>mode == SImode || satisfies_constraint_L (GEN_INT (rest))) + operands[3] = GEN_INT (rest); + else if (can_create_pseudo_p ()) + { + operands[3] = gen_reg_rtx (DImode); + emit_move_insn (operands[3], operands[2]); + emit_insn (gen_adddi3 (operands[0], operands[1], operands[3])); + DONE; + } + else + FAIL; +}) + +(define_insn "one_cmpl<mode>2" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))] + "" + "nor %0,%1,%1") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (not:P (match_operand:P 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:P 2 "=r,r"))] + "" + "@ + nor. %2,%1,%1 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (not:P (match_operand:P 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:P 2 ""))] + "reload_completed" + [(set (match_dup 2) + (not:P (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (not:P (match_operand:P 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (not:P (match_dup 1)))] + "" + "@ + nor. %0,%1,%1 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (not:P (match_operand:P 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "") + (not:P (match_dup 1)))] + "reload_completed" + [(set (match_dup 0) + (not:P (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (minus:SI (match_operand:SI 1 "reg_or_short_operand" "rI") + (match_operand:SI 2 "gpc_reg_operand" "r")))] + "! TARGET_POWERPC" + "{sf%I1|subf%I1c} %0,%2,%1") + +(define_insn "" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r") + (minus:GPR (match_operand:GPR 1 "reg_or_short_operand" "r,I") + (match_operand:GPR 2 "gpc_reg_operand" "r,r")))] + "TARGET_POWERPC" + "@ + subf %0,%2,%1 + subfic %0,%2,%1") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "! TARGET_POWERPC" + "@ + {sf.|subfc.} %3,%2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (minus:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:P 3 "=r,r"))] + "TARGET_POWERPC" + "@ + subf. %3,%2,%1 + #" + [(set_attr "type" "fast_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (minus:P (match_operand:P 1 "gpc_reg_operand" "") + (match_operand:P 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:P 3 ""))] + "reload_completed" + [(set (match_dup 3) + (minus:P (match_dup 1) + (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (minus:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (minus:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWERPC" + "@ + {sf.|subfc.} %0,%2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (minus:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (minus:P (match_dup 1) + (match_dup 2)))] + "TARGET_POWERPC" + "@ + subf. %0,%2,%1 + #" + [(set_attr "type" "fast_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (minus:P (match_operand:P 1 "gpc_reg_operand" "") + (match_operand:P 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "") + (minus:P (match_dup 1) + (match_dup 2)))] + "reload_completed" + [(set (match_dup 0) + (minus:P (match_dup 1) + (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "sub<mode>3" + [(set (match_operand:SDI 0 "gpc_reg_operand" "") + (minus:SDI (match_operand:SDI 1 "reg_or_short_operand" "") + (match_operand:SDI 2 "reg_or_sub_cint_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT) + { + emit_insn (gen_add<mode>3 (operands[0], operands[1], + negate_rtx (<MODE>mode, operands[2]))); + DONE; + } +}") + +;; For SMIN, SMAX, UMIN, and UMAX, we use DEFINE_EXPAND's that involve a doz[i] +;; instruction and some auxiliary computations. Then we just have a single +;; DEFINE_INSN for doz[i] and the define_splits to make them if made by +;; combine. + +(define_expand "sminsi3" + [(set (match_dup 3) + (if_then_else:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1)))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (minus:SI (match_dup 2) (match_dup 3)))] + "TARGET_POWER || TARGET_ISEL" + " +{ + if (TARGET_ISEL) + { + operands[2] = force_reg (SImode, operands[2]); + rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); + DONE; + } + + operands[3] = gen_reg_rtx (SImode); +}") + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (smin:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" ""))) + (clobber (match_operand:SI 3 "gpc_reg_operand" ""))] + "TARGET_POWER" + [(set (match_dup 3) + (if_then_else:SI (gt:SI (match_dup 1) (match_dup 2)) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1)))) + (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 3)))] + "") + +(define_expand "smaxsi3" + [(set (match_dup 3) + (if_then_else:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1)))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (match_dup 3) (match_dup 1)))] + "TARGET_POWER || TARGET_ISEL" + " +{ + if (TARGET_ISEL) + { + operands[2] = force_reg (SImode, operands[2]); + rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); + DONE; + } + operands[3] = gen_reg_rtx (SImode); +}") + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (smax:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" ""))) + (clobber (match_operand:SI 3 "gpc_reg_operand" ""))] + "TARGET_POWER" + [(set (match_dup 3) + (if_then_else:SI (gt:SI (match_dup 1) (match_dup 2)) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1)))) + (set (match_dup 0) (plus:SI (match_dup 3) (match_dup 1)))] + "") + +(define_expand "uminsi3" + [(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_dup 5))) + (set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "") + (match_dup 5))) + (set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4)) + (const_int 0) + (minus:SI (match_dup 4) (match_dup 3)))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (minus:SI (match_dup 2) (match_dup 3)))] + "TARGET_POWER || TARGET_ISEL" + " +{ + if (TARGET_ISEL) + { + rs6000_emit_minmax (operands[0], UMIN, operands[1], operands[2]); + DONE; + } + operands[3] = gen_reg_rtx (SImode); + operands[4] = gen_reg_rtx (SImode); + operands[5] = GEN_INT (-2147483647 - 1); +}") + +(define_expand "umaxsi3" + [(set (match_dup 3) (xor:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_dup 5))) + (set (match_dup 4) (xor:SI (match_operand:SI 2 "gpc_reg_operand" "") + (match_dup 5))) + (set (match_dup 3) (if_then_else:SI (gt (match_dup 3) (match_dup 4)) + (const_int 0) + (minus:SI (match_dup 4) (match_dup 3)))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (match_dup 3) (match_dup 1)))] + "TARGET_POWER || TARGET_ISEL" + " +{ + if (TARGET_ISEL) + { + rs6000_emit_minmax (operands[0], UMAX, operands[1], operands[2]); + DONE; + } + operands[3] = gen_reg_rtx (SImode); + operands[4] = gen_reg_rtx (SImode); + operands[5] = GEN_INT (-2147483647 - 1); +}") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "rI")) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1))))] + "TARGET_POWER" + "doz%I2 %0,%1,%2") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1))) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "TARGET_POWER" + "@ + doz%I2. %3,%1,%2 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1))) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_POWER && reload_completed" + [(set (match_dup 3) + (if_then_else:SI (gt (match_dup 1) (match_dup 2)) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1)))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (if_then_else:SI (gt (match_dup 1) (match_dup 2)) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1))))] + "TARGET_POWER" + "@ + doz%I2. %0,%1,%2 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC + (if_then_else:SI (gt (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (if_then_else:SI (gt (match_dup 1) (match_dup 2)) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1))))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (if_then_else:SI (gt (match_dup 1) (match_dup 2)) + (const_int 0) + (minus:SI (match_dup 2) (match_dup 1)))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; We don't need abs with condition code because such comparisons should +;; never be done. +(define_expand "abssi2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (abs:SI (match_operand:SI 1 "gpc_reg_operand" "")))] + "" + " +{ + if (TARGET_ISEL) + { + emit_insn (gen_abssi2_isel (operands[0], operands[1])); + DONE; + } + else if (! TARGET_POWER) + { + emit_insn (gen_abssi2_nopower (operands[0], operands[1])); + DONE; + } +}") + +(define_insn "*abssi2_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r")))] + "TARGET_POWER" + "abs %0,%1") + +(define_insn_and_split "abs<mode>2_isel" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (abs:GPR (match_operand:GPR 1 "gpc_reg_operand" "b"))) + (clobber (match_scratch:GPR 2 "=&b")) + (clobber (match_scratch:CC 3 "=y"))] + "TARGET_ISEL" + "#" + "&& reload_completed" + [(set (match_dup 2) (neg:GPR (match_dup 1))) + (set (match_dup 3) + (compare:CC (match_dup 1) + (const_int 0))) + (set (match_dup 0) + (if_then_else:GPR (lt (match_dup 3) + (const_int 0)) + (match_dup 2) + (match_dup 1)))] + "") + +(define_insn_and_split "nabs<mode>2_isel" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (neg:GPR (abs:GPR (match_operand:GPR 1 "gpc_reg_operand" "b")))) + (clobber (match_scratch:GPR 2 "=&b")) + (clobber (match_scratch:CC 3 "=y"))] + "TARGET_ISEL" + "#" + "&& reload_completed" + [(set (match_dup 2) (neg:GPR (match_dup 1))) + (set (match_dup 3) + (compare:CC (match_dup 1) + (const_int 0))) + (set (match_dup 0) + (if_then_else:GPR (lt (match_dup 3) + (const_int 0)) + (match_dup 1) + (match_dup 2)))] + "") + +(define_insn_and_split "abssi2_nopower" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r") + (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0"))) + (clobber (match_scratch:SI 2 "=&r,&r"))] + "! TARGET_POWER && ! TARGET_ISEL" + "#" + "&& reload_completed" + [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31))) + (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1))) + (set (match_dup 0) (minus:SI (match_dup 0) (match_dup 2)))] + "") + +(define_insn "*nabs_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r"))))] + "TARGET_POWER" + "nabs %0,%1") + +(define_insn_and_split "*nabs_nopower" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,r") + (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,0")))) + (clobber (match_scratch:SI 2 "=&r,&r"))] + "! TARGET_POWER" + "#" + "&& reload_completed" + [(set (match_dup 2) (ashiftrt:SI (match_dup 1) (const_int 31))) + (set (match_dup 0) (xor:SI (match_dup 2) (match_dup 1))) + (set (match_dup 0) (minus:SI (match_dup 2) (match_dup 0)))] + "") + +(define_expand "neg<mode>2" + [(set (match_operand:SDI 0 "gpc_reg_operand" "") + (neg:SDI (match_operand:SDI 1 "gpc_reg_operand" "")))] + "" + "") + +(define_insn "*neg<mode>2_internal" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))] + "" + "neg %0,%1") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (neg:P (match_operand:P 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:P 2 "=r,r"))] + "" + "@ + neg. %2,%1 + #" + [(set_attr "type" "fast_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (neg:P (match_operand:P 1 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:P 2 ""))] + "reload_completed" + [(set (match_dup 2) + (neg:P (match_dup 1))) + (set (match_dup 0) + (compare:CC (match_dup 2) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 2 "cc_reg_operand" "=x,?y") + (compare:CC (neg:P (match_operand:P 1 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (neg:P (match_dup 1)))] + "" + "@ + neg. %0,%1 + #" + [(set_attr "type" "fast_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_cr0_operand" "") + (compare:CC (neg:P (match_operand:P 1 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "") + (neg:P (match_dup 1)))] + "reload_completed" + [(set (match_dup 0) + (neg:P (match_dup 1))) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "clz<mode>2" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (clz:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))] + "" + "{cntlz|cntlz<wd>} %0,%1" + [(set_attr "type" "cntlz")]) + +(define_expand "ctz<mode>2" + [(set (match_dup 2) + (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" ""))) + (parallel [(set (match_dup 3) (and:GPR (match_dup 1) + (match_dup 2))) + (clobber (scratch:CC))]) + (set (match_dup 4) (clz:GPR (match_dup 3))) + (set (match_operand:GPR 0 "gpc_reg_operand" "") + (minus:GPR (match_dup 5) (match_dup 4)))] + "" + { + operands[2] = gen_reg_rtx (<MODE>mode); + operands[3] = gen_reg_rtx (<MODE>mode); + operands[4] = gen_reg_rtx (<MODE>mode); + operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode) - 1); + }) + +(define_expand "ffs<mode>2" + [(set (match_dup 2) + (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" ""))) + (parallel [(set (match_dup 3) (and:GPR (match_dup 1) + (match_dup 2))) + (clobber (scratch:CC))]) + (set (match_dup 4) (clz:GPR (match_dup 3))) + (set (match_operand:GPR 0 "gpc_reg_operand" "") + (minus:GPR (match_dup 5) (match_dup 4)))] + "" + { + operands[2] = gen_reg_rtx (<MODE>mode); + operands[3] = gen_reg_rtx (<MODE>mode); + operands[4] = gen_reg_rtx (<MODE>mode); + operands[5] = GEN_INT (GET_MODE_BITSIZE (<MODE>mode)); + }) + +(define_insn "popcntb<mode>2" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")] + UNSPEC_POPCNTB))] + "TARGET_POPCNTB" + "popcntb %0,%1") + +(define_insn "popcntd<mode>2" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (popcount:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))] + "TARGET_POPCNTD" + "popcnt<wd> %0,%1") + +(define_expand "popcount<mode>2" + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (popcount:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))] + "TARGET_POPCNTB || TARGET_POPCNTD" + { + rs6000_emit_popcount (operands[0], operands[1]); + DONE; + }) + +(define_insn "parity<mode>2_cmpb" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")] UNSPEC_PARITY))] + "TARGET_CMPB && TARGET_POPCNTB" + "prty<wd> %0,%1") + +(define_expand "parity<mode>2" + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (parity:GPR (match_operand:GPR 1 "gpc_reg_operand" "")))] + "TARGET_POPCNTB" + { + rs6000_emit_parity (operands[0], operands[1]); + DONE; + }) + +;; Since the hardware zeros the upper part of the register, save generating the +;; AND immediate if we are converting to unsigned +(define_insn "*bswaphi2_extenddi" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (zero_extend:DI + (bswap:HI (match_operand:HI 1 "memory_operand" "Z"))))] + "TARGET_POWERPC64" + "lhbrx %0,%y1" + [(set_attr "length" "4") + (set_attr "type" "load")]) + +(define_insn "*bswaphi2_extendsi" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (zero_extend:SI + (bswap:HI (match_operand:HI 1 "memory_operand" "Z"))))] + "TARGET_POWERPC" + "lhbrx %0,%y1" + [(set_attr "length" "4") + (set_attr "type" "load")]) + +(define_expand "bswaphi2" + [(parallel [(set (match_operand:HI 0 "reg_or_mem_operand" "") + (bswap:HI + (match_operand:HI 1 "reg_or_mem_operand" ""))) + (clobber (match_scratch:SI 2 ""))])] + "" +{ + if (!REG_P (operands[0]) && !REG_P (operands[1])) + operands[1] = force_reg (HImode, operands[1]); +}) + +(define_insn "bswaphi2_internal" + [(set (match_operand:HI 0 "reg_or_mem_operand" "=r,Z,&r") + (bswap:HI + (match_operand:HI 1 "reg_or_mem_operand" "Z,r,r"))) + (clobber (match_scratch:SI 2 "=X,X,&r"))] + "TARGET_POWERPC" + "@ + lhbrx %0,%y1 + sthbrx %1,%y0 + #" + [(set_attr "length" "4,4,12") + (set_attr "type" "load,store,*")]) + +(define_split + [(set (match_operand:HI 0 "gpc_reg_operand" "") + (bswap:HI (match_operand:HI 1 "gpc_reg_operand" ""))) + (clobber (match_operand:SI 2 "gpc_reg_operand" ""))] + "TARGET_POWERPC && reload_completed" + [(set (match_dup 3) + (zero_extract:SI (match_dup 4) + (const_int 8) + (const_int 16))) + (set (match_dup 2) + (and:SI (ashift:SI (match_dup 4) + (const_int 8)) + (const_int 65280))) ;; 0xff00 + (set (match_dup 3) + (ior:SI (match_dup 3) + (match_dup 2)))] + " +{ + operands[3] = simplify_gen_subreg (SImode, operands[0], HImode, 0); + operands[4] = simplify_gen_subreg (SImode, operands[1], HImode, 0); +}") + +(define_insn "*bswapsi2_extenddi" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (zero_extend:DI + (bswap:SI (match_operand:SI 1 "memory_operand" "Z"))))] + "TARGET_POWERPC64" + "lwbrx %0,%y1" + [(set_attr "length" "4") + (set_attr "type" "load")]) + +(define_expand "bswapsi2" + [(set (match_operand:SI 0 "reg_or_mem_operand" "") + (bswap:SI + (match_operand:SI 1 "reg_or_mem_operand" "")))] + "" +{ + if (!REG_P (operands[0]) && !REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); +}) + +(define_insn "*bswapsi2_internal" + [(set (match_operand:SI 0 "reg_or_mem_operand" "=r,Z,&r") + (bswap:SI + (match_operand:SI 1 "reg_or_mem_operand" "Z,r,r")))] + "" + "@ + {lbrx|lwbrx} %0,%y1 + {stbrx|stwbrx} %1,%y0 + #" + [(set_attr "length" "4,4,12") + (set_attr "type" "load,store,*")]) + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (bswap:SI (match_operand:SI 1 "gpc_reg_operand" "")))] + "reload_completed" + [(set (match_dup 0) + (rotate:SI (match_dup 1) (const_int 8))) + (set (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 0)) + (match_dup 1)) + (set (zero_extract:SI (match_dup 0) + (const_int 8) + (const_int 16)) + (rotate:SI (match_dup 1) + (const_int 16)))] + "") + +(define_expand "bswapdi2" + [(parallel [(set (match_operand:DI 0 "reg_or_mem_operand" "") + (bswap:DI + (match_operand:DI 1 "reg_or_mem_operand" ""))) + (clobber (match_scratch:DI 2 "")) + (clobber (match_scratch:DI 3 "")) + (clobber (match_scratch:DI 4 ""))])] + "" +{ + if (!REG_P (operands[0]) && !REG_P (operands[1])) + operands[1] = force_reg (DImode, operands[1]); + + if (!TARGET_POWERPC64) + { + /* 32-bit mode needs fewer scratch registers, but 32-bit addressing mode + that uses 64-bit registers needs the same scratch registers as 64-bit + mode. */ + emit_insn (gen_bswapdi2_32bit (operands[0], operands[1])); + DONE; + } +}) + +;; Power7/cell has ldbrx/stdbrx, so use it directly +(define_insn "*bswapdi2_ldbrx" + [(set (match_operand:DI 0 "reg_or_mem_operand" "=&r,Z,??&r") + (bswap:DI (match_operand:DI 1 "reg_or_mem_operand" "Z,r,r"))) + (clobber (match_scratch:DI 2 "=X,X,&r")) + (clobber (match_scratch:DI 3 "=X,X,&r")) + (clobber (match_scratch:DI 4 "=X,X,&r"))] + "TARGET_POWERPC64 && TARGET_LDBRX + && (REG_P (operands[0]) || REG_P (operands[1]))" + "@ + ldbrx %0,%y1 + stdbrx %1,%y0 + #" + [(set_attr "length" "4,4,36") + (set_attr "type" "load,store,*")]) + +;; Non-power7/cell, fall back to use lwbrx/stwbrx +(define_insn "*bswapdi2_64bit" + [(set (match_operand:DI 0 "reg_or_mem_operand" "=&r,Z,??&r") + (bswap:DI (match_operand:DI 1 "reg_or_mem_operand" "Z,r,r"))) + (clobber (match_scratch:DI 2 "=&b,&b,&r")) + (clobber (match_scratch:DI 3 "=&r,&r,&r")) + (clobber (match_scratch:DI 4 "=&r,X,&r"))] + "TARGET_POWERPC64 && !TARGET_LDBRX + && (REG_P (operands[0]) || REG_P (operands[1]))" + "#" + [(set_attr "length" "16,12,36")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (bswap:DI (match_operand:DI 1 "indexed_or_indirect_operand" ""))) + (clobber (match_operand:DI 2 "gpc_reg_operand" "")) + (clobber (match_operand:DI 3 "gpc_reg_operand" "")) + (clobber (match_operand:DI 4 "gpc_reg_operand" ""))] + "TARGET_POWERPC64 && !TARGET_LDBRX && reload_completed" + [(const_int 0)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx op2 = operands[2]; + rtx op3 = operands[3]; + rtx op4 = operands[4]; + rtx op3_32 = simplify_gen_subreg (SImode, op3, DImode, 4); + rtx op4_32 = simplify_gen_subreg (SImode, op4, DImode, 4); + rtx addr1; + rtx addr2; + rtx word_high; + rtx word_low; + + addr1 = XEXP (src, 0); + if (GET_CODE (addr1) == PLUS) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4))); + if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 1), op2)); + addr2 = op2; + } + else + addr2 = gen_rtx_PLUS (Pmode, op2, XEXP (addr1, 1)); + } + else if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, addr1, GEN_INT (4))); + addr2 = op2; + } + else + { + emit_move_insn (op2, GEN_INT (4)); + addr2 = gen_rtx_PLUS (Pmode, op2, addr1); + } + + if (BYTES_BIG_ENDIAN) + { + word_high = change_address (src, SImode, addr1); + word_low = change_address (src, SImode, addr2); + } + else + { + word_high = change_address (src, SImode, addr2); + word_low = change_address (src, SImode, addr1); + } + + emit_insn (gen_bswapsi2 (op3_32, word_low)); + emit_insn (gen_bswapsi2 (op4_32, word_high)); + emit_insn (gen_ashldi3 (dest, op3, GEN_INT (32))); + emit_insn (gen_iordi3 (dest, dest, op4)); +}") + +(define_split + [(set (match_operand:DI 0 "indexed_or_indirect_operand" "") + (bswap:DI (match_operand:DI 1 "gpc_reg_operand" ""))) + (clobber (match_operand:DI 2 "gpc_reg_operand" "")) + (clobber (match_operand:DI 3 "gpc_reg_operand" "")) + (clobber (match_operand:DI 4 "" ""))] + "TARGET_POWERPC64 && !TARGET_LDBRX && reload_completed" + [(const_int 0)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx op2 = operands[2]; + rtx op3 = operands[3]; + rtx src_si = simplify_gen_subreg (SImode, src, DImode, 4); + rtx op3_si = simplify_gen_subreg (SImode, op3, DImode, 4); + rtx addr1; + rtx addr2; + rtx word_high; + rtx word_low; + + addr1 = XEXP (dest, 0); + if (GET_CODE (addr1) == PLUS) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4))); + if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 1), op2)); + addr2 = op2; + } + else + addr2 = gen_rtx_PLUS (Pmode, op2, XEXP (addr1, 1)); + } + else if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, addr1, GEN_INT (4))); + addr2 = op2; + } + else + { + emit_move_insn (op2, GEN_INT (4)); + addr2 = gen_rtx_PLUS (Pmode, op2, addr1); + } + + emit_insn (gen_lshrdi3 (op3, src, GEN_INT (32))); + if (BYTES_BIG_ENDIAN) + { + word_high = change_address (dest, SImode, addr1); + word_low = change_address (dest, SImode, addr2); + emit_insn (gen_bswapsi2 (word_high, src_si)); + emit_insn (gen_bswapsi2 (word_low, op3_si)); + } + else + { + word_high = change_address (dest, SImode, addr2); + word_low = change_address (dest, SImode, addr1); + emit_insn (gen_bswapsi2 (word_low, src_si)); + emit_insn (gen_bswapsi2 (word_high, op3_si)); + } +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (bswap:DI (match_operand:DI 1 "gpc_reg_operand" ""))) + (clobber (match_operand:DI 2 "gpc_reg_operand" "")) + (clobber (match_operand:DI 3 "gpc_reg_operand" "")) + (clobber (match_operand:DI 4 "" ""))] + "TARGET_POWERPC64 && reload_completed" + [(const_int 0)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx op2 = operands[2]; + rtx op3 = operands[3]; + rtx dest_si = simplify_gen_subreg (SImode, dest, DImode, 4); + rtx src_si = simplify_gen_subreg (SImode, src, DImode, 4); + rtx op2_si = simplify_gen_subreg (SImode, op2, DImode, 4); + rtx op3_si = simplify_gen_subreg (SImode, op3, DImode, 4); + + emit_insn (gen_lshrdi3 (op2, src, GEN_INT (32))); + emit_insn (gen_bswapsi2 (dest_si, src_si)); + emit_insn (gen_bswapsi2 (op3_si, op2_si)); + emit_insn (gen_ashldi3 (dest, dest, GEN_INT (32))); + emit_insn (gen_iordi3 (dest, dest, op3)); +}") + +(define_insn "bswapdi2_32bit" + [(set (match_operand:DI 0 "reg_or_mem_operand" "=&r,Z,??&r") + (bswap:DI (match_operand:DI 1 "reg_or_mem_operand" "Z,r,r"))) + (clobber (match_scratch:SI 2 "=&b,&b,X"))] + "!TARGET_POWERPC64 && (REG_P (operands[0]) || REG_P (operands[1]))" + "#" + [(set_attr "length" "16,12,36")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (bswap:DI (match_operand:DI 1 "indexed_or_indirect_operand" ""))) + (clobber (match_operand:SI 2 "gpc_reg_operand" ""))] + "!TARGET_POWERPC64 && reload_completed" + [(const_int 0)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx op2 = operands[2]; + rtx dest_hi = simplify_gen_subreg (SImode, dest, DImode, 0); + rtx dest_lo = simplify_gen_subreg (SImode, dest, DImode, 4); + rtx addr1; + rtx addr2; + rtx word_high; + rtx word_low; + + addr1 = XEXP (src, 0); + if (GET_CODE (addr1) == PLUS) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4))); + if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 1), op2)); + addr2 = op2; + } + else + addr2 = gen_rtx_PLUS (SImode, op2, XEXP (addr1, 1)); + } + else if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, addr1, GEN_INT (4))); + addr2 = op2; + } + else + { + emit_move_insn (op2, GEN_INT (4)); + addr2 = gen_rtx_PLUS (SImode, op2, addr1); + } + + if (BYTES_BIG_ENDIAN) + { + word_high = change_address (src, SImode, addr1); + word_low = change_address (src, SImode, addr2); + } + else + { + word_high = change_address (src, SImode, addr2); + word_low = change_address (src, SImode, addr1); + } + + emit_insn (gen_bswapsi2 (dest_hi, word_low)); + emit_insn (gen_bswapsi2 (dest_lo, word_high)); +}") + +(define_split + [(set (match_operand:DI 0 "indexed_or_indirect_operand" "") + (bswap:DI (match_operand:DI 1 "gpc_reg_operand" ""))) + (clobber (match_operand:SI 2 "gpc_reg_operand" ""))] + "!TARGET_POWERPC64 && reload_completed" + [(const_int 0)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx op2 = operands[2]; + rtx src_high = simplify_gen_subreg (SImode, src, DImode, 0); + rtx src_low = simplify_gen_subreg (SImode, src, DImode, 4); + rtx addr1; + rtx addr2; + rtx word_high; + rtx word_low; + + addr1 = XEXP (dest, 0); + if (GET_CODE (addr1) == PLUS) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 0), GEN_INT (4))); + if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, XEXP (addr1, 1), op2)); + addr2 = op2; + } + else + addr2 = gen_rtx_PLUS (SImode, op2, XEXP (addr1, 1)); + } + else if (TARGET_AVOID_XFORM) + { + emit_insn (gen_add3_insn (op2, addr1, GEN_INT (4))); + addr2 = op2; + } + else + { + emit_move_insn (op2, GEN_INT (4)); + addr2 = gen_rtx_PLUS (SImode, op2, addr1); + } + + if (BYTES_BIG_ENDIAN) + { + word_high = change_address (dest, SImode, addr1); + word_low = change_address (dest, SImode, addr2); + } + else + { + word_high = change_address (dest, SImode, addr2); + word_low = change_address (dest, SImode, addr1); + } + + emit_insn (gen_bswapsi2 (word_high, src_low)); + emit_insn (gen_bswapsi2 (word_low, src_high)); +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (bswap:DI (match_operand:DI 1 "gpc_reg_operand" ""))) + (clobber (match_operand:SI 2 "" ""))] + "!TARGET_POWERPC64 && reload_completed" + [(const_int 0)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx src_high = simplify_gen_subreg (SImode, src, DImode, 0); + rtx src_low = simplify_gen_subreg (SImode, src, DImode, 4); + rtx dest_high = simplify_gen_subreg (SImode, dest, DImode, 0); + rtx dest_low = simplify_gen_subreg (SImode, dest, DImode, 4); + + emit_insn (gen_bswapsi2 (dest_high, src_low)); + emit_insn (gen_bswapsi2 (dest_low, src_high)); +}") + +(define_expand "mulsi3" + [(use (match_operand:SI 0 "gpc_reg_operand" "")) + (use (match_operand:SI 1 "gpc_reg_operand" "")) + (use (match_operand:SI 2 "reg_or_short_operand" ""))] + "" + " +{ + if (TARGET_POWER) + emit_insn (gen_mulsi3_mq (operands[0], operands[1], operands[2])); + else + emit_insn (gen_mulsi3_no_mq (operands[0], operands[1], operands[2])); + DONE; +}") + +(define_insn "mulsi3_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (clobber (match_scratch:SI 3 "=q,q"))] + "TARGET_POWER" + "@ + {muls|mullw} %0,%1,%2 + {muli|mulli} %0,%1,%2" + [(set (attr "type") + (cond [(match_operand:SI 2 "s8bit_cint_operand" "") + (const_string "imul3") + (match_operand:SI 2 "short_cint_operand" "") + (const_string "imul2")] + (const_string "imul")))]) + +(define_insn "mulsi3_no_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,I")))] + "! TARGET_POWER" + "@ + {muls|mullw} %0,%1,%2 + {muli|mulli} %0,%1,%2" + [(set (attr "type") + (cond [(match_operand:SI 2 "s8bit_cint_operand" "") + (const_string "imul3") + (match_operand:SI 2 "short_cint_operand" "") + (const_string "imul2")] + (const_string "imul")))]) + +(define_insn "*mulsi3_mq_internal1" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r")) + (clobber (match_scratch:SI 4 "=q,q"))] + "TARGET_POWER" + "@ + {muls.|mullw.} %3,%1,%2 + #" + [(set_attr "type" "imul_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 "")) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 3) + (mult:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*mulsi3_no_mq_internal1" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "! TARGET_POWER" + "@ + {muls.|mullw.} %3,%1,%2 + #" + [(set_attr "type" "imul_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "! TARGET_POWER && reload_completed" + [(set (match_dup 3) + (mult:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*mulsi3_mq_internal2" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (mult:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 "=q,q"))] + "TARGET_POWER" + "@ + {muls.|mullw.} %0,%1,%2 + #" + [(set_attr "type" "imul_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (mult:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 0) + (mult:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*mulsi3_no_mq_internal2" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (mult:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER" + "@ + {muls.|mullw.} %0,%1,%2 + #" + [(set_attr "type" "imul_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (mult:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (mult:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER && reload_completed" + [(set (match_dup 0) + (mult:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Operand 1 is divided by operand 2; quotient goes to operand +;; 0 and remainder to operand 3. +;; ??? At some point, see what, if anything, we can do about if (x % y == 0). + +(define_expand "divmodsi4" + [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "") + (div:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" ""))) + (set (match_operand:SI 3 "register_operand" "") + (mod:SI (match_dup 1) (match_dup 2)))])] + "TARGET_POWER || (! TARGET_POWER && ! TARGET_POWERPC)" + " +{ + if (! TARGET_POWER && ! TARGET_POWERPC) + { + emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]); + emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]); + emit_insn (gen_divss_call ()); + emit_move_insn (operands[0], gen_rtx_REG (SImode, 3)); + emit_move_insn (operands[3], gen_rtx_REG (SImode, 4)); + DONE; + } +}") + +(define_insn "*divmodsi4_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (div:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (set (match_operand:SI 3 "register_operand" "=q") + (mod:SI (match_dup 1) (match_dup 2)))] + "TARGET_POWER" + "divs %0,%1,%2" + [(set_attr "type" "idiv")]) + +(define_expand "udiv<mode>3" + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (udiv:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "gpc_reg_operand" "")))] + "TARGET_POWERPC || (! TARGET_POWER && ! TARGET_POWERPC)" + " +{ + if (! TARGET_POWER && ! TARGET_POWERPC) + { + emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]); + emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]); + emit_insn (gen_quous_call ()); + emit_move_insn (operands[0], gen_rtx_REG (SImode, 3)); + DONE; + } + else if (TARGET_POWER) + { + emit_insn (gen_udivsi3_mq (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "udivsi3_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (clobber (match_scratch:SI 3 "=q"))] + "TARGET_POWERPC && TARGET_POWER" + "divwu %0,%1,%2" + [(set_attr "type" "idiv")]) + +(define_insn "*udivsi3_no_mq" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (udiv:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") + (match_operand:GPR 2 "gpc_reg_operand" "r")))] + "TARGET_POWERPC && ! TARGET_POWER" + "div<wd>u %0,%1,%2" + [(set (attr "type") + (cond [(match_operand:SI 0 "" "") + (const_string "idiv")] + (const_string "ldiv")))]) + + +;; For powers of two we can do srai/aze for divide and then adjust for +;; modulus. If it isn't a power of two, FAIL on POWER so divmodsi4 will be +;; used; for PowerPC, force operands into register and do a normal divide; +;; for AIX common-mode, use quoss call on register operands. +(define_expand "div<mode>3" + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (div:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "reg_or_cint_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) > 0 + && exact_log2 (INTVAL (operands[2])) >= 0) + ; + else if (TARGET_POWERPC) + { + operands[2] = force_reg (<MODE>mode, operands[2]); + if (TARGET_POWER) + { + emit_insn (gen_divsi3_mq (operands[0], operands[1], operands[2])); + DONE; + } + } + else if (TARGET_POWER) + FAIL; + else + { + emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]); + emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]); + emit_insn (gen_quoss_call ()); + emit_move_insn (operands[0], gen_rtx_REG (SImode, 3)); + DONE; + } +}") + +(define_insn "divsi3_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (div:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (clobber (match_scratch:SI 3 "=q"))] + "TARGET_POWERPC && TARGET_POWER" + "divw %0,%1,%2" + [(set_attr "type" "idiv")]) + +(define_insn "*div<mode>3_no_mq" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (div:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") + (match_operand:GPR 2 "gpc_reg_operand" "r")))] + "TARGET_POWERPC && ! TARGET_POWER" + "div<wd> %0,%1,%2" + [(set (attr "type") + (cond [(match_operand:SI 0 "" "") + (const_string "idiv")] + (const_string "ldiv")))]) + +(define_expand "mod<mode>3" + [(use (match_operand:GPR 0 "gpc_reg_operand" "")) + (use (match_operand:GPR 1 "gpc_reg_operand" "")) + (use (match_operand:GPR 2 "reg_or_cint_operand" ""))] + "" + " +{ + int i; + rtx temp1; + rtx temp2; + + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) <= 0 + || (i = exact_log2 (INTVAL (operands[2]))) < 0) + FAIL; + + temp1 = gen_reg_rtx (<MODE>mode); + temp2 = gen_reg_rtx (<MODE>mode); + + emit_insn (gen_div<mode>3 (temp1, operands[1], operands[2])); + emit_insn (gen_ashl<mode>3 (temp2, temp1, GEN_INT (i))); + emit_insn (gen_sub<mode>3 (operands[0], operands[1], temp2)); + DONE; +}") + +(define_insn "" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (div:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") + (match_operand:GPR 2 "exact_log2_cint_operand" "N")))] + "" + "{srai|sra<wd>i} %0,%1,%p2\;{aze|addze} %0,%0" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (div:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "exact_log2_cint_operand" "N,N")) + (const_int 0))) + (clobber (match_scratch:P 3 "=r,r"))] + "" + "@ + {srai|sra<wd>i} %3,%1,%p2\;{aze.|addze.} %3,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12") + (set_attr "cell_micro" "not")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (div:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "exact_log2_cint_operand" + "")) + (const_int 0))) + (clobber (match_scratch:GPR 3 ""))] + "reload_completed" + [(set (match_dup 3) + (div:<MODE> (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (div:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "exact_log2_cint_operand" "N,N")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (div:P (match_dup 1) (match_dup 2)))] + "" + "@ + {srai|sra<wd>i} %0,%1,%p2\;{aze.|addze.} %0,%0 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12") + (set_attr "cell_micro" "not")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (div:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "exact_log2_cint_operand" + "")) + (const_int 0))) + (set (match_operand:GPR 0 "gpc_reg_operand" "") + (div:GPR (match_dup 1) (match_dup 2)))] + "reload_completed" + [(set (match_dup 0) + (div:<MODE> (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (udiv:SI + (plus:DI (ashift:DI + (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r")) + (const_int 32)) + (zero_extend:DI (match_operand:SI 4 "register_operand" "2"))) + (match_operand:SI 3 "gpc_reg_operand" "r"))) + (set (match_operand:SI 2 "register_operand" "=*q") + (umod:SI + (plus:DI (ashift:DI + (zero_extend:DI (match_dup 1)) (const_int 32)) + (zero_extend:DI (match_dup 4))) + (match_dup 3)))] + "TARGET_POWER" + "div %0,%1,%3" + [(set_attr "type" "idiv")]) + +;; To do unsigned divide we handle the cases of the divisor looking like a +;; negative number. If it is a constant that is less than 2**31, we don't +;; have to worry about the branches. So make a few subroutines here. +;; +;; First comes the normal case. +(define_expand "udivmodsi4_normal" + [(set (match_dup 4) (const_int 0)) + (parallel [(set (match_operand:SI 0 "" "") + (udiv:SI (plus:DI (ashift:DI (zero_extend:DI (match_dup 4)) + (const_int 32)) + (zero_extend:DI (match_operand:SI 1 "" ""))) + (match_operand:SI 2 "" ""))) + (set (match_operand:SI 3 "" "") + (umod:SI (plus:DI (ashift:DI (zero_extend:DI (match_dup 4)) + (const_int 32)) + (zero_extend:DI (match_dup 1))) + (match_dup 2)))])] + "TARGET_POWER" + " +{ operands[4] = gen_reg_rtx (SImode); }") + +;; This handles the branches. +(define_expand "udivmodsi4_tests" + [(set (match_operand:SI 0 "" "") (const_int 0)) + (set (match_operand:SI 3 "" "") (match_operand:SI 1 "" "")) + (set (match_dup 5) (compare:CCUNS (match_dup 1) (match_operand:SI 2 "" ""))) + (set (pc) (if_then_else (ltu (match_dup 5) (const_int 0)) + (label_ref (match_operand:SI 4 "" "")) (pc))) + (set (match_dup 0) (const_int 1)) + (set (match_dup 3) (minus:SI (match_dup 1) (match_dup 2))) + (set (match_dup 6) (compare:CC (match_dup 2) (const_int 0))) + (set (pc) (if_then_else (lt (match_dup 6) (const_int 0)) + (label_ref (match_dup 4)) (pc)))] + "TARGET_POWER" + " +{ operands[5] = gen_reg_rtx (CCUNSmode); + operands[6] = gen_reg_rtx (CCmode); +}") + +(define_expand "udivmodsi4" + [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "") + (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" ""))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (umod:SI (match_dup 1) (match_dup 2)))])] + "" + " +{ + rtx label = 0; + + if (! TARGET_POWER) + { + if (! TARGET_POWERPC) + { + emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]); + emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]); + emit_insn (gen_divus_call ()); + emit_move_insn (operands[0], gen_rtx_REG (SImode, 3)); + emit_move_insn (operands[3], gen_rtx_REG (SImode, 4)); + DONE; + } + else + FAIL; + } + + if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) < 0) + { + operands[2] = force_reg (SImode, operands[2]); + label = gen_label_rtx (); + emit (gen_udivmodsi4_tests (operands[0], operands[1], operands[2], + operands[3], label)); + } + else + operands[2] = force_reg (SImode, operands[2]); + + emit (gen_udivmodsi4_normal (operands[0], operands[1], operands[2], + operands[3])); + if (label) + emit_label (label); + + DONE; +}") + +;; AIX architecture-independent common-mode multiply (DImode), +;; divide/modulus, and quotient subroutine calls. Input operands in R3 and +;; R4; results in R3 and sometimes R4; link register always clobbered by bla +;; instruction; R0 sometimes clobbered; also, MQ sometimes clobbered but +;; assumed unused if generating common-mode, so ignore. +(define_insn "mulh_call" + [(set (reg:SI 3) + (truncate:SI + (lshiftrt:DI (mult:DI (sign_extend:DI (reg:SI 3)) + (sign_extend:DI (reg:SI 4))) + (const_int 32)))) + (clobber (reg:SI LR_REGNO))] + "! TARGET_POWER && ! TARGET_POWERPC" + "bla __mulh" + [(set_attr "type" "imul")]) + +(define_insn "mull_call" + [(set (reg:DI 3) + (mult:DI (sign_extend:DI (reg:SI 3)) + (sign_extend:DI (reg:SI 4)))) + (clobber (reg:SI LR_REGNO)) + (clobber (reg:SI 0))] + "! TARGET_POWER && ! TARGET_POWERPC" + "bla __mull" + [(set_attr "type" "imul")]) + +(define_insn "divss_call" + [(set (reg:SI 3) + (div:SI (reg:SI 3) (reg:SI 4))) + (set (reg:SI 4) + (mod:SI (reg:SI 3) (reg:SI 4))) + (clobber (reg:SI LR_REGNO)) + (clobber (reg:SI 0))] + "! TARGET_POWER && ! TARGET_POWERPC" + "bla __divss" + [(set_attr "type" "idiv")]) + +(define_insn "divus_call" + [(set (reg:SI 3) + (udiv:SI (reg:SI 3) (reg:SI 4))) + (set (reg:SI 4) + (umod:SI (reg:SI 3) (reg:SI 4))) + (clobber (reg:SI LR_REGNO)) + (clobber (reg:SI 0)) + (clobber (match_scratch:CC 0 "=x")) + (clobber (reg:CC CR1_REGNO))] + "! TARGET_POWER && ! TARGET_POWERPC" + "bla __divus" + [(set_attr "type" "idiv")]) + +(define_insn "quoss_call" + [(set (reg:SI 3) + (div:SI (reg:SI 3) (reg:SI 4))) + (clobber (reg:SI LR_REGNO))] + "! TARGET_POWER && ! TARGET_POWERPC" + "bla __quoss" + [(set_attr "type" "idiv")]) + +(define_insn "quous_call" + [(set (reg:SI 3) + (udiv:SI (reg:SI 3) (reg:SI 4))) + (clobber (reg:SI LR_REGNO)) + (clobber (reg:SI 0)) + (clobber (match_scratch:CC 0 "=x")) + (clobber (reg:CC CR1_REGNO))] + "! TARGET_POWER && ! TARGET_POWERPC" + "bla __quous" + [(set_attr "type" "idiv")]) + +;; Logical instructions +;; The logical instructions are mostly combined by using match_operator, +;; but the plain AND insns are somewhat different because there is no +;; plain 'andi' (only 'andi.'), no plain 'andis', and there are all +;; those rotate-and-mask operations. Thus, the AND insns come first. + +(define_expand "andsi3" + [(parallel + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "and_operand" ""))) + (clobber (match_scratch:CC 3 ""))])] + "" + "") + +(define_insn "andsi3_mc" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r") + (match_operand:SI 2 "and_operand" "?r,T,K,L"))) + (clobber (match_scratch:CC 3 "=X,X,x,x"))] + "rs6000_gen_cell_microcode" + "@ + and %0,%1,%2 + {rlinm|rlwinm} %0,%1,0,%m2,%M2 + {andil.|andi.} %0,%1,%b2 + {andiu.|andis.} %0,%1,%u2" + [(set_attr "type" "*,*,fast_compare,fast_compare")]) + +(define_insn "andsi3_nomc" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "and_operand" "?r,T"))) + (clobber (match_scratch:CC 3 "=X,X"))] + "!rs6000_gen_cell_microcode" + "@ + and %0,%1,%2 + {rlinm|rlwinm} %0,%1,0,%m2,%M2") + +(define_insn "andsi3_internal0_nomc" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "and_operand" "?r,T")))] + "!rs6000_gen_cell_microcode" + "@ + and %0,%1,%2 + {rlinm|rlwinm} %0,%1,0,%m2,%M2") + + +;; Note to set cr's other than cr0 we do the and immediate and then +;; the test again -- this avoids a mfcr which on the higher end +;; machines causes an execution serialization + +(define_insn "*andsi3_internal2_mc" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y") + (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r") + (match_operand:SI 2 "and_operand" "r,K,L,T,r,K,L,T")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r,r,r,r,r")) + (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))] + "TARGET_32BIT && rs6000_gen_cell_microcode" + "@ + and. %3,%1,%2 + {andil.|andi.} %3,%1,%b2 + {andiu.|andis.} %3,%1,%u2 + {rlinm.|rlwinm.} %3,%1,0,%m2,%M2 + # + # + # + #" + [(set_attr "type" "fast_compare,fast_compare,fast_compare,delayed_compare,\ + compare,compare,compare,compare") + (set_attr "length" "4,4,4,4,8,8,8,8")]) + +(define_insn "*andsi3_internal3_mc" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y") + (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r") + (match_operand:SI 2 "and_operand" "r,K,L,T,r,K,L,T")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r,r,r,r,r")) + (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))] + "TARGET_64BIT && rs6000_gen_cell_microcode" + "@ + # + {andil.|andi.} %3,%1,%b2 + {andiu.|andis.} %3,%1,%u2 + {rlinm.|rlwinm.} %3,%1,0,%m2,%M2 + # + # + # + #" + [(set_attr "type" "compare,fast_compare,fast_compare,delayed_compare,compare,\ + compare,compare,compare") + (set_attr "length" "8,4,4,4,8,8,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "and_operand" "")) + (const_int 0))) + (clobber (match_scratch:GPR 3 "")) + (clobber (match_scratch:CC 4 ""))] + "reload_completed" + [(parallel [(set (match_dup 3) + (and:<MODE> (match_dup 1) + (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +;; We don't have a 32 bit "and. rt,ra,rb" for ppc64. cr is set from the +;; whole 64 bit reg, and we don't know what is in the high 32 bits. + +(define_split + [(set (match_operand:CC 0 "cc_reg_operand" "") + (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 "")) + (clobber (match_scratch:CC 4 ""))] + "TARGET_POWERPC64 && reload_completed" + [(parallel [(set (match_dup 3) + (and:SI (match_dup 1) + (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*andsi3_internal4" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y") + (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r") + (match_operand:SI 2 "and_operand" "r,K,L,T,r,K,L,T")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r") + (and:SI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))] + "TARGET_32BIT && rs6000_gen_cell_microcode" + "@ + and. %0,%1,%2 + {andil.|andi.} %0,%1,%b2 + {andiu.|andis.} %0,%1,%u2 + {rlinm.|rlwinm.} %0,%1,0,%m2,%M2 + # + # + # + #" + [(set_attr "type" "fast_compare,fast_compare,fast_compare,delayed_compare,\ + compare,compare,compare,compare") + (set_attr "length" "4,4,4,4,8,8,8,8")]) + +(define_insn "*andsi3_internal5_mc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x,?y,??y,??y,?y") + (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r") + (match_operand:SI 2 "and_operand" "r,K,L,T,r,K,L,T")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r") + (and:SI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:CC 4 "=X,X,X,X,X,x,x,X"))] + "TARGET_64BIT && rs6000_gen_cell_microcode" + "@ + # + {andil.|andi.} %0,%1,%b2 + {andiu.|andis.} %0,%1,%u2 + {rlinm.|rlwinm.} %0,%1,0,%m2,%M2 + # + # + # + #" + [(set_attr "type" "compare,fast_compare,fast_compare,delayed_compare,compare,\ + compare,compare,compare") + (set_attr "length" "8,4,4,4,8,8,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "and_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:CC 4 ""))] + "reload_completed" + [(parallel [(set (match_dup 0) + (and:SI (match_dup 1) + (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_split + [(set (match_operand:CC 3 "cc_reg_operand" "") + (compare:CC (and:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (match_dup 1) + (match_dup 2))) + (clobber (match_scratch:CC 4 ""))] + "TARGET_POWERPC64 && reload_completed" + [(parallel [(set (match_dup 0) + (and:SI (match_dup 1) + (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Handle the PowerPC64 rlwinm corner case + +(define_insn_and_split "*andsi3_internal6" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (and:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "mask_operand_wrap" "i")))] + "TARGET_POWERPC64" + "#" + "TARGET_POWERPC64" + [(set (match_dup 0) + (and:SI (rotate:SI (match_dup 1) (match_dup 3)) + (match_dup 4))) + (set (match_dup 0) + (rotate:SI (match_dup 0) (match_dup 5)))] + " +{ + int mb = extract_MB (operands[2]); + int me = extract_ME (operands[2]); + operands[3] = GEN_INT (me + 1); + operands[5] = GEN_INT (32 - (me + 1)); + operands[4] = GEN_INT (~((HOST_WIDE_INT) -1 << (33 + me - mb))); +}" + [(set_attr "length" "8")]) + +(define_expand "iorsi3" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (ior:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_logical_cint_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT + && ! logical_operand (operands[2], SImode)) + { + HOST_WIDE_INT value = INTVAL (operands[2]); + rtx tmp = ((!can_create_pseudo_p () + || rtx_equal_p (operands[0], operands[1])) + ? operands[0] : gen_reg_rtx (SImode)); + + emit_insn (gen_iorsi3 (tmp, operands[1], + GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff)))); + emit_insn (gen_iorsi3 (operands[0], tmp, GEN_INT (value & 0xffff))); + DONE; + } +}") + +(define_expand "xorsi3" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (xor:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_logical_cint_operand" "")))] + "" + " +{ + if (GET_CODE (operands[2]) == CONST_INT + && ! logical_operand (operands[2], SImode)) + { + HOST_WIDE_INT value = INTVAL (operands[2]); + rtx tmp = ((!can_create_pseudo_p () + || rtx_equal_p (operands[0], operands[1])) + ? operands[0] : gen_reg_rtx (SImode)); + + emit_insn (gen_xorsi3 (tmp, operands[1], + GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff)))); + emit_insn (gen_xorsi3 (operands[0], tmp, GEN_INT (value & 0xffff))); + DONE; + } +}") + +(define_insn "*boolsi3_internal1" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r") + (match_operator:SI 3 "boolean_or_operator" + [(match_operand:SI 1 "gpc_reg_operand" "%r,r,r") + (match_operand:SI 2 "logical_operand" "r,K,L")]))] + "" + "@ + %q3 %0,%1,%2 + {%q3il|%q3i} %0,%1,%b2 + {%q3iu|%q3is} %0,%1,%u2") + +(define_insn "*boolsi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:SI 4 "boolean_or_operator" + [(match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "TARGET_32BIT" + "@ + %q4. %3,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*boolsi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(match_operand:SI 1 "gpc_reg_operand" "%r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (match_dup 4))] + "TARGET_32BIT" + "@ + %q4. %0,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (match_dup 4))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Split a logical operation that we can't do in one insn into two insns, +;; each of which does one 16-bit part. This is used by combine. + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (match_operator:SI 3 "boolean_or_operator" + [(match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "non_logical_cint_operand" "")]))] + "" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 0) (match_dup 5))] +" +{ + rtx i; + i = GEN_INT (INTVAL (operands[2]) & (~ (HOST_WIDE_INT) 0xffff)); + operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode, + operands[1], i); + i = GEN_INT (INTVAL (operands[2]) & 0xffff); + operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode, + operands[0], i); +}") + +(define_insn "*boolcsi3_internal1" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (match_operator:SI 3 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "r")) + (match_operand:SI 2 "gpc_reg_operand" "r")]))] + "" + "%q3 %0,%2,%1") + +(define_insn "*boolcsi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")) + (match_operand:SI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "TARGET_32BIT" + "@ + %q4. %3,%2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "")) + (match_operand:SI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*boolcsi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")) + (match_operand:SI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (match_dup 4))] + "TARGET_32BIT" + "@ + %q4. %0,%2,%1 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "")) + (match_operand:SI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (match_dup 4))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*boolccsi3_internal1" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (match_operator:SI 3 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "r")) + (not:SI (match_operand:SI 2 "gpc_reg_operand" "r"))]))] + "" + "%q3 %0,%1,%2") + +(define_insn "*boolccsi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "r,r")) + (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r"))]) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "TARGET_32BIT" + "@ + %q4. %3,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "")) + (not:SI (match_operand:SI 2 "gpc_reg_operand" ""))]) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*boolccsi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r")) + (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r"))]) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (match_dup 4))] + "TARGET_32BIT" + "@ + %q4. %0,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:SI 4 "boolean_operator" + [(not:SI (match_operand:SI 1 "gpc_reg_operand" "")) + (not:SI (match_operand:SI 2 "gpc_reg_operand" ""))]) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (match_dup 4))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; maskir insn. We need four forms because things might be in arbitrary +;; orders. Don't define forms that only set CR fields because these +;; would modify an input register. + +(define_insn "*maskir_internal1" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r")) + (match_operand:SI 1 "gpc_reg_operand" "0")) + (and:SI (match_dup 2) + (match_operand:SI 3 "gpc_reg_operand" "r"))))] + "TARGET_POWER" + "maskir %0,%3,%2") + +(define_insn "*maskir_internal2" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r")) + (match_operand:SI 1 "gpc_reg_operand" "0")) + (and:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_dup 2))))] + "TARGET_POWER" + "maskir %0,%3,%2") + +(define_insn "*maskir_internal3" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ior:SI (and:SI (match_operand:SI 2 "gpc_reg_operand" "r") + (match_operand:SI 3 "gpc_reg_operand" "r")) + (and:SI (not:SI (match_dup 2)) + (match_operand:SI 1 "gpc_reg_operand" "0"))))] + "TARGET_POWER" + "maskir %0,%3,%2") + +(define_insn "*maskir_internal4" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ior:SI (and:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_operand:SI 2 "gpc_reg_operand" "r")) + (and:SI (not:SI (match_dup 2)) + (match_operand:SI 1 "gpc_reg_operand" "0"))))] + "TARGET_POWER" + "maskir %0,%3,%2") + +(define_insn "*maskir_internal5" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (match_operand:SI 1 "gpc_reg_operand" "0,0")) + (and:SI (match_dup 2) + (match_operand:SI 3 "gpc_reg_operand" "r,r"))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1)) + (and:SI (match_dup 2) (match_dup 3))))] + "TARGET_POWER" + "@ + maskir. %0,%3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "")) + (match_operand:SI 1 "gpc_reg_operand" "")) + (and:SI (match_dup 2) + (match_operand:SI 3 "gpc_reg_operand" ""))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1)) + (and:SI (match_dup 2) (match_dup 3))))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1)) + (and:SI (match_dup 2) (match_dup 3)))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*maskir_internal6" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (match_operand:SI 1 "gpc_reg_operand" "0,0")) + (and:SI (match_operand:SI 3 "gpc_reg_operand" "r,r") + (match_dup 2))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1)) + (and:SI (match_dup 3) (match_dup 2))))] + "TARGET_POWER" + "@ + maskir. %0,%3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (ior:SI (and:SI (not:SI (match_operand:SI 2 "gpc_reg_operand" "")) + (match_operand:SI 1 "gpc_reg_operand" "")) + (and:SI (match_operand:SI 3 "gpc_reg_operand" "") + (match_dup 2))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1)) + (and:SI (match_dup 3) (match_dup 2))))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (ior:SI (and:SI (not:SI (match_dup 2)) (match_dup 1)) + (and:SI (match_dup 3) (match_dup 2)))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*maskir_internal7" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (ior:SI (and:SI (match_operand:SI 2 "gpc_reg_operand" "r,r") + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (and:SI (not:SI (match_dup 2)) + (match_operand:SI 1 "gpc_reg_operand" "0,0"))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ior:SI (and:SI (match_dup 2) (match_dup 3)) + (and:SI (not:SI (match_dup 2)) (match_dup 1))))] + "TARGET_POWER" + "@ + maskir. %0,%3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (ior:SI (and:SI (match_operand:SI 2 "gpc_reg_operand" "") + (match_operand:SI 3 "gpc_reg_operand" "")) + (and:SI (not:SI (match_dup 2)) + (match_operand:SI 1 "gpc_reg_operand" ""))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ior:SI (and:SI (match_dup 2) (match_dup 3)) + (and:SI (not:SI (match_dup 2)) (match_dup 1))))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (ior:SI (and:SI (match_dup 2) (match_dup 3)) + (and:SI (not:SI (match_dup 2)) (match_dup 1)))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*maskir_internal8" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (ior:SI (and:SI (match_operand:SI 3 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (and:SI (not:SI (match_dup 2)) + (match_operand:SI 1 "gpc_reg_operand" "0,0"))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ior:SI (and:SI (match_dup 3) (match_dup 2)) + (and:SI (not:SI (match_dup 2)) (match_dup 1))))] + "TARGET_POWER" + "@ + maskir. %0,%3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (ior:SI (and:SI (match_operand:SI 3 "gpc_reg_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "")) + (and:SI (not:SI (match_dup 2)) + (match_operand:SI 1 "gpc_reg_operand" ""))) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ior:SI (and:SI (match_dup 3) (match_dup 2)) + (and:SI (not:SI (match_dup 2)) (match_dup 1))))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (ior:SI (and:SI (match_dup 3) (match_dup 2)) + (and:SI (not:SI (match_dup 2)) (match_dup 1)))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Rotate and shift insns, in all their variants. These support shifts, +;; field inserts and extracts, and various combinations thereof. +(define_expand "insv" + [(set (zero_extract (match_operand 0 "gpc_reg_operand" "") + (match_operand:SI 1 "const_int_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand 3 "gpc_reg_operand" ""))] + "" + " +{ + /* Do not handle 16/8 bit structures that fit in HI/QI modes directly, since + the (SUBREG:SI (REG:HI xxx)) that is otherwise generated can confuse the + compiler if the address of the structure is taken later. Likewise, do + not handle invalid E500 subregs. */ + if (GET_CODE (operands[0]) == SUBREG + && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0]))) < UNITS_PER_WORD + || ((TARGET_E500_DOUBLE || TARGET_SPE) + && invalid_e500_subreg (operands[0], GET_MODE (operands[0]))))) + FAIL; + + if (TARGET_POWERPC64 && GET_MODE (operands[0]) == DImode) + emit_insn (gen_insvdi (operands[0], operands[1], operands[2], operands[3])); + else + emit_insn (gen_insvsi (operands[0], operands[1], operands[2], operands[3])); + DONE; +}") + +(define_insn "insvsi" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:SI 3 "gpc_reg_operand" "r"))] + "" + "* +{ + int start = INTVAL (operands[2]) & 31; + int size = INTVAL (operands[1]) & 31; + + operands[4] = GEN_INT (32 - start - size); + operands[1] = GEN_INT (start + size - 1); + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; +}" + [(set_attr "type" "insert_word")]) + +(define_insn "*insvsi_internal1" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (rotate:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_operand:SI 4 "const_int_operand" "i")))] + "(32 - (INTVAL (operands[4]) & 31)) >= INTVAL (operands[1])" + "* +{ + int shift = INTVAL (operands[4]) & 31; + int start = INTVAL (operands[2]) & 31; + int size = INTVAL (operands[1]) & 31; + + operands[4] = GEN_INT (shift - start - size); + operands[1] = GEN_INT (start + size - 1); + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; +}" + [(set_attr "type" "insert_word")]) + +(define_insn "*insvsi_internal2" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (ashiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_operand:SI 4 "const_int_operand" "i")))] + "(32 - (INTVAL (operands[4]) & 31)) >= INTVAL (operands[1])" + "* +{ + int shift = INTVAL (operands[4]) & 31; + int start = INTVAL (operands[2]) & 31; + int size = INTVAL (operands[1]) & 31; + + operands[4] = GEN_INT (32 - shift - start - size); + operands[1] = GEN_INT (start + size - 1); + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; +}" + [(set_attr "type" "insert_word")]) + +(define_insn "*insvsi_internal3" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (lshiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_operand:SI 4 "const_int_operand" "i")))] + "(32 - (INTVAL (operands[4]) & 31)) >= INTVAL (operands[1])" + "* +{ + int shift = INTVAL (operands[4]) & 31; + int start = INTVAL (operands[2]) & 31; + int size = INTVAL (operands[1]) & 31; + + operands[4] = GEN_INT (32 - shift - start - size); + operands[1] = GEN_INT (start + size - 1); + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; +}" + [(set_attr "type" "insert_word")]) + +(define_insn "*insvsi_internal4" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (zero_extract:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_operand:SI 4 "const_int_operand" "i") + (match_operand:SI 5 "const_int_operand" "i")))] + "INTVAL (operands[4]) >= INTVAL (operands[1])" + "* +{ + int extract_start = INTVAL (operands[5]) & 31; + int extract_size = INTVAL (operands[4]) & 31; + int insert_start = INTVAL (operands[2]) & 31; + int insert_size = INTVAL (operands[1]) & 31; + +/* Align extract field with insert field */ + operands[5] = GEN_INT (extract_start + extract_size - insert_start - insert_size); + operands[1] = GEN_INT (insert_start + insert_size - 1); + return \"{rlimi|rlwimi} %0,%3,%h5,%h2,%h1\"; +}" + [(set_attr "type" "insert_word")]) + +;; combine patterns for rlwimi +(define_insn "*insvsi_internal5" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ior:SI (and:SI (match_operand:SI 4 "gpc_reg_operand" "0") + (match_operand:SI 1 "mask_operand" "i")) + (and:SI (lshiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:SI 5 "mask_operand" "i"))))] + "TARGET_POWERPC && INTVAL(operands[1]) == ~INTVAL(operands[5])" + "* +{ + int me = extract_ME(operands[5]); + int mb = extract_MB(operands[5]); + operands[4] = GEN_INT(32 - INTVAL(operands[2])); + operands[2] = GEN_INT(mb); + operands[1] = GEN_INT(me); + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; +}" + [(set_attr "type" "insert_word")]) + +(define_insn "*insvsi_internal6" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ior:SI (and:SI (lshiftrt:SI (match_operand:SI 3 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:SI 5 "mask_operand" "i")) + (and:SI (match_operand:SI 4 "gpc_reg_operand" "0") + (match_operand:SI 1 "mask_operand" "i"))))] + "TARGET_POWERPC && INTVAL(operands[1]) == ~INTVAL(operands[5])" + "* +{ + int me = extract_ME(operands[5]); + int mb = extract_MB(operands[5]); + operands[4] = GEN_INT(32 - INTVAL(operands[2])); + operands[2] = GEN_INT(mb); + operands[1] = GEN_INT(me); + return \"{rlimi|rlwimi} %0,%3,%h4,%h2,%h1\"; +}" + [(set_attr "type" "insert_word")]) + +(define_insn "insvdi" + [(set (zero_extract:DI (match_operand:DI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:DI 3 "gpc_reg_operand" "r"))] + "TARGET_POWERPC64" + "* +{ + int start = INTVAL (operands[2]) & 63; + int size = INTVAL (operands[1]) & 63; + + operands[1] = GEN_INT (64 - start - size); + return \"rldimi %0,%3,%H1,%H2\"; +}" + [(set_attr "type" "insert_dword")]) + +(define_insn "*insvdi_internal2" + [(set (zero_extract:DI (match_operand:DI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (ashiftrt:DI (match_operand:DI 3 "gpc_reg_operand" "r") + (match_operand:SI 4 "const_int_operand" "i")))] + "TARGET_POWERPC64 + && insvdi_rshift_rlwimi_p (operands[1], operands[2], operands[4])" + "* +{ + int shift = INTVAL (operands[4]) & 63; + int start = (INTVAL (operands[2]) & 63) - 32; + int size = INTVAL (operands[1]) & 63; + + operands[4] = GEN_INT (64 - shift - start - size); + operands[2] = GEN_INT (start); + operands[1] = GEN_INT (start + size - 1); + return \"rlwimi %0,%3,%h4,%h2,%h1\"; +}") + +(define_insn "*insvdi_internal3" + [(set (zero_extract:DI (match_operand:DI 0 "gpc_reg_operand" "+r") + (match_operand:SI 1 "const_int_operand" "i") + (match_operand:SI 2 "const_int_operand" "i")) + (lshiftrt:DI (match_operand:DI 3 "gpc_reg_operand" "r") + (match_operand:SI 4 "const_int_operand" "i")))] + "TARGET_POWERPC64 + && insvdi_rshift_rlwimi_p (operands[1], operands[2], operands[4])" + "* +{ + int shift = INTVAL (operands[4]) & 63; + int start = (INTVAL (operands[2]) & 63) - 32; + int size = INTVAL (operands[1]) & 63; + + operands[4] = GEN_INT (64 - shift - start - size); + operands[2] = GEN_INT (start); + operands[1] = GEN_INT (start + size - 1); + return \"rlwimi %0,%3,%h4,%h2,%h1\"; +}") + +(define_expand "extzv" + [(set (match_operand 0 "gpc_reg_operand" "") + (zero_extract (match_operand 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")))] + "" + " +{ + /* Do not handle 16/8 bit structures that fit in HI/QI modes directly, since + the (SUBREG:SI (REG:HI xxx)) that is otherwise generated can confuse the + compiler if the address of the structure is taken later. */ + if (GET_CODE (operands[0]) == SUBREG + && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (operands[0]))) < UNITS_PER_WORD)) + FAIL; + + if (TARGET_POWERPC64 && GET_MODE (operands[1]) == DImode) + emit_insn (gen_extzvdi (operands[0], operands[1], operands[2], operands[3])); + else + emit_insn (gen_extzvsi (operands[0], operands[1], operands[2], operands[3])); + DONE; +}") + +(define_insn "extzvsi" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i") + (match_operand:SI 3 "const_int_operand" "i")))] + "" + "* +{ + int start = INTVAL (operands[3]) & 31; + int size = INTVAL (operands[2]) & 31; + + if (start + size >= 32) + operands[3] = const0_rtx; + else + operands[3] = GEN_INT (start + size); + return \"{rlinm|rlwinm} %0,%1,%3,%s2,31\"; +}") + +(define_insn "*extzvsi_internal1" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i") + (match_operand:SI 3 "const_int_operand" "i,i")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=r,r"))] + "" + "* +{ + int start = INTVAL (operands[3]) & 31; + int size = INTVAL (operands[2]) & 31; + + /* Force split for non-cc0 compare. */ + if (which_alternative == 1) + return \"#\"; + + /* If the bit-field being tested fits in the upper or lower half of a + word, it is possible to use andiu. or andil. to test it. This is + useful because the condition register set-use delay is smaller for + andi[ul]. than for rlinm. This doesn't work when the starting bit + position is 0 because the LT and GT bits may be set wrong. */ + + if ((start > 0 && start + size <= 16) || start >= 16) + { + operands[3] = GEN_INT (((1 << (16 - (start & 15))) + - (1 << (16 - (start & 15) - size)))); + if (start < 16) + return \"{andiu.|andis.} %4,%1,%3\"; + else + return \"{andil.|andi.} %4,%1,%3\"; + } + + if (start + size >= 32) + operands[3] = const0_rtx; + else + operands[3] = GEN_INT (start + size); + return \"{rlinm.|rlwinm.} %4,%1,%3,%s2,31\"; +}" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "reload_completed" + [(set (match_dup 4) + (zero_extract:SI (match_dup 1) (match_dup 2) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "*extzvsi_internal2" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i") + (match_operand:SI 3 "const_int_operand" "i,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extract:SI (match_dup 1) (match_dup 2) (match_dup 3)))] + "" + "* +{ + int start = INTVAL (operands[3]) & 31; + int size = INTVAL (operands[2]) & 31; + + /* Force split for non-cc0 compare. */ + if (which_alternative == 1) + return \"#\"; + + /* Since we are using the output value, we can't ignore any need for + a shift. The bit-field must end at the LSB. */ + if (start >= 16 && start + size == 32) + { + operands[3] = GEN_INT ((1 << size) - 1); + return \"{andil.|andi.} %0,%1,%3\"; + } + + if (start + size >= 32) + operands[3] = const0_rtx; + else + operands[3] = GEN_INT (start + size); + return \"{rlinm.|rlwinm.} %0,%1,%3,%s2,31\"; +}" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extract:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "") + (match_operand:SI 3 "const_int_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extract:SI (match_dup 1) (match_dup 2) (match_dup 3)))] + "reload_completed" + [(set (match_dup 0) + (zero_extract:SI (match_dup 1) (match_dup 2) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "extzvdi" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i") + (match_operand:SI 3 "const_int_operand" "i")))] + "TARGET_POWERPC64" + "* +{ + int start = INTVAL (operands[3]) & 63; + int size = INTVAL (operands[2]) & 63; + + if (start + size >= 64) + operands[3] = const0_rtx; + else + operands[3] = GEN_INT (start + size); + operands[2] = GEN_INT (64 - size); + return \"rldicl %0,%1,%3,%2\"; +}") + +(define_insn "*extzvdi_internal1" + [(set (match_operand:CC 0 "gpc_reg_operand" "=x") + (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i") + (match_operand:SI 3 "const_int_operand" "i")) + (const_int 0))) + (clobber (match_scratch:DI 4 "=r"))] + "TARGET_64BIT && rs6000_gen_cell_microcode" + "* +{ + int start = INTVAL (operands[3]) & 63; + int size = INTVAL (operands[2]) & 63; + + if (start + size >= 64) + operands[3] = const0_rtx; + else + operands[3] = GEN_INT (start + size); + operands[2] = GEN_INT (64 - size); + return \"rldicl. %4,%1,%3,%2\"; +}" + [(set_attr "type" "compare")]) + +(define_insn "*extzvdi_internal2" + [(set (match_operand:CC 4 "gpc_reg_operand" "=x") + (compare:CC (zero_extract:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i") + (match_operand:SI 3 "const_int_operand" "i")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r") + (zero_extract:DI (match_dup 1) (match_dup 2) (match_dup 3)))] + "TARGET_64BIT && rs6000_gen_cell_microcode" + "* +{ + int start = INTVAL (operands[3]) & 63; + int size = INTVAL (operands[2]) & 63; + + if (start + size >= 64) + operands[3] = const0_rtx; + else + operands[3] = GEN_INT (start + size); + operands[2] = GEN_INT (64 - size); + return \"rldicl. %0,%1,%3,%2\"; +}" + [(set_attr "type" "compare")]) + +(define_insn "rotlsi3" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")))] + "" + "@ + {rlnm|rlwnm} %0,%1,%2,0xffffffff + {rlinm|rlwinm} %0,%1,%h2,0xffffffff" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotlsi3_64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))] + "TARGET_64BIT" + "@ + {rlnm|rlwnm} %0,%1,%2,0xffffffff + {rlinm|rlwinm} %0,%1,%h2,0xffffffff" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotlsi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r"))] + "" + "@ + {rlnm.|rlwnm.} %3,%1,%2,0xffffffff + {rlinm.|rlwinm.} %3,%1,%h2,0xffffffff + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "reload_completed" + [(set (match_dup 3) + (rotate:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*rotlsi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (rotate:SI (match_dup 1) (match_dup 2)))] + "" + "@ + {rlnm.|rlwnm.} %0,%1,%2,0xffffffff + {rlinm.|rlwinm.} %0,%1,%h2,0xffffffff + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (rotate:SI (match_dup 1) (match_dup 2)))] + "reload_completed" + [(set (match_dup 0) + (rotate:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*rotlsi3_internal4" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (and:SI (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")) + (match_operand:SI 3 "mask_operand" "n,n")))] + "" + "@ + {rlnm|rlwnm} %0,%1,%2,%m3,%M3 + {rlinm|rlwinm} %0,%1,%h2,%m3,%M3" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotlsi3_internal5" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (and:SI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (match_operand:SI 3 "mask_operand" "n,n,n,n")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=r,r,r,r"))] + "" + "@ + {rlnm.|rlwnm.} %4,%1,%2,%m3,%M3 + {rlinm.|rlwinm.} %4,%1,%h2,%m3,%M3 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (and:SI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (match_operand:SI 3 "mask_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "reload_completed" + [(set (match_dup 4) + (and:SI (rotate:SI (match_dup 1) + (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "*rotlsi3_internal6" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (and:SI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (match_operand:SI 3 "mask_operand" "n,n,n,n")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (and:SI (rotate:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "" + "@ + {rlnm.|rlwnm.} %0,%1,%2,%m3,%M3 + {rlinm.|rlwinm.} %0,%1,%h2,%m3,%M3 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (and:SI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (match_operand:SI 3 "mask_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (rotate:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "reload_completed" + [(set (match_dup 0) + (and:SI (rotate:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*rotlsi3_internal7" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (zero_extend:SI + (subreg:QI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_cint_operand" "ri")) 0)))] + "" + "{rl%I2nm|rlw%I2nm} %0,%1,%h2,0xff" + [(set (attr "cell_micro") + (if_then_else (match_operand:SI 2 "const_int_operand" "") + (const_string "not") + (const_string "always")))]) + +(define_insn "*rotlsi3_internal8" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:SI + (subreg:QI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r"))] + "" + "@ + {rlnm.|rlwnm.} %3,%1,%2,0xff + {rlinm.|rlwinm.} %3,%1,%h2,0xff + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI + (subreg:QI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "reload_completed" + [(set (match_dup 3) + (zero_extend:SI (subreg:QI + (rotate:SI (match_dup 1) + (match_dup 2)) 0))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*rotlsi3_internal9" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:SI + (subreg:QI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (zero_extend:SI (subreg:QI (rotate:SI (match_dup 1) (match_dup 2)) 0)))] + "" + "@ + {rlnm.|rlwnm.} %0,%1,%2,0xff + {rlinm.|rlwinm.} %0,%1,%h2,0xff + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI + (subreg:QI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (subreg:QI (rotate:SI (match_dup 1) (match_dup 2)) 0)))] + "reload_completed" + [(set (match_dup 0) + (zero_extend:SI (subreg:QI (rotate:SI (match_dup 1) (match_dup 2)) 0))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*rotlsi3_internal10" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extend:SI + (subreg:HI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")) 0)))] + "" + "@ + {rlnm|rlwnm} %0,%1,%2,0xffff + {rlinm|rlwinm} %0,%1,%h2,0xffff" + [(set_attr "type" "var_shift_rotate,integer")]) + + +(define_insn "*rotlsi3_internal11" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:SI + (subreg:HI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r"))] + "" + "@ + {rlnm.|rlwnm.} %3,%1,%2,0xffff + {rlinm.|rlwinm.} %3,%1,%h2,0xffff + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI + (subreg:HI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "reload_completed" + [(set (match_dup 3) + (zero_extend:SI (subreg:HI + (rotate:SI (match_dup 1) + (match_dup 2)) 0))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*rotlsi3_internal12" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:SI + (subreg:HI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (zero_extend:SI (subreg:HI (rotate:SI (match_dup 1) (match_dup 2)) 0)))] + "" + "@ + {rlnm.|rlwnm.} %0,%1,%2,0xffff + {rlinm.|rlwinm.} %0,%1,%h2,0xffff + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:SI + (subreg:HI + (rotate:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (subreg:HI (rotate:SI (match_dup 1) (match_dup 2)) 0)))] + "reload_completed" + [(set (match_dup 0) + (zero_extend:SI (subreg:HI (rotate:SI (match_dup 1) (match_dup 2)) 0))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Note that we use "sle." instead of "sl." so that we can set +;; SHIFT_COUNT_TRUNCATED. + +(define_expand "ashlsi3" + [(use (match_operand:SI 0 "gpc_reg_operand" "")) + (use (match_operand:SI 1 "gpc_reg_operand" "")) + (use (match_operand:SI 2 "reg_or_cint_operand" ""))] + "" + " +{ + if (TARGET_POWER) + emit_insn (gen_ashlsi3_power (operands[0], operands[1], operands[2])); + else + emit_insn (gen_ashlsi3_no_power (operands[0], operands[1], operands[2])); + DONE; +}") + +(define_insn "ashlsi3_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i"))) + (clobber (match_scratch:SI 3 "=q,X"))] + "TARGET_POWER" + "@ + sle %0,%1,%2 + {sli|slwi} %0,%1,%h2") + +(define_insn "ashlsi3_no_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")))] + "! TARGET_POWER" + "@ + {sl|slw} %0,%1,%2 + {sli|slwi} %0,%1,%h2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "*ashlsi3_64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI + (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))] + "TARGET_POWERPC64" + "@ + {sl|slw} %0,%1,%2 + {sli|slwi} %0,%1,%h2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r")) + (clobber (match_scratch:SI 4 "=q,X,q,X"))] + "TARGET_POWER" + "@ + sle. %3,%1,%2 + {sli.|slwi.} %3,%1,%h2 + # + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 "")) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 3) + (ashift:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r"))] + "! TARGET_POWER && TARGET_32BIT" + "@ + {sl.|slw.} %3,%1,%2 + {sli.|slwi.} %3,%1,%h2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "! TARGET_POWER && TARGET_32BIT && reload_completed" + [(set (match_dup 3) + (ashift:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (ashift:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 "=q,X,q,X"))] + "TARGET_POWER" + "@ + sle. %0,%1,%2 + {sli.|slwi.} %0,%1,%h2 + # + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ashift:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 0) + (ashift:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (ashift:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER && TARGET_32BIT" + "@ + {sl.|slw.} %0,%1,%2 + {sli.|slwi.} %0,%1,%h2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ashift:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER && TARGET_32BIT && reload_completed" + [(set (match_dup 0) + (ashift:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "rlwinm" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:SI 3 "mask_operand" "n")))] + "includes_lshift_p (operands[2], operands[3])" + "{rlinm|rlwinm} %0,%1,%h2,%m3,%M3") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:SI 3 "mask_operand" "n,n")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=r,r"))] + "includes_lshift_p (operands[2], operands[3])" + "@ + {rlinm.|rlwinm.} %4,%1,%h2,%m3,%M3 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:SI 3 "mask_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "includes_lshift_p (operands[2], operands[3]) && reload_completed" + [(set (match_dup 4) + (and:SI (ashift:SI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:SI 3 "mask_operand" "n,n")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (and:SI (ashift:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "includes_lshift_p (operands[2], operands[3])" + "@ + {rlinm.|rlwinm.} %0,%1,%h2,%m3,%M3 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:SI (ashift:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:SI 3 "mask_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (ashift:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "includes_lshift_p (operands[2], operands[3]) && reload_completed" + [(set (match_dup 0) + (and:SI (ashift:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; The AIX assembler mis-handles "sri x,x,0", so write that case as +;; "sli x,x,0". +(define_expand "lshrsi3" + [(use (match_operand:SI 0 "gpc_reg_operand" "")) + (use (match_operand:SI 1 "gpc_reg_operand" "")) + (use (match_operand:SI 2 "reg_or_cint_operand" ""))] + "" + " +{ + if (TARGET_POWER) + emit_insn (gen_lshrsi3_power (operands[0], operands[1], operands[2])); + else + emit_insn (gen_lshrsi3_no_power (operands[0], operands[1], operands[2])); + DONE; +}") + +(define_insn "lshrsi3_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,O,i"))) + (clobber (match_scratch:SI 3 "=q,X,X"))] + "TARGET_POWER" + "@ + sre %0,%1,%2 + mr %0,%1 + {s%A2i|s%A2wi} %0,%1,%h2") + +(define_insn "lshrsi3_no_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r") + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "O,r,i")))] + "! TARGET_POWER" + "@ + mr %0,%1 + {sr|srw} %0,%1,%2 + {sri|srwi} %0,%1,%h2" + [(set_attr "type" "integer,var_shift_rotate,shift")]) + +(define_insn "*lshrsi3_64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))] + "TARGET_POWERPC64" + "@ + {sr|srw} %0,%1,%2 + {sri|srwi} %0,%1,%h2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,?y,?y,?y") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,O,i,r,O,i")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,X,r,r,X,r")) + (clobber (match_scratch:SI 4 "=q,X,X,q,X,X"))] + "TARGET_POWER" + "@ + sre. %3,%1,%2 + mr. %1,%1 + {s%A2i.|s%A2wi.} %3,%1,%h2 + # + # + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,4,4,8,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 "")) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 3) + (lshiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,?y,?y,?y") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "O,r,i,O,r,i")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=X,r,r,X,r,r"))] + "! TARGET_POWER && TARGET_32BIT" + "@ + mr. %1,%1 + {sr.|srw.} %3,%1,%2 + {sri.|srwi.} %3,%1,%h2 + # + # + #" + [(set_attr "type" "delayed_compare,var_delayed_compare,delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,4,8,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "! TARGET_POWER && TARGET_32BIT && reload_completed" + [(set (match_dup 3) + (lshiftrt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,?y,?y,?y") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,O,i,r,O,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r,r") + (lshiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 "=q,X,X,q,X,X"))] + "TARGET_POWER" + "@ + sre. %0,%1,%2 + mr. %0,%1 + {s%A2i.|s%A2wi.} %0,%1,%h2 + # + # + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,4,4,8,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (lshiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 0) + (lshiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,?y,?y,?y") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "O,r,i,O,r,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r,r") + (lshiftrt:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER && TARGET_32BIT" + "@ + mr. %0,%1 + {sr.|srw.} %0,%1,%2 + {sri.|srwi.} %0,%1,%h2 + # + # + #" + [(set_attr "type" "delayed_compare,var_delayed_compare,delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,4,8,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (lshiftrt:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER && TARGET_32BIT && reload_completed" + [(set (match_dup 0) + (lshiftrt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:SI 3 "mask_operand" "n")))] + "includes_rshift_p (operands[2], operands[3])" + "{rlinm|rlwinm} %0,%1,%s2,%m3,%M3") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:SI 3 "mask_operand" "n,n")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=r,r"))] + "includes_rshift_p (operands[2], operands[3])" + "@ + {rlinm.|rlwinm.} %4,%1,%s2,%m3,%M3 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:SI 3 "mask_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "includes_rshift_p (operands[2], operands[3]) && reload_completed" + [(set (match_dup 4) + (and:SI (lshiftrt:SI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:SI 3 "mask_operand" "n,n")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (and:SI (lshiftrt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "includes_rshift_p (operands[2], operands[3])" + "@ + {rlinm.|rlwinm.} %0,%1,%s2,%m3,%M3 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:SI (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:SI 3 "mask_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (lshiftrt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "includes_rshift_p (operands[2], operands[3]) && reload_completed" + [(set (match_dup 0) + (and:SI (lshiftrt:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (zero_extend:SI + (subreg:QI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) 0)))] + "includes_rshift_p (operands[2], GEN_INT (255))" + "{rlinm|rlwinm} %0,%1,%s2,0xff") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (zero_extend:SI + (subreg:QI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "includes_rshift_p (operands[2], GEN_INT (255))" + "@ + {rlinm.|rlwinm.} %3,%1,%s2,0xff + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (zero_extend:SI + (subreg:QI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "includes_rshift_p (operands[2], GEN_INT (255)) && reload_completed" + [(set (match_dup 3) + (zero_extend:SI (subreg:QI + (lshiftrt:SI (match_dup 1) + (match_dup 2)) 0))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (zero_extend:SI + (subreg:QI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extend:SI (subreg:QI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0)))] + "includes_rshift_p (operands[2], GEN_INT (255))" + "@ + {rlinm.|rlwinm.} %0,%1,%s2,0xff + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (zero_extend:SI + (subreg:QI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (subreg:QI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0)))] + "includes_rshift_p (operands[2], GEN_INT (255)) && reload_completed" + [(set (match_dup 0) + (zero_extend:SI (subreg:QI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (zero_extend:SI + (subreg:HI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) 0)))] + "includes_rshift_p (operands[2], GEN_INT (65535))" + "{rlinm|rlwinm} %0,%1,%s2,0xffff") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (zero_extend:SI + (subreg:HI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r"))] + "includes_rshift_p (operands[2], GEN_INT (65535))" + "@ + {rlinm.|rlwinm.} %3,%1,%s2,0xffff + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (zero_extend:SI + (subreg:HI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) 0)) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "includes_rshift_p (operands[2], GEN_INT (65535)) && reload_completed" + [(set (match_dup 3) + (zero_extend:SI (subreg:HI + (lshiftrt:SI (match_dup 1) + (match_dup 2)) 0))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (zero_extend:SI + (subreg:HI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (zero_extend:SI (subreg:HI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0)))] + "includes_rshift_p (operands[2], GEN_INT (65535))" + "@ + {rlinm.|rlwinm.} %0,%1,%s2,0xffff + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (zero_extend:SI + (subreg:HI + (lshiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) 0)) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (zero_extend:SI (subreg:HI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0)))] + "includes_rshift_p (operands[2], GEN_INT (65535)) && reload_completed" + [(set (match_dup 0) + (zero_extend:SI (subreg:HI (lshiftrt:SI (match_dup 1) (match_dup 2)) 0))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (const_int 1) + (match_operand:SI 1 "gpc_reg_operand" "r")) + (ashiftrt:SI (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 31)))] + "TARGET_POWER" + "rrib %0,%1,%2") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (const_int 1) + (match_operand:SI 1 "gpc_reg_operand" "r")) + (lshiftrt:SI (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 31)))] + "TARGET_POWER" + "rrib %0,%1,%2") + +(define_insn "" + [(set (zero_extract:SI (match_operand:SI 0 "gpc_reg_operand" "+r") + (const_int 1) + (match_operand:SI 1 "gpc_reg_operand" "r")) + (zero_extract:SI (match_operand:SI 2 "gpc_reg_operand" "r") + (const_int 1) + (const_int 0)))] + "TARGET_POWER" + "rrib %0,%1,%2") + +(define_expand "ashrsi3" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")))] + "" + " +{ + if (TARGET_POWER) + emit_insn (gen_ashrsi3_power (operands[0], operands[1], operands[2])); + else + emit_insn (gen_ashrsi3_no_power (operands[0], operands[1], operands[2])); + DONE; +}") + +(define_insn "ashrsi3_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i"))) + (clobber (match_scratch:SI 3 "=q,X"))] + "TARGET_POWER" + "@ + srea %0,%1,%2 + {srai|srawi} %0,%1,%h2" + [(set_attr "type" "shift")]) + +(define_insn "ashrsi3_no_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")))] + "! TARGET_POWER" + "@ + {sra|sraw} %0,%1,%2 + {srai|srawi} %0,%1,%h2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "*ashrsi3_64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (sign_extend:DI + (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i"))))] + "TARGET_POWERPC64" + "@ + {sra|sraw} %0,%1,%2 + {srai|srawi} %0,%1,%h2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r")) + (clobber (match_scratch:SI 4 "=q,X,q,X"))] + "TARGET_POWER" + "@ + srea. %3,%1,%2 + {srai.|srawi.} %3,%1,%h2 + # + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 "")) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 3) + (ashiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=r,r,r,r"))] + "! TARGET_POWER" + "@ + {sra.|sraw.} %3,%1,%2 + {srai.|srawi.} %3,%1,%h2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "! TARGET_POWER && reload_completed" + [(set (match_dup 3) + (ashiftrt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (ashiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 "=q,X,q,X"))] + "TARGET_POWER" + "@ + srea. %0,%1,%2 + {srai.|srawi.} %0,%1,%h2 + # + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ashiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 0) + (ashiftrt:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (ashiftrt:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER" + "@ + {sra.|sraw.} %0,%1,%2 + {srai.|srawi.} %0,%1,%h2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +;; Builtins to replace a division to generate FRE reciprocal estimate +;; instructions and the necessary fixup instructions +(define_expand "recip<mode>3" + [(match_operand:RECIPF 0 "gpc_reg_operand" "") + (match_operand:RECIPF 1 "gpc_reg_operand" "") + (match_operand:RECIPF 2 "gpc_reg_operand" "")] + "RS6000_RECIP_HAVE_RE_P (<MODE>mode)" +{ + rs6000_emit_swdiv (operands[0], operands[1], operands[2], false); + DONE; +}) + +;; Split to create division from FRE/FRES/etc. and fixup instead of the normal +;; hardware division. This is only done before register allocation and with +;; -ffast-math. This must appear before the divsf3/divdf3 insns. +(define_split + [(set (match_operand:RECIPF 0 "gpc_reg_operand" "") + (div:RECIPF (match_operand 1 "gpc_reg_operand" "") + (match_operand 2 "gpc_reg_operand" "")))] + "RS6000_RECIP_AUTO_RE_P (<MODE>mode) + && can_create_pseudo_p () && optimize_insn_for_speed_p () + && flag_finite_math_only && !flag_trapping_math && flag_reciprocal_math" + [(const_int 0)] +{ + rs6000_emit_swdiv (operands[0], operands[1], operands[2], true); + DONE; +}) + +;; Builtins to replace 1/sqrt(x) with instructions using RSQRTE and the +;; appropriate fixup. +(define_expand "rsqrt<mode>2" + [(match_operand:RECIPF 0 "gpc_reg_operand" "") + (match_operand:RECIPF 1 "gpc_reg_operand" "")] + "RS6000_RECIP_HAVE_RSQRTE_P (<MODE>mode)" +{ + rs6000_emit_swrsqrt (operands[0], operands[1]); + DONE; +}) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (ashiftrt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ashiftrt:SI (match_dup 1) (match_dup 2)))] + "! TARGET_POWER && reload_completed" + [(set (match_dup 0) + (ashiftrt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Floating-point insns, excluding normal data motion. +;; +;; PowerPC has a full set of single-precision floating point instructions. +;; +;; For the POWER architecture, we pretend that we have both SFmode and +;; DFmode insns, while, in fact, all fp insns are actually done in double. +;; The only conversions we will do will be when storing to memory. In that +;; case, we will use the "frsp" instruction before storing. +;; +;; Note that when we store into a single-precision memory location, we need to +;; use the frsp insn first. If the register being stored isn't dead, we +;; need a scratch register for the frsp. But this is difficult when the store +;; is done by reload. It is not incorrect to do the frsp on the register in +;; this case, we just lose precision that we would have otherwise gotten but +;; is not guaranteed. Perhaps this should be tightened up at some point. + +(define_expand "extendsfdf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (float_extend:DF (match_operand:SF 1 "reg_or_none500mem_operand" "")))] + "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + "") + +(define_insn_and_split "*extendsfdf2_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d,d") + (float_extend:DF (match_operand:SF 1 "reg_or_mem_operand" "0,f,m")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" + "@ + # + fmr %0,%1 + lfs%U1%X1 %0,%1" + "&& reload_completed && REG_P (operands[1]) && REGNO (operands[0]) == REGNO (operands[1])" + [(const_int 0)] +{ + emit_note (NOTE_INSN_DELETED); + DONE; +} + [(set_attr "type" "fp,fp,fpload")]) + +(define_expand "truncdfsf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + "") + +(define_insn "*truncdfsf2_fpr" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (float_truncate:SF (match_operand:DF 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" + "frsp %0,%1" + [(set_attr "type" "fp")]) + +(define_insn "aux_truncdfsf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRSP))] + "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS" + "frsp %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "negsf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (neg:SF (match_operand:SF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT" + "") + +(define_insn "*negsf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (neg:SF (match_operand:SF 1 "gpc_reg_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fneg %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "abssf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (abs:SF (match_operand:SF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT" + "") + +(define_insn "*abssf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (abs:SF (match_operand:SF 1 "gpc_reg_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fabs %0,%1" + [(set_attr "type" "fp")]) + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (neg:SF (abs:SF (match_operand:SF 1 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fnabs %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "addsf3" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (plus:SF (match_operand:SF 1 "gpc_reg_operand" "") + (match_operand:SF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT" + "") + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fadds %0,%1,%2" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_addsub_s")]) + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS" + "{fa|fadd} %0,%1,%2" + [(set_attr "type" "fp")]) + +(define_expand "subsf3" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (minus:SF (match_operand:SF 1 "gpc_reg_operand" "") + (match_operand:SF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT" + "") + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (minus:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fsubs %0,%1,%2" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_addsub_s")]) + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (minus:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS" + "{fs|fsub} %0,%1,%2" + [(set_attr "type" "fp")]) + +(define_expand "mulsf3" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (mult:SF (match_operand:SF 1 "gpc_reg_operand" "") + (match_operand:SF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT" + "") + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fmuls %0,%1,%2" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_mul_s")]) + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS" + "{fm|fmul} %0,%1,%2" + [(set_attr "type" "dmul")]) + +(define_expand "divsf3" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (div:SF (match_operand:SF 1 "gpc_reg_operand" "") + (match_operand:SF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU" + "") + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (div:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU" + "fdivs %0,%1,%2" + [(set_attr "type" "sdiv")]) + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (div:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "! TARGET_POWERPC && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU" + "{fd|fdiv} %0,%1,%2" + [(set_attr "type" "ddiv")]) + +(define_insn "fres" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] UNSPEC_FRES))] + "TARGET_FRES" + "fres %0,%1" + [(set_attr "type" "fp")]) + +; builtin fmaf support +(define_insn "*fmasf4_fpr" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (match_operand:SF 3 "gpc_reg_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fmadds %0,%1,%2,%3" + : "{fma|fmadd} %0,%1,%2,%3"); +} + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_insn "*fmssf4_fpr" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (neg:SF (match_operand:SF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fmsubs %0,%1,%2,%3" + : "{fms|fmsub} %0,%1,%2,%3"); +} + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_insn "*nfmasf4_fpr" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (neg:SF (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (match_operand:SF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fnmadds %0,%1,%2,%3" + : "{fnma|fnmadd} %0,%1,%2,%3"); +} + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_insn "*nfmssf4_fpr" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (neg:SF (fma:SF (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f") + (neg:SF (match_operand:SF 3 "gpc_reg_operand" "f")))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" +{ + return (TARGET_POWERPC + ? "fnmsubs %0,%1,%2,%3" + : "{fnms|fnmsub} %0,%1,%2,%3"); +} + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_expand "sqrtsf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "")))] + "(TARGET_PPC_GPOPT || TARGET_POWER2 || TARGET_XILINX_FPU) + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && !TARGET_SIMPLE_FPU" + "") + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))] + "(TARGET_PPC_GPOPT || TARGET_XILINX_FPU) && TARGET_HARD_FLOAT + && TARGET_FPRS && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU" + "fsqrts %0,%1" + [(set_attr "type" "ssqrt")]) + +(define_insn "" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (sqrt:SF (match_operand:SF 1 "gpc_reg_operand" "f")))] + "TARGET_POWER2 && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_SINGLE_FLOAT && !TARGET_SIMPLE_FPU" + "fsqrt %0,%1" + [(set_attr "type" "dsqrt")]) + +(define_insn "*rsqrtsf_internal1" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (unspec:SF [(match_operand:SF 1 "gpc_reg_operand" "f")] + UNSPEC_RSQRT))] + "TARGET_FRSQRTES" + "frsqrtes %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "copysign<mode>3" + [(set (match_dup 3) + (abs:SFDF (match_operand:SFDF 1 "gpc_reg_operand" ""))) + (set (match_dup 4) + (neg:SFDF (abs:SFDF (match_dup 1)))) + (set (match_operand:SFDF 0 "gpc_reg_operand" "") + (if_then_else:SFDF (ge (match_operand:SFDF 2 "gpc_reg_operand" "") + (match_dup 5)) + (match_dup 3) + (match_dup 4)))] + "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> + && ((TARGET_PPC_GFXOPT + && !HONOR_NANS (<MODE>mode) + && !HONOR_SIGNED_ZEROS (<MODE>mode)) + || TARGET_CMPB + || VECTOR_UNIT_VSX_P (<MODE>mode))" +{ + if (TARGET_CMPB || VECTOR_UNIT_VSX_P (<MODE>mode)) + { + emit_insn (gen_copysign<mode>3_fcpsgn (operands[0], operands[1], + operands[2])); + DONE; + } + + operands[3] = gen_reg_rtx (<MODE>mode); + operands[4] = gen_reg_rtx (<MODE>mode); + operands[5] = CONST0_RTX (<MODE>mode); + }) + +;; Use an unspec rather providing an if-then-else in RTL, to prevent the +;; compiler from optimizing -0.0 +(define_insn "copysign<mode>3_fcpsgn" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>") + (match_operand:SFDF 2 "gpc_reg_operand" "<rreg2>")] + UNSPEC_COPYSIGN))] + "TARGET_CMPB && !VECTOR_UNIT_VSX_P (<MODE>mode)" + "fcpsgn %0,%2,%1" + [(set_attr "type" "fp")]) + +;; For MIN, MAX, and conditional move, we use DEFINE_EXPAND's that involve a +;; fsel instruction and some auxiliary computations. Then we just have a +;; single DEFINE_INSN for fsel and the define_splits to make them if made by +;; combine. +(define_expand "smaxsf3" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "") + (match_operand:SF 2 "gpc_reg_operand" "")) + (match_dup 1) + (match_dup 2)))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_SINGLE_FLOAT && !flag_trapping_math" + "{ rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); DONE;}") + +(define_expand "sminsf3" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "") + (match_operand:SF 2 "gpc_reg_operand" "")) + (match_dup 2) + (match_dup 1)))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_SINGLE_FLOAT && !flag_trapping_math" + "{ rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); DONE;}") + +(define_split + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (match_operator:SF 3 "min_max_operator" + [(match_operand:SF 1 "gpc_reg_operand" "") + (match_operand:SF 2 "gpc_reg_operand" "")]))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_SINGLE_FLOAT && !flag_trapping_math" + [(const_int 0)] + " +{ rs6000_emit_minmax (operands[0], GET_CODE (operands[3]), + operands[1], operands[2]); + DONE; +}") + +(define_expand "mov<mode>cc" + [(set (match_operand:GPR 0 "gpc_reg_operand" "") + (if_then_else:GPR (match_operand 1 "comparison_operator" "") + (match_operand:GPR 2 "gpc_reg_operand" "") + (match_operand:GPR 3 "gpc_reg_operand" "")))] + "TARGET_ISEL<sel>" + " +{ + if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; +}") + +;; We use the BASE_REGS for the isel input operands because, if rA is +;; 0, the value of 0 is placed in rD upon truth. Similarly for rB +;; because we may switch the operands and rB may end up being rA. +;; +;; We need 2 patterns: an unsigned and a signed pattern. We could +;; leave out the mode in operand 4 and use one pattern, but reload can +;; change the mode underneath our feet and then gets confused trying +;; to reload the value. +(define_insn "isel_signed_<mode>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r") + (if_then_else:GPR + (match_operator 1 "scc_comparison_operator" + [(match_operand:CC 4 "cc_reg_operand" "y,y") + (const_int 0)]) + (match_operand:GPR 2 "reg_or_cint_operand" "O,b") + (match_operand:GPR 3 "gpc_reg_operand" "r,r")))] + "TARGET_ISEL<sel>" + "* +{ return output_isel (operands); }" + [(set_attr "type" "isel") + (set_attr "length" "4")]) + +(define_insn "isel_unsigned_<mode>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r") + (if_then_else:GPR + (match_operator 1 "scc_comparison_operator" + [(match_operand:CCUNS 4 "cc_reg_operand" "y,y") + (const_int 0)]) + (match_operand:GPR 2 "reg_or_cint_operand" "O,b") + (match_operand:GPR 3 "gpc_reg_operand" "r,r")))] + "TARGET_ISEL<sel>" + "* +{ return output_isel (operands); }" + [(set_attr "type" "isel") + (set_attr "length" "4")]) + +;; These patterns can be useful for combine; they let combine know that +;; isel can handle reversed comparisons so long as the operands are +;; registers. + +(define_insn "*isel_reversed_signed_<mode>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (if_then_else:GPR + (match_operator 1 "scc_rev_comparison_operator" + [(match_operand:CC 4 "cc_reg_operand" "y") + (const_int 0)]) + (match_operand:GPR 2 "gpc_reg_operand" "b") + (match_operand:GPR 3 "gpc_reg_operand" "b")))] + "TARGET_ISEL<sel>" + "* +{ return output_isel (operands); }" + [(set_attr "type" "isel") + (set_attr "length" "4")]) + +(define_insn "*isel_reversed_unsigned_<mode>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (if_then_else:GPR + (match_operator 1 "scc_rev_comparison_operator" + [(match_operand:CCUNS 4 "cc_reg_operand" "y") + (const_int 0)]) + (match_operand:GPR 2 "gpc_reg_operand" "b") + (match_operand:GPR 3 "gpc_reg_operand" "b")))] + "TARGET_ISEL<sel>" + "* +{ return output_isel (operands); }" + [(set_attr "type" "isel") + (set_attr "length" "4")]) + +(define_expand "movsfcc" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (if_then_else:SF (match_operand 1 "comparison_operator" "") + (match_operand:SF 2 "gpc_reg_operand" "") + (match_operand:SF 3 "gpc_reg_operand" "")))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + " +{ + if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; +}") + +(define_insn "*fselsfsf4" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (if_then_else:SF (ge (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 4 "zero_fp_constant" "F")) + (match_operand:SF 2 "gpc_reg_operand" "f") + (match_operand:SF 3 "gpc_reg_operand" "f")))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fsel %0,%1,%2,%3" + [(set_attr "type" "fp")]) + +(define_insn "*fseldfsf4" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (if_then_else:SF (ge (match_operand:DF 1 "gpc_reg_operand" "d") + (match_operand:DF 4 "zero_fp_constant" "F")) + (match_operand:SF 2 "gpc_reg_operand" "f") + (match_operand:SF 3 "gpc_reg_operand" "f")))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_SINGLE_FLOAT" + "fsel %0,%1,%2,%3" + [(set_attr "type" "fp")]) + +(define_expand "negdf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (neg:DF (match_operand:DF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + "") + +(define_insn "*negdf2_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (neg:DF (match_operand:DF 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "fneg %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "absdf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (abs:DF (match_operand:DF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + "") + +(define_insn "*absdf2_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (abs:DF (match_operand:DF 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "fabs %0,%1" + [(set_attr "type" "fp")]) + +(define_insn "*nabsdf2_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (neg:DF (abs:DF (match_operand:DF 1 "gpc_reg_operand" "d"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "fnabs %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "adddf3" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (plus:DF (match_operand:DF 1 "gpc_reg_operand" "") + (match_operand:DF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + "") + +(define_insn "*adddf3_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (plus:DF (match_operand:DF 1 "gpc_reg_operand" "%d") + (match_operand:DF 2 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "{fa|fadd} %0,%1,%2" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_addsub_d")]) + +(define_expand "subdf3" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (minus:DF (match_operand:DF 1 "gpc_reg_operand" "") + (match_operand:DF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + "") + +(define_insn "*subdf3_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (minus:DF (match_operand:DF 1 "gpc_reg_operand" "d") + (match_operand:DF 2 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "{fs|fsub} %0,%1,%2" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_addsub_d")]) + +(define_expand "muldf3" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (mult:DF (match_operand:DF 1 "gpc_reg_operand" "") + (match_operand:DF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + "") + +(define_insn "*muldf3_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (mult:DF (match_operand:DF 1 "gpc_reg_operand" "%d") + (match_operand:DF 2 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "{fm|fmul} %0,%1,%2" + [(set_attr "type" "dmul") + (set_attr "fp_type" "fp_mul_d")]) + +(define_expand "divdf3" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (div:DF (match_operand:DF 1 "gpc_reg_operand" "") + (match_operand:DF 2 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT + && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE) + && !TARGET_SIMPLE_FPU" + "") + +(define_insn "*divdf3_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (div:DF (match_operand:DF 1 "gpc_reg_operand" "d") + (match_operand:DF 2 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && !TARGET_SIMPLE_FPU + && !VECTOR_UNIT_VSX_P (DFmode)" + "{fd|fdiv} %0,%1,%2" + [(set_attr "type" "ddiv")]) + +(define_insn "*fred_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "f")] UNSPEC_FRES))] + "TARGET_FRE && !VECTOR_UNIT_VSX_P (DFmode)" + "fre %0,%1" + [(set_attr "type" "fp")]) + +(define_insn "*rsqrtdf_internal1" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (unspec:DF [(match_operand:DF 1 "gpc_reg_operand" "d")] + UNSPEC_RSQRT))] + "TARGET_FRSQRTE && !VECTOR_UNIT_VSX_P (DFmode)" + "frsqrte %0,%1" + [(set_attr "type" "fp")]) + +; builtin fma support +(define_insn "*fmadf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (match_operand:DF 3 "gpc_reg_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && VECTOR_UNIT_NONE_P (DFmode)" + "{fma|fmadd} %0,%1,%2,%3" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_insn "*fmsdf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (neg:DF (match_operand:DF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && VECTOR_UNIT_NONE_P (DFmode)" + "{fms|fmsub} %0,%1,%2,%3" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_insn "*nfmadf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (neg:DF (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (match_operand:DF 3 "gpc_reg_operand" "f"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && VECTOR_UNIT_NONE_P (DFmode)" + "{fnma|fnmadd} %0,%1,%2,%3" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_insn "*nfmsdf4_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=f") + (neg:DF (fma:DF (match_operand:DF 1 "gpc_reg_operand" "f") + (match_operand:DF 2 "gpc_reg_operand" "f") + (neg:DF (match_operand:DF 3 "gpc_reg_operand" "f")))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && VECTOR_UNIT_NONE_P (DFmode)" + "{fnms|fnmsub} %0,%1,%2,%3" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_maddsub_s")]) + +(define_expand "sqrtdf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "")))] + "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_DOUBLE_FLOAT" + "") + +(define_insn "*sqrtdf2_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (sqrt:DF (match_operand:DF 1 "gpc_reg_operand" "d")))] + "(TARGET_PPC_GPOPT || TARGET_POWER2) && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "fsqrt %0,%1" + [(set_attr "type" "dsqrt")]) + +;; The conditional move instructions allow us to perform max and min +;; operations even when + +(define_expand "smaxdf3" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "") + (match_operand:DF 2 "gpc_reg_operand" "")) + (match_dup 1) + (match_dup 2)))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !flag_trapping_math" + "{ rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); DONE;}") + +(define_expand "smindf3" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "") + (match_operand:DF 2 "gpc_reg_operand" "")) + (match_dup 2) + (match_dup 1)))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !flag_trapping_math" + "{ rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); DONE;}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operator:DF 3 "min_max_operator" + [(match_operand:DF 1 "gpc_reg_operand" "") + (match_operand:DF 2 "gpc_reg_operand" "")]))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !flag_trapping_math" + [(const_int 0)] + " +{ rs6000_emit_minmax (operands[0], GET_CODE (operands[3]), + operands[1], operands[2]); + DONE; +}") + +(define_expand "movdfcc" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (if_then_else:DF (match_operand 1 "comparison_operator" "") + (match_operand:DF 2 "gpc_reg_operand" "") + (match_operand:DF 3 "gpc_reg_operand" "")))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" + " +{ + if (rs6000_emit_cmove (operands[0], operands[1], operands[2], operands[3])) + DONE; + else + FAIL; +}") + +(define_insn "*fseldfdf4" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (if_then_else:DF (ge (match_operand:DF 1 "gpc_reg_operand" "d") + (match_operand:DF 4 "zero_fp_constant" "F")) + (match_operand:DF 2 "gpc_reg_operand" "d") + (match_operand:DF 3 "gpc_reg_operand" "d")))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" + "fsel %0,%1,%2,%3" + [(set_attr "type" "fp")]) + +(define_insn "*fselsfdf4" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (if_then_else:DF (ge (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 4 "zero_fp_constant" "F")) + (match_operand:DF 2 "gpc_reg_operand" "d") + (match_operand:DF 3 "gpc_reg_operand" "d")))] + "TARGET_PPC_GFXOPT && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_SINGLE_FLOAT" + "fsel %0,%1,%2,%3" + [(set_attr "type" "fp")]) + +;; Conversions to and from floating-point. + +; We don't define lfiwax/lfiwzx with the normal definition, because we +; don't want to support putting SImode in FPR registers. +(define_insn "lfiwax" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")] + UNSPEC_LFIWAX))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX" + "lfiwax %0,%y1" + [(set_attr "type" "fpload")]) + +; This split must be run before register allocation because it allocates the +; memory slot that is needed to move values to/from the FPR. We don't allocate +; it earlier to allow for the combiner to merge insns together where it might +; not be needed and also in case the insns are deleted as dead code. + +(define_insn_and_split "floatsi<mode>2_lfiwax" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX + && <SI_CONVERT_FP> && can_create_pseudo_p ()" + "#" + "" + [(pc)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp; + + if (!MEM_P (src) && TARGET_MFPGPR && TARGET_POWERPC64) + tmp = convert_to_mode (DImode, src, false); + else + { + tmp = operands[2]; + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + if (MEM_P (src)) + { + src = rs6000_address_for_fpconvert (src); + emit_insn (gen_lfiwax (tmp, src)); + } + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_move_insn (stack, src); + emit_insn (gen_lfiwax (tmp, stack)); + } + } + emit_insn (gen_floatdi<mode>2 (dest, tmp)); + DONE; +}" + [(set_attr "length" "12") + (set_attr "type" "fpload")]) + +(define_insn_and_split "floatsi<mode>2_lfiwax_mem" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>") + (float:SFDF + (sign_extend:DI + (match_operand:SI 1 "memory_operand" "Z,Z")))) + (clobber (match_scratch:DI 2 "=0,d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWAX + && <SI_CONVERT_FP>" + "#" + "" + [(pc)] + " +{ + operands[1] = rs6000_address_for_fpconvert (operands[1]); + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (DImode); + emit_insn (gen_lfiwax (operands[2], operands[1])); + emit_insn (gen_floatdi<mode>2 (operands[0], operands[2])); + DONE; +}" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) + +(define_insn "lfiwzx" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(match_operand:SI 1 "indexed_or_indirect_operand" "Z")] + UNSPEC_LFIWZX))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX" + "lfiwzx %0,%y1" + [(set_attr "type" "fpload")]) + +(define_insn_and_split "floatunssi<mode>2_lfiwzx" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (unsigned_float:SFDF (match_operand:SI 1 "nonimmediate_operand" "r"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX + && <SI_CONVERT_FP>" + "#" + "" + [(pc)] + " +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp; + + if (!MEM_P (src) && TARGET_MFPGPR && TARGET_POWERPC64) + tmp = convert_to_mode (DImode, src, true); + else + { + tmp = operands[2]; + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + if (MEM_P (src)) + { + src = rs6000_address_for_fpconvert (src); + emit_insn (gen_lfiwzx (tmp, src)); + } + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_move_insn (stack, src); + emit_insn (gen_lfiwzx (tmp, stack)); + } + } + emit_insn (gen_floatdi<mode>2 (dest, tmp)); + DONE; +}" + [(set_attr "length" "12") + (set_attr "type" "fpload")]) + +(define_insn_and_split "floatunssi<mode>2_lfiwzx_mem" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d,<rreg2>") + (unsigned_float:SFDF + (zero_extend:DI + (match_operand:SI 1 "memory_operand" "Z,Z")))) + (clobber (match_scratch:DI 2 "=0,d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LFIWZX + && <SI_CONVERT_FP>" + "#" + "" + [(pc)] + " +{ + operands[1] = rs6000_address_for_fpconvert (operands[1]); + if (GET_CODE (operands[2]) == SCRATCH) + operands[2] = gen_reg_rtx (DImode); + emit_insn (gen_lfiwzx (operands[2], operands[1])); + emit_insn (gen_floatdi<mode>2 (operands[0], operands[2])); + DONE; +}" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) + +; For each of these conversions, there is a define_expand, a define_insn +; with a '#' template, and a define_split (with C code). The idea is +; to allow constant folding with the template of the define_insn, +; then to have the insns split later (between sched1 and final). + +(define_expand "floatsidf2" + [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "") + (float:DF (match_operand:SI 1 "nonimmediate_operand" ""))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_dup 5)) + (clobber (match_dup 6))])] + "TARGET_HARD_FLOAT + && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + " +{ + if (TARGET_E500_DOUBLE) + { + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); + emit_insn (gen_spe_floatsidf2 (operands[0], operands[1])); + DONE; + } + else if (TARGET_LFIWAX && TARGET_FCFID) + { + emit_insn (gen_floatsidf2_lfiwax (operands[0], operands[1])); + DONE; + } + else if (TARGET_FCFID) + { + rtx dreg = operands[1]; + if (!REG_P (dreg)) + dreg = force_reg (SImode, dreg); + dreg = convert_to_mode (DImode, dreg, false); + emit_insn (gen_floatdidf2 (operands[0], dreg)); + DONE; + } + + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); + operands[2] = force_reg (SImode, GEN_INT (0x43300000)); + operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503601774854144\", DFmode)); + operands[4] = rs6000_allocate_stack_temp (DFmode, true, false); + operands[5] = gen_reg_rtx (DFmode); + operands[6] = gen_reg_rtx (SImode); +}") + +(define_insn_and_split "*floatsidf2_internal" + [(set (match_operand:DF 0 "gpc_reg_operand" "=&d") + (float:DF (match_operand:SI 1 "gpc_reg_operand" "r"))) + (use (match_operand:SI 2 "gpc_reg_operand" "r")) + (use (match_operand:DF 3 "gpc_reg_operand" "d")) + (clobber (match_operand:DF 4 "offsettable_mem_operand" "=o")) + (clobber (match_operand:DF 5 "gpc_reg_operand" "=&d")) + (clobber (match_operand:SI 6 "gpc_reg_operand" "=&r"))] + "! TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" + "#" + "" + [(pc)] + " +{ + rtx lowword, highword; + gcc_assert (MEM_P (operands[4])); + highword = adjust_address (operands[4], SImode, 0); + lowword = adjust_address (operands[4], SImode, 4); + if (! WORDS_BIG_ENDIAN) + { + rtx tmp; + tmp = highword; highword = lowword; lowword = tmp; + } + + emit_insn (gen_xorsi3 (operands[6], operands[1], + GEN_INT (~ (HOST_WIDE_INT) 0x7fffffff))); + emit_move_insn (lowword, operands[6]); + emit_move_insn (highword, operands[2]); + emit_move_insn (operands[5], operands[4]); + emit_insn (gen_subdf3 (operands[0], operands[5], operands[3])); + DONE; +}" + [(set_attr "length" "24") + (set_attr "type" "fp")]) + +;; If we don't have a direct conversion to single precision, don't enable this +;; conversion for 32-bit without fast math, because we don't have the insn to +;; generate the fixup swizzle to avoid double rounding problems. +(define_expand "floatunssisf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (unsigned_float:SF (match_operand:SI 1 "nonimmediate_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT + && (!TARGET_FPRS + || (TARGET_FPRS + && ((TARGET_FCFIDUS && TARGET_LFIWZX) + || (TARGET_DOUBLE_FLOAT && TARGET_FCFID + && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))" + " +{ + if (!TARGET_FPRS) + { + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); + } + else if (TARGET_LFIWZX && TARGET_FCFIDUS) + { + emit_insn (gen_floatunssisf2_lfiwzx (operands[0], operands[1])); + DONE; + } + else + { + rtx dreg = operands[1]; + if (!REG_P (dreg)) + dreg = force_reg (SImode, dreg); + dreg = convert_to_mode (DImode, dreg, true); + emit_insn (gen_floatdisf2 (operands[0], dreg)); + DONE; + } +}") + +(define_expand "floatunssidf2" + [(parallel [(set (match_operand:DF 0 "gpc_reg_operand" "") + (unsigned_float:DF (match_operand:SI 1 "nonimmediate_operand" ""))) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_dup 5))])] + "TARGET_HARD_FLOAT + && ((TARGET_FPRS && TARGET_DOUBLE_FLOAT) || TARGET_E500_DOUBLE)" + " +{ + if (TARGET_E500_DOUBLE) + { + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); + emit_insn (gen_spe_floatunssidf2 (operands[0], operands[1])); + DONE; + } + else if (TARGET_LFIWZX && TARGET_FCFID) + { + emit_insn (gen_floatunssidf2_lfiwzx (operands[0], operands[1])); + DONE; + } + else if (TARGET_FCFID) + { + rtx dreg = operands[1]; + if (!REG_P (dreg)) + dreg = force_reg (SImode, dreg); + dreg = convert_to_mode (DImode, dreg, true); + emit_insn (gen_floatdidf2 (operands[0], dreg)); + DONE; + } + + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); + operands[2] = force_reg (SImode, GEN_INT (0x43300000)); + operands[3] = force_reg (DFmode, CONST_DOUBLE_ATOF (\"4503599627370496\", DFmode)); + operands[4] = rs6000_allocate_stack_temp (DFmode, true, false); + operands[5] = gen_reg_rtx (DFmode); +}") + +(define_insn_and_split "*floatunssidf2_internal" + [(set (match_operand:DF 0 "gpc_reg_operand" "=&d") + (unsigned_float:DF (match_operand:SI 1 "gpc_reg_operand" "r"))) + (use (match_operand:SI 2 "gpc_reg_operand" "r")) + (use (match_operand:DF 3 "gpc_reg_operand" "d")) + (clobber (match_operand:DF 4 "offsettable_mem_operand" "=o")) + (clobber (match_operand:DF 5 "gpc_reg_operand" "=&d"))] + "! TARGET_FCFIDU && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !(TARGET_FCFID && TARGET_POWERPC64)" + "#" + "" + [(pc)] + " +{ + rtx lowword, highword; + gcc_assert (MEM_P (operands[4])); + highword = adjust_address (operands[4], SImode, 0); + lowword = adjust_address (operands[4], SImode, 4); + if (! WORDS_BIG_ENDIAN) + { + rtx tmp; + tmp = highword; highword = lowword; lowword = tmp; + } + + emit_move_insn (lowword, operands[1]); + emit_move_insn (highword, operands[2]); + emit_move_insn (operands[5], operands[4]); + emit_insn (gen_subdf3 (operands[0], operands[5], operands[3])); + DONE; +}" + [(set_attr "length" "20") + (set_attr "type" "fp")]) + +(define_expand "fix_trunc<mode>si2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))] + "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT + && ((TARGET_FPRS && <TARGET_FLOAT>) || <E500_CONVERT>)" + " +{ + if (!<E500_CONVERT>) + { + rtx tmp, stack; + + if (TARGET_STFIWX) + emit_insn (gen_fix_trunc<mode>si2_stfiwx (operands[0], operands[1])); + else + { + tmp = gen_reg_rtx (DImode); + stack = rs6000_allocate_stack_temp (DImode, true, false); + emit_insn (gen_fix_trunc<mode>si2_internal (operands[0], operands[1], + tmp, stack)); + } + DONE; + } +}") + +; Like the convert to float patterns, this insn must be split before +; register allocation so that it can allocate the memory slot if it +; needed +(define_insn_and_split "fix_trunc<mode>si2_stfiwx" + [(set (match_operand:SI 0 "general_operand" "=rm") + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && (<MODE>mode != SFmode || TARGET_SINGLE_FLOAT) + && TARGET_STFIWX && can_create_pseudo_p ()" + "#" + "" + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp = operands[2]; + + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwz_<mode> (tmp, src)); + if (MEM_P (dest)) + { + dest = rs6000_address_for_fpconvert (dest); + emit_insn (gen_stfiwx (dest, tmp)); + DONE; + } + else if (TARGET_MFPGPR && TARGET_POWERPC64) + { + dest = gen_lowpart (DImode, dest); + emit_move_insn (dest, tmp); + DONE; + } + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_insn (gen_stfiwx (stack, tmp)); + emit_move_insn (dest, stack); + DONE; + } +} + [(set_attr "length" "12") + (set_attr "type" "fp")]) + +(define_insn_and_split "fix_trunc<mode>si2_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,?r") + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d,<rreg>"))) + (clobber (match_operand:DI 2 "gpc_reg_operand" "=1,d")) + (clobber (match_operand:DI 3 "offsettable_mem_operand" "=o,o"))] + "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_DOUBLE_FLOAT" + "#" + "" + [(pc)] + " +{ + rtx lowword; + gcc_assert (MEM_P (operands[3])); + lowword = adjust_address (operands[3], SImode, WORDS_BIG_ENDIAN ? 4 : 0); + + emit_insn (gen_fctiwz_<mode> (operands[2], operands[1])); + emit_move_insn (operands[3], operands[2]); + emit_move_insn (operands[0], lowword); + DONE; +}" + [(set_attr "length" "16") + (set_attr "type" "fp")]) + +(define_expand "fix_trunc<mode>di2" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS + && TARGET_FCFID" + "") + +(define_insn "*fix_trunc<mode>di2_fctidz" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS + && TARGET_FCFID && !VECTOR_UNIT_VSX_P (<MODE>mode)" + "fctidz %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "fixuns_trunc<mode>si2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT + && ((TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ && TARGET_STFIWX) + || <E500_CONVERT>)" + " +{ + if (!<E500_CONVERT>) + { + emit_insn (gen_fixuns_trunc<mode>si2_stfiwx (operands[0], operands[1])); + DONE; + } +}") + +(define_insn_and_split "fixuns_trunc<mode>si2_stfiwx" + [(set (match_operand:SI 0 "general_operand" "=rm") + (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ + && TARGET_STFIWX && can_create_pseudo_p ()" + "#" + "" + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp = operands[2]; + + if (GET_CODE (tmp) == SCRATCH) + tmp = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwuz_<mode> (tmp, src)); + if (MEM_P (dest)) + { + dest = rs6000_address_for_fpconvert (dest); + emit_insn (gen_stfiwx (dest, tmp)); + DONE; + } + else if (TARGET_MFPGPR && TARGET_POWERPC64) + { + dest = gen_lowpart (DImode, dest); + emit_move_insn (dest, tmp); + DONE; + } + else + { + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + emit_insn (gen_stfiwx (stack, tmp)); + emit_move_insn (dest, stack); + DONE; + } +} + [(set_attr "length" "12") + (set_attr "type" "fp")]) + +(define_expand "fixuns_trunc<mode>di2" + [(set (match_operand:DI 0 "register_operand" "") + (unsigned_fix:DI (match_operand:SFDF 1 "register_operand" "")))] + "TARGET_HARD_FLOAT && (TARGET_FCTIDUZ || VECTOR_UNIT_VSX_P (<MODE>mode))" + "") + +(define_insn "*fixuns_trunc<mode>di2_fctiduz" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unsigned_fix:DI (match_operand:SFDF 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS + && TARGET_FCTIDUZ && !VECTOR_UNIT_VSX_P (<MODE>mode)" + "fctiduz %0,%1" + [(set_attr "type" "fp")]) + +; Here, we use (set (reg) (unspec:DI [(fix:SI ...)] UNSPEC_FCTIWZ)) +; rather than (set (subreg:SI (reg)) (fix:SI ...)) +; because the first makes it clear that operand 0 is not live +; before the instruction. +(define_insn "fctiwz_<mode>" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d"))] + UNSPEC_FCTIWZ))] + "(TARGET_POWER2 || TARGET_POWERPC) && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_DOUBLE_FLOAT" + "{fcirz|fctiwz} %0,%1" + [(set_attr "type" "fp")]) + +(define_insn "fctiwuz_<mode>" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(unsigned_fix:SI + (match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>"))] + UNSPEC_FCTIWUZ))] + "TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> && TARGET_FCTIWUZ" + "fctiwuz %0,%1" + [(set_attr "type" "fp")]) + +;; Only optimize (float (fix x)) -> frz if we are in fast-math mode, since +;; since the friz instruction does not truncate the value if the floating +;; point value is < LONG_MIN or > LONG_MAX. +(define_insn "*friz" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (float:DF (fix:DI (match_operand:DF 1 "gpc_reg_operand" "d"))))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_FPRND + && !VECTOR_UNIT_VSX_P (DFmode) && flag_unsafe_math_optimizations + && !flag_trapping_math && TARGET_FRIZ" + "friz %0,%1" + [(set_attr "type" "fp")]) + +;; Since FCTIWZ doesn't sign extend the upper bits, we have to do a store and a +;; load to properly sign extend the value, but at least doing a store, load +;; into a GPR to sign extend, a store from the GPR and a load back into the FPR +;; if we have 32-bit memory ops +(define_insn_and_split "*round32<mode>2_fprs" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (float:SFDF + (fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))) + (clobber (match_scratch:DI 2 "=d")) + (clobber (match_scratch:DI 3 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && <SI_CONVERT_FP> && TARGET_LFIWAX && TARGET_STFIWX && TARGET_FCFID + && can_create_pseudo_p ()" + "#" + "" + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp1 = operands[2]; + rtx tmp2 = operands[3]; + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + + if (GET_CODE (tmp1) == SCRATCH) + tmp1 = gen_reg_rtx (DImode); + if (GET_CODE (tmp2) == SCRATCH) + tmp2 = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwz_<mode> (tmp1, src)); + emit_insn (gen_stfiwx (stack, tmp1)); + emit_insn (gen_lfiwax (tmp2, stack)); + emit_insn (gen_floatdi<mode>2 (dest, tmp2)); + DONE; +} + [(set_attr "type" "fpload") + (set_attr "length" "16")]) + +(define_insn_and_split "*roundu32<mode>2_fprs" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=d") + (unsigned_float:SFDF + (unsigned_fix:SI (match_operand:SFDF 1 "gpc_reg_operand" "d")))) + (clobber (match_scratch:DI 2 "=d")) + (clobber (match_scratch:DI 3 "=d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && TARGET_LFIWZX && TARGET_STFIWX && TARGET_FCFIDU + && can_create_pseudo_p ()" + "#" + "" + [(pc)] +{ + rtx dest = operands[0]; + rtx src = operands[1]; + rtx tmp1 = operands[2]; + rtx tmp2 = operands[3]; + rtx stack = rs6000_allocate_stack_temp (SImode, false, true); + + if (GET_CODE (tmp1) == SCRATCH) + tmp1 = gen_reg_rtx (DImode); + if (GET_CODE (tmp2) == SCRATCH) + tmp2 = gen_reg_rtx (DImode); + + emit_insn (gen_fctiwuz_<mode> (tmp1, src)); + emit_insn (gen_stfiwx (stack, tmp1)); + emit_insn (gen_lfiwzx (tmp2, stack)); + emit_insn (gen_floatdi<mode>2 (dest, tmp2)); + DONE; +} + [(set_attr "type" "fpload") + (set_attr "length" "16")]) + +;; No VSX equivalent to fctid +(define_insn "lrint<mode>di2" + [(set (match_operand:DI 0 "gpc_reg_operand" "=d") + (unspec:DI [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")] + UNSPEC_FCTID))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>" + "fctid %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "btrunc<mode>2" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")] + UNSPEC_FRIZ))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>" + "") + +(define_insn "*btrunc<mode>2_fpr" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")] + UNSPEC_FRIZ))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> + && !VECTOR_UNIT_VSX_P (<MODE>mode)" + "friz %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "ceil<mode>2" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")] + UNSPEC_FRIP))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>" + "") + +(define_insn "*ceil<mode>2_fpr" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")] + UNSPEC_FRIP))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> + && !VECTOR_UNIT_VSX_P (<MODE>mode)" + "frip %0,%1" + [(set_attr "type" "fp")]) + +(define_expand "floor<mode>2" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "")] + UNSPEC_FRIM))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>" + "") + +(define_insn "*floor<mode>2_fpr" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")] + UNSPEC_FRIM))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT> + && !VECTOR_UNIT_VSX_P (<MODE>mode)" + "frim %0,%1" + [(set_attr "type" "fp")]) + +;; No VSX equivalent to frin +(define_insn "round<mode>2" + [(set (match_operand:SFDF 0 "gpc_reg_operand" "=<rreg2>") + (unspec:SFDF [(match_operand:SFDF 1 "gpc_reg_operand" "<rreg2>")] + UNSPEC_FRIN))] + "TARGET_FPRND && TARGET_HARD_FLOAT && TARGET_FPRS && <TARGET_FLOAT>" + "frin %0,%1" + [(set_attr "type" "fp")]) + +; An UNSPEC is used so we don't have to support SImode in FP registers. +(define_insn "stfiwx" + [(set (match_operand:SI 0 "memory_operand" "=Z") + (unspec:SI [(match_operand:DI 1 "gpc_reg_operand" "d")] + UNSPEC_STFIWX))] + "TARGET_PPC_GFXOPT" + "stfiwx %1,%y0" + [(set_attr "type" "fpstore")]) + +;; If we don't have a direct conversion to single precision, don't enable this +;; conversion for 32-bit without fast math, because we don't have the insn to +;; generate the fixup swizzle to avoid double rounding problems. +(define_expand "floatsisf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (float:SF (match_operand:SI 1 "nonimmediate_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_SINGLE_FLOAT + && (!TARGET_FPRS + || (TARGET_FPRS + && ((TARGET_FCFIDS && TARGET_LFIWAX) + || (TARGET_DOUBLE_FLOAT && TARGET_FCFID + && (TARGET_POWERPC64 || flag_unsafe_math_optimizations)))))" + " +{ + if (!TARGET_FPRS) + { + if (!REG_P (operands[1])) + operands[1] = force_reg (SImode, operands[1]); + } + else if (TARGET_FCFIDS && TARGET_LFIWAX) + { + emit_insn (gen_floatsisf2_lfiwax (operands[0], operands[1])); + DONE; + } + else if (TARGET_FCFID && TARGET_LFIWAX) + { + rtx dfreg = gen_reg_rtx (DFmode); + emit_insn (gen_floatsidf2_lfiwax (dfreg, operands[1])); + emit_insn (gen_truncdfsf2 (operands[0], dfreg)); + DONE; + } + else + { + rtx dreg = operands[1]; + if (!REG_P (dreg)) + dreg = force_reg (SImode, dreg); + dreg = convert_to_mode (DImode, dreg, false); + emit_insn (gen_floatdisf2 (operands[0], dreg)); + DONE; + } +}") + +(define_expand "floatdidf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (float:DF (match_operand:DI 1 "gpc_reg_operand" "")))] + "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS" + "") + +(define_insn "*floatdidf2_fpr" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))] + "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS + && !VECTOR_UNIT_VSX_P (DFmode)" + "fcfid %0,%1" + [(set_attr "type" "fp")]) + +; Allow the combiner to merge source memory operands to the conversion so that +; the optimizer/register allocator doesn't try to load the value too early in a +; GPR and then use store/load to move it to a FPR and suffer from a store-load +; hit. We will split after reload to avoid the trip through the GPRs + +(define_insn_and_split "*floatdidf2_mem" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (float:DF (match_operand:DI 1 "memory_operand" "m"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && TARGET_DOUBLE_FLOAT && TARGET_FPRS && TARGET_FCFID" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (float:DF (match_dup 2)))] + "" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) + +(define_expand "floatunsdidf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (unsigned_float:DF + (match_operand:DI 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && (TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode))" + "") + +(define_insn "*floatunsdidf2_fcfidu" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (unsigned_float:DF (match_operand:DI 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FCFIDU && !VECTOR_UNIT_VSX_P (DFmode)" + "fcfidu %0,%1" + [(set_attr "type" "fp") + (set_attr "length" "4")]) + +(define_insn_and_split "*floatunsdidf2_mem" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (unsigned_float:DF (match_operand:DI 1 "memory_operand" "m"))) + (clobber (match_scratch:DI 2 "=d"))] + "TARGET_HARD_FLOAT && (TARGET_FCFIDU || VECTOR_UNIT_VSX_P (DFmode))" + "#" + "&& reload_completed" + [(set (match_dup 2) (match_dup 1)) + (set (match_dup 0) (unsigned_float:DF (match_dup 2)))] + "" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) + +(define_expand "floatdisf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (float:SF (match_operand:DI 1 "gpc_reg_operand" "")))] + "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && (TARGET_FCFIDS || TARGET_POWERPC64 || flag_unsafe_math_optimizations)" + " +{ + if (!TARGET_FCFIDS) + { + rtx val = operands[1]; + if (!flag_unsafe_math_optimizations) + { + rtx label = gen_label_rtx (); + val = gen_reg_rtx (DImode); + emit_insn (gen_floatdisf2_internal2 (val, operands[1], label)); + emit_label (label); + } + emit_insn (gen_floatdisf2_internal1 (operands[0], val)); + DONE; + } +}") + +(define_insn "floatdisf2_fcfids" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS" + "fcfids %0,%1" + [(set_attr "type" "fp")]) + +(define_insn_and_split "*floatdisf2_mem" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (float:SF (match_operand:DI 1 "memory_operand" "m"))) + (clobber (match_scratch:DI 2 "=f"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && TARGET_DOUBLE_FLOAT && TARGET_FCFIDS" + "#" + "&& reload_completed" + [(pc)] + " +{ + emit_move_insn (operands[2], operands[1]); + emit_insn (gen_floatdisf2_fcfids (operands[0], operands[2])); + DONE; +}" + [(set_attr "length" "8")]) + +;; This is not IEEE compliant if rounding mode is "round to nearest". +;; If the DI->DF conversion is inexact, then it's possible to suffer +;; from double rounding. +;; Instead of creating a new cpu type for two FP operations, just use fp +(define_insn_and_split "floatdisf2_internal1" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (float:SF (match_operand:DI 1 "gpc_reg_operand" "d"))) + (clobber (match_scratch:DF 2 "=d"))] + "TARGET_FCFID && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "#" + "&& reload_completed" + [(set (match_dup 2) + (float:DF (match_dup 1))) + (set (match_dup 0) + (float_truncate:SF (match_dup 2)))] + "" + [(set_attr "length" "8") + (set_attr "type" "fp")]) + +;; Twiddles bits to avoid double rounding. +;; Bits that might be truncated when converting to DFmode are replaced +;; by a bit that won't be lost at that stage, but is below the SFmode +;; rounding position. +(define_expand "floatdisf2_internal2" + [(set (match_dup 3) (ashiftrt:DI (match_operand:DI 1 "" "") + (const_int 53))) + (parallel [(set (match_operand:DI 0 "" "") (and:DI (match_dup 1) + (const_int 2047))) + (clobber (scratch:CC))]) + (set (match_dup 3) (plus:DI (match_dup 3) + (const_int 1))) + (set (match_dup 0) (plus:DI (match_dup 0) + (const_int 2047))) + (set (match_dup 4) (compare:CCUNS (match_dup 3) + (const_int 2))) + (set (match_dup 0) (ior:DI (match_dup 0) + (match_dup 1))) + (parallel [(set (match_dup 0) (and:DI (match_dup 0) + (const_int -2048))) + (clobber (scratch:CC))]) + (set (pc) (if_then_else (geu (match_dup 4) (const_int 0)) + (label_ref (match_operand:DI 2 "" "")) + (pc))) + (set (match_dup 0) (match_dup 1))] + "TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + " +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (CCUNSmode); +}") + +(define_expand "floatunsdisf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS" + "") + +(define_insn "floatunsdisf2_fcfidus" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (unsigned_float:SF (match_operand:DI 1 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS" + "fcfidus %0,%1" + [(set_attr "type" "fp")]) + +(define_insn_and_split "*floatunsdisf2_mem" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (unsigned_float:SF (match_operand:DI 1 "memory_operand" "m"))) + (clobber (match_scratch:DI 2 "=f"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && TARGET_DOUBLE_FLOAT && TARGET_FCFIDUS" + "#" + "&& reload_completed" + [(pc)] + " +{ + emit_move_insn (operands[2], operands[1]); + emit_insn (gen_floatunsdisf2_fcfidus (operands[0], operands[2])); + DONE; +}" + [(set_attr "length" "8") + (set_attr "type" "fpload")]) + +;; Define the DImode operations that can be done in a small number +;; of instructions. The & constraints are to prevent the register +;; allocator from allocating registers that overlap with the inputs +;; (for example, having an input in 7,8 and an output in 6,7). We +;; also allow for the output being the same as one of the inputs. + +(define_insn "*adddi3_noppc64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,&r,r,r") + (plus:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,0,0") + (match_operand:DI 2 "reg_or_short_operand" "r,I,r,I")))] + "! TARGET_POWERPC64" + "* +{ + if (WORDS_BIG_ENDIAN) + return (GET_CODE (operands[2])) != CONST_INT + ? \"{a|addc} %L0,%L1,%L2\;{ae|adde} %0,%1,%2\" + : \"{ai|addic} %L0,%L1,%2\;{a%G2e|add%G2e} %0,%1\"; + else + return (GET_CODE (operands[2])) != CONST_INT + ? \"{a|addc} %0,%1,%2\;{ae|adde} %L0,%L1,%L2\" + : \"{ai|addic} %0,%1,%2\;{a%G2e|add%G2e} %L0,%L1\"; +}" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "*subdi3_noppc64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,&r,r,r,r") + (minus:DI (match_operand:DI 1 "reg_or_short_operand" "r,I,0,r,I") + (match_operand:DI 2 "gpc_reg_operand" "r,r,r,0,0")))] + "! TARGET_POWERPC64" + "* +{ + if (WORDS_BIG_ENDIAN) + return (GET_CODE (operands[1]) != CONST_INT) + ? \"{sf|subfc} %L0,%L2,%L1\;{sfe|subfe} %0,%2,%1\" + : \"{sfi|subfic} %L0,%L2,%1\;{sf%G1e|subf%G1e} %0,%2\"; + else + return (GET_CODE (operands[1]) != CONST_INT) + ? \"{sf|subfc} %0,%2,%1\;{sfe|subfe} %L0,%L2,%L1\" + : \"{sfi|subfic} %0,%2,%1\;{sf%G1e|subf%G1e} %L0,%L2\"; +}" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "*negdi2_noppc64" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r") + (neg:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))] + "! TARGET_POWERPC64" + "* +{ + return (WORDS_BIG_ENDIAN) + ? \"{sfi|subfic} %L0,%L1,0\;{sfze|subfze} %0,%1\" + : \"{sfi|subfic} %0,%1,0\;{sfze|subfze} %L0,%L1\"; +}" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_expand "mulsidi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")) + (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))] + "! TARGET_POWERPC64" + " +{ + if (! TARGET_POWER && ! TARGET_POWERPC) + { + emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]); + emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]); + emit_insn (gen_mull_call ()); + if (WORDS_BIG_ENDIAN) + emit_move_insn (operands[0], gen_rtx_REG (DImode, 3)); + else + { + emit_move_insn (operand_subword (operands[0], 0, 0, DImode), + gen_rtx_REG (SImode, 3)); + emit_move_insn (operand_subword (operands[0], 1, 0, DImode), + gen_rtx_REG (SImode, 4)); + } + DONE; + } + else if (TARGET_POWER) + { + emit_insn (gen_mulsidi3_mq (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "mulsidi3_mq" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r")) + (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r")))) + (clobber (match_scratch:SI 3 "=q"))] + "TARGET_POWER" + "mul %0,%1,%2\;mfmq %L0" + [(set_attr "type" "imul") + (set_attr "length" "8")]) + +(define_insn "*mulsidi3_no_mq" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r") + (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r")) + (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))] + "TARGET_POWERPC && ! TARGET_POWER && ! TARGET_POWERPC64" + "* +{ + return (WORDS_BIG_ENDIAN) + ? \"mulhw %0,%1,%2\;mullw %L0,%1,%2\" + : \"mulhw %L0,%1,%2\;mullw %0,%1,%2\"; +}" + [(set_attr "type" "imul") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")) + (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))] + "TARGET_POWERPC && ! TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (truncate:SI + (lshiftrt:DI (mult:DI (sign_extend:DI (match_dup 1)) + (sign_extend:DI (match_dup 2))) + (const_int 32)))) + (set (match_dup 4) + (mult:SI (match_dup 1) + (match_dup 2)))] + " +{ + int endian = (WORDS_BIG_ENDIAN == 0); + operands[3] = operand_subword (operands[0], endian, 0, DImode); + operands[4] = operand_subword (operands[0], 1 - endian, 0, DImode); +}") + +(define_expand "umulsidi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")) + (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))] + "TARGET_POWERPC && ! TARGET_POWERPC64" + " +{ + if (TARGET_POWER) + { + emit_insn (gen_umulsidi3_mq (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "umulsidi3_mq" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r") + (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r")) + (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r")))) + (clobber (match_scratch:SI 3 "=q"))] + "TARGET_POWERPC && TARGET_POWER" + "* +{ + return (WORDS_BIG_ENDIAN) + ? \"mulhwu %0,%1,%2\;mullw %L0,%1,%2\" + : \"mulhwu %L0,%1,%2\;mullw %0,%1,%2\"; +}" + [(set_attr "type" "imul") + (set_attr "length" "8")]) + +(define_insn "*umulsidi3_no_mq" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r") + (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r")) + (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))] + "TARGET_POWERPC && ! TARGET_POWER && ! TARGET_POWERPC64" + "* +{ + return (WORDS_BIG_ENDIAN) + ? \"mulhwu %0,%1,%2\;mullw %L0,%1,%2\" + : \"mulhwu %L0,%1,%2\;mullw %0,%1,%2\"; +}" + [(set_attr "type" "imul") + (set_attr "length" "8")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (mult:DI (zero_extend:DI (match_operand:SI 1 "gpc_reg_operand" "")) + (zero_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))] + "TARGET_POWERPC && ! TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (truncate:SI + (lshiftrt:DI (mult:DI (zero_extend:DI (match_dup 1)) + (zero_extend:DI (match_dup 2))) + (const_int 32)))) + (set (match_dup 4) + (mult:SI (match_dup 1) + (match_dup 2)))] + " +{ + int endian = (WORDS_BIG_ENDIAN == 0); + operands[3] = operand_subword (operands[0], endian, 0, DImode); + operands[4] = operand_subword (operands[0], 1 - endian, 0, DImode); +}") + +(define_expand "smulsi3_highpart" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (truncate:SI + (lshiftrt:DI (mult:DI (sign_extend:DI + (match_operand:SI 1 "gpc_reg_operand" "")) + (sign_extend:DI + (match_operand:SI 2 "gpc_reg_operand" ""))) + (const_int 32))))] + "" + " +{ + if (! TARGET_POWER && ! TARGET_POWERPC) + { + emit_move_insn (gen_rtx_REG (SImode, 3), operands[1]); + emit_move_insn (gen_rtx_REG (SImode, 4), operands[2]); + emit_insn (gen_mulh_call ()); + emit_move_insn (operands[0], gen_rtx_REG (SImode, 3)); + DONE; + } + else if (TARGET_POWER) + { + emit_insn (gen_smulsi3_highpart_mq (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "smulsi3_highpart_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (truncate:SI + (lshiftrt:DI (mult:DI (sign_extend:DI + (match_operand:SI 1 "gpc_reg_operand" "%r")) + (sign_extend:DI + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=q"))] + "TARGET_POWER" + "mul %0,%1,%2" + [(set_attr "type" "imul")]) + +(define_insn "*smulsi3_highpart_no_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (truncate:SI + (lshiftrt:DI (mult:DI (sign_extend:DI + (match_operand:SI 1 "gpc_reg_operand" "%r")) + (sign_extend:DI + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (const_int 32))))] + "TARGET_POWERPC && ! TARGET_POWER" + "mulhw %0,%1,%2" + [(set_attr "type" "imul")]) + +(define_expand "umulsi3_highpart" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (truncate:SI + (lshiftrt:DI (mult:DI (zero_extend:DI + (match_operand:SI 1 "gpc_reg_operand" "")) + (zero_extend:DI + (match_operand:SI 2 "gpc_reg_operand" ""))) + (const_int 32))))] + "TARGET_POWERPC" + " +{ + if (TARGET_POWER) + { + emit_insn (gen_umulsi3_highpart_mq (operands[0], operands[1], operands[2])); + DONE; + } +}") + +(define_insn "umulsi3_highpart_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (truncate:SI + (lshiftrt:DI (mult:DI (zero_extend:DI + (match_operand:SI 1 "gpc_reg_operand" "%r")) + (zero_extend:DI + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (const_int 32)))) + (clobber (match_scratch:SI 3 "=q"))] + "TARGET_POWERPC && TARGET_POWER" + "mulhwu %0,%1,%2" + [(set_attr "type" "imul")]) + +(define_insn "*umulsi3_highpart_no_mq" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (truncate:SI + (lshiftrt:DI (mult:DI (zero_extend:DI + (match_operand:SI 1 "gpc_reg_operand" "%r")) + (zero_extend:DI + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (const_int 32))))] + "TARGET_POWERPC && ! TARGET_POWER" + "mulhwu %0,%1,%2" + [(set_attr "type" "imul")]) + +;; If operands 0 and 2 are in the same register, we have a problem. But +;; operands 0 and 1 (the usual case) can be in the same register. That's +;; why we have the strange constraints below. +(define_insn "ashldi3_power" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,&r") + (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,0,r") + (match_operand:SI 2 "reg_or_cint_operand" "M,i,r,r"))) + (clobber (match_scratch:SI 3 "=X,q,q,q"))] + "TARGET_POWER" + "@ + {sli|slwi} %0,%L1,%h2\;{cal %L0,0(0)|li %L0,0} + sl%I2q %L0,%L1,%h2\;sll%I2q %0,%1,%h2 + sl%I2q %L0,%L1,%h2\;sll%I2q %0,%1,%h2 + sl%I2q %L0,%L1,%h2\;sll%I2q %0,%1,%h2" + [(set_attr "length" "8")]) + +(define_insn "lshrdi3_power" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,&r") + (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,0,r") + (match_operand:SI 2 "reg_or_cint_operand" "M,i,r,r"))) + (clobber (match_scratch:SI 3 "=X,q,q,q"))] + "TARGET_POWER" + "@ + {s%A2i|s%A2wi} %L0,%1,%h2\;{cal %0,0(0)|li %0,0} + sr%I2q %0,%1,%h2\;srl%I2q %L0,%L1,%h2 + sr%I2q %0,%1,%h2\;srl%I2q %L0,%L1,%h2 + sr%I2q %0,%1,%h2\;srl%I2q %L0,%L1,%h2" + [(set_attr "length" "8")]) + +;; Shift by a variable amount is too complex to be worth open-coding. We +;; just handle shifts by constants. +(define_insn "ashrdi3_power" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r") + (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "M,i"))) + (clobber (match_scratch:SI 3 "=X,q"))] + "TARGET_POWER" + "@ + {srai|srawi} %0,%1,31\;{srai|srawi} %L0,%1,%h2 + sraiq %0,%1,%h2\;srliq %L0,%L1,%h2" + [(set_attr "type" "shift") + (set_attr "length" "8")]) + +(define_insn "ashrdi3_no_power" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,&r") + (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "M,i")))] + "TARGET_32BIT && !TARGET_POWERPC64 && !TARGET_POWER && WORDS_BIG_ENDIAN" + "@ + {srai|srawi} %0,%1,31\;{srai|srawi} %L0,%1,%h2 + {sri|srwi} %L0,%L1,%h2\;insrwi %L0,%1,%h2,0\;{srai|srawi} %0,%1,%h2" + [(set_attr "type" "two,three") + (set_attr "length" "8,12")]) + +(define_insn "*ashrdisi3_noppc64" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (subreg:SI (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (const_int 32)) 4))] + "TARGET_32BIT && !TARGET_POWERPC64" + "* +{ + if (REGNO (operands[0]) == REGNO (operands[1])) + return \"\"; + else + return \"mr %0,%1\"; +}" + [(set_attr "length" "4")]) + + +;; PowerPC64 DImode operations. + +(define_expand "absdi2" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (abs:DI (match_operand:DI 1 "gpc_reg_operand" "")))] + "TARGET_POWERPC64" + " +{ + if (TARGET_ISEL) + emit_insn (gen_absdi2_isel (operands[0], operands[1])); + else + emit_insn (gen_absdi2_internal (operands[0], operands[1])); + DONE; +}") + +(define_insn_and_split "absdi2_internal" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r") + (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0"))) + (clobber (match_scratch:DI 2 "=&r,&r"))] + "TARGET_POWERPC64 && !TARGET_ISEL" + "#" + "&& reload_completed" + [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63))) + (set (match_dup 0) (xor:DI (match_dup 2) (match_dup 1))) + (set (match_dup 0) (minus:DI (match_dup 0) (match_dup 2)))] + "") + +(define_insn_and_split "*nabsdi2" + [(set (match_operand:DI 0 "gpc_reg_operand" "=&r,r") + (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,0")))) + (clobber (match_scratch:DI 2 "=&r,&r"))] + "TARGET_POWERPC64 && !TARGET_ISEL" + "#" + "&& reload_completed" + [(set (match_dup 2) (ashiftrt:DI (match_dup 1) (const_int 63))) + (set (match_dup 0) (xor:DI (match_dup 2) (match_dup 1))) + (set (match_dup 0) (minus:DI (match_dup 2) (match_dup 0)))] + "") + +(define_insn "muldi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (mult:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r") + (match_operand:DI 2 "reg_or_short_operand" "r,I")))] + "TARGET_POWERPC64" + "@ + mulld %0,%1,%2 + mulli %0,%1,%2" + [(set (attr "type") + (cond [(match_operand:SI 2 "s8bit_cint_operand" "") + (const_string "imul3") + (match_operand:SI 2 "short_cint_operand" "") + (const_string "imul2")] + (const_string "lmul")))]) + +(define_insn "*muldi3_internal1" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (mult:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r") + (match_operand:DI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r"))] + "TARGET_POWERPC64" + "@ + mulld. %3,%1,%2 + #" + [(set_attr "type" "lmul_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (mult:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (mult:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*muldi3_internal2" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (mult:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r") + (match_operand:DI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (mult:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64" + "@ + mulld. %0,%1,%2 + #" + [(set_attr "type" "lmul_compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (mult:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (mult:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (mult:DI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "smuldi3_highpart" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (truncate:DI + (lshiftrt:TI (mult:TI (sign_extend:TI + (match_operand:DI 1 "gpc_reg_operand" "%r")) + (sign_extend:TI + (match_operand:DI 2 "gpc_reg_operand" "r"))) + (const_int 64))))] + "TARGET_POWERPC64" + "mulhd %0,%1,%2" + [(set_attr "type" "lmul")]) + +(define_insn "umuldi3_highpart" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (truncate:DI + (lshiftrt:TI (mult:TI (zero_extend:TI + (match_operand:DI 1 "gpc_reg_operand" "%r")) + (zero_extend:TI + (match_operand:DI 2 "gpc_reg_operand" "r"))) + (const_int 64))))] + "TARGET_POWERPC64" + "mulhdu %0,%1,%2" + [(set_attr "type" "lmul")]) + +(define_insn "rotldi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i")))] + "TARGET_POWERPC64" + "@ + rldcl %0,%1,%2,0 + rldicl %0,%1,%H2,0" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotldi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r"))] + "TARGET_64BIT" + "@ + rldcl. %3,%1,%2,0 + rldicl. %3,%1,%H2,0 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (rotate:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (rotate:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT" + "@ + rldcl. %0,%1,%2,0 + rldicl. %0,%1,%H2,0 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (rotate:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (rotate:DI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal4" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (and:DI (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i")) + (match_operand:DI 3 "mask64_operand" "n,n")))] + "TARGET_POWERPC64" + "@ + rldc%B3 %0,%1,%2,%S3 + rldic%B3 %0,%1,%H2,%S3" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotldi3_internal5" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (and:DI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) + (match_operand:DI 3 "mask64_operand" "n,n,n,n")) + (const_int 0))) + (clobber (match_scratch:DI 4 "=r,r,r,r"))] + "TARGET_64BIT" + "@ + rldc%B3. %4,%1,%2,%S3 + rldic%B3. %4,%1,%H2,%S3 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (and:DI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) + (match_operand:DI 3 "mask64_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 4 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 4) + (and:DI (rotate:DI (match_dup 1) + (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal6" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (and:DI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) + (match_operand:DI 3 "mask64_operand" "n,n,n,n")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (and:DI (rotate:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_64BIT" + "@ + rldc%B3. %0,%1,%2,%S3 + rldic%B3. %0,%1,%H2,%S3 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (and:DI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) + (match_operand:DI 3 "mask64_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (and:DI (rotate:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (and:DI (rotate:DI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal7" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI + (subreg:QI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i")) 0)))] + "TARGET_POWERPC64" + "@ + rldcl %0,%1,%2,56 + rldicl %0,%1,%H2,56" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotldi3_internal8" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:DI + (subreg:QI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r"))] + "TARGET_64BIT" + "@ + rldcl. %3,%1,%2,56 + rldicl. %3,%1,%H2,56 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI + (subreg:QI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (zero_extend:DI (subreg:QI + (rotate:DI (match_dup 1) + (match_dup 2)) 0))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal9" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:DI + (subreg:QI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (zero_extend:DI (subreg:QI (rotate:DI (match_dup 1) (match_dup 2)) 0)))] + "TARGET_64BIT" + "@ + rldcl. %0,%1,%2,56 + rldicl. %0,%1,%H2,56 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI + (subreg:QI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (zero_extend:DI (subreg:QI (rotate:DI (match_dup 1) (match_dup 2)) 0)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:QI (rotate:DI (match_dup 1) (match_dup 2)) 0))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal10" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI + (subreg:HI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i")) 0)))] + "TARGET_POWERPC64" + "@ + rldcl %0,%1,%2,48 + rldicl %0,%1,%H2,48" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotldi3_internal11" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:DI + (subreg:HI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r"))] + "TARGET_64BIT" + "@ + rldcl. %3,%1,%2,48 + rldicl. %3,%1,%H2,48 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI + (subreg:HI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (zero_extend:DI (subreg:HI + (rotate:DI (match_dup 1) + (match_dup 2)) 0))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal12" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:DI + (subreg:HI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (zero_extend:DI (subreg:HI (rotate:DI (match_dup 1) (match_dup 2)) 0)))] + "TARGET_64BIT" + "@ + rldcl. %0,%1,%2,48 + rldicl. %0,%1,%H2,48 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI + (subreg:HI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (zero_extend:DI (subreg:HI (rotate:DI (match_dup 1) (match_dup 2)) 0)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:HI (rotate:DI (match_dup 1) (match_dup 2)) 0))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal13" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (zero_extend:DI + (subreg:SI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i")) 0)))] + "TARGET_POWERPC64" + "@ + rldcl %0,%1,%2,32 + rldicl %0,%1,%H2,32" + [(set_attr "type" "var_shift_rotate,integer")]) + +(define_insn "*rotldi3_internal14" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:DI + (subreg:SI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r"))] + "TARGET_64BIT" + "@ + rldcl. %3,%1,%2,32 + rldicl. %3,%1,%H2,32 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI + (subreg:SI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (zero_extend:DI (subreg:SI + (rotate:DI (match_dup 1) + (match_dup 2)) 0))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*rotldi3_internal15" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (zero_extend:DI + (subreg:SI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:DI 2 "reg_or_cint_operand" "r,i,r,i")) 0)) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (zero_extend:DI (subreg:SI (rotate:DI (match_dup 1) (match_dup 2)) 0)))] + "TARGET_64BIT" + "@ + rldcl. %0,%1,%2,32 + rldicl. %0,%1,%H2,32 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (zero_extend:DI + (subreg:SI + (rotate:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_cint_operand" "")) 0)) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (zero_extend:DI (subreg:SI (rotate:DI (match_dup 1) (match_dup 2)) 0)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (zero_extend:DI (subreg:SI (rotate:DI (match_dup 1) (match_dup 2)) 0))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "ashldi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")))] + "TARGET_POWERPC64 || TARGET_POWER" + " +{ + if (TARGET_POWERPC64) + ; + else if (TARGET_POWER) + { + emit_insn (gen_ashldi3_power (operands[0], operands[1], operands[2])); + DONE; + } + else + FAIL; +}") + +(define_insn "*ashldi3_internal1" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")))] + "TARGET_POWERPC64" + "@ + sld %0,%1,%2 + sldi %0,%1,%H2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "*ashldi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r"))] + "TARGET_64BIT" + "@ + sld. %3,%1,%2 + sldi. %3,%1,%H2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (ashift:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*ashldi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (ashift:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT" + "@ + sld. %0,%1,%2 + sldi. %0,%1,%H2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (ashift:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (ashift:DI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*ashldi3_internal4" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:DI 3 "const_int_operand" "n")))] + "TARGET_POWERPC64 && includes_rldic_lshift_p (operands[2], operands[3])" + "rldic %0,%1,%H2,%W3") + +(define_insn "ashldi3_internal5" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:DI 3 "const_int_operand" "n,n")) + (const_int 0))) + (clobber (match_scratch:DI 4 "=r,r"))] + "TARGET_64BIT && includes_rldic_lshift_p (operands[2], operands[3])" + "@ + rldic. %4,%1,%H2,%W3 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:DI 3 "const_int_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 4 ""))] + "TARGET_POWERPC64 && reload_completed + && includes_rldic_lshift_p (operands[2], operands[3])" + [(set (match_dup 4) + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "*ashldi3_internal6" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:DI 3 "const_int_operand" "n,n")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_64BIT && includes_rldic_lshift_p (operands[2], operands[3])" + "@ + rldic. %0,%1,%H2,%W3 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:DI 3 "const_int_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWERPC64 && reload_completed + && includes_rldic_lshift_p (operands[2], operands[3])" + [(set (match_dup 0) + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*ashldi3_internal7" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "const_int_operand" "i")) + (match_operand:DI 3 "mask64_operand" "n")))] + "TARGET_POWERPC64 && includes_rldicr_lshift_p (operands[2], operands[3])" + "rldicr %0,%1,%H2,%S3") + +(define_insn "ashldi3_internal8" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:DI 3 "mask64_operand" "n,n")) + (const_int 0))) + (clobber (match_scratch:DI 4 "=r,r"))] + "TARGET_64BIT && includes_rldicr_lshift_p (operands[2], operands[3])" + "@ + rldicr. %4,%1,%H2,%S3 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:DI 3 "mask64_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 4 ""))] + "TARGET_POWERPC64 && reload_completed + && includes_rldicr_lshift_p (operands[2], operands[3])" + [(set (match_dup 4) + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "*ashldi3_internal9" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "const_int_operand" "i,i")) + (match_operand:DI 3 "mask64_operand" "n,n")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_64BIT && includes_rldicr_lshift_p (operands[2], operands[3])" + "@ + rldicr. %0,%1,%H2,%S3 + #" + [(set_attr "type" "compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (and:DI (ashift:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "const_int_operand" "")) + (match_operand:DI 3 "mask64_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWERPC64 && reload_completed + && includes_rldicr_lshift_p (operands[2], operands[3])" + [(set (match_dup 0) + (and:DI (ashift:DI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "lshrdi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")))] + "TARGET_POWERPC64 || TARGET_POWER" + " +{ + if (TARGET_POWERPC64) + ; + else if (TARGET_POWER) + { + emit_insn (gen_lshrdi3_power (operands[0], operands[1], operands[2])); + DONE; + } + else + FAIL; +}") + +(define_insn "*lshrdi3_internal1" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")))] + "TARGET_POWERPC64" + "@ + srd %0,%1,%2 + srdi %0,%1,%H2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "*lshrdi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r"))] + "TARGET_64BIT " + "@ + srd. %3,%1,%2 + srdi. %3,%1,%H2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (lshiftrt:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*lshrdi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (lshiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT" + "@ + srd. %0,%1,%2 + srdi. %0,%1,%H2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (lshiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (lshiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (lshiftrt:DI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "ashrdi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")))] + "WORDS_BIG_ENDIAN" + " +{ + if (TARGET_POWERPC64) + ; + else if (TARGET_POWER && GET_CODE (operands[2]) == CONST_INT) + { + emit_insn (gen_ashrdi3_power (operands[0], operands[1], operands[2])); + DONE; + } + else if (TARGET_32BIT && GET_CODE (operands[2]) == CONST_INT + && WORDS_BIG_ENDIAN) + { + emit_insn (gen_ashrdi3_no_power (operands[0], operands[1], operands[2])); + DONE; + } + else + FAIL; +}") + +(define_insn "*ashrdi3_internal1" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i")))] + "TARGET_POWERPC64" + "@ + srad %0,%1,%2 + sradi %0,%1,%H2" + [(set_attr "type" "var_shift_rotate,shift")]) + +(define_insn "*ashrdi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r"))] + "TARGET_64BIT" + "@ + srad. %3,%1,%2 + sradi. %3,%1,%H2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) + (ashiftrt:DI (match_dup 1) (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*ashrdi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,i,r,i")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (ashiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_64BIT" + "@ + srad. %0,%1,%2 + sradi. %0,%1,%H2 + # + #" + [(set_attr "type" "var_delayed_compare,delayed_compare,var_delayed_compare,delayed_compare") + (set_attr "length" "4,4,8,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC (ashiftrt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_cint_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (ashiftrt:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) + (ashiftrt:DI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "anddi3" + [(parallel + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (and:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "and64_2_operand" ""))) + (clobber (match_scratch:CC 3 ""))])] + "TARGET_POWERPC64" + "") + +(define_insn "anddi3_mc" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r,r") + (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r") + (match_operand:DI 2 "and64_2_operand" "?r,S,T,K,J,t"))) + (clobber (match_scratch:CC 3 "=X,X,X,x,x,X"))] + "TARGET_POWERPC64 && rs6000_gen_cell_microcode" + "@ + and %0,%1,%2 + rldic%B2 %0,%1,0,%S2 + rlwinm %0,%1,0,%m2,%M2 + andi. %0,%1,%b2 + andis. %0,%1,%u2 + #" + [(set_attr "type" "*,*,*,fast_compare,fast_compare,*") + (set_attr "length" "4,4,4,4,4,8")]) + +(define_insn "anddi3_nomc" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r") + (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r") + (match_operand:DI 2 "and64_2_operand" "?r,S,T,t"))) + (clobber (match_scratch:CC 3 "=X,X,X,X"))] + "TARGET_POWERPC64 && !rs6000_gen_cell_microcode" + "@ + and %0,%1,%2 + rldic%B2 %0,%1,0,%S2 + rlwinm %0,%1,0,%m2,%M2 + #" + [(set_attr "length" "4,4,4,8")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (and:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "mask64_2_operand" ""))) + (clobber (match_scratch:CC 3 ""))] + "TARGET_POWERPC64 + && (fixed_regs[CR0_REGNO] || !logical_operand (operands[2], DImode)) + && !mask_operand (operands[2], DImode) + && !mask64_operand (operands[2], DImode)" + [(set (match_dup 0) + (and:DI (rotate:DI (match_dup 1) + (match_dup 4)) + (match_dup 5))) + (set (match_dup 0) + (and:DI (rotate:DI (match_dup 0) + (match_dup 6)) + (match_dup 7)))] +{ + build_mask64_2_operands (operands[2], &operands[4]); +}) + +(define_insn "*anddi3_internal2_mc" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,x,x,?y,?y,?y,??y,??y,?y") + (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r,r,r") + (match_operand:DI 2 "and64_2_operand" "r,S,T,K,J,t,r,S,T,K,J,t")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r,r,r,r,r,r,r,r,r,r,r")) + (clobber (match_scratch:CC 4 "=X,X,X,X,X,X,X,X,X,x,x,X"))] + "TARGET_64BIT && rs6000_gen_cell_microcode" + "@ + and. %3,%1,%2 + rldic%B2. %3,%1,0,%S2 + rlwinm. %3,%1,0,%m2,%M2 + andi. %3,%1,%b2 + andis. %3,%1,%u2 + # + # + # + # + # + # + #" + [(set_attr "type" "fast_compare,compare,delayed_compare,fast_compare,\ + fast_compare,compare,compare,compare,compare,compare,\ + compare,compare") + (set_attr "length" "4,4,4,4,4,8,8,8,8,8,8,12")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_operand" "") + (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "mask64_2_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 "")) + (clobber (match_scratch:CC 4 ""))] + "TARGET_64BIT && reload_completed + && (fixed_regs[CR0_REGNO] || !logical_operand (operands[2], DImode)) + && !mask_operand (operands[2], DImode) + && !mask64_operand (operands[2], DImode)" + [(set (match_dup 3) + (and:DI (rotate:DI (match_dup 1) + (match_dup 5)) + (match_dup 6))) + (parallel [(set (match_dup 0) + (compare:CC (and:DI (rotate:DI (match_dup 3) + (match_dup 7)) + (match_dup 8)) + (const_int 0))) + (clobber (match_dup 3))])] + " +{ + build_mask64_2_operands (operands[2], &operands[5]); +}") + +(define_insn "*anddi3_internal3_mc" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,x,x,x,x,?y,?y,?y,??y,??y,?y") + (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r,r,r") + (match_operand:DI 2 "and64_2_operand" "r,S,T,K,J,t,r,S,T,K,J,t")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r,r,r,r,r,r,r,r,r,r") + (and:DI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:CC 4 "=X,X,X,X,X,X,X,X,X,x,x,X"))] + "TARGET_64BIT && rs6000_gen_cell_microcode" + "@ + and. %0,%1,%2 + rldic%B2. %0,%1,0,%S2 + rlwinm. %0,%1,0,%m2,%M2 + andi. %0,%1,%b2 + andis. %0,%1,%u2 + # + # + # + # + # + # + #" + [(set_attr "type" "fast_compare,compare,delayed_compare,fast_compare,\ + fast_compare,compare,compare,compare,compare,compare,\ + compare,compare") + (set_attr "length" "4,4,4,4,4,8,8,8,8,8,8,12")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "and64_2_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (and:DI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:CC 4 ""))] + "TARGET_64BIT && reload_completed" + [(parallel [(set (match_dup 0) + (and:DI (match_dup 1) (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_split + [(set (match_operand:CC 3 "cc_reg_operand" "") + (compare:CC (and:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "mask64_2_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (and:DI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:CC 4 ""))] + "TARGET_64BIT && reload_completed + && (fixed_regs[CR0_REGNO] || !logical_operand (operands[2], DImode)) + && !mask_operand (operands[2], DImode) + && !mask64_operand (operands[2], DImode)" + [(set (match_dup 0) + (and:DI (rotate:DI (match_dup 1) + (match_dup 5)) + (match_dup 6))) + (parallel [(set (match_dup 3) + (compare:CC (and:DI (rotate:DI (match_dup 0) + (match_dup 7)) + (match_dup 8)) + (const_int 0))) + (set (match_dup 0) + (and:DI (rotate:DI (match_dup 0) + (match_dup 7)) + (match_dup 8)))])] + " +{ + build_mask64_2_operands (operands[2], &operands[5]); +}") + +(define_expand "iordi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (ior:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_logical_cint_operand" "")))] + "TARGET_POWERPC64" + " +{ + if (non_logical_cint_operand (operands[2], DImode)) + { + HOST_WIDE_INT value; + rtx tmp = ((!can_create_pseudo_p () + || rtx_equal_p (operands[0], operands[1])) + ? operands[0] : gen_reg_rtx (DImode)); + + if (GET_CODE (operands[2]) == CONST_INT) + { + value = INTVAL (operands[2]); + emit_insn (gen_iordi3 (tmp, operands[1], + GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff)))); + } + else + { + value = CONST_DOUBLE_LOW (operands[2]); + emit_insn (gen_iordi3 (tmp, operands[1], + immed_double_const (value + & (~ (HOST_WIDE_INT) 0xffff), + 0, DImode))); + } + + emit_insn (gen_iordi3 (operands[0], tmp, GEN_INT (value & 0xffff))); + DONE; + } +}") + +(define_expand "xordi3" + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (xor:DI (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "reg_or_logical_cint_operand" "")))] + "TARGET_POWERPC64" + " +{ + if (non_logical_cint_operand (operands[2], DImode)) + { + HOST_WIDE_INT value; + rtx tmp = ((!can_create_pseudo_p () + || rtx_equal_p (operands[0], operands[1])) + ? operands[0] : gen_reg_rtx (DImode)); + + if (GET_CODE (operands[2]) == CONST_INT) + { + value = INTVAL (operands[2]); + emit_insn (gen_xordi3 (tmp, operands[1], + GEN_INT (value & (~ (HOST_WIDE_INT) 0xffff)))); + } + else + { + value = CONST_DOUBLE_LOW (operands[2]); + emit_insn (gen_xordi3 (tmp, operands[1], + immed_double_const (value + & (~ (HOST_WIDE_INT) 0xffff), + 0, DImode))); + } + + emit_insn (gen_xordi3 (operands[0], tmp, GEN_INT (value & 0xffff))); + DONE; + } +}") + +(define_insn "*booldi3_internal1" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r,r,r") + (match_operator:DI 3 "boolean_or_operator" + [(match_operand:DI 1 "gpc_reg_operand" "%r,r,r") + (match_operand:DI 2 "logical_operand" "r,K,JF")]))] + "TARGET_POWERPC64" + "@ + %q3 %0,%1,%2 + %q3i %0,%1,%b2 + %q3is %0,%1,%u2") + +(define_insn "*booldi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:DI 4 "boolean_or_operator" + [(match_operand:DI 1 "gpc_reg_operand" "%r,r") + (match_operand:DI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r"))] + "TARGET_64BIT" + "@ + %q4. %3,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*booldi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:DI 4 "boolean_or_operator" + [(match_operand:DI 1 "gpc_reg_operand" "%r,r") + (match_operand:DI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (match_dup 4))] + "TARGET_64BIT" + "@ + %q4. %0,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (match_dup 4))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +;; Split a logical operation that we can't do in one insn into two insns, +;; each of which does one 16-bit part. This is used by combine. + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operator:DI 3 "boolean_or_operator" + [(match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "non_logical_cint_operand" "")]))] + "TARGET_POWERPC64" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 0) (match_dup 5))] +" +{ + rtx i3,i4; + + if (GET_CODE (operands[2]) == CONST_DOUBLE) + { + HOST_WIDE_INT value = CONST_DOUBLE_LOW (operands[2]); + i3 = immed_double_const (value & (~ (HOST_WIDE_INT) 0xffff), + 0, DImode); + i4 = GEN_INT (value & 0xffff); + } + else + { + i3 = GEN_INT (INTVAL (operands[2]) + & (~ (HOST_WIDE_INT) 0xffff)); + i4 = GEN_INT (INTVAL (operands[2]) & 0xffff); + } + operands[4] = gen_rtx_fmt_ee (GET_CODE (operands[3]), DImode, + operands[1], i3); + operands[5] = gen_rtx_fmt_ee (GET_CODE (operands[3]), DImode, + operands[0], i4); +}") + +(define_insn "*boolcdi3_internal1" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (match_operator:DI 3 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "r")) + (match_operand:DI 2 "gpc_reg_operand" "r")]))] + "TARGET_POWERPC64" + "%q3 %0,%2,%1") + +(define_insn "*boolcdi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")) + (match_operand:DI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r"))] + "TARGET_64BIT" + "@ + %q4. %3,%2,%1 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "")) + (match_operand:DI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*boolcdi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r")) + (match_operand:DI 2 "gpc_reg_operand" "r,r")]) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (match_dup 4))] + "TARGET_64BIT" + "@ + %q4. %0,%2,%1 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "")) + (match_operand:DI 2 "gpc_reg_operand" "")]) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (match_dup 4))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*boolccdi3_internal1" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (match_operator:DI 3 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "r")) + (not:DI (match_operand:DI 2 "gpc_reg_operand" "r"))]))] + "TARGET_POWERPC64" + "%q3 %0,%1,%2") + +(define_insn "*boolccdi3_internal2" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "r,r")) + (not:DI (match_operand:DI 2 "gpc_reg_operand" "r,r"))]) + (const_int 0))) + (clobber (match_scratch:DI 3 "=r,r"))] + "TARGET_64BIT" + "@ + %q4. %3,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "")) + (not:DI (match_operand:DI 2 "gpc_reg_operand" ""))]) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 3) (match_dup 4)) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*boolccdi3_internal3" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "%r,r")) + (not:DI (match_operand:DI 2 "gpc_reg_operand" "r,r"))]) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (match_dup 4))] + "TARGET_64BIT" + "@ + %q4. %0,%1,%2 + #" + [(set_attr "type" "fast_compare,compare") + (set_attr "length" "4,8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operator:DI 4 "boolean_operator" + [(not:DI (match_operand:DI 1 "gpc_reg_operand" "")) + (not:DI (match_operand:DI 2 "gpc_reg_operand" ""))]) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (match_dup 4))] + "TARGET_POWERPC64 && reload_completed" + [(set (match_dup 0) (match_dup 4)) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_expand "smindi3" + [(match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")] + "TARGET_ISEL64" + " +{ + rs6000_emit_minmax (operands[0], SMIN, operands[1], operands[2]); + DONE; +}") + +(define_expand "smaxdi3" + [(match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")] + "TARGET_ISEL64" + " +{ + rs6000_emit_minmax (operands[0], SMAX, operands[1], operands[2]); + DONE; +}") + +(define_expand "umindi3" + [(match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")] + "TARGET_ISEL64" + " +{ + rs6000_emit_minmax (operands[0], UMIN, operands[1], operands[2]); + DONE; +}") + +(define_expand "umaxdi3" + [(match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "gpc_reg_operand" "") + (match_operand:DI 2 "gpc_reg_operand" "")] + "TARGET_ISEL64" + " +{ + rs6000_emit_minmax (operands[0], UMAX, operands[1], operands[2]); + DONE; +}") + + +;; Now define ways of moving data around. + +;; Set up a register with a value from the GOT table + +(define_expand "movsi_got" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (unspec:SI [(match_operand:SI 1 "got_operand" "") + (match_dup 2)] UNSPEC_MOVSI_GOT))] + "DEFAULT_ABI == ABI_V4 && flag_pic == 1" + " +{ + if (GET_CODE (operands[1]) == CONST) + { + rtx offset = const0_rtx; + HOST_WIDE_INT value; + + operands[1] = eliminate_constant_term (XEXP (operands[1], 0), &offset); + value = INTVAL (offset); + if (value != 0) + { + rtx tmp = (!can_create_pseudo_p () + ? operands[0] + : gen_reg_rtx (Pmode)); + emit_insn (gen_movsi_got (tmp, operands[1])); + emit_insn (gen_addsi3 (operands[0], tmp, offset)); + DONE; + } + } + + operands[2] = rs6000_got_register (operands[1]); +}") + +(define_insn "*movsi_got_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec:SI [(match_operand:SI 1 "got_no_const_operand" "") + (match_operand:SI 2 "gpc_reg_operand" "b")] + UNSPEC_MOVSI_GOT))] + "DEFAULT_ABI == ABI_V4 && flag_pic == 1" + "{l|lwz} %0,%a1@got(%2)" + [(set_attr "type" "load")]) + +;; Used by sched, shorten_branches and final when the GOT pseudo reg +;; didn't get allocated to a hard register. +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (unspec:SI [(match_operand:SI 1 "got_no_const_operand" "") + (match_operand:SI 2 "memory_operand" "")] + UNSPEC_MOVSI_GOT))] + "DEFAULT_ABI == ABI_V4 + && flag_pic == 1 + && (reload_in_progress || reload_completed)" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (unspec:SI [(match_dup 1)(match_dup 0)] + UNSPEC_MOVSI_GOT))] + "") + +;; For SI, we special-case integers that can't be loaded in one insn. We +;; do the load 16-bits at a time. We could do this by loading from memory, +;; and this is even supposed to be faster, but it is simpler not to get +;; integers in the TOC. +(define_insn "movsi_low" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mem:SI (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (match_operand 2 "" ""))))] + "TARGET_MACHO && ! TARGET_64BIT" + "{l|lwz} %0,lo16(%2)(%1)" + [(set_attr "type" "load") + (set_attr "length" "4")]) + +(define_insn "*movsi_internal1" + [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h") + (match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0"))] + "!TARGET_SINGLE_FPU && + (gpc_reg_operand (operands[0], SImode) || gpc_reg_operand (operands[1], SImode))" + "@ + mr %0,%1 + {cal|la} %0,%a1 + {l%U1%X1|lwz%U1%X1} %0,%1 + {st%U0%X0|stw%U0%X0} %1,%0 + {lil|li} %0,%1 + {liu|lis} %0,%v1 + # + {cal|la} %0,%a1 + mf%1 %0 + mt%0 %1 + mt%0 %1 + mt%0 %1 + {cror 0,0,0|nop}" + [(set_attr "type" "*,*,load,store,*,*,*,*,mfjmpr,*,mtjmpr,*,*") + (set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4,4")]) + +(define_insn "*movsi_internal1_single" + [(set (match_operand:SI 0 "rs6000_nonimmediate_operand" "=r,r,r,m,r,r,r,r,r,*q,*c*l,*h,*h,m,*f") + (match_operand:SI 1 "input_operand" "r,U,m,r,I,L,n,R,*h,r,r,r,0,f,m"))] + "TARGET_SINGLE_FPU && + (gpc_reg_operand (operands[0], SImode) || gpc_reg_operand (operands[1], SImode))" + "@ + mr %0,%1 + {cal|la} %0,%a1 + {l%U1%X1|lwz%U1%X1} %0,%1 + {st%U0%X0|stw%U0%X0} %1,%0 + {lil|li} %0,%1 + {liu|lis} %0,%v1 + # + {cal|la} %0,%a1 + mf%1 %0 + mt%0 %1 + mt%0 %1 + mt%0 %1 + {cror 0,0,0|nop} + stfs%U0%X0 %1, %0 + lfs%U1%X1 %0, %1" + [(set_attr "type" "*,*,load,store,*,*,*,*,mfjmpr,*,mtjmpr,*,*,*,*") + (set_attr "length" "4,4,4,4,4,4,8,4,4,4,4,4,4,4,4")]) + +;; Split a load of a large constant into the appropriate two-insn +;; sequence. + +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (match_operand:SI 1 "const_int_operand" ""))] + "(unsigned HOST_WIDE_INT) (INTVAL (operands[1]) + 0x8000) >= 0x10000 + && (INTVAL (operands[1]) & 0xffff) != 0" + [(set (match_dup 0) + (match_dup 2)) + (set (match_dup 0) + (ior:SI (match_dup 0) + (match_dup 3)))] + " +{ rtx tem = rs6000_emit_set_const (operands[0], SImode, operands[1], 2); + + if (tem == operands[0]) + DONE; + else + FAIL; +}") + +(define_insn "*mov<mode>_internal2" + [(set (match_operand:CC 2 "cc_reg_operand" "=y,x,?y") + (compare:CC (match_operand:P 1 "gpc_reg_operand" "0,r,r") + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r,r") (match_dup 1))] + "" + "@ + {cmpi|cmp<wd>i} %2,%0,0 + mr. %0,%1 + #" + [(set_attr "type" "cmp,compare,cmp") + (set_attr "length" "4,4,8")]) + +(define_split + [(set (match_operand:CC 2 "cc_reg_not_micro_cr0_operand" "") + (compare:CC (match_operand:P 1 "gpc_reg_operand" "") + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "") (match_dup 1))] + "reload_completed" + [(set (match_dup 0) (match_dup 1)) + (set (match_dup 2) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*movhi_internal" + [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,m,r,r,*q,*c*l,*h") + (match_operand:HI 1 "input_operand" "r,m,r,i,*h,r,r,0"))] + "gpc_reg_operand (operands[0], HImode) + || gpc_reg_operand (operands[1], HImode)" + "@ + mr %0,%1 + lhz%U1%X1 %0,%1 + sth%U0%X0 %1,%0 + {lil|li} %0,%w1 + mf%1 %0 + mt%0 %1 + mt%0 %1 + {cror 0,0,0|nop}" + [(set_attr "type" "*,load,store,*,mfjmpr,*,mtjmpr,*")]) + +(define_expand "mov<mode>" + [(set (match_operand:INT 0 "general_operand" "") + (match_operand:INT 1 "any_operand" ""))] + "" + "{ rs6000_emit_move (operands[0], operands[1], <MODE>mode); DONE; }") + +(define_insn "*movqi_internal" + [(set (match_operand:QI 0 "nonimmediate_operand" "=r,r,m,r,r,*q,*c*l,*h") + (match_operand:QI 1 "input_operand" "r,m,r,i,*h,r,r,0"))] + "gpc_reg_operand (operands[0], QImode) + || gpc_reg_operand (operands[1], QImode)" + "@ + mr %0,%1 + lbz%U1%X1 %0,%1 + stb%U0%X0 %1,%0 + {lil|li} %0,%1 + mf%1 %0 + mt%0 %1 + mt%0 %1 + {cror 0,0,0|nop}" + [(set_attr "type" "*,load,store,*,mfjmpr,*,mtjmpr,*")]) + +;; Here is how to move condition codes around. When we store CC data in +;; an integer register or memory, we store just the high-order 4 bits. +;; This lets us not shift in the most common case of CR0. +(define_expand "movcc" + [(set (match_operand:CC 0 "nonimmediate_operand" "") + (match_operand:CC 1 "nonimmediate_operand" ""))] + "" + "") + +(define_insn "*movcc_internal1" + [(set (match_operand:CC 0 "nonimmediate_operand" "=y,x,?y,y,r,r,r,r,r,q,cl,r,m") + (match_operand:CC 1 "general_operand" "y,r,r,O,x,y,r,I,h,r,r,m,r"))] + "register_operand (operands[0], CCmode) + || register_operand (operands[1], CCmode)" + "@ + mcrf %0,%1 + mtcrf 128,%1 + {rlinm|rlwinm} %1,%1,%F0,0xffffffff\;mtcrf %R0,%1\;{rlinm|rlwinm} %1,%1,%f0,0xffffffff + crxor %0,%0,%0 + mfcr %0%Q1 + mfcr %0%Q1\;{rlinm|rlwinm} %0,%0,%f1,0xf0000000 + mr %0,%1 + {lil|li} %0,%1 + mf%1 %0 + mt%0 %1 + mt%0 %1 + {l%U1%X1|lwz%U1%X1} %0,%1 + {st%U0%U1|stw%U0%U1} %1,%0" + [(set (attr "type") + (cond [(eq_attr "alternative" "0,3") + (const_string "cr_logical") + (eq_attr "alternative" "1,2") + (const_string "mtcr") + (eq_attr "alternative" "6,7,9") + (const_string "integer") + (eq_attr "alternative" "8") + (const_string "mfjmpr") + (eq_attr "alternative" "10") + (const_string "mtjmpr") + (eq_attr "alternative" "11") + (const_string "load") + (eq_attr "alternative" "12") + (const_string "store") + (ne (symbol_ref "TARGET_MFCRF") (const_int 0)) + (const_string "mfcrf") + ] + (const_string "mfcr"))) + (set_attr "length" "4,4,12,4,4,8,4,4,4,4,4,4,4")]) + +;; For floating-point, we normally deal with the floating-point registers +;; unless -msoft-float is used. The sole exception is that parameter passing +;; can produce floating-point values in fixed-point registers. Unless the +;; value is a simple constant or already in memory, we deal with this by +;; allocating memory and copying the value explicitly via that memory location. +(define_expand "movsf" + [(set (match_operand:SF 0 "nonimmediate_operand" "") + (match_operand:SF 1 "any_operand" ""))] + "" + "{ rs6000_emit_move (operands[0], operands[1], SFmode); DONE; }") + +(define_split + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (match_operand:SF 1 "const_double_operand" ""))] + "reload_completed + && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31) + || (GET_CODE (operands[0]) == SUBREG + && GET_CODE (SUBREG_REG (operands[0])) == REG + && REGNO (SUBREG_REG (operands[0])) <= 31))" + [(set (match_dup 2) (match_dup 3))] + " +{ + long l; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_SINGLE (rv, l); + + if (! TARGET_POWERPC64) + operands[2] = operand_subword (operands[0], 0, 0, SFmode); + else + operands[2] = gen_lowpart (SImode, operands[0]); + + operands[3] = gen_int_mode (l, SImode); +}") + +(define_insn "*movsf_hardfloat" + [(set (match_operand:SF 0 "nonimmediate_operand" "=!r,!r,m,f,f,m,*c*l,*q,!r,*h,!r,!r") + (match_operand:SF 1 "input_operand" "r,m,r,f,m,f,r,r,h,0,G,Fn"))] + "(gpc_reg_operand (operands[0], SFmode) + || gpc_reg_operand (operands[1], SFmode)) + && (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT)" + "@ + mr %0,%1 + {l%U1%X1|lwz%U1%X1} %0,%1 + {st%U0%X0|stw%U0%X0} %1,%0 + fmr %0,%1 + lfs%U1%X1 %0,%1 + stfs%U0%X0 %1,%0 + mt%0 %1 + mt%0 %1 + mf%1 %0 + {cror 0,0,0|nop} + # + #" + [(set_attr "type" "*,load,store,fp,fpload,fpstore,mtjmpr,*,mfjmpr,*,*,*") + (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,8")]) + +(define_insn "*movsf_softfloat" + [(set (match_operand:SF 0 "nonimmediate_operand" "=r,cl,q,r,r,m,r,r,r,r,r,*h") + (match_operand:SF 1 "input_operand" "r,r,r,h,m,r,I,L,R,G,Fn,0"))] + "(gpc_reg_operand (operands[0], SFmode) + || gpc_reg_operand (operands[1], SFmode)) + && (TARGET_SOFT_FLOAT || !TARGET_FPRS)" + "@ + mr %0,%1 + mt%0 %1 + mt%0 %1 + mf%1 %0 + {l%U1%X1|lwz%U1%X1} %0,%1 + {st%U0%X0|stw%U0%X0} %1,%0 + {lil|li} %0,%1 + {liu|lis} %0,%v1 + {cal|la} %0,%a1 + # + # + {cror 0,0,0|nop}" + [(set_attr "type" "*,mtjmpr,*,mfjmpr,load,store,*,*,*,*,*,*") + (set_attr "length" "4,4,4,4,4,4,4,4,4,4,8,4")]) + + +(define_expand "movdf" + [(set (match_operand:DF 0 "nonimmediate_operand" "") + (match_operand:DF 1 "any_operand" ""))] + "" + "{ rs6000_emit_move (operands[0], operands[1], DFmode); DONE; }") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "const_int_operand" ""))] + "! TARGET_POWERPC64 && reload_completed + && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31) + || (GET_CODE (operands[0]) == SUBREG + && GET_CODE (SUBREG_REG (operands[0])) == REG + && REGNO (SUBREG_REG (operands[0])) <= 31))" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 1))] + " +{ + int endian = (WORDS_BIG_ENDIAN == 0); + HOST_WIDE_INT value = INTVAL (operands[1]); + + operands[2] = operand_subword (operands[0], endian, 0, DFmode); + operands[3] = operand_subword (operands[0], 1 - endian, 0, DFmode); +#if HOST_BITS_PER_WIDE_INT == 32 + operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx; +#else + operands[4] = GEN_INT (value >> 32); + operands[1] = GEN_INT (((value & 0xffffffff) ^ 0x80000000) - 0x80000000); +#endif +}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "const_double_operand" ""))] + "! TARGET_POWERPC64 && reload_completed + && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31) + || (GET_CODE (operands[0]) == SUBREG + && GET_CODE (SUBREG_REG (operands[0])) == REG + && REGNO (SUBREG_REG (operands[0])) <= 31))" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + int endian = (WORDS_BIG_ENDIAN == 0); + long l[2]; + REAL_VALUE_TYPE rv; + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_DOUBLE (rv, l); + + operands[2] = operand_subword (operands[0], endian, 0, DFmode); + operands[3] = operand_subword (operands[0], 1 - endian, 0, DFmode); + operands[4] = gen_int_mode (l[endian], SImode); + operands[5] = gen_int_mode (l[1 - endian], SImode); +}") + +(define_split + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "const_double_operand" ""))] + "TARGET_POWERPC64 && reload_completed + && ((GET_CODE (operands[0]) == REG && REGNO (operands[0]) <= 31) + || (GET_CODE (operands[0]) == SUBREG + && GET_CODE (SUBREG_REG (operands[0])) == REG + && REGNO (SUBREG_REG (operands[0])) <= 31))" + [(set (match_dup 2) (match_dup 3))] + " +{ + int endian = (WORDS_BIG_ENDIAN == 0); + long l[2]; + REAL_VALUE_TYPE rv; +#if HOST_BITS_PER_WIDE_INT >= 64 + HOST_WIDE_INT val; +#endif + + REAL_VALUE_FROM_CONST_DOUBLE (rv, operands[1]); + REAL_VALUE_TO_TARGET_DOUBLE (rv, l); + + operands[2] = gen_lowpart (DImode, operands[0]); + /* HIGHPART is lower memory address when WORDS_BIG_ENDIAN. */ +#if HOST_BITS_PER_WIDE_INT >= 64 + val = ((HOST_WIDE_INT)(unsigned long)l[endian] << 32 + | ((HOST_WIDE_INT)(unsigned long)l[1 - endian])); + + operands[3] = gen_int_mode (val, DImode); +#else + operands[3] = immed_double_const (l[1 - endian], l[endian], DImode); +#endif +}") + +;; Don't have reload use general registers to load a constant. First, +;; it might not work if the output operand is the equivalent of +;; a non-offsettable memref, but also it is less efficient than loading +;; the constant into an FP register, since it will probably be used there. +;; The "??" is a kludge until we can figure out a more reasonable way +;; of handling these non-offsettable values. +(define_insn "*movdf_hardfloat32" + [(set (match_operand:DF 0 "nonimmediate_operand" "=!r,??r,m,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,!r,!r,!r") + (match_operand:DF 1 "input_operand" "r,m,r,ws,wa,Z,Z,ws,wa,d,m,d,j,G,H,F"))] + "! TARGET_POWERPC64 && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && (gpc_reg_operand (operands[0], DFmode) + || gpc_reg_operand (operands[1], DFmode))" + "* +{ + switch (which_alternative) + { + default: + gcc_unreachable (); + case 0: + case 1: + case 2: + return \"#\"; + case 3: + case 4: + return \"xxlor %x0,%x1,%x1\"; + case 5: + case 6: + return \"lxsd%U1x %x0,%y1\"; + case 7: + case 8: + return \"stxsd%U0x %x1,%y0\"; + case 9: + return \"fmr %0,%1\"; + case 10: + return \"lfd%U1%X1 %0,%1\"; + case 11: + return \"stfd%U0%X0 %1,%0\"; + case 12: + return \"xxlxor %x0,%x0,%x0\"; + case 13: + case 14: + case 15: + return \"#\"; + } +}" + [(set_attr "type" "two,load,store,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,*,*,*") + (set_attr "length" "8,16,16,4,4,4,4,4,4,4,4,4,4,8,12,16")]) + +(define_insn "*movdf_softfloat32" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,r,m,r,r,r") + (match_operand:DF 1 "input_operand" "r,m,r,G,H,F"))] + "! TARGET_POWERPC64 + && ((TARGET_FPRS && TARGET_SINGLE_FLOAT) + || TARGET_SOFT_FLOAT || TARGET_E500_SINGLE) + && (gpc_reg_operand (operands[0], DFmode) + || gpc_reg_operand (operands[1], DFmode))" + "#" + [(set_attr "type" "two,load,store,*,*,*") + (set_attr "length" "8,8,8,8,12,16")]) + +; ld/std require word-aligned displacements -> 'Y' constraint. +; List Y->r and r->Y before r->r for reload. +(define_insn "*movdf_hardfloat64_mfpgpr" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,*c*l,!r,*h,!r,!r,!r,r,d") + (match_operand:DF 1 "input_operand" "r,Y,r,ws,?wa,Z,Z,ws,wa,d,m,d,j,r,h,0,G,H,F,d,r"))] + "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_DOUBLE_FLOAT + && (gpc_reg_operand (operands[0], DFmode) + || gpc_reg_operand (operands[1], DFmode))" + "@ + std%U0%X0 %1,%0 + ld%U1%X1 %0,%1 + mr %0,%1 + xxlor %x0,%x1,%x1 + xxlor %x0,%x1,%x1 + lxsd%U1x %x0,%y1 + lxsd%U1x %x0,%y1 + stxsd%U0x %x1,%y0 + stxsd%U0x %x1,%y0 + fmr %0,%1 + lfd%U1%X1 %0,%1 + stfd%U0%X0 %1,%0 + xxlxor %x0,%x0,%x0 + mt%0 %1 + mf%1 %0 + {cror 0,0,0|nop} + # + # + # + mftgpr %0,%1 + mffgpr %0,%1" + [(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,mtjmpr,mfjmpr,*,*,*,*,mftgpr,mffgpr") + (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16,4,4")]) + +; ld/std require word-aligned displacements -> 'Y' constraint. +; List Y->r and r->Y before r->r for reload. +(define_insn "*movdf_hardfloat64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=Y,r,!r,ws,?wa,ws,?wa,Z,?Z,d,d,m,wa,*c*l,!r,*h,!r,!r,!r") + (match_operand:DF 1 "input_operand" "r,Y,r,ws,wa,Z,Z,ws,wa,d,m,d,j,r,h,0,G,H,F"))] + "TARGET_POWERPC64 && !TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS + && TARGET_DOUBLE_FLOAT + && (gpc_reg_operand (operands[0], DFmode) + || gpc_reg_operand (operands[1], DFmode))" + "@ + std%U0%X0 %1,%0 + ld%U1%X1 %0,%1 + mr %0,%1 + xxlor %x0,%x1,%x1 + xxlor %x0,%x1,%x1 + lxsd%U1x %x0,%y1 + lxsd%U1x %x0,%y1 + stxsd%U0x %x1,%y0 + stxsd%U0x %x1,%y0 + fmr %0,%1 + lfd%U1%X1 %0,%1 + stfd%U0%X0 %1,%0 + xxlxor %x0,%x0,%x0 + mt%0 %1 + mf%1 %0 + {cror 0,0,0|nop} + # + # + #" + [(set_attr "type" "store,load,*,fp,fp,fpload,fpload,fpstore,fpstore,fp,fpload,fpstore,vecsimple,mtjmpr,mfjmpr,*,*,*,*") + (set_attr "length" "4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,8,12,16")]) + +(define_insn "*movdf_softfloat64" + [(set (match_operand:DF 0 "nonimmediate_operand" "=r,Y,r,cl,r,r,r,r,*h") + (match_operand:DF 1 "input_operand" "Y,r,r,r,h,G,H,F,0"))] + "TARGET_POWERPC64 && (TARGET_SOFT_FLOAT || !TARGET_FPRS) + && (gpc_reg_operand (operands[0], DFmode) + || gpc_reg_operand (operands[1], DFmode))" + "@ + ld%U1%X1 %0,%1 + std%U0%X0 %1,%0 + mr %0,%1 + mt%0 %1 + mf%1 %0 + # + # + # + {cror 0,0,0|nop}" + [(set_attr "type" "load,store,*,mtjmpr,mfjmpr,*,*,*,*") + (set_attr "length" "4,4,4,4,4,8,12,16,4")]) + +(define_expand "movtf" + [(set (match_operand:TF 0 "general_operand" "") + (match_operand:TF 1 "any_operand" ""))] + "!TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128" + "{ rs6000_emit_move (operands[0], operands[1], TFmode); DONE; }") + +; It's important to list the o->f and f->o moves before f->f because +; otherwise reload, given m->f, will try to pick f->f and reload it, +; which doesn't make progress. Likewise r->Y must be before r->r. +(define_insn_and_split "*movtf_internal" + [(set (match_operand:TF 0 "nonimmediate_operand" "=o,d,d,r,Y,r") + (match_operand:TF 1 "input_operand" "d,o,d,YGHF,r,r"))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128 + && (gpc_reg_operand (operands[0], TFmode) + || gpc_reg_operand (operands[1], TFmode))" + "#" + "&& reload_completed" + [(pc)] +{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; } + [(set_attr "length" "8,8,8,20,20,16")]) + +(define_insn_and_split "*movtf_softfloat" + [(set (match_operand:TF 0 "rs6000_nonimmediate_operand" "=r,Y,r") + (match_operand:TF 1 "input_operand" "YGHF,r,r"))] + "!TARGET_IEEEQUAD + && (TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_LONG_DOUBLE_128 + && (gpc_reg_operand (operands[0], TFmode) + || gpc_reg_operand (operands[1], TFmode))" + "#" + "&& reload_completed" + [(pc)] +{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; } + [(set_attr "length" "20,20,16")]) + +(define_expand "extenddftf2" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (float_extend:TF (match_operand:DF 1 "input_operand" "")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" +{ + if (TARGET_E500_DOUBLE) + emit_insn (gen_spe_extenddftf2 (operands[0], operands[1])); + else + emit_insn (gen_extenddftf2_fprs (operands[0], operands[1])); + DONE; +}) + +(define_expand "extenddftf2_fprs" + [(parallel [(set (match_operand:TF 0 "nonimmediate_operand" "") + (float_extend:TF (match_operand:DF 1 "input_operand" ""))) + (use (match_dup 2))])] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && TARGET_LONG_DOUBLE_128" +{ + operands[2] = CONST0_RTX (DFmode); + /* Generate GOT reference early for SVR4 PIC. */ + if (DEFAULT_ABI == ABI_V4 && flag_pic) + operands[2] = validize_mem (force_const_mem (DFmode, operands[2])); +}) + +(define_insn_and_split "*extenddftf2_internal" + [(set (match_operand:TF 0 "nonimmediate_operand" "=o,d,&d,r") + (float_extend:TF (match_operand:DF 1 "input_operand" "dr,md,md,rmGHF"))) + (use (match_operand:DF 2 "zero_reg_mem_operand" "rd,m,d,n"))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && TARGET_LONG_DOUBLE_128" + "#" + "&& reload_completed" + [(pc)] +{ + const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0; + const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode); + emit_move_insn (simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word), + operands[1]); + emit_move_insn (simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word), + operands[2]); + DONE; +}) + +(define_expand "extendsftf2" + [(set (match_operand:TF 0 "nonimmediate_operand" "") + (float_extend:TF (match_operand:SF 1 "gpc_reg_operand" "")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" +{ + rtx tmp = gen_reg_rtx (DFmode); + emit_insn (gen_extendsfdf2 (tmp, operands[1])); + emit_insn (gen_extenddftf2 (operands[0], tmp)); + DONE; +}) + +(define_expand "trunctfdf2" + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" + "") + +(define_insn_and_split "trunctfdf2_internal1" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d,?d") + (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "0,d")))] + "!TARGET_IEEEQUAD && !TARGET_XL_COMPAT + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128" + "@ + # + fmr %0,%1" + "&& reload_completed && REGNO (operands[0]) == REGNO (operands[1])" + [(const_int 0)] +{ + emit_note (NOTE_INSN_DELETED); + DONE; +} + [(set_attr "type" "fp")]) + +(define_insn "trunctfdf2_internal2" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "d")))] + "!TARGET_IEEEQUAD && TARGET_XL_COMPAT + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && TARGET_LONG_DOUBLE_128" + "fadd %0,%1,%L1" + [(set_attr "type" "fp") + (set_attr "fp_type" "fp_addsub_d")]) + +(define_expand "trunctfsf2" + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" +{ + if (TARGET_E500_DOUBLE) + emit_insn (gen_spe_trunctfsf2 (operands[0], operands[1])); + else + emit_insn (gen_trunctfsf2_fprs (operands[0], operands[1])); + DONE; +}) + +(define_insn_and_split "trunctfsf2_fprs" + [(set (match_operand:SF 0 "gpc_reg_operand" "=f") + (float_truncate:SF (match_operand:TF 1 "gpc_reg_operand" "d"))) + (clobber (match_scratch:DF 2 "=d"))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT + && TARGET_LONG_DOUBLE_128" + "#" + "&& reload_completed" + [(set (match_dup 2) + (float_truncate:DF (match_dup 1))) + (set (match_dup 0) + (float_truncate:SF (match_dup 2)))] + "") + +(define_expand "floatsitf2" + [(set (match_operand:TF 0 "gpc_reg_operand" "") + (float:TF (match_operand:SI 1 "gpc_reg_operand" "")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" +{ + rtx tmp = gen_reg_rtx (DFmode); + expand_float (tmp, operands[1], false); + emit_insn (gen_extenddftf2 (operands[0], tmp)); + DONE; +}) + +; fadd, but rounding towards zero. +; This is probably not the optimal code sequence. +(define_insn "fix_trunc_helper" + [(set (match_operand:DF 0 "gpc_reg_operand" "=d") + (unspec:DF [(match_operand:TF 1 "gpc_reg_operand" "d")] + UNSPEC_FIX_TRUNC_TF)) + (clobber (match_operand:DF 2 "gpc_reg_operand" "=&d"))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT" + "mffs %2\n\tmtfsb1 31\n\tmtfsb0 30\n\tfadd %0,%1,%L1\n\tmtfsf 1,%2" + [(set_attr "type" "fp") + (set_attr "length" "20")]) + +(define_expand "fix_trunctfsi2" + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (fix:SI (match_operand:TF 1 "gpc_reg_operand" "")))] + "!TARGET_IEEEQUAD + && (TARGET_POWER2 || TARGET_POWERPC) + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" +{ + if (TARGET_E500_DOUBLE) + emit_insn (gen_spe_fix_trunctfsi2 (operands[0], operands[1])); + else + emit_insn (gen_fix_trunctfsi2_fprs (operands[0], operands[1])); + DONE; +}) + +(define_expand "fix_trunctfsi2_fprs" + [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "") + (fix:SI (match_operand:TF 1 "gpc_reg_operand" ""))) + (clobber (match_dup 2)) + (clobber (match_dup 3)) + (clobber (match_dup 4)) + (clobber (match_dup 5))])] + "!TARGET_IEEEQUAD + && (TARGET_POWER2 || TARGET_POWERPC) + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128" +{ + operands[2] = gen_reg_rtx (DFmode); + operands[3] = gen_reg_rtx (DFmode); + operands[4] = gen_reg_rtx (DImode); + operands[5] = assign_stack_temp (DImode, GET_MODE_SIZE (DImode), 0); +}) + +(define_insn_and_split "*fix_trunctfsi2_internal" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (fix:SI (match_operand:TF 1 "gpc_reg_operand" "d"))) + (clobber (match_operand:DF 2 "gpc_reg_operand" "=d")) + (clobber (match_operand:DF 3 "gpc_reg_operand" "=&d")) + (clobber (match_operand:DI 4 "gpc_reg_operand" "=d")) + (clobber (match_operand:DI 5 "offsettable_mem_operand" "=o"))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128" + "#" + "" + [(pc)] +{ + rtx lowword; + emit_insn (gen_fix_trunc_helper (operands[2], operands[1], operands[3])); + + gcc_assert (MEM_P (operands[5])); + lowword = adjust_address (operands[5], SImode, WORDS_BIG_ENDIAN ? 4 : 0); + + emit_insn (gen_fctiwz_df (operands[4], operands[2])); + emit_move_insn (operands[5], operands[4]); + emit_move_insn (operands[0], lowword); + DONE; +}) + +(define_expand "negtf2" + [(set (match_operand:TF 0 "gpc_reg_operand" "") + (neg:TF (match_operand:TF 1 "gpc_reg_operand" "")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" + "") + +(define_insn "negtf2_internal" + [(set (match_operand:TF 0 "gpc_reg_operand" "=d") + (neg:TF (match_operand:TF 1 "gpc_reg_operand" "d")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128" + "* +{ + if (REGNO (operands[0]) == REGNO (operands[1]) + 1) + return \"fneg %L0,%L1\;fneg %0,%1\"; + else + return \"fneg %0,%1\;fneg %L0,%L1\"; +}" + [(set_attr "type" "fp") + (set_attr "length" "8")]) + +(define_expand "abstf2" + [(set (match_operand:TF 0 "gpc_reg_operand" "") + (abs:TF (match_operand:TF 1 "gpc_reg_operand" "")))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT + && (TARGET_FPRS || TARGET_E500_DOUBLE) + && TARGET_LONG_DOUBLE_128" + " +{ + rtx label = gen_label_rtx (); + if (TARGET_E500_DOUBLE) + { + if (flag_finite_math_only && !flag_trapping_math) + emit_insn (gen_spe_abstf2_tst (operands[0], operands[1], label)); + else + emit_insn (gen_spe_abstf2_cmp (operands[0], operands[1], label)); + } + else + emit_insn (gen_abstf2_internal (operands[0], operands[1], label)); + emit_label (label); + DONE; +}") + +(define_expand "abstf2_internal" + [(set (match_operand:TF 0 "gpc_reg_operand" "") + (match_operand:TF 1 "gpc_reg_operand" "")) + (set (match_dup 3) (match_dup 5)) + (set (match_dup 5) (abs:DF (match_dup 5))) + (set (match_dup 4) (compare:CCFP (match_dup 3) (match_dup 5))) + (set (pc) (if_then_else (eq (match_dup 4) (const_int 0)) + (label_ref (match_operand 2 "" "")) + (pc))) + (set (match_dup 6) (neg:DF (match_dup 6)))] + "!TARGET_IEEEQUAD + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && TARGET_LONG_DOUBLE_128" + " +{ + const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode); + const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0; + operands[3] = gen_reg_rtx (DFmode); + operands[4] = gen_reg_rtx (CCFPmode); + operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word); + operands[6] = simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word); +}") + +;; Next come the multi-word integer load and store and the load and store +;; multiple insns. + +; List r->r after r->"o<>", otherwise reload will try to reload a +; non-offsettable address by using r->r which won't make progress. +(define_insn "*movdi_internal32" + [(set (match_operand:DI 0 "rs6000_nonimmediate_operand" "=o<>,r,r,*d,*d,m,r,?wa") + (match_operand:DI 1 "input_operand" "r,r,m,d,m,d,IJKnGHF,O"))] + "! TARGET_POWERPC64 + && (gpc_reg_operand (operands[0], DImode) + || gpc_reg_operand (operands[1], DImode))" + "@ + # + # + # + fmr %0,%1 + lfd%U1%X1 %0,%1 + stfd%U0%X0 %1,%0 + # + xxlxor %x0,%x0,%x0" + [(set_attr "type" "load,*,store,fp,fpload,fpstore,*,vecsimple")]) + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "! TARGET_POWERPC64 && reload_completed + && gpr_or_gpr_p (operands[0], operands[1])" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 1))] + " +{ + HOST_WIDE_INT value = INTVAL (operands[1]); + operands[2] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN == 0, + DImode); + operands[3] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN != 0, + DImode); +#if HOST_BITS_PER_WIDE_INT == 32 + operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx; +#else + operands[4] = GEN_INT (value >> 32); + operands[1] = GEN_INT (((value & 0xffffffff) ^ 0x80000000) - 0x80000000); +#endif +}") + +(define_split + [(set (match_operand:DIFD 0 "rs6000_nonimmediate_operand" "") + (match_operand:DIFD 1 "input_operand" ""))] + "reload_completed && !TARGET_POWERPC64 + && gpr_or_gpr_p (operands[0], operands[1])" + [(pc)] +{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }) + +(define_insn "*movdi_mfpgpr" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*d,*d,m,r,*h,*h,r,*d") + (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,d,m,d,*h,r,0,*d,r"))] + "TARGET_POWERPC64 && TARGET_MFPGPR && TARGET_HARD_FLOAT && TARGET_FPRS + && (gpc_reg_operand (operands[0], DImode) + || gpc_reg_operand (operands[1], DImode))" + "@ + mr %0,%1 + ld%U1%X1 %0,%1 + std%U0%X0 %1,%0 + li %0,%1 + lis %0,%v1 + # + {cal|la} %0,%a1 + fmr %0,%1 + lfd%U1%X1 %0,%1 + stfd%U0%X0 %1,%0 + mf%1 %0 + mt%0 %1 + {cror 0,0,0|nop} + mftgpr %0,%1 + mffgpr %0,%1" + [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*,mftgpr,mffgpr") + (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4,4")]) + +(define_insn "*movdi_internal64" + [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,*d,*d,m,r,*h,*h,?wa") + (match_operand:DI 1 "input_operand" "r,m,r,I,L,nF,R,d,m,d,*h,r,0,O"))] + "TARGET_POWERPC64 && (!TARGET_MFPGPR || !TARGET_HARD_FLOAT || !TARGET_FPRS) + && (gpc_reg_operand (operands[0], DImode) + || gpc_reg_operand (operands[1], DImode))" + "@ + mr %0,%1 + ld%U1%X1 %0,%1 + std%U0%X0 %1,%0 + li %0,%1 + lis %0,%v1 + # + {cal|la} %0,%a1 + fmr %0,%1 + lfd%U1%X1 %0,%1 + stfd%U0%X0 %1,%0 + mf%1 %0 + mt%0 %1 + {cror 0,0,0|nop} + xxlxor %x0,%x0,%x0" + [(set_attr "type" "*,load,store,*,*,*,*,fp,fpload,fpstore,mfjmpr,mtjmpr,*,vecsimple") + (set_attr "length" "4,4,4,4,4,20,4,4,4,4,4,4,4,4")]) + +;; immediate value valid for a single instruction hiding in a const_double +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (match_operand:DI 1 "const_double_operand" "F"))] + "HOST_BITS_PER_WIDE_INT == 32 && TARGET_POWERPC64 + && GET_CODE (operands[1]) == CONST_DOUBLE + && num_insns_constant (operands[1], DImode) == 1" + "* +{ + return ((unsigned HOST_WIDE_INT) + (CONST_DOUBLE_LOW (operands[1]) + 0x8000) < 0x10000) + ? \"li %0,%1\" : \"lis %0,%v1\"; +}") + +;; Generate all one-bits and clear left or right. +;; Use (and:DI (rotate:DI ...)) to avoid anddi3 unnecessary clobber. +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "mask64_operand" ""))] + "TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1" + [(set (match_dup 0) (const_int -1)) + (set (match_dup 0) + (and:DI (rotate:DI (match_dup 0) + (const_int 0)) + (match_dup 1)))] + "") + +;; Split a load of a large constant into the appropriate five-instruction +;; sequence. Handle anything in a constant number of insns. +;; When non-easy constants can go in the TOC, this should use +;; easy_fp_constant predicate. +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_int_operand" ""))] + "TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] + " +{ rtx tem = rs6000_emit_set_const (operands[0], DImode, operands[1], 5); + + if (tem == operands[0]) + DONE; + else + FAIL; +}") + +(define_split + [(set (match_operand:DI 0 "gpc_reg_operand" "") + (match_operand:DI 1 "const_double_operand" ""))] + "TARGET_POWERPC64 && num_insns_constant (operands[1], DImode) > 1" + [(set (match_dup 0) (match_dup 2)) + (set (match_dup 0) (plus:DI (match_dup 0) (match_dup 3)))] + " +{ rtx tem = rs6000_emit_set_const (operands[0], DImode, operands[1], 5); + + if (tem == operands[0]) + DONE; + else + FAIL; +}") + +;; TImode is similar, except that we usually want to compute the address into +;; a register and use lsi/stsi (the exception is during reload). MQ is also +;; clobbered in stsi for POWER, so we need a SCRATCH for it. + +;; We say that MQ is clobbered in the last alternative because the first +;; alternative would never get used otherwise since it would need a reload +;; while the 2nd alternative would not. We put memory cases first so they +;; are preferred. Otherwise, we'd try to reload the output instead of +;; giving the SCRATCH mq. + +(define_insn "*movti_power" + [(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,m,????r,????r,????r,r") + (match_operand:TI 1 "input_operand" "r,r,r,Q,m,n")) + (clobber (match_scratch:SI 2 "=q,q#X,X,X,X,X"))] + "TARGET_POWER && ! TARGET_POWERPC64 + && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))" + "* +{ + switch (which_alternative) + { + default: + gcc_unreachable (); + + case 0: + if (TARGET_STRING) + return \"{stsi|stswi} %1,%P0,16\"; + case 1: + case 2: + return \"#\"; + case 3: + /* If the address is not used in the output, we can use lsi. Otherwise, + fall through to generating four loads. */ + if (TARGET_STRING + && ! reg_overlap_mentioned_p (operands[0], operands[1])) + return \"{lsi|lswi} %0,%P1,16\"; + /* ... fall through ... */ + case 4: + case 5: + return \"#\"; + } +}" + [(set_attr "type" "store,store,*,load,load,*")]) + +(define_insn "*movti_string" + [(set (match_operand:TI 0 "reg_or_mem_operand" "=Q,o<>,????r,????r,????r,r") + (match_operand:TI 1 "input_operand" "r,r,r,Q,m,n"))] + "! TARGET_POWER && ! TARGET_POWERPC64 + && (gpc_reg_operand (operands[0], TImode) || gpc_reg_operand (operands[1], TImode))" + "* +{ + switch (which_alternative) + { + default: + gcc_unreachable (); + case 0: + if (TARGET_STRING) + return \"{stsi|stswi} %1,%P0,16\"; + case 1: + case 2: + return \"#\"; + case 3: + /* If the address is not used in the output, we can use lsi. Otherwise, + fall through to generating four loads. */ + if (TARGET_STRING + && ! reg_overlap_mentioned_p (operands[0], operands[1])) + return \"{lsi|lswi} %0,%P1,16\"; + /* ... fall through ... */ + case 4: + case 5: + return \"#\"; + } +}" + [(set_attr "type" "store_ux,store_ux,*,load_ux,load_ux,*") + (set (attr "cell_micro") (if_then_else (eq (symbol_ref "TARGET_STRING") (const_int 1)) + (const_string "always") + (const_string "conditional")))]) + +(define_insn "*movti_ppc64" + [(set (match_operand:TI 0 "nonimmediate_operand" "=r,o<>,r") + (match_operand:TI 1 "input_operand" "r,r,m"))] + "(TARGET_POWERPC64 && (gpc_reg_operand (operands[0], TImode) + || gpc_reg_operand (operands[1], TImode))) + && VECTOR_MEM_NONE_P (TImode)" + "#" + [(set_attr "type" "*,store,load")]) + +(define_split + [(set (match_operand:TI 0 "gpc_reg_operand" "") + (match_operand:TI 1 "const_double_operand" ""))] + "TARGET_POWERPC64 && VECTOR_MEM_NONE_P (TImode)" + [(set (match_dup 2) (match_dup 4)) + (set (match_dup 3) (match_dup 5))] + " +{ + operands[2] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN == 0, + TImode); + operands[3] = operand_subword_force (operands[0], WORDS_BIG_ENDIAN != 0, + TImode); + if (GET_CODE (operands[1]) == CONST_DOUBLE) + { + operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1])); + operands[5] = GEN_INT (CONST_DOUBLE_LOW (operands[1])); + } + else if (GET_CODE (operands[1]) == CONST_INT) + { + operands[4] = GEN_INT (- (INTVAL (operands[1]) < 0)); + operands[5] = operands[1]; + } + else + FAIL; +}") + +(define_split + [(set (match_operand:TI 0 "nonimmediate_operand" "") + (match_operand:TI 1 "input_operand" ""))] + "reload_completed && VECTOR_MEM_NONE_P (TImode) + && gpr_or_gpr_p (operands[0], operands[1])" + [(pc)] +{ rs6000_split_multireg_move (operands[0], operands[1]); DONE; }) + +(define_expand "load_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (use (match_operand:SI 2 "" ""))])] + "TARGET_STRING && !TARGET_POWERPC64" + " +{ + int regno; + int count; + rtx op1; + int i; + + /* Support only loading a constant number of fixed-point registers from + memory and only bother with this if more than two; the machine + doesn't support more than eight. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) <= 2 + || INTVAL (operands[2]) > 8 + || GET_CODE (operands[1]) != MEM + || GET_CODE (operands[0]) != REG + || REGNO (operands[0]) >= 32) + FAIL; + + count = INTVAL (operands[2]); + regno = REGNO (operands[0]); + + operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count)); + op1 = replace_equiv_address (operands[1], + force_reg (SImode, XEXP (operands[1], 0))); + + for (i = 0; i < count; i++) + XVECEXP (operands[3], 0, i) + = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, regno + i), + adjust_address_nv (op1, SImode, i * 4)); +}") + +(define_insn "*ldmsi8" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 2 "gpc_reg_operand" "") + (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b"))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24)))) + (set (match_operand:SI 9 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 28))))])] + "TARGET_STRING && XVECLEN (operands[0], 0) == 8" + "* +{ return rs6000_output_load_multiple (operands); }" + [(set_attr "type" "load_ux") + (set_attr "length" "32")]) + +(define_insn "*ldmsi7" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 2 "gpc_reg_operand" "") + (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b"))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20)))) + (set (match_operand:SI 8 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 24))))])] + "TARGET_STRING && XVECLEN (operands[0], 0) == 7" + "* +{ return rs6000_output_load_multiple (operands); }" + [(set_attr "type" "load_ux") + (set_attr "length" "32")]) + +(define_insn "*ldmsi6" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 2 "gpc_reg_operand" "") + (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b"))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16)))) + (set (match_operand:SI 7 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 20))))])] + "TARGET_STRING && XVECLEN (operands[0], 0) == 6" + "* +{ return rs6000_output_load_multiple (operands); }" + [(set_attr "type" "load_ux") + (set_attr "length" "32")]) + +(define_insn "*ldmsi5" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 2 "gpc_reg_operand" "") + (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b"))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12)))) + (set (match_operand:SI 6 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 16))))])] + "TARGET_STRING && XVECLEN (operands[0], 0) == 5" + "* +{ return rs6000_output_load_multiple (operands); }" + [(set_attr "type" "load_ux") + (set_attr "length" "32")]) + +(define_insn "*ldmsi4" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 2 "gpc_reg_operand" "") + (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b"))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8)))) + (set (match_operand:SI 5 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 12))))])] + "TARGET_STRING && XVECLEN (operands[0], 0) == 4" + "* +{ return rs6000_output_load_multiple (operands); }" + [(set_attr "type" "load_ux") + (set_attr "length" "32")]) + +(define_insn "*ldmsi3" + [(match_parallel 0 "load_multiple_operation" + [(set (match_operand:SI 2 "gpc_reg_operand" "") + (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b"))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 4)))) + (set (match_operand:SI 4 "gpc_reg_operand" "") + (mem:SI (plus:SI (match_dup 1) (const_int 8))))])] + "TARGET_STRING && XVECLEN (operands[0], 0) == 3" + "* +{ return rs6000_output_load_multiple (operands); }" + [(set_attr "type" "load_ux") + (set_attr "length" "32")]) + +(define_expand "store_multiple" + [(match_par_dup 3 [(set (match_operand:SI 0 "" "") + (match_operand:SI 1 "" "")) + (clobber (scratch:SI)) + (use (match_operand:SI 2 "" ""))])] + "TARGET_STRING && !TARGET_POWERPC64" + " +{ + int regno; + int count; + rtx to; + rtx op0; + int i; + + /* Support only storing a constant number of fixed-point registers to + memory and only bother with this if more than two; the machine + doesn't support more than eight. */ + if (GET_CODE (operands[2]) != CONST_INT + || INTVAL (operands[2]) <= 2 + || INTVAL (operands[2]) > 8 + || GET_CODE (operands[0]) != MEM + || GET_CODE (operands[1]) != REG + || REGNO (operands[1]) >= 32) + FAIL; + + count = INTVAL (operands[2]); + regno = REGNO (operands[1]); + + operands[3] = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count + 1)); + to = force_reg (SImode, XEXP (operands[0], 0)); + op0 = replace_equiv_address (operands[0], to); + + XVECEXP (operands[3], 0, 0) + = gen_rtx_SET (VOIDmode, adjust_address_nv (op0, SImode, 0), operands[1]); + XVECEXP (operands[3], 0, 1) = gen_rtx_CLOBBER (VOIDmode, + gen_rtx_SCRATCH (SImode)); + + for (i = 1; i < count; i++) + XVECEXP (operands[3], 0, i + 1) + = gen_rtx_SET (VOIDmode, + adjust_address_nv (op0, SImode, i * 4), + gen_rtx_REG (SImode, regno + i)); +}") + +(define_insn "*stmsi8" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=X")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 8 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 9 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 10 "gpc_reg_operand" "r"))])] + "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 9" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi7" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=X")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 8 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 9 "gpc_reg_operand" "r"))])] + "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 8" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi6" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=X")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 8 "gpc_reg_operand" "r"))])] + "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 7" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi5" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=X")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r"))])] + "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 6" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi4" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=X")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r"))])] + "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 5" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi3" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=X")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r"))])] + "TARGET_STRING && !TARGET_POWER && XVECLEN (operands[0], 0) == 4" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi8_power" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=q")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 8 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 9 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 28))) + (match_operand:SI 10 "gpc_reg_operand" "r"))])] + "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 9" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi7_power" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=q")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 8 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 24))) + (match_operand:SI 9 "gpc_reg_operand" "r"))])] + "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 8" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi6_power" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=q")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 20))) + (match_operand:SI 8 "gpc_reg_operand" "r"))])] + "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 7" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi5_power" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=q")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 16))) + (match_operand:SI 7 "gpc_reg_operand" "r"))])] + "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 6" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi4_power" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=q")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 12))) + (match_operand:SI 6 "gpc_reg_operand" "r"))])] + "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 5" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*stmsi3_power" + [(match_parallel 0 "store_multiple_operation" + [(set (mem:SI (match_operand:SI 1 "gpc_reg_operand" "b")) + (match_operand:SI 2 "gpc_reg_operand" "r")) + (clobber (match_scratch:SI 3 "=q")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 4))) + (match_operand:SI 4 "gpc_reg_operand" "r")) + (set (mem:SI (plus:SI (match_dup 1) (const_int 8))) + (match_operand:SI 5 "gpc_reg_operand" "r"))])] + "TARGET_STRING && TARGET_POWER && XVECLEN (operands[0], 0) == 4" + "{stsi|stswi} %2,%1,%O0" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always")]) + +(define_expand "setmemsi" + [(parallel [(set (match_operand:BLK 0 "" "") + (match_operand 2 "const_int_operand" "")) + (use (match_operand:SI 1 "" "")) + (use (match_operand:SI 3 "" ""))])] + "" + " +{ + /* If value to set is not zero, use the library routine. */ + if (operands[2] != const0_rtx) + FAIL; + + if (expand_block_clear (operands)) + DONE; + else + FAIL; +}") + +;; String/block move insn. +;; Argument 0 is the destination +;; Argument 1 is the source +;; Argument 2 is the length +;; Argument 3 is the alignment + +(define_expand "movmemsi" + [(parallel [(set (match_operand:BLK 0 "" "") + (match_operand:BLK 1 "" "")) + (use (match_operand:SI 2 "" "")) + (use (match_operand:SI 3 "" ""))])] + "" + " +{ + if (expand_block_move (operands)) + DONE; + else + FAIL; +}") + +;; Move up to 32 bytes at a time. The fixed registers are needed because the +;; register allocator doesn't have a clue about allocating 8 word registers. +;; rD/rS = r5 is preferred, efficient form. +(define_expand "movmemsi_8reg" + [(parallel [(set (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (clobber (reg:SI 5)) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 10)) + (clobber (reg:SI 11)) + (clobber (reg:SI 12)) + (clobber (match_scratch:SI 4 ""))])] + "TARGET_STRING" + "") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:SI 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=&r")) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 10)) + (clobber (reg:SI 11)) + (clobber (reg:SI 12)) + (clobber (match_scratch:SI 5 "=q"))] + "TARGET_STRING && TARGET_POWER + && ((INTVAL (operands[2]) > 24 && INTVAL (operands[2]) < 32) + || INTVAL (operands[2]) == 0) + && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 12) + && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12) + && REGNO (operands[4]) == 5" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +(define_insn "" + [(set (mem:BLK (match_operand:P 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:P 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=&r")) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 10)) + (clobber (reg:SI 11)) + (clobber (reg:SI 12)) + (clobber (match_scratch:SI 5 "=X"))] + "TARGET_STRING && ! TARGET_POWER + && ((INTVAL (operands[2]) > 24 && INTVAL (operands[2]) < 32) + || INTVAL (operands[2]) == 0) + && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 12) + && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 12) + && REGNO (operands[4]) == 5" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +;; Move up to 24 bytes at a time. The fixed registers are needed because the +;; register allocator doesn't have a clue about allocating 6 word registers. +;; rD/rS = r5 is preferred, efficient form. +(define_expand "movmemsi_6reg" + [(parallel [(set (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (clobber (reg:SI 5)) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 10)) + (clobber (match_scratch:SI 4 ""))])] + "TARGET_STRING" + "") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:SI 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=&r")) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 10)) + (clobber (match_scratch:SI 5 "=q"))] + "TARGET_STRING && TARGET_POWER + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 24 + && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 10) + && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 10) + && REGNO (operands[4]) == 5" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +(define_insn "" + [(set (mem:BLK (match_operand:P 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:P 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=&r")) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (reg:SI 9)) + (clobber (reg:SI 10)) + (clobber (match_scratch:SI 5 "=X"))] + "TARGET_STRING && ! TARGET_POWER + && INTVAL (operands[2]) > 16 && INTVAL (operands[2]) <= 32 + && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 10) + && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 10) + && REGNO (operands[4]) == 5" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +;; Move up to 16 bytes at a time, using 4 fixed registers to avoid spill +;; problems with TImode. +;; rD/rS = r5 is preferred, efficient form. +(define_expand "movmemsi_4reg" + [(parallel [(set (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (clobber (reg:SI 5)) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (match_scratch:SI 4 ""))])] + "TARGET_STRING" + "") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:SI 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=&r")) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (match_scratch:SI 5 "=q"))] + "TARGET_STRING && TARGET_POWER + && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16 + && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 8) + && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 8) + && REGNO (operands[4]) == 5" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +(define_insn "" + [(set (mem:BLK (match_operand:P 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:P 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_operand:SI 4 "gpc_reg_operand" "=&r")) + (clobber (reg:SI 6)) + (clobber (reg:SI 7)) + (clobber (reg:SI 8)) + (clobber (match_scratch:SI 5 "=X"))] + "TARGET_STRING && ! TARGET_POWER + && INTVAL (operands[2]) > 8 && INTVAL (operands[2]) <= 16 + && (REGNO (operands[0]) < 5 || REGNO (operands[0]) > 8) + && (REGNO (operands[1]) < 5 || REGNO (operands[1]) > 8) + && REGNO (operands[4]) == 5" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +;; Move up to 8 bytes at a time. +(define_expand "movmemsi_2reg" + [(parallel [(set (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (clobber (match_scratch:DI 4 "")) + (clobber (match_scratch:SI 5 ""))])] + "TARGET_STRING && ! TARGET_POWERPC64" + "") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:SI 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_scratch:DI 4 "=&r")) + (clobber (match_scratch:SI 5 "=q"))] + "TARGET_STRING && TARGET_POWER && ! TARGET_POWERPC64 + && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:SI 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_scratch:DI 4 "=&r")) + (clobber (match_scratch:SI 5 "=X"))] + "TARGET_STRING && ! TARGET_POWER && ! TARGET_POWERPC64 + && INTVAL (operands[2]) > 4 && INTVAL (operands[2]) <= 8" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +;; Move up to 4 bytes at a time. +(define_expand "movmemsi_1reg" + [(parallel [(set (match_operand 0 "" "") + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (match_operand 3 "" "")) + (clobber (match_scratch:SI 4 "")) + (clobber (match_scratch:SI 5 ""))])] + "TARGET_STRING" + "") + +(define_insn "" + [(set (mem:BLK (match_operand:SI 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:SI 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_scratch:SI 4 "=&r")) + (clobber (match_scratch:SI 5 "=q"))] + "TARGET_STRING && TARGET_POWER + && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +(define_insn "" + [(set (mem:BLK (match_operand:P 0 "gpc_reg_operand" "b")) + (mem:BLK (match_operand:P 1 "gpc_reg_operand" "b"))) + (use (match_operand:SI 2 "immediate_operand" "i")) + (use (match_operand:SI 3 "immediate_operand" "i")) + (clobber (match_scratch:SI 4 "=&r")) + (clobber (match_scratch:SI 5 "=X"))] + "TARGET_STRING && ! TARGET_POWER + && INTVAL (operands[2]) > 0 && INTVAL (operands[2]) <= 4" + "{lsi|lswi} %4,%1,%2\;{stsi|stswi} %4,%0,%2" + [(set_attr "type" "store_ux") + (set_attr "cell_micro" "always") + (set_attr "length" "8")]) + +;; Define insns that do load or store with update. Some of these we can +;; get by using pre-decrement or pre-increment, but the hardware can also +;; do cases where the increment is not the size of the object. +;; +;; In all these cases, we use operands 0 and 1 for the register being +;; incremented because those are the operands that local-alloc will +;; tie and these are the pair most likely to be tieable (and the ones +;; that will benefit the most). + +(define_insn "*movdi_update1" + [(set (match_operand:DI 3 "gpc_reg_operand" "=r,r") + (mem:DI (plus:DI (match_operand:DI 1 "gpc_reg_operand" "0,0") + (match_operand:DI 2 "reg_or_aligned_short_operand" "r,I")))) + (set (match_operand:DI 0 "gpc_reg_operand" "=b,b") + (plus:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && TARGET_UPDATE + && (!avoiding_indexed_address_p (DImode) + || !gpc_reg_operand (operands[2], DImode))" + "@ + ldux %3,%0,%2 + ldu %3,%2(%0)" + [(set_attr "type" "load_ux,load_u")]) + +(define_insn "movdi_<mode>_update" + [(set (mem:DI (plus:P (match_operand:P 1 "gpc_reg_operand" "0,0") + (match_operand:P 2 "reg_or_aligned_short_operand" "r,I"))) + (match_operand:DI 3 "gpc_reg_operand" "r,r")) + (set (match_operand:P 0 "gpc_reg_operand" "=b,b") + (plus:P (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && TARGET_UPDATE + && (!avoiding_indexed_address_p (Pmode) + || !gpc_reg_operand (operands[2], Pmode) + || (REG_P (operands[0]) + && REGNO (operands[0]) == STACK_POINTER_REGNUM))" + "@ + stdux %3,%0,%2 + stdu %3,%2(%0)" + [(set_attr "type" "store_ux,store_u")]) + +;; This pattern is only conditional on TARGET_POWERPC64, as it is +;; needed for stack allocation, even if the user passes -mno-update. +(define_insn "movdi_<mode>_update_stack" + [(set (mem:DI (plus:P (match_operand:P 1 "gpc_reg_operand" "0,0") + (match_operand:P 2 "reg_or_aligned_short_operand" "r,I"))) + (match_operand:DI 3 "gpc_reg_operand" "r,r")) + (set (match_operand:P 0 "gpc_reg_operand" "=b,b") + (plus:P (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64" + "@ + stdux %3,%0,%2 + stdu %3,%2(%0)" + [(set_attr "type" "store_ux,store_u")]) + +(define_insn "*movsi_update1" + [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r") + (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I")))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + {lux|lwzux} %3,%0,%2 + {lu|lwzu} %3,%2(%0)" + [(set_attr "type" "load_ux,load_u")]) + +(define_insn "*movsi_update2" + [(set (match_operand:DI 3 "gpc_reg_operand" "=r") + (sign_extend:DI + (mem:SI (plus:DI (match_operand:DI 1 "gpc_reg_operand" "0") + (match_operand:DI 2 "gpc_reg_operand" "r"))))) + (set (match_operand:DI 0 "gpc_reg_operand" "=b") + (plus:DI (match_dup 1) (match_dup 2)))] + "TARGET_POWERPC64 && rs6000_gen_cell_microcode + && !avoiding_indexed_address_p (DImode)" + "lwaux %3,%0,%2" + [(set_attr "type" "load_ext_ux")]) + +(define_insn "movsi_update" + [(set (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode) + || (REG_P (operands[0]) + && REGNO (operands[0]) == STACK_POINTER_REGNUM))" + "@ + {stux|stwux} %3,%0,%2 + {stu|stwu} %3,%2(%0)" + [(set_attr "type" "store_ux,store_u")]) + +;; This is an unconditional pattern; needed for stack allocation, even +;; if the user passes -mno-update. +(define_insn "movsi_update_stack" + [(set (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "" + "@ + {stux|stwux} %3,%0,%2 + {stu|stwu} %3,%2(%0)" + [(set_attr "type" "store_ux,store_u")]) + +(define_insn "*movhi_update1" + [(set (match_operand:HI 3 "gpc_reg_operand" "=r,r") + (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I")))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + lhzux %3,%0,%2 + lhzu %3,%2(%0)" + [(set_attr "type" "load_ux,load_u")]) + +(define_insn "*movhi_update2" + [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r") + (zero_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + lhzux %3,%0,%2 + lhzu %3,%2(%0)" + [(set_attr "type" "load_ux,load_u")]) + +(define_insn "*movhi_update3" + [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r") + (sign_extend:SI + (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE && rs6000_gen_cell_microcode + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + lhaux %3,%0,%2 + lhau %3,%2(%0)" + [(set_attr "type" "load_ext_ux,load_ext_u")]) + +(define_insn "*movhi_update4" + [(set (mem:HI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (match_operand:HI 3 "gpc_reg_operand" "r,r")) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + sthux %3,%0,%2 + sthu %3,%2(%0)" + [(set_attr "type" "store_ux,store_u")]) + +(define_insn "*movqi_update1" + [(set (match_operand:QI 3 "gpc_reg_operand" "=r,r") + (mem:QI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I")))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + lbzux %3,%0,%2 + lbzu %3,%2(%0)" + [(set_attr "type" "load_ux,load_u")]) + +(define_insn "*movqi_update2" + [(set (match_operand:SI 3 "gpc_reg_operand" "=r,r") + (zero_extend:SI + (mem:QI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + lbzux %3,%0,%2 + lbzu %3,%2(%0)" + [(set_attr "type" "load_ux,load_u")]) + +(define_insn "*movqi_update3" + [(set (mem:QI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (match_operand:QI 3 "gpc_reg_operand" "r,r")) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + stbux %3,%0,%2 + stbu %3,%2(%0)" + [(set_attr "type" "store_ux,store_u")]) + +(define_insn "*movsf_update1" + [(set (match_operand:SF 3 "gpc_reg_operand" "=f,f") + (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I")))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT && TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + lfsux %3,%0,%2 + lfsu %3,%2(%0)" + [(set_attr "type" "fpload_ux,fpload_u")]) + +(define_insn "*movsf_update2" + [(set (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (match_operand:SF 3 "gpc_reg_operand" "f,f")) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT && TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + stfsux %3,%0,%2 + stfsu %3,%2(%0)" + [(set_attr "type" "fpstore_ux,fpstore_u")]) + +(define_insn "*movsf_update3" + [(set (match_operand:SF 3 "gpc_reg_operand" "=r,r") + (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I")))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + {lux|lwzux} %3,%0,%2 + {lu|lwzu} %3,%2(%0)" + [(set_attr "type" "load_ux,load_u")]) + +(define_insn "*movsf_update4" + [(set (mem:SF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (match_operand:SF 3 "gpc_reg_operand" "r,r")) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "(TARGET_SOFT_FLOAT || !TARGET_FPRS) && TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + {stux|stwux} %3,%0,%2 + {stu|stwu} %3,%2(%0)" + [(set_attr "type" "store_ux,store_u")]) + +(define_insn "*movdf_update1" + [(set (match_operand:DF 3 "gpc_reg_operand" "=d,d") + (mem:DF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I")))) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + lfdux %3,%0,%2 + lfdu %3,%2(%0)" + [(set_attr "type" "fpload_ux,fpload_u")]) + +(define_insn "*movdf_update2" + [(set (mem:DF (plus:SI (match_operand:SI 1 "gpc_reg_operand" "0,0") + (match_operand:SI 2 "reg_or_short_operand" "r,I"))) + (match_operand:DF 3 "gpc_reg_operand" "d,d")) + (set (match_operand:SI 0 "gpc_reg_operand" "=b,b") + (plus:SI (match_dup 1) (match_dup 2)))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_UPDATE + && (!avoiding_indexed_address_p (SImode) + || !gpc_reg_operand (operands[2], SImode))" + "@ + stfdux %3,%0,%2 + stfdu %3,%2(%0)" + [(set_attr "type" "fpstore_ux,fpstore_u")]) + +;; Peephole to convert two consecutive FP loads or stores into lfq/stfq. + +(define_insn "*lfq_power2" + [(set (match_operand:V2DF 0 "gpc_reg_operand" "=f") + (match_operand:V2DF 1 "memory_operand" ""))] + "TARGET_POWER2 + && TARGET_HARD_FLOAT && TARGET_FPRS" + "lfq%U1%X1 %0,%1") + +(define_peephole2 + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "memory_operand" "")) + (set (match_operand:DF 2 "gpc_reg_operand" "") + (match_operand:DF 3 "memory_operand" ""))] + "TARGET_POWER2 + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && registers_ok_for_quad_peep (operands[0], operands[2]) + && mems_ok_for_quad_peep (operands[1], operands[3])" + [(set (match_dup 0) + (match_dup 1))] + "operands[1] = widen_memory_access (operands[1], V2DFmode, 0); + operands[0] = gen_rtx_REG (V2DFmode, REGNO (operands[0]));") + +(define_insn "*stfq_power2" + [(set (match_operand:V2DF 0 "memory_operand" "") + (match_operand:V2DF 1 "gpc_reg_operand" "f"))] + "TARGET_POWER2 + && TARGET_HARD_FLOAT && TARGET_FPRS" + "stfq%U0%X0 %1,%0") + + +(define_peephole2 + [(set (match_operand:DF 0 "memory_operand" "") + (match_operand:DF 1 "gpc_reg_operand" "")) + (set (match_operand:DF 2 "memory_operand" "") + (match_operand:DF 3 "gpc_reg_operand" ""))] + "TARGET_POWER2 + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && registers_ok_for_quad_peep (operands[1], operands[3]) + && mems_ok_for_quad_peep (operands[0], operands[2])" + [(set (match_dup 0) + (match_dup 1))] + "operands[0] = widen_memory_access (operands[0], V2DFmode, 0); + operands[1] = gen_rtx_REG (V2DFmode, REGNO (operands[1]));") + +;; After inserting conditional returns we can sometimes have +;; unnecessary register moves. Unfortunately we cannot have a +;; modeless peephole here, because some single SImode sets have early +;; clobber outputs. Although those sets expand to multi-ppc-insn +;; sequences, using get_attr_length here will smash the operands +;; array. Neither is there an early_cobbler_p predicate. +;; Disallow subregs for E500 so we don't munge frob_di_df_2. +(define_peephole2 + [(set (match_operand:DF 0 "gpc_reg_operand" "") + (match_operand:DF 1 "any_operand" "")) + (set (match_operand:DF 2 "gpc_reg_operand" "") + (match_dup 0))] + "!(TARGET_E500_DOUBLE && GET_CODE (operands[2]) == SUBREG) + && peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) (match_dup 1))]) + +(define_peephole2 + [(set (match_operand:SF 0 "gpc_reg_operand" "") + (match_operand:SF 1 "any_operand" "")) + (set (match_operand:SF 2 "gpc_reg_operand" "") + (match_dup 0))] + "peep2_reg_dead_p (2, operands[0])" + [(set (match_dup 2) (match_dup 1))]) + + +;; TLS support. + +;; Mode attributes for different ABIs. +(define_mode_iterator TLSmode [(SI "! TARGET_64BIT") (DI "TARGET_64BIT")]) +(define_mode_attr tls_abi_suffix [(SI "32") (DI "64")]) +(define_mode_attr tls_sysv_suffix [(SI "si") (DI "di")]) +(define_mode_attr tls_insn_suffix [(SI "wz") (DI "d")]) + +(define_insn_and_split "tls_gd_aix<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s")) + (match_operand 4 "" "g"))) + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX" +{ + if (TARGET_CMODEL != CMODEL_SMALL) + return "addis %0,%1,%2@got@tlsgd@ha\;addi %0,%0,%2@got@tlsgd@l\;bl %z3\;%."; + else + return "addi %0,%1,%2@got@tlsgd\;bl %z3\;%."; +} + "&& TARGET_TLS_MARKERS" + [(set (match_dup 0) + (unspec:TLSmode [(match_dup 1) + (match_dup 2)] + UNSPEC_TLSGD)) + (parallel [(set (match_dup 0) + (call (mem:TLSmode (match_dup 3)) + (match_dup 4))) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD) + (clobber (reg:SI LR_REGNO))])] + "" + [(set_attr "type" "two") + (set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 16) + (const_int 12)))]) + +(define_insn_and_split "tls_gd_sysv<TLSmode:tls_sysv_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 3 "symbol_ref_operand" "s")) + (match_operand 4 "" "g"))) + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4" +{ + if (flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + return "addi %0,%1,%2@got@tlsgd\;bl %z3+32768@plt"; + else + return "addi %0,%1,%2@got@tlsgd\;bl %z3@plt"; + } + else + return "addi %0,%1,%2@got@tlsgd\;bl %z3"; +} + "&& TARGET_TLS_MARKERS" + [(set (match_dup 0) + (unspec:TLSmode [(match_dup 1) + (match_dup 2)] + UNSPEC_TLSGD)) + (parallel [(set (match_dup 0) + (call (mem:TLSmode (match_dup 3)) + (match_dup 4))) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD) + (clobber (reg:SI LR_REGNO))])] + "" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn_and_split "*tls_gd<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS" + "addi %0,%1,%2@got@tlsgd" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 3) + (const:TLSmode + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD))))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 3) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGD)))] + " +{ + operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_gd_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (const:TLSmode + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD)))))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%2@got@tlsgd@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_gd_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD)))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addi %0,%1,%2@got@tlsgd@l" + [(set_attr "length" "4")]) + +(define_insn "*tls_gd_call_aix<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX && TARGET_TLS_MARKERS" + "bl %z1(%3@tlsgd)\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*tls_gd_call_sysv<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (unspec:TLSmode [(match_operand:TLSmode 3 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS" +{ + if (flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + return "bl %z1+32768(%3@tlsgd)@plt"; + return "bl %z1(%3@tlsgd)@plt"; + } + return "bl %z1(%3@tlsgd)"; +} + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn_and_split "tls_ld_aix<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s")) + (match_operand 3 "" "g"))) + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")] + UNSPEC_TLSLD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX" +{ + if (TARGET_CMODEL != CMODEL_SMALL) + return "addis %0,%1,%&@got@tlsld@ha\;addi %0,%0,%&@got@tlsld@l\;bl %z2\;%."; + else + return "addi %0,%1,%&@got@tlsld\;bl %z2\;%."; +} + "&& TARGET_TLS_MARKERS" + [(set (match_dup 0) + (unspec:TLSmode [(match_dup 1)] + UNSPEC_TLSLD)) + (parallel [(set (match_dup 0) + (call (mem:TLSmode (match_dup 2)) + (match_dup 3))) + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD) + (clobber (reg:SI LR_REGNO))])] + "" + [(set_attr "type" "two") + (set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 16) + (const_int 12)))]) + +(define_insn_and_split "tls_ld_sysv<TLSmode:tls_sysv_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 2 "symbol_ref_operand" "s")) + (match_operand 3 "" "g"))) + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")] + UNSPEC_TLSLD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4" +{ + if (flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + return "addi %0,%1,%&@got@tlsld\;bl %z2+32768@plt"; + else + return "addi %0,%1,%&@got@tlsld\;bl %z2@plt"; + } + else + return "addi %0,%1,%&@got@tlsld\;bl %z2"; +} + "&& TARGET_TLS_MARKERS" + [(set (match_dup 0) + (unspec:TLSmode [(match_dup 1)] + UNSPEC_TLSLD)) + (parallel [(set (match_dup 0) + (call (mem:TLSmode (match_dup 2)) + (match_dup 3))) + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD) + (clobber (reg:SI LR_REGNO))])] + "" + [(set_attr "length" "8")]) + +(define_insn_and_split "*tls_ld<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b")] + UNSPEC_TLSLD))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS" + "addi %0,%1,%&@got@tlsld" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 2) + (const:TLSmode + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD))))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 2) + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))] + " +{ + operands[2] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_ld_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (const:TLSmode + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%&@got@tlsld@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_ld_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD)))] + "HAVE_AS_TLS && TARGET_TLS_MARKERS && TARGET_CMODEL != CMODEL_SMALL" + "addi %0,%1,%&@got@tlsld@l" + [(set_attr "length" "4")]) + +(define_insn "*tls_ld_call_aix<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_AIX && TARGET_TLS_MARKERS" + "bl %z1(%&@tlsld)\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*tls_ld_call_sysv<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (call (mem:TLSmode (match_operand:TLSmode 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (unspec:TLSmode [(const_int 0)] UNSPEC_TLSLD) + (clobber (reg:SI LR_REGNO))] + "HAVE_AS_TLS && DEFAULT_ABI == ABI_V4 && TARGET_TLS_MARKERS" +{ + if (flag_pic) + { + if (TARGET_SECURE_PLT && flag_pic == 2) + return "bl %z1+32768(%&@tlsld)@plt"; + return "bl %z1(%&@tlsld)@plt"; + } + return "bl %z1(%&@tlsld)"; +} + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "tls_dtprel_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSDTPREL))] + "HAVE_AS_TLS" + "addi %0,%1,%2@dtprel") + +(define_insn "tls_dtprel_ha_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSDTPRELHA))] + "HAVE_AS_TLS" + "addis %0,%1,%2@dtprel@ha") + +(define_insn "tls_dtprel_lo_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSDTPRELLO))] + "HAVE_AS_TLS" + "addi %0,%1,%2@dtprel@l") + +(define_insn_and_split "tls_got_dtprel_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTDTPREL))] + "HAVE_AS_TLS" + "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel(%1)" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 3) + (const:TLSmode + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL))))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 3) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTDTPREL)))] + " +{ + operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_got_dtprel_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (const:TLSmode + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTDTPREL)))))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%2@got@dtprel@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_got_dtprel_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTDTPREL)))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "l<TLSmode:tls_insn_suffix> %0,%2@got@dtprel@l(%1)" + [(set_attr "length" "4")]) + +(define_insn "tls_tprel_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSTPREL))] + "HAVE_AS_TLS" + "addi %0,%1,%2@tprel") + +(define_insn "tls_tprel_ha_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSTPRELHA))] + "HAVE_AS_TLS" + "addis %0,%1,%2@tprel@ha") + +(define_insn "tls_tprel_lo_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSTPRELLO))] + "HAVE_AS_TLS" + "addi %0,%1,%2@tprel@l") + +;; "b" output constraint here and on tls_tls input to support linker tls +;; optimization. The linker may edit the instructions emitted by a +;; tls_got_tprel/tls_tls pair to addis,addi. +(define_insn_and_split "tls_got_tprel_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTTPREL))] + "HAVE_AS_TLS" + "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel(%1)" + "&& TARGET_CMODEL != CMODEL_SMALL" + [(set (match_dup 3) + (const:TLSmode + (plus:TLSmode (match_dup 1) + (high:TLSmode + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL))))) + (set (match_dup 0) + (lo_sum:TLSmode (match_dup 3) + (unspec:TLSmode [(match_dup 2)] UNSPEC_TLSGOTTPREL)))] + " +{ + operands[3] = gen_reg_rtx (TARGET_64BIT ? DImode : SImode); +}" + [(set (attr "length") + (if_then_else (ne (symbol_ref "TARGET_CMODEL") (symbol_ref "CMODEL_SMALL")) + (const_int 8) + (const_int 4)))]) + +(define_insn "*tls_got_tprel_high<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=b") + (const:TLSmode + (plus:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (high:TLSmode + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTTPREL)))))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "addis %0,%1,%2@got@tprel@ha" + [(set_attr "length" "4")]) + +(define_insn "*tls_got_tprel_low<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (lo_sum:TLSmode (match_operand:TLSmode 1 "gpc_reg_operand" "b") + (unspec:TLSmode [(match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSGOTTPREL)))] + "HAVE_AS_TLS && TARGET_CMODEL != CMODEL_SMALL" + "l<TLSmode:tls_insn_suffix> %0,%2@got@tprel@l(%1)" + [(set_attr "length" "4")]) + +(define_insn "tls_tls_<TLSmode:tls_abi_suffix>" + [(set (match_operand:TLSmode 0 "gpc_reg_operand" "=r") + (unspec:TLSmode [(match_operand:TLSmode 1 "gpc_reg_operand" "b") + (match_operand:TLSmode 2 "rs6000_tls_symbol_ref" "")] + UNSPEC_TLSTLS))] + "HAVE_AS_TLS" + "add %0,%1,%2@tls") + +;; Next come insns related to the calling sequence. +;; +;; First, an insn to allocate new stack space for dynamic use (e.g., alloca). +;; We move the back-chain and decrement the stack pointer. + +(define_expand "allocate_stack" + [(set (match_operand 0 "gpc_reg_operand" "") + (minus (reg 1) (match_operand 1 "reg_or_short_operand" ""))) + (set (reg 1) + (minus (reg 1) (match_dup 1)))] + "" + " +{ rtx chain = gen_reg_rtx (Pmode); + rtx stack_bot = gen_rtx_MEM (Pmode, stack_pointer_rtx); + rtx neg_op0; + rtx insn, par, set, mem; + + emit_move_insn (chain, stack_bot); + + /* Check stack bounds if necessary. */ + if (crtl->limit_stack) + { + rtx available; + available = expand_binop (Pmode, sub_optab, + stack_pointer_rtx, stack_limit_rtx, + NULL_RTX, 1, OPTAB_WIDEN); + emit_insn (gen_cond_trap (LTU, available, operands[1], const0_rtx)); + } + + if (GET_CODE (operands[1]) != CONST_INT + || INTVAL (operands[1]) < -32767 + || INTVAL (operands[1]) > 32768) + { + neg_op0 = gen_reg_rtx (Pmode); + if (TARGET_32BIT) + emit_insn (gen_negsi2 (neg_op0, operands[1])); + else + emit_insn (gen_negdi2 (neg_op0, operands[1])); + } + else + neg_op0 = GEN_INT (- INTVAL (operands[1])); + + insn = emit_insn ((* ((TARGET_32BIT) ? gen_movsi_update_stack + : gen_movdi_di_update_stack)) + (stack_pointer_rtx, stack_pointer_rtx, neg_op0, + chain)); + /* Since we didn't use gen_frame_mem to generate the MEM, grab + it now and set the alias set/attributes. The above gen_*_update + calls will generate a PARALLEL with the MEM set being the first + operation. */ + par = PATTERN (insn); + gcc_assert (GET_CODE (par) == PARALLEL); + set = XVECEXP (par, 0, 0); + gcc_assert (GET_CODE (set) == SET); + mem = SET_DEST (set); + gcc_assert (MEM_P (mem)); + MEM_NOTRAP_P (mem) = 1; + set_mem_alias_set (mem, get_frame_alias_set ()); + + emit_move_insn (operands[0], virtual_stack_dynamic_rtx); + DONE; +}") + +;; These patterns say how to save and restore the stack pointer. We need not +;; save the stack pointer at function level since we are careful to +;; preserve the backchain. At block level, we have to restore the backchain +;; when we restore the stack pointer. +;; +;; For nonlocal gotos, we must save both the stack pointer and its +;; backchain and restore both. Note that in the nonlocal case, the +;; save area is a memory location. + +(define_expand "save_stack_function" + [(match_operand 0 "any_operand" "") + (match_operand 1 "any_operand" "")] + "" + "DONE;") + +(define_expand "restore_stack_function" + [(match_operand 0 "any_operand" "") + (match_operand 1 "any_operand" "")] + "" + "DONE;") + +;; Adjust stack pointer (op0) to a new value (op1). +;; First copy old stack backchain to new location, and ensure that the +;; scheduler won't reorder the sp assignment before the backchain write. +(define_expand "restore_stack_block" + [(set (match_dup 2) (match_dup 3)) + (set (match_dup 4) (match_dup 2)) + (set (match_dup 5) (unspec:BLK [(match_dup 5)] UNSPEC_TIE)) + (set (match_operand 0 "register_operand" "") + (match_operand 1 "register_operand" ""))] + "" + " +{ + operands[1] = force_reg (Pmode, operands[1]); + operands[2] = gen_reg_rtx (Pmode); + operands[3] = gen_frame_mem (Pmode, operands[0]); + operands[4] = gen_frame_mem (Pmode, operands[1]); + operands[5] = gen_frame_mem (BLKmode, operands[0]); +}") + +(define_expand "save_stack_nonlocal" + [(set (match_dup 3) (match_dup 4)) + (set (match_operand 0 "memory_operand" "") (match_dup 3)) + (set (match_dup 2) (match_operand 1 "register_operand" ""))] + "" + " +{ + int units_per_word = (TARGET_32BIT) ? 4 : 8; + + /* Copy the backchain to the first word, sp to the second. */ + operands[0] = adjust_address_nv (operands[0], Pmode, 0); + operands[2] = adjust_address_nv (operands[0], Pmode, units_per_word); + operands[3] = gen_reg_rtx (Pmode); + operands[4] = gen_frame_mem (Pmode, operands[1]); +}") + +(define_expand "restore_stack_nonlocal" + [(set (match_dup 2) (match_operand 1 "memory_operand" "")) + (set (match_dup 3) (match_dup 4)) + (set (match_dup 5) (match_dup 2)) + (set (match_dup 6) (unspec:BLK [(match_dup 6)] UNSPEC_TIE)) + (set (match_operand 0 "register_operand" "") (match_dup 3))] + "" + " +{ + int units_per_word = (TARGET_32BIT) ? 4 : 8; + + /* Restore the backchain from the first word, sp from the second. */ + operands[2] = gen_reg_rtx (Pmode); + operands[3] = gen_reg_rtx (Pmode); + operands[1] = adjust_address_nv (operands[1], Pmode, 0); + operands[4] = adjust_address_nv (operands[1], Pmode, units_per_word); + operands[5] = gen_frame_mem (Pmode, operands[3]); + operands[6] = gen_frame_mem (BLKmode, operands[0]); +}") + +;; TOC register handling. + +;; Code to initialize the TOC register... + +(define_insn "load_toc_aix_si" + [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec:SI [(const_int 0)] UNSPEC_TOC)) + (use (reg:SI 2))])] + "DEFAULT_ABI == ABI_AIX && TARGET_32BIT" + "* +{ + char buf[30]; + ASM_GENERATE_INTERNAL_LABEL (buf, \"LCTOC\", 1); + operands[1] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); + operands[2] = gen_rtx_REG (Pmode, 2); + return \"{l|lwz} %0,%1(%2)\"; +}" + [(set_attr "type" "load")]) + +(define_insn "load_toc_aix_di" + [(parallel [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (unspec:DI [(const_int 0)] UNSPEC_TOC)) + (use (reg:DI 2))])] + "DEFAULT_ABI == ABI_AIX && TARGET_64BIT" + "* +{ + char buf[30]; +#ifdef TARGET_RELOCATABLE + ASM_GENERATE_INTERNAL_LABEL (buf, \"LCTOC\", + !TARGET_MINIMAL_TOC || TARGET_RELOCATABLE); +#else + ASM_GENERATE_INTERNAL_LABEL (buf, \"LCTOC\", 1); +#endif + if (TARGET_ELF) + strcat (buf, \"@toc\"); + operands[1] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (buf)); + operands[2] = gen_rtx_REG (Pmode, 2); + return \"ld %0,%1(%2)\"; +}" + [(set_attr "type" "load")]) + +(define_insn "load_toc_v4_pic_si" + [(set (reg:SI LR_REGNO) + (unspec:SI [(const_int 0)] UNSPEC_TOC))] + "DEFAULT_ABI == ABI_V4 && flag_pic == 1 && TARGET_32BIT" + "bl _GLOBAL_OFFSET_TABLE_@local-4" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "load_toc_v4_PIC_1" + [(set (reg:SI LR_REGNO) + (match_operand:SI 0 "immediate_operand" "s")) + (use (unspec [(match_dup 0)] UNSPEC_TOC))] + "TARGET_ELF && DEFAULT_ABI != ABI_AIX + && (flag_pic == 2 || (flag_pic && TARGET_SECURE_PLT))" + "bcl 20,31,%0\\n%0:" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "load_toc_v4_PIC_1b" + [(set (reg:SI LR_REGNO) + (unspec:SI [(match_operand:SI 0 "immediate_operand" "s") + (label_ref (match_operand 1 "" ""))] + UNSPEC_TOCPTR)) + (match_dup 1)] + "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2" + "bcl 20,31,$+8\;.long %0-$" + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "load_toc_v4_PIC_2" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (mem:SI (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (minus:SI (match_operand:SI 2 "immediate_operand" "s") + (match_operand:SI 3 "immediate_operand" "s")))))] + "TARGET_ELF && DEFAULT_ABI != ABI_AIX && flag_pic == 2" + "{l|lwz} %0,%2-%3(%1)" + [(set_attr "type" "load")]) + +(define_insn "load_toc_v4_PIC_3b" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (high:SI + (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s") + (match_operand:SI 3 "symbol_ref_operand" "s")))))] + "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic" + "{cau|addis} %0,%1,%2-%3@ha") + +(define_insn "load_toc_v4_PIC_3c" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b") + (minus:SI (match_operand:SI 2 "symbol_ref_operand" "s") + (match_operand:SI 3 "symbol_ref_operand" "s"))))] + "TARGET_ELF && TARGET_SECURE_PLT && DEFAULT_ABI != ABI_AIX && flag_pic" + "{cal %0,%2-%3@l(%1)|addi %0,%1,%2-%3@l}") + +;; If the TOC is shared over a translation unit, as happens with all +;; the kinds of PIC that we support, we need to restore the TOC +;; pointer only when jumping over units of translation. +;; On Darwin, we need to reload the picbase. + +(define_expand "builtin_setjmp_receiver" + [(use (label_ref (match_operand 0 "" "")))] + "(DEFAULT_ABI == ABI_V4 && flag_pic == 1) + || (TARGET_TOC && TARGET_MINIMAL_TOC) + || (DEFAULT_ABI == ABI_DARWIN && flag_pic)" + " +{ +#if TARGET_MACHO + if (DEFAULT_ABI == ABI_DARWIN) + { + rtx picrtx = gen_rtx_SYMBOL_REF (Pmode, MACHOPIC_FUNCTION_BASE_NAME); + rtx picreg = gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM); + rtx tmplabrtx; + char tmplab[20]; + + crtl->uses_pic_offset_table = 1; + ASM_GENERATE_INTERNAL_LABEL(tmplab, \"LSJR\", + CODE_LABEL_NUMBER (operands[0])); + tmplabrtx = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (tmplab)); + + emit_insn (gen_load_macho_picbase (tmplabrtx)); + emit_move_insn (picreg, gen_rtx_REG (Pmode, LR_REGNO)); + emit_insn (gen_macho_correct_pic (picreg, picreg, picrtx, tmplabrtx)); + } + else +#endif + rs6000_emit_load_toc_table (FALSE); + DONE; +}") + +;; Elf specific ways of loading addresses for non-PIC code. +;; The output of this could be r0, but we make a very strong +;; preference for a base register because it will usually +;; be needed there. +(define_insn "elf_high" + [(set (match_operand:SI 0 "gpc_reg_operand" "=b*r") + (high:SI (match_operand 1 "" "")))] + "TARGET_ELF && ! TARGET_64BIT" + "{liu|lis} %0,%1@ha") + +(define_insn "elf_low" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (lo_sum:SI (match_operand:SI 1 "gpc_reg_operand" "b,!*r") + (match_operand 2 "" "")))] + "TARGET_ELF && ! TARGET_64BIT" + "@ + {cal|la} %0,%2@l(%1) + {ai|addic} %0,%1,%K2") + +;; Largetoc support +(define_insn "largetoc_high" + [(set (match_operand:DI 0 "gpc_reg_operand" "=b") + (const:DI + (plus:DI (match_operand:DI 1 "gpc_reg_operand" "b") + (high:DI (match_operand:DI 2 "" "")))))] + "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" + "{cau|addis} %0,%1,%2@ha") + +(define_insn "largetoc_low" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (lo_sum:DI (match_operand:DI 1 "gpc_reg_operand" "b") + (match_operand:DI 2 "" "")))] + "TARGET_ELF && TARGET_CMODEL != CMODEL_SMALL" + "{cal %0,%2@l(%1)|addi %0,%1,%2@l}") + +;; A function pointer under AIX is a pointer to a data area whose first word +;; contains the actual address of the function, whose second word contains a +;; pointer to its TOC, and whose third word contains a value to place in the +;; static chain register (r11). Note that if we load the static chain, our +;; "trampoline" need not have any executable code. + +(define_expand "call_indirect_aix32" + [(set (match_dup 2) + (mem:SI (match_operand:SI 0 "gpc_reg_operand" ""))) + (set (match_dup 3) + (reg:SI 2)) + (set (reg:SI 11) + (mem:SI (plus:SI (match_dup 0) + (const_int 8)))) + (parallel [(call (mem:SI (match_dup 2)) + (match_operand 1 "" "")) + (use (match_dup 4)) + (set (reg:SI 2) (match_dup 3)) + (use (reg:SI 11)) + (clobber (reg:SI LR_REGNO))])] + "TARGET_32BIT" + " +{ + operands[2] = gen_reg_rtx (SImode); + operands[3] = gen_rtx_MEM (SImode, + gen_rtx_PLUS (SImode, stack_pointer_rtx, + GEN_INT (20))); + + operands[4] = gen_rtx_MEM (SImode, + gen_rtx_PLUS (SImode, operands[0], + GEN_INT (4))); + + /* Make sure the compiler does not optimize away the store of the TOC. */ + MEM_VOLATILE_P (operands[3]) = 1; +}") + +(define_expand "call_indirect_aix64" + [(set (match_dup 2) + (mem:DI (match_operand:DI 0 "gpc_reg_operand" ""))) + (set (match_dup 3) + (reg:DI 2)) + (set (reg:DI 11) + (mem:DI (plus:DI (match_dup 0) + (const_int 16)))) + (parallel [(call (mem:SI (match_dup 2)) + (match_operand 1 "" "")) + (use (match_dup 4)) + (set (reg:DI 2) (match_dup 3)) + (use (reg:DI 11)) + (clobber (reg:DI LR_REGNO))])] + "TARGET_64BIT" + " +{ + operands[2] = gen_reg_rtx (DImode); + operands[3] = gen_rtx_MEM (DImode, + gen_rtx_PLUS (DImode, stack_pointer_rtx, + GEN_INT (40))); + + operands[4] = gen_rtx_MEM (DImode, + gen_rtx_PLUS (DImode, operands[0], + GEN_INT (8))); + + /* Make sure the compiler does not optimize away the store of the TOC. */ + MEM_VOLATILE_P (operands[3]) = 1; +}") + +(define_expand "call_value_indirect_aix32" + [(set (match_dup 3) + (mem:SI (match_operand:SI 1 "gpc_reg_operand" ""))) + (set (match_dup 4) + (reg:SI 2)) + (set (reg:SI 11) + (mem:SI (plus:SI (match_dup 1) + (const_int 8)))) + (parallel [(set (match_operand 0 "" "") + (call (mem:SI (match_dup 3)) + (match_operand 2 "" ""))) + (use (match_dup 5)) + (set (reg:SI 2) (match_dup 4)) + (use (reg:SI 11)) + (clobber (reg:SI LR_REGNO))])] + "TARGET_32BIT" + " +{ + operands[3] = gen_reg_rtx (SImode); + operands[4] = gen_rtx_MEM (SImode, + gen_rtx_PLUS (SImode, stack_pointer_rtx, + GEN_INT (20))); + + operands[5] = gen_rtx_MEM (SImode, + gen_rtx_PLUS (SImode, operands[1], + GEN_INT (4))); + + /* Make sure the compiler does not optimize away the store of the TOC. */ + MEM_VOLATILE_P (operands[4]) = 1; +}") + +(define_expand "call_value_indirect_aix64" + [(set (match_dup 3) + (mem:DI (match_operand:DI 1 "gpc_reg_operand" ""))) + (set (match_dup 4) + (reg:DI 2)) + (set (reg:DI 11) + (mem:DI (plus:DI (match_dup 1) + (const_int 16)))) + (parallel [(set (match_operand 0 "" "") + (call (mem:SI (match_dup 3)) + (match_operand 2 "" ""))) + (use (match_dup 5)) + (set (reg:DI 2) (match_dup 4)) + (use (reg:DI 11)) + (clobber (reg:DI LR_REGNO))])] + "TARGET_64BIT" + " +{ + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_rtx_MEM (DImode, + gen_rtx_PLUS (DImode, stack_pointer_rtx, + GEN_INT (40))); + + operands[5] = gen_rtx_MEM (DImode, + gen_rtx_PLUS (DImode, operands[1], + GEN_INT (8))); + + /* Make sure the compiler does not optimize away the store of the TOC. */ + MEM_VOLATILE_P (operands[4]) = 1; +}") + +;; Now the definitions for the call and call_value insns +(define_expand "call" + [(parallel [(call (mem:SI (match_operand 0 "address_operand" "")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (clobber (reg:SI LR_REGNO))])] + "" + " +{ +#if TARGET_MACHO + if (MACHOPIC_INDIRECT) + operands[0] = machopic_indirect_call_target (operands[0]); +#endif + + gcc_assert (GET_CODE (operands[0]) == MEM); + gcc_assert (GET_CODE (operands[1]) == CONST_INT); + + operands[0] = XEXP (operands[0], 0); + + if (GET_CODE (operands[0]) != SYMBOL_REF + || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[0])) + || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[2]) & CALL_LONG) != 0)) + { + if (INTVAL (operands[2]) & CALL_LONG) + operands[0] = rs6000_longcall_ref (operands[0]); + + switch (DEFAULT_ABI) + { + case ABI_V4: + case ABI_DARWIN: + operands[0] = force_reg (Pmode, operands[0]); + break; + + case ABI_AIX: + /* AIX function pointers are really pointers to a three word + area. */ + emit_call_insn (TARGET_32BIT + ? gen_call_indirect_aix32 (force_reg (SImode, + operands[0]), + operands[1]) + : gen_call_indirect_aix64 (force_reg (DImode, + operands[0]), + operands[1])); + DONE; + + default: + gcc_unreachable (); + } + } +}") + +(define_expand "call_value" + [(parallel [(set (match_operand 0 "" "") + (call (mem:SI (match_operand 1 "address_operand" "")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (clobber (reg:SI LR_REGNO))])] + "" + " +{ +#if TARGET_MACHO + if (MACHOPIC_INDIRECT) + operands[1] = machopic_indirect_call_target (operands[1]); +#endif + + gcc_assert (GET_CODE (operands[1]) == MEM); + gcc_assert (GET_CODE (operands[2]) == CONST_INT); + + operands[1] = XEXP (operands[1], 0); + + if (GET_CODE (operands[1]) != SYMBOL_REF + || (DEFAULT_ABI == ABI_AIX && !SYMBOL_REF_FUNCTION_P (operands[1])) + || (DEFAULT_ABI != ABI_DARWIN && (INTVAL (operands[3]) & CALL_LONG) != 0)) + { + if (INTVAL (operands[3]) & CALL_LONG) + operands[1] = rs6000_longcall_ref (operands[1]); + + switch (DEFAULT_ABI) + { + case ABI_V4: + case ABI_DARWIN: + operands[1] = force_reg (Pmode, operands[1]); + break; + + case ABI_AIX: + /* AIX function pointers are really pointers to a three word + area. */ + emit_call_insn (TARGET_32BIT + ? gen_call_value_indirect_aix32 (operands[0], + force_reg (SImode, + operands[1]), + operands[2]) + : gen_call_value_indirect_aix64 (operands[0], + force_reg (DImode, + operands[1]), + operands[2])); + DONE; + + default: + gcc_unreachable (); + } + } +}") + +;; Call to function in current module. No TOC pointer reload needed. +;; Operand2 is nonzero if we are using the V.4 calling sequence and +;; either the function was not prototyped, or it was prototyped as a +;; variable argument function. It is > 0 if FP registers were passed +;; and < 0 if they were not. + +(define_insn "*call_local32" + [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s")) + (match_operand 1 "" "g,g")) + (use (match_operand:SI 2 "immediate_operand" "O,n")) + (clobber (reg:SI LR_REGNO))] + "(INTVAL (operands[2]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z0@local\" : \"bl %z0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + +(define_insn "*call_local64" + [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s")) + (match_operand 1 "" "g,g")) + (use (match_operand:SI 2 "immediate_operand" "O,n")) + (clobber (reg:SI LR_REGNO))] + "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z0@local\" : \"bl %z0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + +(define_insn "*call_value_local32" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s")) + (match_operand 2 "" "g,g"))) + (use (match_operand:SI 3 "immediate_operand" "O,n")) + (clobber (reg:SI LR_REGNO))] + "(INTVAL (operands[3]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@local\" : \"bl %z1\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + + +(define_insn "*call_value_local64" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s")) + (match_operand 2 "" "g,g"))) + (use (match_operand:SI 3 "immediate_operand" "O,n")) + (clobber (reg:SI LR_REGNO))] + "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"bl %z1@local\" : \"bl %z1\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + +;; Call to function which may be in another module. Restore the TOC +;; pointer (r2) after the call unless this is System V. +;; Operand1 is nonzero if we are using the V.4 calling sequence and +;; either the function was not prototyped, or it was prototyped as a +;; variable argument function. It is > 0 if FP registers were passed +;; and < 0 if they were not. +;; Operand2 is the address of the 3 word function pointer that offset 4 points +;; to the value to be loaded in the TOC register. Do not split the load from +;; the call, as it may move the load of the TOC before any addresses using +;; the TOC. + +(define_insn "*call_indirect_nonlocal_aix32" + [(call (mem:SI (match_operand:SI 0 "register_operand" "c,*l")) + (match_operand 1 "" "g,g")) + (use (match_operand:SI 2 "memory_operand" "m,m")) + (set (reg:SI 2) (match_operand:SI 3 "memory_operand" "m,m")) + (use (reg:SI 11)) + (clobber (reg:SI LR_REGNO))] + "TARGET_32BIT && DEFAULT_ABI == ABI_AIX" + "{l|lwz} 2,%2\;b%T0l\;{l|lwz} 2,%3" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + +(define_insn "*call_nonlocal_aix32" + [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s")) + (match_operand 1 "" "g")) + (use (match_operand:SI 2 "immediate_operand" "O")) + (clobber (reg:SI LR_REGNO))] + "TARGET_32BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[2]) & CALL_LONG) == 0" + "bl %z0\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*call_indirect_nonlocal_aix64" + [(call (mem:SI (match_operand:DI 0 "register_operand" "c,*l")) + (match_operand 1 "" "g,g")) + (use (match_operand:DI 2 "memory_operand" "m,m")) + (set (reg:DI 2) (match_operand:DI 3 "memory_operand" "m,m")) + (use (reg:DI 11)) + (clobber (reg:DI LR_REGNO))] + "TARGET_64BIT && DEFAULT_ABI == ABI_AIX" + "ld 2,%2\;b%T0l\;ld 2,%3" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + +(define_insn "*call_nonlocal_aix64" + [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s")) + (match_operand 1 "" "g")) + (use (match_operand:SI 2 "immediate_operand" "O")) + (clobber (reg:SI LR_REGNO))] + "TARGET_64BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[2]) & CALL_LONG) == 0" + "bl %z0\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*call_value_indirect_nonlocal_aix32" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "register_operand" "c,*l")) + (match_operand 2 "" "g,g"))) + (use (match_operand:SI 3 "memory_operand" "m,m")) + (set (reg:SI 2) (match_operand:SI 4 "memory_operand" "m,m")) + (use (reg:SI 11)) + (clobber (reg:SI LR_REGNO))] + "TARGET_32BIT && DEFAULT_ABI == ABI_AIX" + "{l|lwz} 2,%3\;b%T1l\;{l|lwz} 2,%4" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + +(define_insn "*call_value_nonlocal_aix32" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (use (match_operand:SI 3 "immediate_operand" "O")) + (clobber (reg:SI LR_REGNO))] + "TARGET_32BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[3]) & CALL_LONG) == 0" + "bl %z1\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +(define_insn "*call_value_indirect_nonlocal_aix64" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:DI 1 "register_operand" "c,*l")) + (match_operand 2 "" "g,g"))) + (use (match_operand:DI 3 "memory_operand" "m,m")) + (set (reg:DI 2) (match_operand:DI 4 "memory_operand" "m,m")) + (use (reg:DI 11)) + (clobber (reg:DI LR_REGNO))] + "TARGET_64BIT && DEFAULT_ABI == ABI_AIX" + "ld 2,%3\;b%T1l\;ld 2,%4" + [(set_attr "type" "jmpreg") + (set_attr "length" "12")]) + +(define_insn "*call_value_nonlocal_aix64" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (use (match_operand:SI 3 "immediate_operand" "O")) + (clobber (reg:SI LR_REGNO))] + "TARGET_64BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[3]) & CALL_LONG) == 0" + "bl %z1\;%." + [(set_attr "type" "branch") + (set_attr "length" "8")]) + +;; A function pointer under System V is just a normal pointer +;; operands[0] is the function pointer +;; operands[1] is the stack size to clean up +;; operands[2] is the value FUNCTION_ARG returns for the VOID argument +;; which indicates how to set cr1 + +(define_insn "*call_indirect_nonlocal_sysv<mode>" + [(call (mem:SI (match_operand:P 0 "register_operand" "c,*l,c,*l")) + (match_operand 1 "" "g,g,g,g")) + (use (match_operand:SI 2 "immediate_operand" "O,O,n,n")) + (clobber (reg:SI LR_REGNO))] + "DEFAULT_ABI == ABI_V4 + || DEFAULT_ABI == ABI_DARWIN" +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn ("crxor 6,6,6", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn ("creqv 6,6,6", operands); + + return "b%T0l"; +} + [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg") + (set_attr "length" "4,4,8,8")]) + +(define_insn_and_split "*call_nonlocal_sysv<mode>" + [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s")) + (match_operand 1 "" "g,g")) + (use (match_operand:SI 2 "immediate_operand" "O,n")) + (clobber (reg:SI LR_REGNO))] + "(DEFAULT_ABI == ABI_DARWIN + || (DEFAULT_ABI == ABI_V4 + && (INTVAL (operands[2]) & CALL_LONG) == 0))" +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn ("crxor 6,6,6", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn ("creqv 6,6,6", operands); + +#if TARGET_MACHO + return output_call(insn, operands, 0, 2); +#else + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + gcc_assert (!TARGET_SECURE_PLT); + return "bl %z0@plt"; + } + else + return "bl %z0"; +#endif +} + "DEFAULT_ABI == ABI_V4 + && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0]) + && (INTVAL (operands[2]) & CALL_LONG) == 0" + [(parallel [(call (mem:SI (match_dup 0)) + (match_dup 1)) + (use (match_dup 2)) + (use (match_dup 3)) + (clobber (reg:SI LR_REGNO))])] +{ + operands[3] = pic_offset_table_rtx; +} + [(set_attr "type" "branch,branch") + (set_attr "length" "4,8")]) + +(define_insn "*call_nonlocal_sysv_secure<mode>" + [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s")) + (match_operand 1 "" "g,g")) + (use (match_operand:SI 2 "immediate_operand" "O,n")) + (use (match_operand:SI 3 "register_operand" "r,r")) + (clobber (reg:SI LR_REGNO))] + "(DEFAULT_ABI == ABI_V4 + && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[0]) + && (INTVAL (operands[2]) & CALL_LONG) == 0)" +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn ("crxor 6,6,6", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn ("creqv 6,6,6", operands); + + if (flag_pic == 2) + /* The magic 32768 offset here and in the other sysv call insns + corresponds to the offset of r30 in .got2, as given by LCTOC1. + See sysv4.h:toc_section. */ + return "bl %z0+32768@plt"; + else + return "bl %z0@plt"; +} + [(set_attr "type" "branch,branch") + (set_attr "length" "4,8")]) + +(define_insn "*call_value_indirect_nonlocal_sysv<mode>" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "register_operand" "c,*l,c,*l")) + (match_operand 2 "" "g,g,g,g"))) + (use (match_operand:SI 3 "immediate_operand" "O,O,n,n")) + (clobber (reg:SI LR_REGNO))] + "DEFAULT_ABI == ABI_V4 + || DEFAULT_ABI == ABI_DARWIN" +{ + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn ("crxor 6,6,6", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn ("creqv 6,6,6", operands); + + return "b%T1l"; +} + [(set_attr "type" "jmpreg,jmpreg,jmpreg,jmpreg") + (set_attr "length" "4,4,8,8")]) + +(define_insn_and_split "*call_value_nonlocal_sysv<mode>" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s")) + (match_operand 2 "" "g,g"))) + (use (match_operand:SI 3 "immediate_operand" "O,n")) + (clobber (reg:SI LR_REGNO))] + "(DEFAULT_ABI == ABI_DARWIN + || (DEFAULT_ABI == ABI_V4 + && (INTVAL (operands[3]) & CALL_LONG) == 0))" +{ + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn ("crxor 6,6,6", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn ("creqv 6,6,6", operands); + +#if TARGET_MACHO + return output_call(insn, operands, 1, 3); +#else + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + gcc_assert (!TARGET_SECURE_PLT); + return "bl %z1@plt"; + } + else + return "bl %z1"; +#endif +} + "DEFAULT_ABI == ABI_V4 + && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1]) + && (INTVAL (operands[3]) & CALL_LONG) == 0" + [(parallel [(set (match_dup 0) + (call (mem:SI (match_dup 1)) + (match_dup 2))) + (use (match_dup 3)) + (use (match_dup 4)) + (clobber (reg:SI LR_REGNO))])] +{ + operands[4] = pic_offset_table_rtx; +} + [(set_attr "type" "branch,branch") + (set_attr "length" "4,8")]) + +(define_insn "*call_value_nonlocal_sysv_secure<mode>" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s")) + (match_operand 2 "" "g,g"))) + (use (match_operand:SI 3 "immediate_operand" "O,n")) + (use (match_operand:SI 4 "register_operand" "r,r")) + (clobber (reg:SI LR_REGNO))] + "(DEFAULT_ABI == ABI_V4 + && TARGET_SECURE_PLT && flag_pic && !SYMBOL_REF_LOCAL_P (operands[1]) + && (INTVAL (operands[3]) & CALL_LONG) == 0)" +{ + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn ("crxor 6,6,6", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn ("creqv 6,6,6", operands); + + if (flag_pic == 2) + return "bl %z1+32768@plt"; + else + return "bl %z1@plt"; +} + [(set_attr "type" "branch,branch") + (set_attr "length" "4,8")]) + +;; 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, const0_rtx, 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; +}") + +;; sibling call patterns +(define_expand "sibcall" + [(parallel [(call (mem:SI (match_operand 0 "address_operand" "")) + (match_operand 1 "" "")) + (use (match_operand 2 "" "")) + (use (reg:SI LR_REGNO)) + (return)])] + "" + " +{ +#if TARGET_MACHO + if (MACHOPIC_INDIRECT) + operands[0] = machopic_indirect_call_target (operands[0]); +#endif + + gcc_assert (GET_CODE (operands[0]) == MEM); + gcc_assert (GET_CODE (operands[1]) == CONST_INT); + + operands[0] = XEXP (operands[0], 0); +}") + +;; this and similar patterns must be marked as using LR, otherwise +;; dataflow will try to delete the store into it. This is true +;; even when the actual reg to jump to is in CTR, when LR was +;; saved and restored around the PIC-setting BCL. +(define_insn "*sibcall_local32" + [(call (mem:SI (match_operand:SI 0 "current_file_function_operand" "s,s")) + (match_operand 1 "" "g,g")) + (use (match_operand:SI 2 "immediate_operand" "O,n")) + (use (reg:SI LR_REGNO)) + (return)] + "(INTVAL (operands[2]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z0@local\" : \"b %z0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + +(define_insn "*sibcall_local64" + [(call (mem:SI (match_operand:DI 0 "current_file_function_operand" "s,s")) + (match_operand 1 "" "g,g")) + (use (match_operand:SI 2 "immediate_operand" "O,n")) + (use (reg:SI LR_REGNO)) + (return)] + "TARGET_64BIT && (INTVAL (operands[2]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z0@local\" : \"b %z0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + +(define_insn "*sibcall_value_local32" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "current_file_function_operand" "s,s")) + (match_operand 2 "" "g,g"))) + (use (match_operand:SI 3 "immediate_operand" "O,n")) + (use (reg:SI LR_REGNO)) + (return)] + "(INTVAL (operands[3]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z1@local\" : \"b %z1\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + + +(define_insn "*sibcall_value_local64" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:DI 1 "current_file_function_operand" "s,s")) + (match_operand 2 "" "g,g"))) + (use (match_operand:SI 3 "immediate_operand" "O,n")) + (use (reg:SI LR_REGNO)) + (return)] + "TARGET_64BIT && (INTVAL (operands[3]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[3]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[3]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + return (DEFAULT_ABI == ABI_V4 && flag_pic) ? \"b %z1@local\" : \"b %z1\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "4,8")]) + +(define_insn "*sibcall_nonlocal_aix32" + [(call (mem:SI (match_operand:SI 0 "symbol_ref_operand" "s")) + (match_operand 1 "" "g")) + (use (match_operand:SI 2 "immediate_operand" "O")) + (use (reg:SI LR_REGNO)) + (return)] + "TARGET_32BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[2]) & CALL_LONG) == 0" + "b %z0" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*sibcall_nonlocal_aix64" + [(call (mem:SI (match_operand:DI 0 "symbol_ref_operand" "s")) + (match_operand 1 "" "g")) + (use (match_operand:SI 2 "immediate_operand" "O")) + (use (reg:SI LR_REGNO)) + (return)] + "TARGET_64BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[2]) & CALL_LONG) == 0" + "b %z0" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*sibcall_value_nonlocal_aix32" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:SI 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (use (match_operand:SI 3 "immediate_operand" "O")) + (use (reg:SI LR_REGNO)) + (return)] + "TARGET_32BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[3]) & CALL_LONG) == 0" + "b %z1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*sibcall_value_nonlocal_aix64" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:DI 1 "symbol_ref_operand" "s")) + (match_operand 2 "" "g"))) + (use (match_operand:SI 3 "immediate_operand" "O")) + (use (reg:SI LR_REGNO)) + (return)] + "TARGET_64BIT + && DEFAULT_ABI == ABI_AIX + && (INTVAL (operands[3]) & CALL_LONG) == 0" + "b %z1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*sibcall_nonlocal_sysv<mode>" + [(call (mem:SI (match_operand:P 0 "symbol_ref_operand" "s,s")) + (match_operand 1 "" "")) + (use (match_operand 2 "immediate_operand" "O,n")) + (use (reg:SI LR_REGNO)) + (return)] + "(DEFAULT_ABI == ABI_DARWIN + || DEFAULT_ABI == ABI_V4) + && (INTVAL (operands[2]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + gcc_assert (!TARGET_SECURE_PLT); + return \"b %z0@plt\"; + } + else + return \"b %z0\"; +}" + [(set_attr "type" "branch,branch") + (set_attr "length" "4,8")]) + +(define_expand "sibcall_value" + [(parallel [(set (match_operand 0 "register_operand" "") + (call (mem:SI (match_operand 1 "address_operand" "")) + (match_operand 2 "" ""))) + (use (match_operand 3 "" "")) + (use (reg:SI LR_REGNO)) + (return)])] + "" + " +{ +#if TARGET_MACHO + if (MACHOPIC_INDIRECT) + operands[1] = machopic_indirect_call_target (operands[1]); +#endif + + gcc_assert (GET_CODE (operands[1]) == MEM); + gcc_assert (GET_CODE (operands[2]) == CONST_INT); + + operands[1] = XEXP (operands[1], 0); +}") + +(define_insn "*sibcall_value_nonlocal_sysv<mode>" + [(set (match_operand 0 "" "") + (call (mem:SI (match_operand:P 1 "symbol_ref_operand" "s,s")) + (match_operand 2 "" ""))) + (use (match_operand:SI 3 "immediate_operand" "O,n")) + (use (reg:SI LR_REGNO)) + (return)] + "(DEFAULT_ABI == ABI_DARWIN + || DEFAULT_ABI == ABI_V4) + && (INTVAL (operands[3]) & CALL_LONG) == 0" + "* +{ + if (INTVAL (operands[2]) & CALL_V4_SET_FP_ARGS) + output_asm_insn (\"crxor 6,6,6\", operands); + + else if (INTVAL (operands[2]) & CALL_V4_CLEAR_FP_ARGS) + output_asm_insn (\"creqv 6,6,6\", operands); + + if (DEFAULT_ABI == ABI_V4 && flag_pic) + { + gcc_assert (!TARGET_SECURE_PLT); + return \"b %z1@plt\"; + } + else + return \"b %z1\"; +}" + [(set_attr "type" "branch,branch") + (set_attr "length" "4,8")]) + +(define_expand "sibcall_epilogue" + [(use (const_int 0))] + "TARGET_SCHED_PROLOG" + " +{ + rs6000_emit_epilogue (TRUE); + DONE; +}") + +;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and +;; all of memory. This blocks insns from being moved across this point. + +(define_insn "blockage" + [(unspec_volatile [(const_int 0)] UNSPECV_BLOCK)] + "" + "") + +(define_insn "probe_stack" + [(set (match_operand 0 "memory_operand" "=m") + (unspec [(const_int 0)] UNSPEC_PROBE_STACK))] + "" + "* +{ + operands[1] = gen_rtx_REG (Pmode, 0); + return \"{st%U0%X0|stw%U0%X0} %1,%0\"; +}" + [(set_attr "type" "store") + (set_attr "length" "4")]) + +(define_insn "probe_stack_range<P:mode>" + [(set (match_operand:P 0 "register_operand" "=r") + (unspec_volatile:P [(match_operand:P 1 "register_operand" "0") + (match_operand:P 2 "register_operand" "r")] + UNSPECV_PROBE_STACK_RANGE))] + "" + "* return output_probe_stack_range (operands[0], operands[2]);" + [(set_attr "type" "three")]) + +;; Compare insns are next. Note that the RS/6000 has two types of compares, +;; signed & unsigned, and one type of branch. +;; +;; Start with the DEFINE_EXPANDs to generate the rtl for compares, scc +;; insns, and branches. + +(define_expand "cbranch<mode>4" + [(use (match_operator 0 "rs6000_cbranch_operator" + [(match_operand:GPR 1 "gpc_reg_operand" "") + (match_operand:GPR 2 "reg_or_short_operand" "")])) + (use (match_operand 3 ""))] + "" + " +{ + /* Take care of the possibility that operands[2] might be negative but + this might be a logical operation. That insn doesn't exist. */ + if (GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) < 0) + { + operands[2] = force_reg (<MODE>mode, operands[2]); + operands[0] = gen_rtx_fmt_ee (GET_CODE (operands[0]), + GET_MODE (operands[0]), + operands[1], operands[2]); + } + + rs6000_emit_cbranch (<MODE>mode, operands); + DONE; +}") + +(define_expand "cbranch<mode>4" + [(use (match_operator 0 "rs6000_cbranch_operator" + [(match_operand:FP 1 "gpc_reg_operand" "") + (match_operand:FP 2 "gpc_reg_operand" "")])) + (use (match_operand 3 ""))] + "" + " +{ + rs6000_emit_cbranch (<MODE>mode, operands); + DONE; +}") + +(define_expand "cstore<mode>4" + [(use (match_operator 1 "rs6000_cbranch_operator" + [(match_operand:GPR 2 "gpc_reg_operand" "") + (match_operand:GPR 3 "reg_or_short_operand" "")])) + (clobber (match_operand:SI 0 "register_operand"))] + "" + " +{ + /* Take care of the possibility that operands[3] might be negative but + this might be a logical operation. That insn doesn't exist. */ + if (GET_CODE (operands[3]) == CONST_INT + && INTVAL (operands[3]) < 0) + { + operands[3] = force_reg (<MODE>mode, operands[3]); + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), + GET_MODE (operands[1]), + operands[2], operands[3]); + } + + /* For SNE, we would prefer that the xor/abs sequence be used for integers. + For SEQ, likewise, except that comparisons with zero should be done + with an scc insns. However, due to the order that combine see the + resulting insns, we must, in fact, allow SEQ for integers. Fail in + the cases we don't want to handle or are best handled by portable + code. */ + if (GET_CODE (operands[1]) == NE) + FAIL; + if ((GET_CODE (operands[1]) == LT || GET_CODE (operands[1]) == LE + || GET_CODE (operands[1]) == GT || GET_CODE (operands[1]) == GE) + && operands[3] == const0_rtx) + FAIL; + rs6000_emit_sCOND (<MODE>mode, operands); + DONE; +}") + +(define_expand "cstore<mode>4" + [(use (match_operator 1 "rs6000_cbranch_operator" + [(match_operand:FP 2 "gpc_reg_operand" "") + (match_operand:FP 3 "gpc_reg_operand" "")])) + (clobber (match_operand:SI 0 "register_operand"))] + "" + " +{ + rs6000_emit_sCOND (<MODE>mode, operands); + DONE; +}") + + +(define_expand "stack_protect_set" + [(match_operand 0 "memory_operand" "") + (match_operand 1 "memory_operand" "")] + "" +{ +#ifdef TARGET_THREAD_SSP_OFFSET + rtx tlsreg = gen_rtx_REG (Pmode, TARGET_64BIT ? 13 : 2); + rtx addr = gen_rtx_PLUS (Pmode, tlsreg, GEN_INT (TARGET_THREAD_SSP_OFFSET)); + operands[1] = gen_rtx_MEM (Pmode, addr); +#endif + if (TARGET_64BIT) + emit_insn (gen_stack_protect_setdi (operands[0], operands[1])); + else + emit_insn (gen_stack_protect_setsi (operands[0], operands[1])); + DONE; +}) + +(define_insn "stack_protect_setsi" + [(set (match_operand:SI 0 "memory_operand" "=m") + (unspec:SI [(match_operand:SI 1 "memory_operand" "m")] UNSPEC_SP_SET)) + (set (match_scratch:SI 2 "=&r") (const_int 0))] + "TARGET_32BIT" + "{l%U1%X1|lwz%U1%X1} %2,%1\;{st%U0%X0|stw%U0%X0} %2,%0\;{lil|li} %2,0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "stack_protect_setdi" + [(set (match_operand:DI 0 "memory_operand" "=m") + (unspec:DI [(match_operand:DI 1 "memory_operand" "m")] UNSPEC_SP_SET)) + (set (match_scratch:DI 2 "=&r") (const_int 0))] + "TARGET_64BIT" + "ld%U1%X1 %2,%1\;std%U0%X0 %2,%0\;{lil|li} %2,0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_expand "stack_protect_test" + [(match_operand 0 "memory_operand" "") + (match_operand 1 "memory_operand" "") + (match_operand 2 "" "")] + "" +{ + rtx test, op0, op1; +#ifdef TARGET_THREAD_SSP_OFFSET + rtx tlsreg = gen_rtx_REG (Pmode, TARGET_64BIT ? 13 : 2); + rtx addr = gen_rtx_PLUS (Pmode, tlsreg, GEN_INT (TARGET_THREAD_SSP_OFFSET)); + operands[1] = gen_rtx_MEM (Pmode, addr); +#endif + op0 = operands[0]; + op1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, operands[1]), UNSPEC_SP_TEST); + test = gen_rtx_EQ (VOIDmode, op0, op1); + emit_jump_insn (gen_cbranchsi4 (test, op0, op1, operands[2])); + DONE; +}) + +(define_insn "stack_protect_testsi" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=x,?y") + (unspec:CCEQ [(match_operand:SI 1 "memory_operand" "m,m") + (match_operand:SI 2 "memory_operand" "m,m")] + UNSPEC_SP_TEST)) + (set (match_scratch:SI 4 "=r,r") (const_int 0)) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "TARGET_32BIT" + "@ + {l%U1%X1|lwz%U1%X1} %3,%1\;{l%U2%X2|lwz%U2%X2} %4,%2\;xor. %3,%3,%4\;{lil|li} %4,0 + {l%U1%X1|lwz%U1%X1} %3,%1\;{l%U2%X2|lwz%U2%X2} %4,%2\;{cmpl|cmplw} %0,%3,%4\;{lil|li} %3,0\;{lil|li} %4,0" + [(set_attr "length" "16,20")]) + +(define_insn "stack_protect_testdi" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=x,?y") + (unspec:CCEQ [(match_operand:DI 1 "memory_operand" "m,m") + (match_operand:DI 2 "memory_operand" "m,m")] + UNSPEC_SP_TEST)) + (set (match_scratch:DI 4 "=r,r") (const_int 0)) + (clobber (match_scratch:DI 3 "=&r,&r"))] + "TARGET_64BIT" + "@ + ld%U1%X1 %3,%1\;ld%U2%X2 %4,%2\;xor. %3,%3,%4\;{lil|li} %4,0 + ld%U1%X1 %3,%1\;ld%U2%X2 %4,%2\;cmpld %0,%3,%4\;{lil|li} %3,0\;{lil|li} %4,0" + [(set_attr "length" "16,20")]) + + +;; Here are the actual compare insns. +(define_insn "*cmp<mode>_internal1" + [(set (match_operand:CC 0 "cc_reg_operand" "=y") + (compare:CC (match_operand:GPR 1 "gpc_reg_operand" "r") + (match_operand:GPR 2 "reg_or_short_operand" "rI")))] + "" + "{cmp%I2|cmp<wd>%I2} %0,%1,%2" + [(set_attr "type" "cmp")]) + +;; If we are comparing a register for equality with a large constant, +;; we can do this with an XOR followed by a compare. But this is profitable +;; only if the large constant is only used for the comparison (and in this +;; case we already have a register to reuse as scratch). +;; +;; For 64-bit registers, we could only do so if the constant's bit 15 is clear: +;; otherwise we'd need to XOR with FFFFFFFF????0000 which is not available. + +(define_peephole2 + [(set (match_operand:SI 0 "register_operand") + (match_operand:SI 1 "logical_const_operand" "")) + (set (match_dup 0) (match_operator:SI 3 "boolean_or_operator" + [(match_dup 0) + (match_operand:SI 2 "logical_const_operand" "")])) + (set (match_operand:CC 4 "cc_reg_operand" "") + (compare:CC (match_operand:SI 5 "gpc_reg_operand" "") + (match_dup 0))) + (set (pc) + (if_then_else (match_operator 6 "equality_operator" + [(match_dup 4) (const_int 0)]) + (match_operand 7 "" "") + (match_operand 8 "" "")))] + "peep2_reg_dead_p (3, operands[0]) + && peep2_reg_dead_p (4, operands[4])" + [(set (match_dup 0) (xor:SI (match_dup 5) (match_dup 9))) + (set (match_dup 4) (compare:CC (match_dup 0) (match_dup 10))) + (set (pc) (if_then_else (match_dup 6) (match_dup 7) (match_dup 8)))] + +{ + /* Get the constant we are comparing against, and see what it looks like + when sign-extended from 16 to 32 bits. Then see what constant we could + XOR with SEXTC to get the sign-extended value. */ + rtx cnst = simplify_const_binary_operation (GET_CODE (operands[3]), + SImode, + operands[1], operands[2]); + HOST_WIDE_INT c = INTVAL (cnst); + HOST_WIDE_INT sextc = ((c & 0xffff) ^ 0x8000) - 0x8000; + HOST_WIDE_INT xorv = c ^ sextc; + + operands[9] = GEN_INT (xorv); + operands[10] = GEN_INT (sextc); +}) + +(define_insn "*cmpsi_internal2" + [(set (match_operand:CCUNS 0 "cc_reg_operand" "=y") + (compare:CCUNS (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_u_short_operand" "rK")))] + "" + "{cmpl%I2|cmplw%I2} %0,%1,%b2" + [(set_attr "type" "cmp")]) + +(define_insn "*cmpdi_internal2" + [(set (match_operand:CCUNS 0 "cc_reg_operand" "=y") + (compare:CCUNS (match_operand:DI 1 "gpc_reg_operand" "r") + (match_operand:DI 2 "reg_or_u_short_operand" "rK")))] + "" + "cmpld%I2 %0,%1,%b2" + [(set_attr "type" "cmp")]) + +;; The following two insns don't exist as single insns, but if we provide +;; them, we can swap an add and compare, which will enable us to overlap more +;; of the required delay between a compare and branch. We generate code for +;; them by splitting. + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=y") + (compare:CC (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "short_cint_operand" "i"))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "i")))] + "" + "#" + [(set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:CCUNS 3 "cc_reg_operand" "=y") + (compare:CCUNS (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "u_short_cint_operand" "i"))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "i")))] + "" + "#" + [(set_attr "length" "8")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_operand" "") + (compare:CC (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "short_cint_operand" ""))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "")))] + "" + [(set (match_dup 3) (compare:CC (match_dup 1) (match_dup 2))) + (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 4)))]) + +(define_split + [(set (match_operand:CCUNS 3 "cc_reg_operand" "") + (compare:CCUNS (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "u_short_cint_operand" ""))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (match_dup 1) (match_operand:SI 4 "short_cint_operand" "")))] + "" + [(set (match_dup 3) (compare:CCUNS (match_dup 1) (match_dup 2))) + (set (match_dup 0) (plus:SI (match_dup 1) (match_dup 4)))]) + +(define_insn "*cmpsf_internal1" + [(set (match_operand:CCFP 0 "cc_reg_operand" "=y") + (compare:CCFP (match_operand:SF 1 "gpc_reg_operand" "f") + (match_operand:SF 2 "gpc_reg_operand" "f")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT" + "fcmpu %0,%1,%2" + [(set_attr "type" "fpcompare")]) + +(define_insn "*cmpdf_internal1" + [(set (match_operand:CCFP 0 "cc_reg_operand" "=y") + (compare:CCFP (match_operand:DF 1 "gpc_reg_operand" "d") + (match_operand:DF 2 "gpc_reg_operand" "d")))] + "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT + && !VECTOR_UNIT_VSX_P (DFmode)" + "fcmpu %0,%1,%2" + [(set_attr "type" "fpcompare")]) + +;; Only need to compare second words if first words equal +(define_insn "*cmptf_internal1" + [(set (match_operand:CCFP 0 "cc_reg_operand" "=y") + (compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "d") + (match_operand:TF 2 "gpc_reg_operand" "d")))] + "!TARGET_IEEEQUAD && !TARGET_XL_COMPAT + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LONG_DOUBLE_128" + "fcmpu %0,%1,%2\;bne %0,$+8\;fcmpu %0,%L1,%L2" + [(set_attr "type" "fpcompare") + (set_attr "length" "12")]) + +(define_insn_and_split "*cmptf_internal2" + [(set (match_operand:CCFP 0 "cc_reg_operand" "=y") + (compare:CCFP (match_operand:TF 1 "gpc_reg_operand" "d") + (match_operand:TF 2 "gpc_reg_operand" "d"))) + (clobber (match_scratch:DF 3 "=d")) + (clobber (match_scratch:DF 4 "=d")) + (clobber (match_scratch:DF 5 "=d")) + (clobber (match_scratch:DF 6 "=d")) + (clobber (match_scratch:DF 7 "=d")) + (clobber (match_scratch:DF 8 "=d")) + (clobber (match_scratch:DF 9 "=d")) + (clobber (match_scratch:DF 10 "=d")) + (clobber (match_scratch:GPR 11 "=b"))] + "!TARGET_IEEEQUAD && TARGET_XL_COMPAT + && TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT && TARGET_LONG_DOUBLE_128" + "#" + "&& reload_completed" + [(set (match_dup 3) (match_dup 14)) + (set (match_dup 4) (match_dup 15)) + (set (match_dup 9) (abs:DF (match_dup 5))) + (set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 3))) + (set (pc) (if_then_else (ne (match_dup 0) (const_int 0)) + (label_ref (match_dup 12)) + (pc))) + (set (match_dup 0) (compare:CCFP (match_dup 5) (match_dup 7))) + (set (pc) (label_ref (match_dup 13))) + (match_dup 12) + (set (match_dup 10) (minus:DF (match_dup 5) (match_dup 7))) + (set (match_dup 9) (minus:DF (match_dup 6) (match_dup 8))) + (set (match_dup 9) (plus:DF (match_dup 10) (match_dup 9))) + (set (match_dup 0) (compare:CCFP (match_dup 9) (match_dup 4))) + (match_dup 13)] +{ + REAL_VALUE_TYPE rv; + const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0; + const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode); + + operands[5] = simplify_gen_subreg (DFmode, operands[1], TFmode, hi_word); + operands[6] = simplify_gen_subreg (DFmode, operands[1], TFmode, lo_word); + operands[7] = simplify_gen_subreg (DFmode, operands[2], TFmode, hi_word); + operands[8] = simplify_gen_subreg (DFmode, operands[2], TFmode, lo_word); + operands[12] = gen_label_rtx (); + operands[13] = gen_label_rtx (); + real_inf (&rv); + operands[14] = force_const_mem (DFmode, + CONST_DOUBLE_FROM_REAL_VALUE (rv, DFmode)); + operands[15] = force_const_mem (DFmode, + CONST_DOUBLE_FROM_REAL_VALUE (dconst0, + DFmode)); + if (TARGET_TOC) + { + rtx tocref; + tocref = create_TOC_reference (XEXP (operands[14], 0), operands[11]); + operands[14] = gen_const_mem (DFmode, tocref); + tocref = create_TOC_reference (XEXP (operands[15], 0), operands[11]); + operands[15] = gen_const_mem (DFmode, tocref); + set_mem_alias_set (operands[14], get_TOC_alias_set ()); + set_mem_alias_set (operands[15], get_TOC_alias_set ()); + } +}) + +;; Now we have the scc insns. We can do some combinations because of the +;; way the machine works. +;; +;; Note that this is probably faster if we can put an insn between the +;; mfcr and rlinm, but this is tricky. Let's leave it for now. In most +;; cases the insns below which don't use an intermediate CR field will +;; be used instead. +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (match_operator:SI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y") + (const_int 0)]))] + "" + "mfcr %0%Q2\;{rlinm|rlwinm} %0,%0,%J1,1" + [(set (attr "type") + (cond [(ne (symbol_ref "TARGET_MFCRF") (const_int 0)) + (const_string "mfcrf") + ] + (const_string "mfcr"))) + (set_attr "length" "8")]) + +;; Same as above, but get the GT bit. +(define_insn "move_from_CR_gt_bit" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec:SI [(match_operand 1 "cc_reg_operand" "y")] UNSPEC_MV_CR_GT))] + "TARGET_HARD_FLOAT && !TARGET_FPRS" + "mfcr %0\;{rlinm|rlwinm} %0,%0,%D1,31,31" + [(set_attr "type" "mfcr") + (set_attr "length" "8")]) + +;; Same as above, but get the OV/ORDERED bit. +(define_insn "move_from_CR_ov_bit" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec:SI [(match_operand 1 "cc_reg_operand" "y")] UNSPEC_MV_CR_OV))] + "TARGET_ISEL" + "mfcr %0\;{rlinm|rlwinm} %0,%0,%t1,1" + [(set_attr "type" "mfcr") + (set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (match_operator:DI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y") + (const_int 0)]))] + "TARGET_POWERPC64" + "mfcr %0%Q2\;{rlinm|rlwinm} %0,%0,%J1,1" + [(set (attr "type") + (cond [(ne (symbol_ref "TARGET_MFCRF") (const_int 0)) + (const_string "mfcrf") + ] + (const_string "mfcr"))) + (set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC (match_operator:SI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y,y") + (const_int 0)]) + (const_int 0))) + (set (match_operand:SI 3 "gpc_reg_operand" "=r,r") + (match_op_dup 1 [(match_dup 2) (const_int 0)]))] + "TARGET_32BIT" + "@ + mfcr %3%Q2\;{rlinm.|rlwinm.} %3,%3,%J1,1 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "8,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC (match_operator:SI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "") + (const_int 0)]) + (const_int 0))) + (set (match_operand:SI 3 "gpc_reg_operand" "") + (match_op_dup 1 [(match_dup 2) (const_int 0)]))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 3) + (match_op_dup 1 [(match_dup 2) (const_int 0)])) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ashift:SI (match_operator:SI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y") + (const_int 0)]) + (match_operand:SI 3 "const_int_operand" "n")))] + "" + "* +{ + int is_bit = ccr_bit (operands[1], 1); + int put_bit = 31 - (INTVAL (operands[3]) & 31); + int count; + + if (is_bit >= put_bit) + count = is_bit - put_bit; + else + count = 32 - (put_bit - is_bit); + + operands[4] = GEN_INT (count); + operands[5] = GEN_INT (put_bit); + + return \"mfcr %0%Q2\;{rlinm|rlwinm} %0,%0,%4,%5,%5\"; +}" + [(set (attr "type") + (cond [(ne (symbol_ref "TARGET_MFCRF") (const_int 0)) + (const_string "mfcrf") + ] + (const_string "mfcr"))) + (set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (ashift:SI (match_operator:SI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y,y") + (const_int 0)]) + (match_operand:SI 3 "const_int_operand" "n,n")) + (const_int 0))) + (set (match_operand:SI 4 "gpc_reg_operand" "=r,r") + (ashift:SI (match_op_dup 1 [(match_dup 2) (const_int 0)]) + (match_dup 3)))] + "" + "* +{ + int is_bit = ccr_bit (operands[1], 1); + int put_bit = 31 - (INTVAL (operands[3]) & 31); + int count; + + /* Force split for non-cc0 compare. */ + if (which_alternative == 1) + return \"#\"; + + if (is_bit >= put_bit) + count = is_bit - put_bit; + else + count = 32 - (put_bit - is_bit); + + operands[5] = GEN_INT (count); + operands[6] = GEN_INT (put_bit); + + return \"mfcr %4%Q2\;{rlinm.|rlwinm.} %4,%4,%5,%6,%6\"; +}" + [(set_attr "type" "delayed_compare") + (set_attr "length" "8,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (ashift:SI (match_operator:SI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "") + (const_int 0)]) + (match_operand:SI 3 "const_int_operand" "")) + (const_int 0))) + (set (match_operand:SI 4 "gpc_reg_operand" "") + (ashift:SI (match_op_dup 1 [(match_dup 2) (const_int 0)]) + (match_dup 3)))] + "reload_completed" + [(set (match_dup 4) + (ashift:SI (match_op_dup 1 [(match_dup 2) (const_int 0)]) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +;; There is a 3 cycle delay between consecutive mfcr instructions +;; so it is useful to combine 2 scc instructions to use only one mfcr. + +(define_peephole + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (match_operator:SI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y") + (const_int 0)])) + (set (match_operand:SI 3 "gpc_reg_operand" "=r") + (match_operator:SI 4 "scc_comparison_operator" + [(match_operand 5 "cc_reg_operand" "y") + (const_int 0)]))] + "REGNO (operands[2]) != REGNO (operands[5])" + "mfcr %3\;{rlinm|rlwinm} %0,%3,%J1,1\;{rlinm|rlwinm} %3,%3,%J4,1" + [(set_attr "type" "mfcr") + (set_attr "length" "12")]) + +(define_peephole + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (match_operator:DI 1 "scc_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y") + (const_int 0)])) + (set (match_operand:DI 3 "gpc_reg_operand" "=r") + (match_operator:DI 4 "scc_comparison_operator" + [(match_operand 5 "cc_reg_operand" "y") + (const_int 0)]))] + "TARGET_POWERPC64 && REGNO (operands[2]) != REGNO (operands[5])" + "mfcr %3\;{rlinm|rlwinm} %0,%3,%J1,1\;{rlinm|rlwinm} %3,%3,%J4,1" + [(set_attr "type" "mfcr") + (set_attr "length" "12")]) + +;; There are some scc insns that can be done directly, without a compare. +;; These are faster because they don't involve the communications between +;; the FXU and branch units. In fact, we will be replacing all of the +;; integer scc insns here or in the portable methods in emit_store_flag. +;; +;; Also support (neg (scc ..)) since that construct is used to replace +;; branches, (plus (scc ..) ..) since that construct is common and +;; takes no more insns than scc, and (and (neg (scc ..)) ..) in the +;; cases where it is no more expensive than (neg (scc ..)). + +;; Have reload force a constant into a register for the simple insns that +;; otherwise won't accept constants. We do this because it is faster than +;; the cmp/mfcr sequence we would otherwise generate. + +(define_mode_attr scc_eq_op2 [(SI "rKLI") + (DI "rKJI")]) + +(define_insn_and_split "*eq<mode>" + [(set (match_operand:GPR 0 "gpc_reg_operand" "=r") + (eq:GPR (match_operand:GPR 1 "gpc_reg_operand" "r") + (match_operand:GPR 2 "scc_eq_operand" "<scc_eq_op2>")))] + "!TARGET_POWER" + "#" + "!TARGET_POWER" + [(set (match_dup 0) + (clz:GPR (match_dup 3))) + (set (match_dup 0) + (lshiftrt:GPR (match_dup 0) (match_dup 4)))] + { + if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0) + { + /* Use output operand as intermediate. */ + operands[3] = operands[0]; + + if (logical_operand (operands[2], <MODE>mode)) + emit_insn (gen_rtx_SET (VOIDmode, operands[3], + gen_rtx_XOR (<MODE>mode, + operands[1], operands[2]))); + else + emit_insn (gen_rtx_SET (VOIDmode, operands[3], + gen_rtx_PLUS (<MODE>mode, operands[1], + negate_rtx (<MODE>mode, + operands[2])))); + } + else + operands[3] = operands[1]; + + operands[4] = GEN_INT (exact_log2 (GET_MODE_BITSIZE (<MODE>mode))); + }) + +(define_insn_and_split "*eq<mode>_compare" + [(set (match_operand:CC 3 "cc_reg_operand" "=y") + (compare:CC + (eq:P (match_operand:P 1 "gpc_reg_operand" "=r") + (match_operand:P 2 "scc_eq_operand" "<scc_eq_op2>")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r") + (eq:P (match_dup 1) (match_dup 2)))] + "!TARGET_POWER && optimize_size" + "#" + "!TARGET_POWER && optimize_size" + [(set (match_dup 0) + (clz:P (match_dup 4))) + (parallel [(set (match_dup 3) + (compare:CC (lshiftrt:P (match_dup 0) (match_dup 5)) + (const_int 0))) + (set (match_dup 0) + (lshiftrt:P (match_dup 0) (match_dup 5)))])] + { + if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0) + { + /* Use output operand as intermediate. */ + operands[4] = operands[0]; + + if (logical_operand (operands[2], <MODE>mode)) + emit_insn (gen_rtx_SET (VOIDmode, operands[4], + gen_rtx_XOR (<MODE>mode, + operands[1], operands[2]))); + else + emit_insn (gen_rtx_SET (VOIDmode, operands[4], + gen_rtx_PLUS (<MODE>mode, operands[1], + negate_rtx (<MODE>mode, + operands[2])))); + } + else + operands[4] = operands[1]; + + operands[5] = GEN_INT (exact_log2 (GET_MODE_BITSIZE (<MODE>mode))); + }) + +(define_insn "*eqsi_power" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r,r") + (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r") + (match_operand:SI 2 "reg_or_cint_operand" "r,O,K,L,I"))) + (clobber (match_scratch:SI 3 "=r,&r,r,r,r"))] + "TARGET_POWER" + "@ + xor %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0 + {sfi|subfic} %3,%1,0\;{ae|adde} %0,%3,%1 + {xoril|xori} %0,%1,%b2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0 + {xoriu|xoris} %0,%1,%u2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0 + {sfi|subfic} %0,%1,%2\;{sfi|subfic} %3,%0,0\;{ae|adde} %0,%3,%0" + [(set_attr "type" "three,two,three,three,three") + (set_attr "length" "12,8,12,12,12")]) + +;; We have insns of the form shown by the first define_insn below. If +;; there is something inside the comparison operation, we must split it. +(define_split + [(set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (match_operator 1 "comparison_operator" + [(match_operand:SI 2 "" "") + (match_operand:SI 3 + "reg_or_cint_operand" "")]) + (match_operand:SI 4 "gpc_reg_operand" ""))) + (clobber (match_operand:SI 5 "register_operand" ""))] + "! gpc_reg_operand (operands[2], SImode)" + [(set (match_dup 5) (match_dup 2)) + (set (match_dup 2) (plus:SI (match_op_dup 1 [(match_dup 2) (match_dup 3)]) + (match_dup 4)))]) + +(define_insn "*plus_eqsi" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r,&r,&r,&r") + (plus:SI (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r") + (match_operand:SI 2 "scc_eq_operand" "r,O,K,L,I")) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r,r")))] + "TARGET_32BIT" + "@ + xor %0,%1,%2\;{sfi|subfic} %0,%0,0\;{aze|addze} %0,%3 + {sfi|subfic} %0,%1,0\;{aze|addze} %0,%3 + {xoril|xori} %0,%1,%b2\;{sfi|subfic} %0,%0,0\;{aze|addze} %0,%3 + {xoriu|xoris} %0,%1,%u2\;{sfi|subfic} %0,%0,0\;{aze|addze} %0,%3 + {sfi|subfic} %0,%1,%2\;{sfi|subfic} %0,%0,0\;{aze|addze} %0,%3" + [(set_attr "type" "three,two,three,three,three") + (set_attr "length" "12,8,12,12,12")]) + +(define_insn "*compare_plus_eqsi" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,x,x,x,?y,?y,?y,?y,?y") + (compare:CC + (plus:SI + (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r") + (match_operand:SI 2 "scc_eq_operand" "r,O,K,L,I,r,O,K,L,I")) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r,r,r,r,r,r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r,&r,&r,&r,&r,&r,&r,&r,&r"))] + "TARGET_32BIT && optimize_size" + "@ + xor %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3 + {sfi|subfic} %4,%1,0\;{aze.|addze.} %4,%3 + {xoril|xori} %4,%1,%b2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3 + {xoriu|xoris} %4,%1,%u2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3 + {sfi|subfic} %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3 + # + # + # + # + #" + [(set_attr "type" "compare") + (set_attr "length" "12,8,12,12,12,16,12,16,16,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI + (eq:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "scc_eq_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_32BIT && optimize_size && reload_completed" + [(set (match_dup 4) + (plus:SI (eq:SI (match_dup 1) + (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "*plus_eqsi_compare" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,x,x,x,?y,?y,?y,?y,?y") + (compare:CC + (plus:SI + (eq:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r,r,r,r,r,r,r") + (match_operand:SI 2 "scc_eq_operand" "r,O,K,L,I,r,O,K,L,I")) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r,r,r,r,r,r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r,&r,&r,&r,&r,&r,&r,&r,&r") + (plus:SI (eq:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_32BIT && optimize_size" + "@ + xor %0,%1,%2\;{sfi|subfic} %0,%0,0\;{aze.|addze.} %0,%3 + {sfi|subfic} %0,%1,0\;{aze.|addze.} %0,%3 + {xoril|xori} %0,%1,%b2\;{sfi|subfic} %0,%0,0\;{aze.|addze.} %0,%3 + {xoriu|xoris} %0,%1,%u2\;{sfi|subfic} %0,%0,0\;{aze.|addze.} %0,%3 + {sfi|subfic} %0,%1,%2\;{sfi|subfic} %0,%0,0\;{aze.|addze.} %0,%3 + # + # + # + # + #" + [(set_attr "type" "compare") + (set_attr "length" "12,8,12,12,12,16,12,16,16,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI + (eq:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "scc_eq_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (eq:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_32BIT && optimize_size && reload_completed" + [(set (match_dup 0) + (plus:SI (eq:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*neg_eq0<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (neg:P (eq:P (match_operand:P 1 "gpc_reg_operand" "r") + (const_int 0))))] + "" + "{ai|addic} %0,%1,-1\;{sfe|subfe} %0,%0,%0" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn_and_split "*neg_eq<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (neg:P (eq:P (match_operand:P 1 "gpc_reg_operand" "%r") + (match_operand:P 2 "scc_eq_operand" "<scc_eq_op2>"))))] + "" + "#" + "" + [(set (match_dup 0) (neg:P (eq:P (match_dup 3) (const_int 0))))] + { + if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) != 0) + { + /* Use output operand as intermediate. */ + operands[3] = operands[0]; + + if (logical_operand (operands[2], <MODE>mode)) + emit_insn (gen_rtx_SET (VOIDmode, operands[3], + gen_rtx_XOR (<MODE>mode, + operands[1], operands[2]))); + else + emit_insn (gen_rtx_SET (VOIDmode, operands[3], + gen_rtx_PLUS (<MODE>mode, operands[1], + negate_rtx (<MODE>mode, + operands[2])))); + } + else + operands[3] = operands[1]; + }) + +;; Simplify (ne X (const_int 0)) on the PowerPC. No need to on the Power, +;; since it nabs/sr is just as fast. +(define_insn "*ne0si" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r") + (lshiftrt:SI (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r"))) + (const_int 31))) + (clobber (match_scratch:SI 2 "=&r"))] + "! TARGET_POWER && TARGET_32BIT && !TARGET_ISEL" + "{ai|addic} %2,%1,-1\;{sfe|subfe} %0,%2,%1" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "*ne0di" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (lshiftrt:DI (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r"))) + (const_int 63))) + (clobber (match_scratch:DI 2 "=&r"))] + "TARGET_64BIT" + "addic %2,%1,-1\;subfe %0,%2,%1" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +;; This is what (plus (ne X (const_int 0)) Y) looks like. +(define_insn "*plus_ne0si" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (plus:SI (lshiftrt:SI + (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r"))) + (const_int 31)) + (match_operand:SI 2 "gpc_reg_operand" "r"))) + (clobber (match_scratch:SI 3 "=&r"))] + "TARGET_32BIT" + "{ai|addic} %3,%1,-1\;{aze|addze} %0,%2" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "*plus_ne0di" + [(set (match_operand:DI 0 "gpc_reg_operand" "=r") + (plus:DI (lshiftrt:DI + (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r"))) + (const_int 63)) + (match_operand:DI 2 "gpc_reg_operand" "r"))) + (clobber (match_scratch:DI 3 "=&r"))] + "TARGET_64BIT" + "addic %3,%1,-1\;addze %0,%2" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "*compare_plus_ne0si" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (lshiftrt:SI + (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))) + (const_int 31)) + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=&r,&r")) + (clobber (match_scratch:SI 4 "=X,&r"))] + "TARGET_32BIT" + "@ + {ai|addic} %3,%1,-1\;{aze.|addze.} %3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (lshiftrt:SI + (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" ""))) + (const_int 31)) + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 "")) + (clobber (match_scratch:SI 4 ""))] + "TARGET_32BIT && reload_completed" + [(parallel [(set (match_dup 3) + (plus:SI (lshiftrt:SI (neg:SI (abs:SI (match_dup 1))) + (const_int 31)) + (match_dup 2))) + (clobber (match_dup 4))]) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*compare_plus_ne0di" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:DI (lshiftrt:DI + (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))) + (const_int 63)) + (match_operand:DI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=&r,&r"))] + "TARGET_64BIT" + "@ + addic %3,%1,-1\;addze. %3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (plus:DI (lshiftrt:DI + (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" ""))) + (const_int 63)) + (match_operand:DI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_64BIT && reload_completed" + [(set (match_dup 3) + (plus:DI (lshiftrt:DI (neg:DI (abs:DI (match_dup 1))) + (const_int 63)) + (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "*plus_ne0si_compare" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (lshiftrt:SI + (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" "r,r"))) + (const_int 31)) + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (plus:SI (lshiftrt:SI (neg:SI (abs:SI (match_dup 1))) (const_int 31)) + (match_dup 2))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "TARGET_32BIT" + "@ + {ai|addic} %3,%1,-1\;{aze.|addze.} %0,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (lshiftrt:SI + (neg:SI (abs:SI (match_operand:SI 1 "gpc_reg_operand" ""))) + (const_int 31)) + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (lshiftrt:SI (neg:SI (abs:SI (match_dup 1))) (const_int 31)) + (match_dup 2))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_32BIT && reload_completed" + [(parallel [(set (match_dup 0) + (plus:SI (lshiftrt:SI (neg:SI (abs:SI (match_dup 1))) (const_int 31)) + (match_dup 2))) + (clobber (match_dup 3))]) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*plus_ne0di_compare" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:DI (lshiftrt:DI + (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" "r,r"))) + (const_int 63)) + (match_operand:DI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=r,r") + (plus:DI (lshiftrt:DI (neg:DI (abs:DI (match_dup 1))) (const_int 63)) + (match_dup 2))) + (clobber (match_scratch:DI 3 "=&r,&r"))] + "TARGET_64BIT" + "@ + addic %3,%1,-1\;addze. %0,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (plus:DI (lshiftrt:DI + (neg:DI (abs:DI (match_operand:DI 1 "gpc_reg_operand" ""))) + (const_int 63)) + (match_operand:DI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (plus:DI (lshiftrt:DI (neg:DI (abs:DI (match_dup 1))) (const_int 63)) + (match_dup 2))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_64BIT && reload_completed" + [(parallel [(set (match_dup 0) + (plus:DI (lshiftrt:DI (neg:DI (abs:DI (match_dup 1))) (const_int 63)) + (match_dup 2))) + (clobber (match_dup 3))]) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,O"))) + (clobber (match_scratch:SI 3 "=r,X"))] + "TARGET_POWER" + "@ + doz %3,%2,%1\;{sfi|subfic} %0,%3,0\;{ae|adde} %0,%0,%3 + {ai|addic} %0,%1,-1\;{aze|addze} %0,%0\;{sri|srwi} %0,%0,31" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,O,r,O")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r") + (le:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 3 "=r,X,r,X"))] + "TARGET_POWER" + "@ + doz %3,%2,%1\;{sfi|subfic} %0,%3,0\;{ae.|adde.} %0,%0,%3 + {ai|addic} %0,%1,-1\;{aze|addze} %0,%0\;{sri.|srwi.} %0,%0,31 + # + #" + [(set_attr "type" "compare,delayed_compare,compare,delayed_compare") + (set_attr "length" "12,12,16,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (le:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (le:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 0) + (le:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 3))]) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r") + (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,O")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")))] + "TARGET_POWER" + "@ + doz %0,%2,%1\;{sfi|subfic} %0,%0,0\;{aze|addze} %0,%3 + {srai|srawi} %0,%1,31\;{sf|subfc} %0,%1,%0\;{aze|addze} %0,%3" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,O,r,O")) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))] + "TARGET_POWER" + "@ + doz %4,%2,%1\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3 + {srai|srawi} %4,%1,31\;{sf|subfc} %4,%1,%4\;{aze.|addze.} %4,%3 + # + #" + [(set_attr "type" "compare") + (set_attr "length" "12,12,16,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(set (match_dup 4) + (plus:SI (le:SI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,O,r,O")) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r,&r,&r") + (plus:SI (le:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER" + "@ + doz %0,%2,%1\;{sfi|subfic} %0,%0,0\;{aze.|addze.} %0,%3 + {srai|srawi} %0,%1,31\;{sf|subfc} %0,%1,%0\;{aze.|addze.} %0,%3 + # + #" + [(set_attr "type" "compare") + (set_attr "length" "12,12,16,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (le:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (plus:SI (le:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (neg:SI (le:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,O"))))] + "TARGET_POWER" + "@ + doz %0,%2,%1\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0 + {ai|addic} %0,%1,-1\;{aze|addze} %0,%0\;{srai|srawi} %0,%0,31" + [(set_attr "length" "12")]) + +(define_insn "*leu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (leu:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "reg_or_short_operand" "rI")))] + "" + "{sf%I2|subf%I2c} %0,%1,%2\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "*leu<mode>_compare" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (leu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_short_operand" "rI,rI")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (leu:P (match_dup 1) (match_dup 2)))] + "" + "@ + {sf%I2|subf%I2c} %0,%1,%2\;{cal %0,0(0)|li %0,0}\;{ae.|adde.} %0,%0,%0 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC + (leu:P (match_operand:P 1 "gpc_reg_operand" "") + (match_operand:P 2 "reg_or_short_operand" "")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "") + (leu:P (match_dup 1) (match_dup 2)))] + "reload_completed" + [(set (match_dup 0) + (leu:P (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*plus_leu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=&r") + (plus:P (leu:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "reg_or_short_operand" "rI")) + (match_operand:P 3 "gpc_reg_operand" "r")))] + "" + "{sf%I2|subf%I2c} %0,%1,%2\;{aze|addze} %0,%3" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r"))] + "TARGET_32BIT" + "@ + {sf%I2|subf%I2c} %4,%1,%2\;{aze.|addze.} %4,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 4) + (plus:SI (leu:SI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r") + (plus:SI (leu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_32BIT" + "@ + {sf%I2|subf%I2c} %0,%1,%2\;{aze.|addze.} %0,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "8,12")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (leu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (leu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) + (plus:SI (leu:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*neg_leu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (neg:P (leu:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "reg_or_short_operand" "rI"))))] + "" + "{sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0\;nand %0,%0,%0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "*and_neg_leu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=&r") + (and:P (neg:P + (leu:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "reg_or_short_operand" "rI"))) + (match_operand:P 3 "gpc_reg_operand" "r")))] + "" + "{sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0\;andc %0,%3,%0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (and:SI (neg:SI + (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r"))] + "TARGET_32BIT" + "@ + {sf%I2|subf%I2c} %4,%1,%2\;{sfe|subfe} %4,%4,%4\;andc. %4,%3,%4 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (and:SI (neg:SI + (leu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" ""))) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 4) + (and:SI (neg:SI (leu:SI (match_dup 1) (match_dup 2))) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (and:SI (neg:SI + (leu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI"))) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r") + (and:SI (neg:SI (leu:SI (match_dup 1) (match_dup 2))) (match_dup 3)))] + "TARGET_32BIT" + "@ + {sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0\;andc. %0,%3,%0 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (and:SI (neg:SI + (leu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" ""))) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (neg:SI (leu:SI (match_dup 1) (match_dup 2))) (match_dup 3)))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) + (and:SI (neg:SI (leu:SI (match_dup 1) (match_dup 2))) + (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "rI")))] + "TARGET_POWER" + "doz%I2 %0,%1,%2\;nabs %0,%0\;{sri|srwi} %0,%0,31" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (lt:SI (match_dup 1) (match_dup 2)))] + "TARGET_POWER" + "@ + doz%I2 %0,%1,%2\;nabs %0,%0\;{sri.|srwi.} %0,%0,31 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC + (lt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (lt:SI (match_dup 1) (match_dup 2)))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (lt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r") + (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "rI")) + (match_operand:SI 3 "gpc_reg_operand" "r")))] + "TARGET_POWER" + "doz%I2 %0,%1,%2\;{ai|addic} %0,%0,-1\;{aze|addze} %0,%3" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r"))] + "TARGET_POWER" + "@ + doz%I2 %4,%1,%2\;{ai|addic} %4,%4,-1\;{aze.|addze.} %4,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(set (match_dup 4) + (plus:SI (lt:SI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r") + (plus:SI (lt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER" + "@ + doz%I2 %0,%1,%2\;{ai|addic} %0,%0,-1\;{aze.|addze.} %0,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (lt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (plus:SI (lt:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (neg:SI (lt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "rI"))))] + "TARGET_POWER" + "doz%I2 %0,%1,%2\;nabs %0,%0\;{srai|srawi} %0,%0,31" + [(set_attr "length" "12")]) + +(define_insn_and_split "*ltu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (ltu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P")))] + "" + "#" + "" + [(set (match_dup 0) (neg:P (ltu:P (match_dup 1) (match_dup 2)))) + (set (match_dup 0) (neg:P (match_dup 0)))] + "") + +(define_insn_and_split "*ltu<mode>_compare" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (ltu:P (match_operand:P 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P,r,P")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r,r,r") + (ltu:P (match_dup 1) (match_dup 2)))] + "" + "#" + "" + [(set (match_dup 0) (neg:P (ltu:P (match_dup 1) (match_dup 2)))) + (parallel [(set (match_dup 3) + (compare:CC (neg:P (match_dup 0)) (const_int 0))) + (set (match_dup 0) (neg:P (match_dup 0)))])] + "") + +(define_insn_and_split "*plus_ltu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=&r,r") + (plus:P (ltu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P")) + (match_operand:P 3 "reg_or_short_operand" "rI,rI")))] + "" + "#" + "&& !reg_overlap_mentioned_p (operands[0], operands[3])" + [(set (match_dup 0) (neg:P (ltu:P (match_dup 1) (match_dup 2)))) + (set (match_dup 0) (minus:P (match_dup 3) (match_dup 0)))] + "") + +(define_insn_and_split "*plus_ltu<mode>_compare" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (plus:P (ltu:P (match_operand:P 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P,r,P")) + (match_operand:P 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=&r,&r,&r,&r") + (plus:P (ltu:P (match_dup 1) (match_dup 2)) (match_dup 3)))] + "" + "#" + "&& !reg_overlap_mentioned_p (operands[0], operands[3])" + [(set (match_dup 0) (neg:P (ltu:P (match_dup 1) (match_dup 2)))) + (parallel [(set (match_dup 4) + (compare:CC (minus:P (match_dup 3) (match_dup 0)) + (const_int 0))) + (set (match_dup 0) (minus:P (match_dup 3) (match_dup 0)))])] + "") + +(define_insn "*neg_ltu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (neg:P (ltu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P"))))] + "" + "@ + {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0 + {ai|addic} %0,%1,%n2\;{sfe|subfe} %0,%0,%0" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "rI"))) + (clobber (match_scratch:SI 3 "=r"))] + "TARGET_POWER" + "doz%I2 %3,%1,%2\;{sfi|subfic} %0,%3,0\;{ae|adde} %0,%0,%3" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (ge:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 3 "=r,r"))] + "TARGET_POWER" + "@ + doz%I2 %3,%1,%2\;{sfi|subfic} %0,%3,0\;{ae.|adde.} %0,%0,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (ge:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (ge:SI (match_dup 1) (match_dup 2))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_POWER && reload_completed" + [(parallel [(set (match_dup 0) + (ge:SI (match_dup 1) (match_dup 2))) + (clobber (match_dup 3))]) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r") + (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "rI")) + (match_operand:SI 3 "gpc_reg_operand" "r")))] + "TARGET_POWER" + "doz%I2 %0,%1,%2\;{sfi|subfic} %0,%0,0\;{aze|addze} %0,%3" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r"))] + "TARGET_POWER" + "@ + doz%I2 %4,%1,%2\;{sfi|subfic} %4,%4,0\;{aze.|addze.} %4,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(set (match_dup 4) + (plus:SI (ge:SI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "rI,rI")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r") + (plus:SI (ge:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER" + "@ + doz%I2 %0,%1,%2\;{sfi|subfic} %0,%0,0\;{aze.|addze.} %0,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (ge:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (plus:SI (ge:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (neg:SI (ge:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "rI"))))] + "TARGET_POWER" + "doz%I2 %0,%1,%2\;{ai|addic} %0,%0,-1\;{sfe|subfe} %0,%0,%0" + [(set_attr "length" "12")]) + +(define_insn "*geu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (geu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P")))] + "" + "@ + {sf|subfc} %0,%2,%1\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0 + {ai|addic} %0,%1,%n2\;{cal %0,0(0)|li %0,0}\;{ae|adde} %0,%0,%0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "*geu<mode>_compare" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (geu:P (match_operand:P 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P,r,P")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r,r,r") + (geu:P (match_dup 1) (match_dup 2)))] + "" + "@ + {sf|subfc} %0,%2,%1\;{cal %0,0(0)|li %0,0}\;{ae.|adde.} %0,%0,%0 + {ai|addic} %0,%1,%n2\;{cal %0,0(0)|li %0,0}\;{ae.|adde.} %0,%0,%0 + # + #" + [(set_attr "type" "compare") + (set_attr "length" "12,12,16,16")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (geu:P (match_operand:P 1 "gpc_reg_operand" "") + (match_operand:P 2 "reg_or_neg_short_operand" "")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "") + (geu:P (match_dup 1) (match_dup 2)))] + "reload_completed" + [(set (match_dup 0) + (geu:P (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*plus_geu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=&r,&r") + (plus:P (geu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P")) + (match_operand:P 3 "gpc_reg_operand" "r,r")))] + "" + "@ + {sf|subfc} %0,%2,%1\;{aze|addze} %0,%3 + {ai|addic} %0,%1,%n2\;{aze|addze} %0,%3" + [(set_attr "type" "two") + (set_attr "length" "8")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (plus:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P")) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))] + "TARGET_32BIT" + "@ + {sf|subfc} %4,%2,%1\;{aze.|addze.} %4,%3 + {ai|addic} %4,%1,%n2\;{aze.|addze.} %4,%3 + # + #" + [(set_attr "type" "compare") + (set_attr "length" "8,8,12,12")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_neg_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 4) + (plus:SI (geu:SI (match_dup 1) (match_dup 2)) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (plus:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P")) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r,&r,&r") + (plus:SI (geu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_32BIT" + "@ + {sf|subfc} %0,%2,%1\;{aze.|addze.} %0,%3 + {ai|addic} %0,%1,%n2\;{aze.|addze.} %0,%3 + # + #" + [(set_attr "type" "compare") + (set_attr "length" "8,8,12,12")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (geu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_neg_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (geu:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) + (plus:SI (geu:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*neg_geu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (neg:P (geu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_short_operand" "r,I"))))] + "" + "@ + {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0\;nand %0,%0,%0 + {sfi|subfic} %0,%1,-1\;{a%I2|add%I2c} %0,%0,%2\;{sfe|subfe} %0,%0,%0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "*and_neg_geu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=&r,&r") + (and:P (neg:P + (geu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_neg_short_operand" "r,P"))) + (match_operand:P 3 "gpc_reg_operand" "r,r")))] + "" + "@ + {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0\;andc %0,%3,%0 + {ai|addic} %0,%1,%n2\;{sfe|subfe} %0,%0,%0\;andc %0,%3,%0" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (and:SI (neg:SI + (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r,&r,&r"))] + "TARGET_32BIT" + "@ + {sf|subfc} %4,%2,%1\;{sfe|subfe} %4,%4,%4\;andc. %4,%3,%4 + {ai|addic} %4,%1,%n2\;{sfe|subfe} %4,%4,%4\;andc. %4,%3,%4 + # + #" + [(set_attr "type" "compare") + (set_attr "length" "12,12,16,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (and:SI (neg:SI + (geu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_neg_short_operand" ""))) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 4) + (and:SI (neg:SI (geu:SI (match_dup 1) (match_dup 2))) + (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (and:SI (neg:SI + (geu:SI (match_operand:SI 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:SI 2 "reg_or_neg_short_operand" "r,P,r,P"))) + (match_operand:SI 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r,&r,&r") + (and:SI (neg:SI (geu:SI (match_dup 1) (match_dup 2))) (match_dup 3)))] + "TARGET_32BIT" + "@ + {sf|subfc} %0,%2,%1\;{sfe|subfe} %0,%0,%0\;andc. %0,%3,%0 + {ai|addic} %0,%1,%n2\;{sfe|subfe} %0,%0,%0\;andc. %0,%3,%0 + # + #" + [(set_attr "type" "compare") + (set_attr "length" "12,12,16,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (and:SI (neg:SI + (geu:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_neg_short_operand" ""))) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (and:SI (neg:SI (geu:SI (match_dup 1) (match_dup 2))) (match_dup 3)))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) + (and:SI (neg:SI (geu:SI (match_dup 1) (match_dup 2))) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "r")))] + "TARGET_POWER" + "doz %0,%2,%1\;nabs %0,%0\;{sri|srwi} %0,%0,31" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=r,r") + (gt:SI (match_dup 1) (match_dup 2)))] + "TARGET_POWER" + "@ + doz %0,%2,%1\;nabs %0,%0\;{sri.|srwi.} %0,%0,31 + #" + [(set_attr "type" "delayed_compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC + (gt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (gt:SI (match_dup 1) (match_dup 2)))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (gt:SI (match_dup 1) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "*plus_gt0<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=&r") + (plus:P (gt:P (match_operand:P 1 "gpc_reg_operand" "r") + (const_int 0)) + (match_operand:P 2 "gpc_reg_operand" "r")))] + "" + "{a|addc} %0,%1,%1\;{sfe|subfe} %0,%1,%0\;{aze|addze} %0,%2" + [(set_attr "type" "three") + (set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (const_int 0)) + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 3 "=&r,&r"))] + "TARGET_32BIT" + "@ + {a|addc} %3,%1,%1\;{sfe|subfe} %3,%1,%3\;{aze.|addze.} %3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (const_int 0)) + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 3 ""))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 3) + (plus:SI (gt:SI (match_dup 1) (const_int 0)) + (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:DI (gt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (const_int 0)) + (match_operand:DI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:DI 3 "=&r,&r"))] + "TARGET_64BIT" + "@ + addc %3,%1,%1\;subfe %3,%1,%3\;addze. %3,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (plus:DI (gt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (const_int 0)) + (match_operand:DI 2 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:DI 3 ""))] + "TARGET_64BIT && reload_completed" + [(set (match_dup 3) + (plus:DI (gt:DI (match_dup 1) (const_int 0)) + (match_dup 2))) + (set (match_dup 0) + (compare:CC (match_dup 3) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (const_int 0)) + (match_operand:SI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r") + (plus:SI (gt:SI (match_dup 1) (const_int 0)) (match_dup 2)))] + "TARGET_32BIT" + "@ + {a|addc} %0,%1,%1\;{sfe|subfe} %0,%1,%0\;{aze.|addze.} %0,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (const_int 0)) + (match_operand:SI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (gt:SI (match_dup 1) (const_int 0)) (match_dup 2)))] + "TARGET_32BIT && reload_completed" + [(set (match_dup 0) + (plus:SI (gt:SI (match_dup 1) (const_int 0)) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:DI (gt:DI (match_operand:DI 1 "gpc_reg_operand" "r,r") + (const_int 0)) + (match_operand:DI 2 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "=&r,&r") + (plus:DI (gt:DI (match_dup 1) (const_int 0)) (match_dup 2)))] + "TARGET_64BIT" + "@ + addc %0,%1,%1\;subfe %0,%1,%0\;addze. %0,%2 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 3 "cc_reg_not_micro_cr0_operand" "") + (compare:CC + (plus:DI (gt:DI (match_operand:DI 1 "gpc_reg_operand" "") + (const_int 0)) + (match_operand:DI 2 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:DI 0 "gpc_reg_operand" "") + (plus:DI (gt:DI (match_dup 1) (const_int 0)) (match_dup 2)))] + "TARGET_64BIT && reload_completed" + [(set (match_dup 0) + (plus:DI (gt:DI (match_dup 1) (const_int 0)) (match_dup 2))) + (set (match_dup 3) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=&r") + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "r")) + (match_operand:SI 3 "gpc_reg_operand" "r")))] + "TARGET_POWER" + "doz %0,%2,%1\;{ai|addic} %0,%0,-1\;{aze|addze} %0,%3" + [(set_attr "length" "12")]) + +(define_insn "" + [(set (match_operand:CC 0 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,r")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (clobber (match_scratch:SI 4 "=&r,&r"))] + "TARGET_POWER" + "@ + doz %4,%2,%1\;{ai|addic} %4,%4,-1\;{aze.|addze.} %4,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 0 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (clobber (match_scratch:SI 4 ""))] + "TARGET_POWER && reload_completed" + [(set (match_dup 4) + (plus:SI (gt:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 0) + (compare:CC (match_dup 4) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,?y") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r,r") + (match_operand:SI 2 "reg_or_short_operand" "r,r")) + (match_operand:SI 3 "gpc_reg_operand" "r,r")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "=&r,&r") + (plus:SI (gt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER" + "@ + doz %0,%2,%1\;{ai|addic} %0,%0,-1\;{aze.|addze.} %0,%3 + #" + [(set_attr "type" "compare") + (set_attr "length" "12,16")]) + +(define_split + [(set (match_operand:CC 4 "cc_reg_not_cr0_operand" "") + (compare:CC + (plus:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "") + (match_operand:SI 2 "reg_or_short_operand" "")) + (match_operand:SI 3 "gpc_reg_operand" "")) + (const_int 0))) + (set (match_operand:SI 0 "gpc_reg_operand" "") + (plus:SI (gt:SI (match_dup 1) (match_dup 2)) (match_dup 3)))] + "TARGET_POWER && reload_completed" + [(set (match_dup 0) + (plus:SI (gt:SI (match_dup 1) (match_dup 2)) (match_dup 3))) + (set (match_dup 4) + (compare:CC (match_dup 0) + (const_int 0)))] + "") + +(define_insn "" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (neg:SI (gt:SI (match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand:SI 2 "reg_or_short_operand" "r"))))] + "TARGET_POWER" + "doz %0,%2,%1\;nabs %0,%0\;{srai|srawi} %0,%0,31" + [(set_attr "length" "12")]) + +(define_insn_and_split "*gtu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (gtu:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "reg_or_short_operand" "rI")))] + "" + "#" + "" + [(set (match_dup 0) (neg:P (gtu:P (match_dup 1) (match_dup 2)))) + (set (match_dup 0) (neg:P (match_dup 0)))] + "") + +(define_insn_and_split "*gtu<mode>_compare" + [(set (match_operand:CC 3 "cc_reg_operand" "=x,?y") + (compare:CC + (gtu:P (match_operand:P 1 "gpc_reg_operand" "r,r") + (match_operand:P 2 "reg_or_short_operand" "rI,rI")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=r,r") + (gtu:P (match_dup 1) (match_dup 2)))] + "" + "#" + "" + [(set (match_dup 0) (neg:P (gtu:P (match_dup 1) (match_dup 2)))) + (parallel [(set (match_dup 3) + (compare:CC (neg:P (match_dup 0)) (const_int 0))) + (set (match_dup 0) (neg:P (match_dup 0)))])] + "") + +(define_insn_and_split "*plus_gtu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=&r") + (plus:P (gtu:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "reg_or_short_operand" "rI")) + (match_operand:P 3 "reg_or_short_operand" "rI")))] + "" + "#" + "&& !reg_overlap_mentioned_p (operands[0], operands[3])" + [(set (match_dup 0) (neg:P (gtu:P (match_dup 1) (match_dup 2)))) + (set (match_dup 0) (minus:P (match_dup 3) (match_dup 0)))] + "") + +(define_insn_and_split "*plus_gtu<mode>_compare" + [(set (match_operand:CC 4 "cc_reg_operand" "=x,x,?y,?y") + (compare:CC + (plus:P (gtu:P (match_operand:P 1 "gpc_reg_operand" "r,r,r,r") + (match_operand:P 2 "reg_or_short_operand" "I,r,I,r")) + (match_operand:P 3 "gpc_reg_operand" "r,r,r,r")) + (const_int 0))) + (set (match_operand:P 0 "gpc_reg_operand" "=&r,&r,&r,&r") + (plus:P (gtu:P (match_dup 1) (match_dup 2)) (match_dup 3)))] + "" + "#" + "&& !reg_overlap_mentioned_p (operands[0], operands[3])" + [(set (match_dup 0) (neg:P (gtu:P (match_dup 1) (match_dup 2)))) + (parallel [(set (match_dup 4) + (compare:CC (minus:P (match_dup 3) (match_dup 0)) + (const_int 0))) + (set (match_dup 0) (minus:P (match_dup 3) (match_dup 0)))])] + "") + +(define_insn "*neg_gtu<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (neg:P (gtu:P (match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "reg_or_short_operand" "rI"))))] + "" + "{sf%I2|subf%I2c} %0,%1,%2\;{sfe|subfe} %0,%0,%0" + [(set_attr "type" "two") + (set_attr "length" "8")]) + + +;; Define both directions of branch and return. If we need a reload +;; register, we'd rather use CR0 since it is much easier to copy a +;; register CC value to there. + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 1 "branch_comparison_operator" + [(match_operand 2 + "cc_reg_operand" "y") + (const_int 0)]) + (label_ref (match_operand 0 "" "")) + (pc)))] + "" + "* +{ + return output_cbranch (operands[1], \"%l0\", 0, insn); +}" + [(set_attr "type" "branch")]) + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "branch_comparison_operator" + [(match_operand 1 + "cc_reg_operand" "y") + (const_int 0)]) + (return) + (pc)))] + "direct_return ()" + "* +{ + return output_cbranch (operands[0], NULL, 0, insn); +}" + [(set_attr "type" "jmpreg") + (set_attr "length" "4")]) + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 1 "branch_comparison_operator" + [(match_operand 2 + "cc_reg_operand" "y") + (const_int 0)]) + (pc) + (label_ref (match_operand 0 "" ""))))] + "" + "* +{ + return output_cbranch (operands[1], \"%l0\", 1, insn); +}" + [(set_attr "type" "branch")]) + +(define_insn "" + [(set (pc) + (if_then_else (match_operator 0 "branch_comparison_operator" + [(match_operand 1 + "cc_reg_operand" "y") + (const_int 0)]) + (pc) + (return)))] + "direct_return ()" + "* +{ + return output_cbranch (operands[0], NULL, 1, insn); +}" + [(set_attr "type" "jmpreg") + (set_attr "length" "4")]) + +;; Logic on condition register values. + +; This pattern matches things like +; (set (reg:CCEQ 68) (compare:CCEQ (ior:SI (gt:SI (reg:CCFP 68) (const_int 0)) +; (eq:SI (reg:CCFP 68) (const_int 0))) +; (const_int 1))) +; which are generated by the branch logic. +; Prefer destructive operations where BT = BB (for crXX BT,BA,BB) + +(define_insn "*cceq_ior_compare" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y,?y") + (compare:CCEQ (match_operator:SI 1 "boolean_operator" + [(match_operator:SI 2 + "branch_positive_comparison_operator" + [(match_operand 3 + "cc_reg_operand" "y,y") + (const_int 0)]) + (match_operator:SI 4 + "branch_positive_comparison_operator" + [(match_operand 5 + "cc_reg_operand" "0,y") + (const_int 0)])]) + (const_int 1)))] + "" + "cr%q1 %E0,%j2,%j4" + [(set_attr "type" "cr_logical,delayed_cr")]) + +; Why is the constant -1 here, but 1 in the previous pattern? +; Because ~1 has all but the low bit set. +(define_insn "" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y,?y") + (compare:CCEQ (match_operator:SI 1 "boolean_or_operator" + [(not:SI (match_operator:SI 2 + "branch_positive_comparison_operator" + [(match_operand 3 + "cc_reg_operand" "y,y") + (const_int 0)])) + (match_operator:SI 4 + "branch_positive_comparison_operator" + [(match_operand 5 + "cc_reg_operand" "0,y") + (const_int 0)])]) + (const_int -1)))] + "" + "cr%q1 %E0,%j2,%j4" + [(set_attr "type" "cr_logical,delayed_cr")]) + +(define_insn "*cceq_rev_compare" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y,?y") + (compare:CCEQ (match_operator:SI 1 + "branch_positive_comparison_operator" + [(match_operand 2 + "cc_reg_operand" "0,y") + (const_int 0)]) + (const_int 0)))] + "" + "{crnor %E0,%j1,%j1|crnot %E0,%j1}" + [(set_attr "type" "cr_logical,delayed_cr")]) + +;; If we are comparing the result of two comparisons, this can be done +;; using creqv or crxor. + +(define_insn_and_split "" + [(set (match_operand:CCEQ 0 "cc_reg_operand" "=y") + (compare:CCEQ (match_operator 1 "branch_comparison_operator" + [(match_operand 2 "cc_reg_operand" "y") + (const_int 0)]) + (match_operator 3 "branch_comparison_operator" + [(match_operand 4 "cc_reg_operand" "y") + (const_int 0)])))] + "" + "#" + "" + [(set (match_dup 0) (compare:CCEQ (xor:SI (match_dup 1) (match_dup 3)) + (match_dup 5)))] + " +{ + int positive_1, positive_2; + + positive_1 = branch_positive_comparison_operator (operands[1], + GET_MODE (operands[1])); + positive_2 = branch_positive_comparison_operator (operands[3], + GET_MODE (operands[3])); + + if (! positive_1) + operands[1] = gen_rtx_fmt_ee (rs6000_reverse_condition (GET_MODE (operands[2]), + GET_CODE (operands[1])), + SImode, + operands[2], const0_rtx); + else if (GET_MODE (operands[1]) != SImode) + operands[1] = gen_rtx_fmt_ee (GET_CODE (operands[1]), SImode, + operands[2], const0_rtx); + + if (! positive_2) + operands[3] = gen_rtx_fmt_ee (rs6000_reverse_condition (GET_MODE (operands[4]), + GET_CODE (operands[3])), + SImode, + operands[4], const0_rtx); + else if (GET_MODE (operands[3]) != SImode) + operands[3] = gen_rtx_fmt_ee (GET_CODE (operands[3]), SImode, + operands[4], const0_rtx); + + if (positive_1 == positive_2) + { + operands[1] = gen_rtx_NOT (SImode, operands[1]); + operands[5] = constm1_rtx; + } + else + { + operands[5] = const1_rtx; + } +}") + +;; Unconditional branch and return. + +(define_insn "jump" + [(set (pc) + (label_ref (match_operand 0 "" "")))] + "" + "b %l0" + [(set_attr "type" "branch")]) + +(define_insn "return" + [(return)] + "direct_return ()" + "{br|blr}" + [(set_attr "type" "jmpreg")]) + +(define_expand "indirect_jump" + [(set (pc) (match_operand 0 "register_operand" ""))]) + +(define_insn "*indirect_jump<mode>" + [(set (pc) (match_operand:P 0 "register_operand" "c,*l"))] + "" + "@ + bctr + {br|blr}" + [(set_attr "type" "jmpreg")]) + +;; Table jump for switch statements: +(define_expand "tablejump" + [(use (match_operand 0 "" "")) + (use (label_ref (match_operand 1 "" "")))] + "" + " +{ + if (TARGET_32BIT) + emit_jump_insn (gen_tablejumpsi (operands[0], operands[1])); + else + emit_jump_insn (gen_tablejumpdi (operands[0], operands[1])); + DONE; +}") + +(define_expand "tablejumpsi" + [(set (match_dup 3) + (plus:SI (match_operand:SI 0 "" "") + (match_dup 2))) + (parallel [(set (pc) (match_dup 3)) + (use (label_ref (match_operand 1 "" "")))])] + "TARGET_32BIT" + " +{ operands[0] = force_reg (SImode, operands[0]); + operands[2] = force_reg (SImode, gen_rtx_LABEL_REF (SImode, operands[1])); + operands[3] = gen_reg_rtx (SImode); +}") + +(define_expand "tablejumpdi" + [(set (match_dup 4) + (sign_extend:DI (match_operand:SI 0 "lwa_operand" ""))) + (set (match_dup 3) + (plus:DI (match_dup 4) + (match_dup 2))) + (parallel [(set (pc) (match_dup 3)) + (use (label_ref (match_operand 1 "" "")))])] + "TARGET_64BIT" + " +{ operands[2] = force_reg (DImode, gen_rtx_LABEL_REF (DImode, operands[1])); + operands[3] = gen_reg_rtx (DImode); + operands[4] = gen_reg_rtx (DImode); +}") + +(define_insn "*tablejump<mode>_internal1" + [(set (pc) + (match_operand:P 0 "register_operand" "c,*l")) + (use (label_ref (match_operand 1 "" "")))] + "" + "@ + bctr + {br|blr}" + [(set_attr "type" "jmpreg")]) + +(define_insn "nop" + [(const_int 0)] + "" + "{cror 0,0,0|nop}") + +;; Define the subtract-one-and-jump insns, starting with the template +;; so loop.c knows what to generate. + +(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 this on innermost loops. */ + if (INTVAL (operands[3]) > 1) + FAIL; + if (TARGET_64BIT) + { + if (GET_MODE (operands[0]) != DImode) + FAIL; + emit_jump_insn (gen_ctrdi (operands[0], operands[4])); + } + else + { + if (GET_MODE (operands[0]) != SImode) + FAIL; + emit_jump_insn (gen_ctrsi (operands[0], operands[4])); + } + DONE; +}") + +(define_expand "ctr<mode>" + [(parallel [(set (pc) + (if_then_else (ne (match_operand:P 0 "register_operand" "") + (const_int 1)) + (label_ref (match_operand 1 "" "")) + (pc))) + (set (match_dup 0) + (plus:P (match_dup 0) + (const_int -1))) + (clobber (match_scratch:CC 2 "")) + (clobber (match_scratch:P 3 ""))])] + "" + "") + +;; We need to be able to do this for any operand, including MEM, or we +;; will cause reload to blow up since we don't allow output reloads on +;; JUMP_INSNs. +;; For the length attribute to be calculated correctly, the +;; label MUST be operand 0. + +(define_insn "*ctr<mode>_internal1" + [(set (pc) + (if_then_else (ne (match_operand:P 1 "register_operand" "c,*r,*r,*r") + (const_int 1)) + (label_ref (match_operand 0 "" "")) + (pc))) + (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*q*c*l") + (plus:P (match_dup 1) + (const_int -1))) + (clobber (match_scratch:CC 3 "=X,&x,&x,&x")) + (clobber (match_scratch:P 4 "=X,X,&r,r"))] + "" + "* +{ + if (which_alternative != 0) + return \"#\"; + else if (get_attr_length (insn) == 4) + return \"{bdn|bdnz} %l0\"; + else + return \"bdz $+8\;b %l0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "*,12,16,16")]) + +(define_insn "*ctr<mode>_internal2" + [(set (pc) + (if_then_else (ne (match_operand:P 1 "register_operand" "c,*r,*r,*r") + (const_int 1)) + (pc) + (label_ref (match_operand 0 "" "")))) + (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*q*c*l") + (plus:P (match_dup 1) + (const_int -1))) + (clobber (match_scratch:CC 3 "=X,&x,&x,&x")) + (clobber (match_scratch:P 4 "=X,X,&r,r"))] + "" + "* +{ + if (which_alternative != 0) + return \"#\"; + else if (get_attr_length (insn) == 4) + return \"bdz %l0\"; + else + return \"{bdn|bdnz} $+8\;b %l0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "*,12,16,16")]) + +;; Similar but use EQ + +(define_insn "*ctr<mode>_internal5" + [(set (pc) + (if_then_else (eq (match_operand:P 1 "register_operand" "c,*r,*r,*r") + (const_int 1)) + (label_ref (match_operand 0 "" "")) + (pc))) + (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*q*c*l") + (plus:P (match_dup 1) + (const_int -1))) + (clobber (match_scratch:CC 3 "=X,&x,&x,&x")) + (clobber (match_scratch:P 4 "=X,X,&r,r"))] + "" + "* +{ + if (which_alternative != 0) + return \"#\"; + else if (get_attr_length (insn) == 4) + return \"bdz %l0\"; + else + return \"{bdn|bdnz} $+8\;b %l0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "*,12,16,16")]) + +(define_insn "*ctr<mode>_internal6" + [(set (pc) + (if_then_else (eq (match_operand:P 1 "register_operand" "c,*r,*r,*r") + (const_int 1)) + (pc) + (label_ref (match_operand 0 "" "")))) + (set (match_operand:P 2 "nonimmediate_operand" "=1,*r,m,*q*c*l") + (plus:P (match_dup 1) + (const_int -1))) + (clobber (match_scratch:CC 3 "=X,&x,&x,&x")) + (clobber (match_scratch:P 4 "=X,X,&r,r"))] + "" + "* +{ + if (which_alternative != 0) + return \"#\"; + else if (get_attr_length (insn) == 4) + return \"{bdn|bdnz} %l0\"; + else + return \"bdz $+8\;b %l0\"; +}" + [(set_attr "type" "branch") + (set_attr "length" "*,12,16,16")]) + +;; Now the splitters if we could not allocate the CTR register + +(define_split + [(set (pc) + (if_then_else (match_operator 2 "comparison_operator" + [(match_operand:P 1 "gpc_reg_operand" "") + (const_int 1)]) + (match_operand 5 "" "") + (match_operand 6 "" ""))) + (set (match_operand:P 0 "gpc_reg_operand" "") + (plus:P (match_dup 1) (const_int -1))) + (clobber (match_scratch:CC 3 "")) + (clobber (match_scratch:P 4 ""))] + "reload_completed" + [(parallel [(set (match_dup 3) + (compare:CC (plus:P (match_dup 1) + (const_int -1)) + (const_int 0))) + (set (match_dup 0) + (plus:P (match_dup 1) + (const_int -1)))]) + (set (pc) (if_then_else (match_dup 7) + (match_dup 5) + (match_dup 6)))] + " +{ operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[2]), VOIDmode, + operands[3], const0_rtx); }") + +(define_split + [(set (pc) + (if_then_else (match_operator 2 "comparison_operator" + [(match_operand:P 1 "gpc_reg_operand" "") + (const_int 1)]) + (match_operand 5 "" "") + (match_operand 6 "" ""))) + (set (match_operand:P 0 "nonimmediate_operand" "") + (plus:P (match_dup 1) (const_int -1))) + (clobber (match_scratch:CC 3 "")) + (clobber (match_scratch:P 4 ""))] + "reload_completed && ! gpc_reg_operand (operands[0], SImode)" + [(parallel [(set (match_dup 3) + (compare:CC (plus:P (match_dup 1) + (const_int -1)) + (const_int 0))) + (set (match_dup 4) + (plus:P (match_dup 1) + (const_int -1)))]) + (set (match_dup 0) + (match_dup 4)) + (set (pc) (if_then_else (match_dup 7) + (match_dup 5) + (match_dup 6)))] + " +{ operands[7] = gen_rtx_fmt_ee (GET_CODE (operands[2]), VOIDmode, + operands[3], const0_rtx); }") + +(define_insn "trap" + [(trap_if (const_int 1) (const_int 0))] + "" + "{t 31,0,0|trap}" + [(set_attr "type" "trap")]) + +(define_expand "ctrap<mode>4" + [(trap_if (match_operator 0 "ordered_comparison_operator" + [(match_operand:GPR 1 "register_operand") + (match_operand:GPR 2 "reg_or_short_operand")]) + (match_operand 3 "zero_constant" ""))] + "" + "") + +(define_insn "" + [(trap_if (match_operator 0 "ordered_comparison_operator" + [(match_operand:GPR 1 "register_operand" "r") + (match_operand:GPR 2 "reg_or_short_operand" "rI")]) + (const_int 0))] + "" + "{t|t<wd>}%V0%I2 %1,%2" + [(set_attr "type" "trap")]) + +;; Insns related to generating the function prologue and epilogue. + +(define_expand "prologue" + [(use (const_int 0))] + "TARGET_SCHED_PROLOG" + " +{ + rs6000_emit_prologue (); + DONE; +}") + +(define_insn "*movesi_from_cr_one" + [(match_parallel 0 "mfcr_operation" + [(set (match_operand:SI 1 "gpc_reg_operand" "=r") + (unspec:SI [(match_operand:CC 2 "cc_reg_operand" "y") + (match_operand 3 "immediate_operand" "n")] + UNSPEC_MOVESI_FROM_CR))])] + "TARGET_MFCRF" + "* +{ + int mask = 0; + int i; + for (i = 0; i < XVECLEN (operands[0], 0); i++) + { + mask = INTVAL (XVECEXP (SET_SRC (XVECEXP (operands[0], 0, i)), 0, 1)); + operands[4] = GEN_INT (mask); + output_asm_insn (\"mfcr %1,%4\", operands); + } + return \"\"; +}" + [(set_attr "type" "mfcrf")]) + +(define_insn "movesi_from_cr" + [(set (match_operand:SI 0 "gpc_reg_operand" "=r") + (unspec:SI [(reg:CC CR0_REGNO) (reg:CC CR1_REGNO) + (reg:CC CR2_REGNO) (reg:CC CR3_REGNO) + (reg:CC CR4_REGNO) (reg:CC CR5_REGNO) + (reg:CC CR6_REGNO) (reg:CC CR7_REGNO)] + UNSPEC_MOVESI_FROM_CR))] + "" + "mfcr %0" + [(set_attr "type" "mfcr")]) + +(define_insn "*stmw" + [(match_parallel 0 "stmw_operation" + [(set (match_operand:SI 1 "memory_operand" "=m") + (match_operand:SI 2 "gpc_reg_operand" "r"))])] + "TARGET_MULTIPLE" + "{stm|stmw} %2,%1" + [(set_attr "type" "store_ux")]) + +; The following comment applies to: +; save_gpregs_* +; save_fpregs_* +; restore_gpregs* +; return_and_restore_gpregs* +; return_and_restore_fpregs* +; return_and_restore_fpregs_aix* +; +; The out-of-line save / restore functions expects one input argument. +; Since those are not standard call_insn's, we must avoid using +; MATCH_OPERAND for that argument. That way the register rename +; optimization will not try to rename this register. +; Each pattern is repeated for each possible register number used in +; various ABIs (r11, r1, and for some functions r12) + +(define_insn "*save_gpregs_<mode>_r11" + [(match_parallel 0 "any_parallel_operand" + [(clobber (reg:P 65)) + (use (match_operand:P 1 "symbol_ref_operand" "s")) + (use (reg:P 11)) + (set (match_operand:P 2 "memory_operand" "=m") + (match_operand:P 3 "gpc_reg_operand" "r"))])] + "" + "bl %1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*save_gpregs_<mode>_r12" + [(match_parallel 0 "any_parallel_operand" + [(clobber (reg:P 65)) + (use (match_operand:P 1 "symbol_ref_operand" "s")) + (use (reg:P 12)) + (set (match_operand:P 2 "memory_operand" "=m") + (match_operand:P 3 "gpc_reg_operand" "r"))])] + "" + "bl %1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*save_gpregs_<mode>_r1" + [(match_parallel 0 "any_parallel_operand" + [(clobber (reg:P 65)) + (use (match_operand:P 1 "symbol_ref_operand" "s")) + (use (reg:P 1)) + (set (match_operand:P 2 "memory_operand" "=m") + (match_operand:P 3 "gpc_reg_operand" "r"))])] + "" + "bl %1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*save_fpregs_<mode>_r11" + [(match_parallel 0 "any_parallel_operand" + [(clobber (reg:P 65)) + (use (match_operand:P 1 "symbol_ref_operand" "s")) + (use (reg:P 11)) + (set (match_operand:DF 2 "memory_operand" "=m") + (match_operand:DF 3 "gpc_reg_operand" "d"))])] + "" + "bl %1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*save_fpregs_<mode>_r12" + [(match_parallel 0 "any_parallel_operand" + [(clobber (reg:P 65)) + (use (match_operand:P 1 "symbol_ref_operand" "s")) + (use (reg:P 12)) + (set (match_operand:DF 2 "memory_operand" "=m") + (match_operand:DF 3 "gpc_reg_operand" "d"))])] + "" + "bl %1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*save_fpregs_<mode>_r1" + [(match_parallel 0 "any_parallel_operand" + [(clobber (reg:P 65)) + (use (match_operand:P 1 "symbol_ref_operand" "s")) + (use (reg:P 1)) + (set (match_operand:DF 2 "memory_operand" "=m") + (match_operand:DF 3 "gpc_reg_operand" "d"))])] + "" + "bl %1" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +; These are to explain that changes to the stack pointer should +; not be moved over stores to stack memory. +(define_insn "stack_tie" + [(set (match_operand:BLK 0 "memory_operand" "+m") + (unspec:BLK [(match_dup 0)] UNSPEC_TIE))] + "" + "" + [(set_attr "length" "0")]) + +; Like stack_tie, but depend on both fp and sp based memory. +(define_insn "frame_tie" + [(set (match_operand:BLK 0 "memory_operand" "+m") + (unspec:BLK [(match_dup 0) + (match_operand:BLK 1 "memory_operand" "m")] UNSPEC_TIE))] + "" + "" + [(set_attr "length" "0")]) + + +(define_expand "epilogue" + [(use (const_int 0))] + "TARGET_SCHED_PROLOG" + " +{ + rs6000_emit_epilogue (FALSE); + DONE; +}") + +; On some processors, doing the mtcrf one CC register at a time is +; faster (like on the 604e). On others, doing them all at once is +; faster; for instance, on the 601 and 750. + +(define_expand "movsi_to_cr_one" + [(set (match_operand:CC 0 "cc_reg_operand" "") + (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "") + (match_dup 2)] UNSPEC_MOVESI_TO_CR))] + "" + "operands[2] = GEN_INT (1 << (75 - REGNO (operands[0])));") + +(define_insn "*movsi_to_cr" + [(match_parallel 0 "mtcrf_operation" + [(set (match_operand:CC 1 "cc_reg_operand" "=y") + (unspec:CC [(match_operand:SI 2 "gpc_reg_operand" "r") + (match_operand 3 "immediate_operand" "n")] + UNSPEC_MOVESI_TO_CR))])] + "" + "* +{ + int mask = 0; + int i; + for (i = 0; i < XVECLEN (operands[0], 0); i++) + mask |= INTVAL (XVECEXP (SET_SRC (XVECEXP (operands[0], 0, i)), 0, 1)); + operands[4] = GEN_INT (mask); + return \"mtcrf %4,%2\"; +}" + [(set_attr "type" "mtcr")]) + +(define_insn "*mtcrfsi" + [(set (match_operand:CC 0 "cc_reg_operand" "=y") + (unspec:CC [(match_operand:SI 1 "gpc_reg_operand" "r") + (match_operand 2 "immediate_operand" "n")] + UNSPEC_MOVESI_TO_CR))] + "GET_CODE (operands[0]) == REG + && CR_REGNO_P (REGNO (operands[0])) + && GET_CODE (operands[2]) == CONST_INT + && INTVAL (operands[2]) == 1 << (75 - REGNO (operands[0]))" + "mtcrf %R0,%1" + [(set_attr "type" "mtcr")]) + +; The load-multiple instructions have similar properties. +; Note that "load_multiple" is a name known to the machine-independent +; code that actually corresponds to the PowerPC load-string. + +(define_insn "*lmw" + [(match_parallel 0 "lmw_operation" + [(set (match_operand:SI 1 "gpc_reg_operand" "=r") + (match_operand:SI 2 "memory_operand" "m"))])] + "TARGET_MULTIPLE" + "{lm|lmw} %1,%2" + [(set_attr "type" "load_ux") + (set_attr "cell_micro" "always")]) + +(define_insn "*return_internal_<mode>" + [(return) + (use (match_operand:P 0 "register_operand" "lc"))] + "" + "b%T0" + [(set_attr "type" "jmpreg")]) + +; FIXME: This would probably be somewhat simpler if the Cygnus sibcall +; stuff was in GCC. Oh, and "any_parallel_operand" is a bit flexible... + +; The following comment applies to: +; save_gpregs_* +; save_fpregs_* +; restore_gpregs* +; return_and_restore_gpregs* +; return_and_restore_fpregs* +; return_and_restore_fpregs_aix* +; +; The out-of-line save / restore functions expects one input argument. +; Since those are not standard call_insn's, we must avoid using +; MATCH_OPERAND for that argument. That way the register rename +; optimization will not try to rename this register. +; Each pattern is repeated for each possible register number used in +; various ABIs (r11, r1, and for some functions r12) + +(define_insn "*restore_gpregs_<mode>_r11" + [(match_parallel 0 "any_parallel_operand" + [(clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 11)) + (set (match_operand:P 3 "gpc_reg_operand" "=r") + (match_operand:P 4 "memory_operand" "m"))])] + "" + "bl %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*restore_gpregs_<mode>_r12" + [(match_parallel 0 "any_parallel_operand" + [(clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 12)) + (set (match_operand:P 3 "gpc_reg_operand" "=r") + (match_operand:P 4 "memory_operand" "m"))])] + "" + "bl %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*restore_gpregs_<mode>_r1" + [(match_parallel 0 "any_parallel_operand" + [(clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 1)) + (set (match_operand:P 3 "gpc_reg_operand" "=r") + (match_operand:P 4 "memory_operand" "m"))])] + "" + "bl %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_gpregs_<mode>_r11" + [(match_parallel 0 "any_parallel_operand" + [(return) + (clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 11)) + (set (match_operand:P 3 "gpc_reg_operand" "=r") + (match_operand:P 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_gpregs_<mode>_r12" + [(match_parallel 0 "any_parallel_operand" + [(return) + (clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 12)) + (set (match_operand:P 3 "gpc_reg_operand" "=r") + (match_operand:P 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_gpregs_<mode>_r1" + [(match_parallel 0 "any_parallel_operand" + [(return) + (clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 1)) + (set (match_operand:P 3 "gpc_reg_operand" "=r") + (match_operand:P 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_fpregs_<mode>_r11" + [(match_parallel 0 "any_parallel_operand" + [(return) + (clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 11)) + (set (match_operand:DF 3 "gpc_reg_operand" "=d") + (match_operand:DF 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_fpregs_<mode>_r12" + [(match_parallel 0 "any_parallel_operand" + [(return) + (clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 12)) + (set (match_operand:DF 3 "gpc_reg_operand" "=d") + (match_operand:DF 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_fpregs_<mode>_r1" + [(match_parallel 0 "any_parallel_operand" + [(return) + (clobber (match_operand:P 1 "register_operand" "=l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 1)) + (set (match_operand:DF 3 "gpc_reg_operand" "=d") + (match_operand:DF 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_fpregs_aix_<mode>_r11" + [(match_parallel 0 "any_parallel_operand" + [(return) + (use (match_operand:P 1 "register_operand" "l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 11)) + (set (match_operand:DF 3 "gpc_reg_operand" "=d") + (match_operand:DF 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +(define_insn "*return_and_restore_fpregs_aix_<mode>_r1" + [(match_parallel 0 "any_parallel_operand" + [(return) + (use (match_operand:P 1 "register_operand" "l")) + (use (match_operand:P 2 "symbol_ref_operand" "s")) + (use (reg:P 1)) + (set (match_operand:DF 3 "gpc_reg_operand" "=d") + (match_operand:DF 4 "memory_operand" "m"))])] + "" + "b %2" + [(set_attr "type" "branch") + (set_attr "length" "4")]) + +; This is used in compiling the unwind routines. +(define_expand "eh_return" + [(use (match_operand 0 "general_operand" ""))] + "" + " +{ + if (TARGET_32BIT) + emit_insn (gen_eh_set_lr_si (operands[0])); + else + emit_insn (gen_eh_set_lr_di (operands[0])); + DONE; +}") + +; We can't expand this before we know where the link register is stored. +(define_insn "eh_set_lr_<mode>" + [(unspec_volatile [(match_operand:P 0 "register_operand" "r")] + UNSPECV_EH_RR) + (clobber (match_scratch:P 1 "=&b"))] + "" + "#") + +(define_split + [(unspec_volatile [(match_operand 0 "register_operand" "")] UNSPECV_EH_RR) + (clobber (match_scratch 1 ""))] + "reload_completed" + [(const_int 0)] + " +{ + rs6000_emit_eh_reg_restore (operands[0], operands[1]); + DONE; +}") + +(define_insn "prefetch" + [(prefetch (match_operand 0 "indexed_or_indirect_address" "a") + (match_operand:SI 1 "const_int_operand" "n") + (match_operand:SI 2 "const_int_operand" "n"))] + "TARGET_POWERPC" + "* +{ + if (GET_CODE (operands[0]) == REG) + return INTVAL (operands[1]) ? \"dcbtst 0,%0\" : \"dcbt 0,%0\"; + return INTVAL (operands[1]) ? \"dcbtst %a0\" : \"dcbt %a0\"; +}" + [(set_attr "type" "load")]) + +(define_insn "bpermd_<mode>" + [(set (match_operand:P 0 "gpc_reg_operand" "=r") + (unspec:P [(match_operand:P 1 "gpc_reg_operand" "r") + (match_operand:P 2 "gpc_reg_operand" "r")] UNSPEC_BPERM))] + "TARGET_POPCNTD" + "bpermd %0,%1,%2" + [(set_attr "type" "integer")]) + + +;; Builtin fma support. Handle +;; Note that the conditions for expansion are in the FMA_F iterator. + +(define_expand "fma<mode>4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (match_operand:FMA_F 3 "register_operand" "")))] + "" + "") + +; Altivec only has fma and nfms. +(define_expand "fms<mode>4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (neg:FMA_F (match_operand:FMA_F 3 "register_operand" ""))))] + "!VECTOR_UNIT_ALTIVEC_P (<MODE>mode)" + "") + +;; If signed zeros are ignored, -(a * b - c) = -a * b + c. +(define_expand "fnma<mode>4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (neg:FMA_F (match_operand:FMA_F 3 "register_operand" "")))))] + "!HONOR_SIGNED_ZEROS (<MODE>mode)" + "") + +;; If signed zeros are ignored, -(a * b + c) = -a * b - c. +(define_expand "fnms<mode>4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (match_operand:FMA_F 3 "register_operand" ""))))] + "!HONOR_SIGNED_ZEROS (<MODE>mode) && !VECTOR_UNIT_ALTIVEC_P (<MODE>mode)" + "") + +; Not an official optab name, but used from builtins. +(define_expand "nfma<mode>4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (match_operand:FMA_F 3 "register_operand" ""))))] + "!VECTOR_UNIT_ALTIVEC_P (<MODE>mode)" + "") + +; Not an official optab name, but used from builtins. +(define_expand "nfms<mode>4" + [(set (match_operand:FMA_F 0 "register_operand" "") + (neg:FMA_F + (fma:FMA_F + (match_operand:FMA_F 1 "register_operand" "") + (match_operand:FMA_F 2 "register_operand" "") + (neg:FMA_F (match_operand:FMA_F 3 "register_operand" "")))))] + "" + "") + + + +(include "sync.md") +(include "vector.md") +(include "vsx.md") +(include "altivec.md") +(include "spe.md") +(include "dfp.md") +(include "paired.md") |