;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler
;; Copyright (C) 1990-2018 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
;; .
;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
;;
;; REGNOS
;;
(define_constants
[(FIRST_GPR_REGNO 0)
(STACK_POINTER_REGNUM 1)
(TOC_REGNUM 2)
(STATIC_CHAIN_REGNUM 11)
(HARD_FRAME_POINTER_REGNUM 31)
(LAST_GPR_REGNO 31)
(FIRST_FPR_REGNO 32)
(LAST_FPR_REGNO 63)
(LR_REGNO 65)
(CTR_REGNO 66)
(ARG_POINTER_REGNUM 67)
(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)
(FRAME_POINTER_REGNUM 113)
(TFHAR_REGNO 114)
(TFIAR_REGNO 115)
(TEXASR_REGNO 116)
(FIRST_SPE_HIGH_REGNO 117)
(LAST_SPE_HIGH_REGNO 148)
])
;;
;; UNSPEC usage
;;
(define_c_enum "unspec"
[UNSPEC_FRSP ; frsp for POWER machines
UNSPEC_PROBE_STACK ; probe stack memory reference
UNSPEC_TOCPTR ; address of a word pointing to the TOC
UNSPEC_TOC ; address of the TOC (more-or-less)
UNSPEC_TOCSLOT ; offset from r1 of toc pointer save slot
UNSPEC_MOVSI_GOT
UNSPEC_MV_CR_OV ; move_from_CR_ov_bit
UNSPEC_FCTIWZ
UNSPEC_FRIM
UNSPEC_FRIN
UNSPEC_FRIP
UNSPEC_FRIZ
UNSPEC_XSRDPI
UNSPEC_LD_MPIC ; load_macho_picbase
UNSPEC_RELD_MPIC ; re-load_macho_picbase
UNSPEC_MPIC_CORRECT ; macho_correct_pic
UNSPEC_TLSGD
UNSPEC_TLSLD
UNSPEC_MOVESI_FROM_CR
UNSPEC_MOVESI_TO_CR
UNSPEC_TLSDTPREL
UNSPEC_TLSDTPRELHA
UNSPEC_TLSDTPRELLO
UNSPEC_TLSGOTDTPREL
UNSPEC_TLSTPREL
UNSPEC_TLSTPRELHA
UNSPEC_TLSTPRELLO
UNSPEC_TLSGOTTPREL
UNSPEC_TLSTLS
UNSPEC_FIX_TRUNC_TF ; fadd, rounding towards zero
UNSPEC_MV_CR_GT ; move_from_CR_gt_bit
UNSPEC_STFIWX
UNSPEC_POPCNTB
UNSPEC_FRES
UNSPEC_SP_SET
UNSPEC_SP_TEST
UNSPEC_SYNC
UNSPEC_LWSYNC
UNSPEC_SYNC_OP
UNSPEC_ATOMIC
UNSPEC_CMPXCHG
UNSPEC_XCHG
UNSPEC_AND
UNSPEC_DLMZB
UNSPEC_DLMZB_CR
UNSPEC_DLMZB_STRLEN
UNSPEC_RSQRT
UNSPEC_TOCREL
UNSPEC_MACHOPIC_OFFSET
UNSPEC_BPERM
UNSPEC_COPYSIGN
UNSPEC_PARITY
UNSPEC_CMPB
UNSPEC_FCTIW
UNSPEC_FCTID
UNSPEC_LFIWAX
UNSPEC_LFIWZX
UNSPEC_FCTIWUZ
UNSPEC_NOP
UNSPEC_GRP_END_NOP
UNSPEC_P8V_FMRGOW
UNSPEC_P8V_MTVSRWZ
UNSPEC_P8V_RELOAD_FROM_GPR
UNSPEC_P8V_MTVSRD
UNSPEC_P8V_XXPERMDI
UNSPEC_P8V_RELOAD_FROM_VSX
UNSPEC_ADDG6S
UNSPEC_CDTBCD
UNSPEC_CBCDTD
UNSPEC_DIVE
UNSPEC_DIVEU
UNSPEC_UNPACK_128BIT
UNSPEC_PACK_128BIT
UNSPEC_LSQ
UNSPEC_FUSION_GPR
UNSPEC_STACK_CHECK
UNSPEC_CMPRB
UNSPEC_CMPRB2
UNSPEC_CMPEQB
UNSPEC_FUSION_P9
UNSPEC_FUSION_ADDIS
UNSPEC_ROUND_TO_ODD
UNSPEC_SIGNBIT
UNSPEC_SF_FROM_SI
UNSPEC_SI_FROM_SF
])
;;
;; UNSPEC_VOLATILE usage
;;
(define_c_enum "unspecv"
[UNSPECV_BLOCK
UNSPECV_LL ; load-locked
UNSPECV_SC ; store-conditional
UNSPECV_PROBE_STACK_RANGE ; probe range of stack addresses
UNSPECV_EH_RR ; eh_reg_restore
UNSPECV_ISYNC ; isync instruction
UNSPECV_MFTB ; move from time base
UNSPECV_DARN ; darn 1 (deliver a random number)
UNSPECV_DARN_32 ; darn 2
UNSPECV_DARN_RAW ; darn 0
UNSPECV_NLGR ; non-local goto receiver
UNSPECV_MFFS ; Move from FPSCR
UNSPECV_MTFSF ; Move to FPSCR Fields
UNSPECV_SPLIT_STACK_RETURN ; A camouflaged return
])
;; Define an insn type attribute. This is used in function unit delay
;; computations.
(define_attr "type"
"integer,two,three,
add,logical,shift,insert,
mul,halfmul,div,
exts,cntlz,popcnt,isel,
load,store,fpload,fpstore,vecload,vecstore,
cmp,
branch,jmpreg,mfjmpr,mtjmpr,trap,isync,sync,load_l,store_c,
cr_logical,delayed_cr,mfcr,mfcrf,mtcr,
fpcompare,fp,fpsimple,dmul,sdiv,ddiv,ssqrt,dsqrt,
brinc,
vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,
vecfloat,vecfdiv,vecdouble,mffgpr,mftgpr,crypto,
veclogical,veccmpfx,vecexts,vecmove,
htm,htmsimple,dfp"
(const_string "integer"))
;; What data size does this instruction work on?
;; This is used for insert, mul and others as necessary.
(define_attr "size" "8,16,32,64,128" (const_string "32"))
;; Is this instruction record form ("dot", signed compare to 0, writing CR0)?
;; This is used for add, logical, shift, exts, mul.
(define_attr "dot" "no,yes" (const_string "no"))
;; Does this instruction sign-extend its result?
;; This is used for load insns.
(define_attr "sign_extend" "no,yes" (const_string "no"))
;; Does this instruction use indexed (that is, reg+reg) addressing?
;; This is used for load and store insns. If operand 0 or 1 is a MEM
;; it is automatically set based on that. If a load or store instruction
;; has fewer than two operands it needs to set this attribute manually
;; or the compiler will crash.
(define_attr "indexed" "no,yes"
(if_then_else (ior (match_operand 0 "indexed_address_mem")
(match_operand 1 "indexed_address_mem"))
(const_string "yes")
(const_string "no")))
;; Does this instruction use update addressing?
;; This is used for load and store insns. See the comments for "indexed".
(define_attr "update" "no,yes"
(if_then_else (ior (match_operand 0 "update_address_mem")
(match_operand 1 "update_address_mem"))
(const_string "yes")
(const_string "no")))
;; Is this instruction using operands[2] as shift amount, and can that be a
;; register?
;; This is used for shift insns.
(define_attr "maybe_var_shift" "no,yes" (const_string "no"))
;; Is this instruction using a shift amount from a register?
;; This is used for shift insns.
(define_attr "var_shift" "no,yes"
(if_then_else (and (eq_attr "type" "shift")
(eq_attr "maybe_var_shift" "yes"))
(if_then_else (match_operand 2 "gpc_reg_operand")
(const_string "yes")
(const_string "no"))
(const_string "no")))
;; Is copying of this instruction disallowed?
(define_attr "cannot_copy" "no,yes" (const_string "no"))
;; 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-opts.h.
(define_attr "cpu"
"ppc601,ppc603,ppc604,ppc604e,ppc620,ppc630,
ppc750,ppc7400,ppc7450,
ppc403,ppc405,ppc440,ppc476,
ppc8540,ppc8548,ppce300c2,ppce300c3,ppce500mc,ppce500mc64,ppce5500,ppce6500,
power4,power5,power6,power7,power8,power9,
rs64a,mpccore,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 (ior (and (eq_attr "type" "shift,exts,mul")
(eq_attr "dot" "yes"))
(and (eq_attr "type" "load")
(eq_attr "sign_extend" "yes"))
(and (eq_attr "type" "shift")
(eq_attr "var_shift" "yes")))
(const_string "always")
(const_string "not")))
(automata_option "ndfa")
(include "rs64.md")
(include "mpc.md")
(include "40x.md")
(include "440.md")
(include "476.md")
(include "601.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 "e5500.md")
(include "e6500.md")
(include "power4.md")
(include "power5.md")
(include "power6.md")
(include "power7.md")
(include "power8.md")
(include "power9.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 PTI])
; Any supported integer mode that fits in one register.
(define_mode_iterator INT1 [QI HI SI (DI "TARGET_POWERPC64")])
; Integer modes supported in VSX registers with ISA 3.0 instructions
(define_mode_iterator INT_ISA3 [QI HI SI DI])
; Everything we can extend QImode to.
(define_mode_iterator EXTQI [SI (DI "TARGET_POWERPC64")])
; Everything we can extend HImode to.
(define_mode_iterator EXTHI [SI (DI "TARGET_POWERPC64")])
; Everything we can extend SImode to.
(define_mode_iterator EXTSI [(DI "TARGET_POWERPC64")])
; QImode or HImode for small integer moves and small atomic ops
(define_mode_iterator QHI [QI HI])
; QImode, HImode, SImode for fused ops only for GPR loads
(define_mode_iterator QHSI [QI HI SI])
; HImode or SImode for sign extended fusion ops
(define_mode_iterator HSI [HI SI])
; SImode or DImode, even if DImode doesn't fit in GPRs.
(define_mode_iterator SDI [SI DI])
; Types that can be fused with an ADDIS instruction to load or store a GPR
; register that has reg+offset addressing.
(define_mode_iterator GPR_FUSION [QI
HI
SI
(DI "TARGET_POWERPC64")
SF
(DF "TARGET_POWERPC64")])
; Types that can be fused with an ADDIS instruction to load or store a FPR
; register that has reg+offset addressing.
(define_mode_iterator FPR_FUSION [DI SF DF])
; 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")])
; Iterator to add PTImode along with TImode (TImode can go in VSX registers,
; PTImode is GPR only)
(define_mode_iterator TI2 [TI PTI])
; 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_HARD_FLOAT
&& (TARGET_FPRS || TARGET_E500_DOUBLE)
&& TARGET_LONG_DOUBLE_128")
(IF "TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_LONG_DOUBLE_128")
(KF "TARGET_FLOAT128_TYPE")
(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)")
(KF "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (KFmode)")
(TF "TARGET_FLOAT128_HW && FLOAT128_IEEE_P (TFmode)")
])
; Floating point move iterators to combine binary and decimal moves
(define_mode_iterator FMOVE32 [SF SD])
(define_mode_iterator FMOVE64 [DF DD])
(define_mode_iterator FMOVE64X [DI DF DD])
(define_mode_iterator FMOVE128 [(TF "TARGET_LONG_DOUBLE_128")
(IF "FLOAT128_IBM_P (IFmode)")
(TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
(define_mode_iterator FMOVE128_FPR [(TF "FLOAT128_2REG_P (TFmode)")
(IF "FLOAT128_2REG_P (IFmode)")
(TD "TARGET_HARD_FLOAT && TARGET_FPRS")])
; Iterators for 128 bit types for direct move
(define_mode_iterator FMOVE128_GPR [(TI "TARGET_VSX_TIMODE")
(V16QI "")
(V8HI "")
(V4SI "")
(V4SF "")
(V2DI "")
(V2DF "")
(V1TI "")
(KF "FLOAT128_VECTOR_P (KFmode)")
(TF "FLOAT128_VECTOR_P (TFmode)")])
; Iterator for 128-bit VSX types for pack/unpack
(define_mode_iterator FMOVE128_VSX [V1TI KF])
; Whether a floating point move is ok, don't allow SD without hardware FP
(define_mode_attr fmove_ok [(SF "")
(DF "")
(SD "TARGET_HARD_FLOAT && TARGET_FPRS")
(DD "")])
; Convert REAL_VALUE to the appropriate bits
(define_mode_attr real_value_to_target [(SF "REAL_VALUE_TO_TARGET_SINGLE")
(DF "REAL_VALUE_TO_TARGET_DOUBLE")
(SD "REAL_VALUE_TO_TARGET_DECIMAL32")
(DD "REAL_VALUE_TO_TARGET_DECIMAL64")])
; Whether 0.0 has an all-zero bit pattern
(define_mode_attr zero_fp [(SF "j")
(DF "j")
(TF "j")
(IF "j")
(KF "j")
(SD "wn")
(DD "wn")
(TD "wn")])
; Definitions for 64-bit VSX
(define_mode_attr f64_vsx [(DF "ws") (DD "wn")])
; Definitions for 64-bit direct move
(define_mode_attr f64_dm [(DF "wk") (DD "wh")])
; Definitions for 64-bit use of altivec registers
(define_mode_attr f64_av [(DF "wv") (DD "wn")])
; Definitions for 64-bit access to ISA 3.0 (power9) vector
(define_mode_attr f64_p9 [(DF "wb") (DD "wn")])
; 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])
; Like SFDF, but a different name to match conditional move where the
; comparison operands may be a different mode than the input operands.
(define_mode_iterator SFDF2 [SF DF])
; Iterator for 128-bit floating point that uses the IBM double-double format
(define_mode_iterator IBM128 [(IF "FLOAT128_IBM_P (IFmode)")
(TF "FLOAT128_IBM_P (TFmode)")])
; Iterator for 128-bit floating point that uses IEEE 128-bit float
(define_mode_iterator IEEE128 [(KF "FLOAT128_IEEE_P (KFmode)")
(TF "FLOAT128_IEEE_P (TFmode)")])
; Iterator for 128-bit floating point
(define_mode_iterator FLOAT128 [(KF "TARGET_FLOAT128_TYPE")
(IF "TARGET_FLOAT128_TYPE")
(TF "TARGET_LONG_DOUBLE_128")])
; Iterator for signbit on 64-bit machines with direct move
(define_mode_iterator SIGNBIT [(KF "FLOAT128_VECTOR_P (KFmode)")
(TF "FLOAT128_VECTOR_P (TFmode)")])
; Iterator for ISA 3.0 supported floating point types
(define_mode_iterator FP_ISA3 [SF DF])
; SF/DF suffix for traditional floating instructions
(define_mode_attr Ftrad [(SF "s") (DF "")])
; SF/DF suffix for VSX instructions
(define_mode_attr Fvsx [(SF "sp") (DF "dp")])
; SF/DF constraint for arithmetic on traditional floating point registers
(define_mode_attr Ff [(SF "f") (DF "d") (DI "d")])
; SF/DF constraint for arithmetic on VSX registers using instructions added in
; ISA 2.06 (power7). This includes instructions that normally target DF mode,
; but are used on SFmode, since internally SFmode values are kept in the DFmode
; format.
(define_mode_attr Fv [(SF "ww") (DF "ws") (DI "wi")])
; SF/DF constraint for arithmetic on VSX registers. This is intended to be
; used for DFmode instructions added in ISA 2.06 (power7) and SFmode
; instructions added in ISA 2.07 (power8)
(define_mode_attr Fv2 [(SF "wy") (DF "ws") (DI "wi")])
; SF/DF constraint for arithmetic on altivec registers
(define_mode_attr Fa [(SF "wu") (DF "wv")])
; s/d suffix for things like fp_addsub_s/fp_addsub_d
(define_mode_attr Fs [(SF "s") (DF "d")])
; FRE/FRES support
(define_mode_attr Ffre [(SF "fres") (DF "fre")])
(define_mode_attr FFRE [(SF "FRES") (DF "FRE")])
; Conditional returns.
(define_code_iterator any_return [return simple_return])
(define_code_attr return_pred [(return "direct_return ()")
(simple_return "1")])
(define_code_attr return_str [(return "") (simple_return "simple_")])
; Logical operators.
(define_code_iterator iorxor [ior xor])
(define_code_iterator and_ior_xor [and ior xor])
; Signed/unsigned variants of ops.
(define_code_iterator any_extend [sign_extend zero_extend])
(define_code_iterator any_fix [fix unsigned_fix])
(define_code_iterator any_float [float unsigned_float])
(define_code_attr u [(sign_extend "")
(zero_extend "u")
(fix "")
(unsigned_fix "u")])
(define_code_attr su [(sign_extend "s")
(zero_extend "u")
(fix "s")
(unsigned_fix "u")
(float "s")
(unsigned_float "u")])
(define_code_attr az [(sign_extend "a")
(zero_extend "z")
(fix "a")
(unsigned_fix "z")
(float "a")
(unsigned_float "z")])
(define_code_attr uns [(fix "")
(unsigned_fix "uns")
(float "")
(unsigned_float "uns")])
; 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")
(V16QI "b")
(V8HI "h")
(V4SI "w")
(V2DI "d")
(V1TI "q")
(TI "q")])
;; How many bits in this mode?
(define_mode_attr bits [(QI "8") (HI "16") (SI "32") (DI "64")])
; DImode bits
(define_mode_attr dbits [(QI "56") (HI "48") (SI "32")])
;; ISEL/ISEL64 target selection
(define_mode_attr sel [(SI "") (DI "64")])
;; Bitmask for shift instructions
(define_mode_attr hH [(SI "h") (DI "H")])
;; A mode twice the size of the given mode
(define_mode_attr dmode [(SI "di") (DI "ti")])
(define_mode_attr DMODE [(SI "DI") (DI "TI")])
;; 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 ptrload [(SI "lwz")
(DI "ld")])
(define_mode_attr ptrm [(SI "m")
(DI "Y")])
(define_mode_attr rreg [(SF "f")
(DF "ws")
(TF "f")
(TD "f")
(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")])
;; Mode iterator for logical operations on 128-bit types
(define_mode_iterator BOOL_128 [TI
PTI
(V16QI "TARGET_ALTIVEC")
(V8HI "TARGET_ALTIVEC")
(V4SI "TARGET_ALTIVEC")
(V4SF "TARGET_ALTIVEC")
(V2DI "TARGET_ALTIVEC")
(V2DF "TARGET_ALTIVEC")
(V1TI "TARGET_ALTIVEC")])
;; For the GPRs we use 3 constraints for register outputs, two that are the
;; same as the output register, and a third where the output register is an
;; early clobber, so we don't have to deal with register overlaps. For the
;; vector types, we prefer to use the vector registers. For TI mode, allow
;; either.
;; Mode attribute for boolean operation register constraints for output
(define_mode_attr BOOL_REGS_OUTPUT [(TI "&r,r,r,wt,v")
(PTI "&r,r,r")
(V16QI "wa,v,&?r,?r,?r")
(V8HI "wa,v,&?r,?r,?r")
(V4SI "wa,v,&?r,?r,?r")
(V4SF "wa,v,&?r,?r,?r")
(V2DI "wa,v,&?r,?r,?r")
(V2DF "wa,v,&?r,?r,?r")
(V1TI "wa,v,&?r,?r,?r")])
;; Mode attribute for boolean operation register constraints for operand1
(define_mode_attr BOOL_REGS_OP1 [(TI "r,0,r,wt,v")
(PTI "r,0,r")
(V16QI "wa,v,r,0,r")
(V8HI "wa,v,r,0,r")
(V4SI "wa,v,r,0,r")
(V4SF "wa,v,r,0,r")
(V2DI "wa,v,r,0,r")
(V2DF "wa,v,r,0,r")
(V1TI "wa,v,r,0,r")])
;; Mode attribute for boolean operation register constraints for operand2
(define_mode_attr BOOL_REGS_OP2 [(TI "r,r,0,wt,v")
(PTI "r,r,0")
(V16QI "wa,v,r,r,0")
(V8HI "wa,v,r,r,0")
(V4SI "wa,v,r,r,0")
(V4SF "wa,v,r,r,0")
(V2DI "wa,v,r,r,0")
(V2DF "wa,v,r,r,0")
(V1TI "wa,v,r,r,0")])
;; Mode attribute for boolean operation register constraints for operand1
;; for one_cmpl. To simplify things, we repeat the constraint where 0
;; is used for operand1 or operand2
(define_mode_attr BOOL_REGS_UNARY [(TI "r,0,0,wt,v")
(PTI "r,0,0")
(V16QI "wa,v,r,0,0")
(V8HI "wa,v,r,0,0")
(V4SI "wa,v,r,0,0")
(V4SF "wa,v,r,0,0")
(V2DI "wa,v,r,0,0")
(V2DF "wa,v,r,0,0")
(V1TI "wa,v,r,0,0")])
;; Reload iterator for creating the function to allocate a base register to
;; supplement addressing modes.
(define_mode_iterator RELOAD [V16QI V8HI V4SI V2DI V4SF V2DF V1TI
SF SD SI DF DD DI TI PTI KF IF TF])
;; Iterate over smin, smax
(define_code_iterator fp_minmax [smin smax])
(define_code_attr minmax [(smin "min")
(smax "max")])
(define_code_attr SMINMAX [(smin "SMIN")
(smax "SMAX")])
;; Iterator to optimize the following cases:
;; D-form load to FPR register & move to Altivec register
;; Move Altivec register to FPR register and store
(define_mode_iterator ALTIVEC_DFORM [DF
SF
(DI "TARGET_POWERPC64")])
;; Start with fixed-point load and store insns. Here we put only the more
;; complex forms. Basic data transfer is done later.
(define_insn "zero_extendqi2"
[(set (match_operand:EXTQI 0 "gpc_reg_operand" "=r,r,^wJwK,^wK")
(zero_extend:EXTQI (match_operand:QI 1 "reg_or_mem_operand" "m,r,Z,wK")))]
""
"@
lbz%U1%X1 %0,%1
rlwinm %0,%1,0,0xff
lxsibzx %x0,%y1
vextractub %0,%1,7"
[(set_attr "type" "load,shift,fpload,vecperm")])
(define_insn_and_split "*zero_extendqi2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (zero_extend:EXTQI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:EXTQI 0 "=r,r"))]
"rs6000_gen_cell_microcode"
"@
andi. %0,%1,0xff
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(zero_extend:EXTQI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*zero_extendqi2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (zero_extend:EXTQI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:EXTQI 0 "gpc_reg_operand" "=r,r")
(zero_extend:EXTQI (match_dup 1)))]
"rs6000_gen_cell_microcode"
"@
andi. %0,%1,0xff
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(zero_extend:EXTQI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "zero_extendhi2"
[(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r,r,^wJwK,^wK")
(zero_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "m,r,Z,wK")))]
""
"@
lhz%U1%X1 %0,%1
rlwinm %0,%1,0,0xffff
lxsihzx %x0,%y1
vextractuh %0,%1,6"
[(set_attr "type" "load,shift,fpload,vecperm")])
(define_insn_and_split "*zero_extendhi2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (zero_extend:EXTHI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:EXTHI 0 "=r,r"))]
"rs6000_gen_cell_microcode"
"@
andi. %0,%1,0xffff
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(zero_extend:EXTHI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*zero_extendhi2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (zero_extend:EXTHI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r,r")
(zero_extend:EXTHI (match_dup 1)))]
"rs6000_gen_cell_microcode"
"@
andi. %0,%1,0xffff
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(zero_extend:EXTHI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "zero_extendsi2"
[(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r,r,wz,wu,wj,r,wJwK")
(zero_extend:EXTSI (match_operand:SI 1 "reg_or_mem_operand" "m,r,Z,Z,r,wIwH,wJwK")))]
""
"@
lwz%U1%X1 %0,%1
rldicl %0,%1,0,32
lfiwzx %0,%y1
lxsiwzx %x0,%y1
mtvsrwz %x0,%1
mfvsrwz %0,%x1
xxextractuw %x0,%x1,4"
[(set_attr "type" "load,shift,fpload,fpload,mffgpr,mftgpr,vecexts")])
(define_insn_and_split "*zero_extendsi2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (zero_extend:EXTSI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:EXTSI 0 "=r,r"))]
"rs6000_gen_cell_microcode"
"@
rldicl. %0,%1,0,32
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(zero_extend:DI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "shift")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*zero_extendsi2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (zero_extend:EXTSI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r,r")
(zero_extend:EXTSI (match_dup 1)))]
"rs6000_gen_cell_microcode"
"@
rldicl. %0,%1,0,32
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(zero_extend:EXTSI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "shift")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "extendqi2"
[(set (match_operand:EXTQI 0 "gpc_reg_operand" "=r,?*wK")
(sign_extend:EXTQI (match_operand:QI 1 "gpc_reg_operand" "r,?*wK")))]
""
"@
extsb %0,%1
vextsb2d %0,%1"
[(set_attr "type" "exts,vecperm")])
(define_insn_and_split "*extendqi2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (sign_extend:EXTQI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:EXTQI 0 "=r,r"))]
"rs6000_gen_cell_microcode"
"@
extsb. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(sign_extend:EXTQI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "exts")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*extendqi2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (sign_extend:EXTQI (match_operand:QI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:EXTQI 0 "gpc_reg_operand" "=r,r")
(sign_extend:EXTQI (match_dup 1)))]
"rs6000_gen_cell_microcode"
"@
extsb. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(sign_extend:EXTQI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "exts")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_expand "extendhi2"
[(set (match_operand:EXTHI 0 "gpc_reg_operand")
(sign_extend:EXTHI (match_operand:HI 1 "gpc_reg_operand")))]
""
"")
(define_insn "*extendhi2"
[(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r,r,?*wK,?*wK")
(sign_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "m,r,Z,wK")))]
"rs6000_gen_cell_microcode || TARGET_VSX_SMALL_INTEGER"
"@
lha%U1%X1 %0,%1
extsh %0,%1
#
vextsh2d %0,%1"
[(set_attr "type" "load,exts,fpload,vecperm")
(set_attr "sign_extend" "yes")
(set_attr "length" "4,4,8,4")])
(define_split
[(set (match_operand:EXTHI 0 "altivec_register_operand")
(sign_extend:EXTHI
(match_operand:HI 1 "indexed_or_indirect_operand")))]
"TARGET_P9_VECTOR && reload_completed"
[(set (match_dup 2)
(match_dup 1))
(set (match_dup 0)
(sign_extend:EXTHI (match_dup 2)))]
{
operands[2] = gen_rtx_REG (HImode, REGNO (operands[0]));
})
(define_insn "*extendhi2_noload"
[(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r")
(sign_extend:EXTHI (match_operand:HI 1 "gpc_reg_operand" "r")))]
"!rs6000_gen_cell_microcode"
"extsh %0,%1"
[(set_attr "type" "exts")])
(define_insn_and_split "*extendhi2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (sign_extend:EXTHI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:EXTHI 0 "=r,r"))]
"rs6000_gen_cell_microcode"
"@
extsh. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(sign_extend:EXTHI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "exts")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*extendhi2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (sign_extend:EXTHI (match_operand:HI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:EXTHI 0 "gpc_reg_operand" "=r,r")
(sign_extend:EXTHI (match_dup 1)))]
"rs6000_gen_cell_microcode"
"@
extsh. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(sign_extend:EXTHI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "exts")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "extendsi2"
[(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r,r,wl,wu,wj,wK,wH")
(sign_extend:EXTSI (match_operand:SI 1 "lwa_operand" "YZ,r,Z,Z,r,wK,wH")))]
""
"@
lwa%U1%X1 %0,%1
extsw %0,%1
lfiwax %0,%y1
lxsiwax %x0,%y1
mtvsrwa %x0,%1
vextsw2d %0,%1
#"
[(set_attr "type" "load,exts,fpload,fpload,mffgpr,vecexts,vecperm")
(set_attr "sign_extend" "yes")
(set_attr "length" "4,4,4,4,4,4,8")])
(define_split
[(set (match_operand:DI 0 "altivec_register_operand")
(sign_extend:DI (match_operand:SI 1 "altivec_register_operand")))]
"TARGET_VSX_SMALL_INTEGER && TARGET_P8_VECTOR && !TARGET_P9_VECTOR
&& reload_completed"
[(const_int 0)]
{
rtx dest = operands[0];
rtx src = operands[1];
int dest_regno = REGNO (dest);
int src_regno = REGNO (src);
rtx dest_v2di = gen_rtx_REG (V2DImode, dest_regno);
rtx src_v4si = gen_rtx_REG (V4SImode, src_regno);
if (VECTOR_ELT_ORDER_BIG)
{
emit_insn (gen_altivec_vupkhsw (dest_v2di, src_v4si));
emit_insn (gen_vsx_xxspltd_v2di (dest_v2di, dest_v2di, const1_rtx));
}
else
{
emit_insn (gen_altivec_vupklsw (dest_v2di, src_v4si));
emit_insn (gen_vsx_xxspltd_v2di (dest_v2di, dest_v2di, const0_rtx));
}
DONE;
})
(define_insn_and_split "*extendsi2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (sign_extend:EXTSI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:EXTSI 0 "=r,r"))]
"rs6000_gen_cell_microcode"
"@
extsw. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(sign_extend:EXTSI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "exts")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*extendsi2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (sign_extend:EXTSI (match_operand:SI 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:EXTSI 0 "gpc_reg_operand" "=r,r")
(sign_extend:EXTSI (match_dup 1)))]
"rs6000_gen_cell_microcode"
"@
extsw. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(sign_extend:EXTSI (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "exts")
(set_attr "dot" "yes")
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
(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" "halfmul")])
;; 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 (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 (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_addsi3 (result, result, constm1_rtx));
DONE;
})
;; Fixed-point arithmetic insns.
(define_expand "add3"
[(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 == DImode && !TARGET_POWERPC64)
{
rtx lo0 = gen_lowpart (SImode, operands[0]);
rtx lo1 = gen_lowpart (SImode, operands[1]);
rtx lo2 = gen_lowpart (SImode, operands[2]);
rtx hi0 = gen_highpart (SImode, operands[0]);
rtx hi1 = gen_highpart (SImode, operands[1]);
rtx hi2 = gen_highpart_mode (SImode, DImode, operands[2]);
if (!reg_or_short_operand (lo2, SImode))
lo2 = force_reg (SImode, lo2);
if (!adde_operand (hi2, SImode))
hi2 = force_reg (SImode, hi2);
emit_insn (gen_addsi3_carry (lo0, lo1, lo2));
emit_insn (gen_addsi3_carry_in (hi0, hi1, hi2));
DONE;
}
if (CONST_INT_P (operands[2]) && !add_operand (operands[2], mode))
{
rtx tmp = ((!can_create_pseudo_p ()
|| rtx_equal_p (operands[0], operands[1]))
? operands[0] : gen_reg_rtx (mode));
/* Adding a constant to r0 is not a valid insn, so use a different
strategy in that case. */
if (reg_or_subregno (operands[1]) == 0 || reg_or_subregno (tmp) == 0)
{
if (operands[0] == operands[1])
FAIL;
rs6000_emit_move (operands[0], operands[2], mode);
emit_insn (gen_add3 (operands[0], operands[1], operands[0]));
DONE;
}
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);
if (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_add3 (tmp, operands[1], GEN_INT (rest)));
emit_insn (gen_add3 (operands[0], tmp, GEN_INT (low)));
DONE;
}
})
(define_insn "*add3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r,r")
(plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b")
(match_operand:GPR 2 "add_operand" "r,I,L")))]
""
"@
add %0,%1,%2
addi %0,%1,%2
addis %0,%1,%v2"
[(set_attr "type" "add")])
(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"
"addis %0,%1,ha16(%2)"
[(set_attr "type" "add")])
(define_insn_and_split "*add3_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))]
"mode == Pmode"
"@
add. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(plus:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*add3_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(plus:GPR (match_dup 1)
(match_dup 2)))]
"mode == Pmode"
"@
add. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(plus:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*add3_imm_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b")
(match_operand:GPR 2 "short_cint_operand" "I,I"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))
(clobber (reg:GPR CA_REGNO))]
"mode == Pmode"
"@
addic. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(plus:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*add3_imm_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b")
(match_operand:GPR 2 "short_cint_operand" "I,I"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(plus:GPR (match_dup 1)
(match_dup 2)))
(clobber (reg:GPR CA_REGNO))]
"mode == Pmode"
"@
addic. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(plus:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
;; 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);
operands[4] = GEN_INT (low);
if (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 "add3_carry"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(plus:P (match_operand:P 1 "gpc_reg_operand" "r")
(match_operand:P 2 "reg_or_short_operand" "rI")))
(set (reg:P CA_REGNO)
(ltu:P (plus:P (match_dup 1)
(match_dup 2))
(match_dup 1)))]
""
"add%I2c %0,%1,%2"
[(set_attr "type" "add")])
(define_insn "*add3_imm_carry_pos"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(plus:P (match_operand:P 1 "gpc_reg_operand" "r")
(match_operand:P 2 "short_cint_operand" "n")))
(set (reg:P CA_REGNO)
(geu:P (match_dup 1)
(match_operand:P 3 "const_int_operand" "n")))]
"INTVAL (operands[2]) > 0
&& INTVAL (operands[2]) + INTVAL (operands[3]) == 0"
"addic %0,%1,%2"
[(set_attr "type" "add")])
(define_insn "*add3_imm_carry_0"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(match_operand:P 1 "gpc_reg_operand" "r"))
(set (reg:P CA_REGNO)
(const_int 0))]
""
"addic %0,%1,0"
[(set_attr "type" "add")])
(define_insn "*add3_imm_carry_m1"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(plus:P (match_operand:P 1 "gpc_reg_operand" "r")
(const_int -1)))
(set (reg:P CA_REGNO)
(ne:P (match_dup 1)
(const_int 0)))]
""
"addic %0,%1,-1"
[(set_attr "type" "add")])
(define_insn "*add3_imm_carry_neg"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(plus:P (match_operand:P 1 "gpc_reg_operand" "r")
(match_operand:P 2 "short_cint_operand" "n")))
(set (reg:P CA_REGNO)
(gtu:P (match_dup 1)
(match_operand:P 3 "const_int_operand" "n")))]
"INTVAL (operands[2]) < 0
&& INTVAL (operands[2]) + INTVAL (operands[3]) == -1"
"addic %0,%1,%2"
[(set_attr "type" "add")])
(define_expand "add3_carry_in"
[(parallel [
(set (match_operand:GPR 0 "gpc_reg_operand")
(plus:GPR (plus:GPR (match_operand:GPR 1 "gpc_reg_operand")
(match_operand:GPR 2 "adde_operand"))
(reg:GPR CA_REGNO)))
(clobber (reg:GPR CA_REGNO))])]
""
{
if (operands[2] == const0_rtx)
{
emit_insn (gen_add3_carry_in_0 (operands[0], operands[1]));
DONE;
}
if (operands[2] == constm1_rtx)
{
emit_insn (gen_add3_carry_in_m1 (operands[0], operands[1]));
DONE;
}
})
(define_insn "*add3_carry_in_internal"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
(match_operand:GPR 2 "gpc_reg_operand" "r"))
(reg:GPR CA_REGNO)))
(clobber (reg:GPR CA_REGNO))]
""
"adde %0,%1,%2"
[(set_attr "type" "add")])
(define_insn "add3_carry_in_0"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
(reg:GPR CA_REGNO)))
(clobber (reg:GPR CA_REGNO))]
""
"addze %0,%1"
[(set_attr "type" "add")])
(define_insn "add3_carry_in_m1"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
(reg:GPR CA_REGNO))
(const_int -1)))
(clobber (reg:GPR CA_REGNO))]
""
"addme %0,%1"
[(set_attr "type" "add")])
(define_expand "one_cmpl2"
[(set (match_operand:SDI 0 "gpc_reg_operand" "")
(not:SDI (match_operand:SDI 1 "gpc_reg_operand" "")))]
""
{
if (mode == DImode && !TARGET_POWERPC64)
{
rs6000_split_logical (operands, NOT, false, false, false);
DONE;
}
})
(define_insn "*one_cmpl2"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))]
""
"not %0,%1")
(define_insn_and_split "*one_cmpl2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))]
"mode == Pmode && rs6000_gen_cell_microcode"
"@
not. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(not:GPR (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*one_cmpl2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(not:GPR (match_dup 1)))]
"mode == Pmode && rs6000_gen_cell_microcode"
"@
not. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(not:GPR (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_expand "sub3"
[(set (match_operand:SDI 0 "gpc_reg_operand" "")
(minus:SDI (match_operand:SDI 1 "reg_or_short_operand" "")
(match_operand:SDI 2 "gpc_reg_operand" "")))]
""
{
if (mode == DImode && !TARGET_POWERPC64)
{
rtx lo0 = gen_lowpart (SImode, operands[0]);
rtx lo1 = gen_lowpart (SImode, operands[1]);
rtx lo2 = gen_lowpart (SImode, operands[2]);
rtx hi0 = gen_highpart (SImode, operands[0]);
rtx hi1 = gen_highpart_mode (SImode, DImode, operands[1]);
rtx hi2 = gen_highpart (SImode, operands[2]);
if (!reg_or_short_operand (lo1, SImode))
lo1 = force_reg (SImode, lo1);
if (!adde_operand (hi1, SImode))
hi1 = force_reg (SImode, hi1);
emit_insn (gen_subfsi3_carry (lo0, lo2, lo1));
emit_insn (gen_subfsi3_carry_in (hi0, hi2, hi1));
DONE;
}
if (short_cint_operand (operands[1], mode))
{
emit_insn (gen_subf3_imm (operands[0], operands[2], operands[1]));
DONE;
}
})
(define_insn "*subf3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(minus:GPR (match_operand:GPR 2 "gpc_reg_operand" "r")
(match_operand:GPR 1 "gpc_reg_operand" "r")))]
""
"subf %0,%1,%2"
[(set_attr "type" "add")])
(define_insn_and_split "*subf3_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (minus:GPR (match_operand:GPR 2 "gpc_reg_operand" "r,r")
(match_operand:GPR 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))]
"mode == Pmode"
"@
subf. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(minus:GPR (match_dup 2)
(match_dup 1)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*subf3_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (minus:GPR (match_operand:GPR 2 "gpc_reg_operand" "r,r")
(match_operand:GPR 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(minus:GPR (match_dup 2)
(match_dup 1)))]
"mode == Pmode"
"@
subf. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(minus:GPR (match_dup 2)
(match_dup 1)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "subf3_imm"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(minus:GPR (match_operand:GPR 2 "short_cint_operand" "I")
(match_operand:GPR 1 "gpc_reg_operand" "r")))
(clobber (reg:GPR CA_REGNO))]
""
"subfic %0,%1,%2"
[(set_attr "type" "add")])
(define_insn_and_split "subf3_carry_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (minus:P (match_operand:P 2 "gpc_reg_operand" "r,r")
(match_operand:P 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:P 0 "gpc_reg_operand" "=r,r")
(minus:P (match_dup 2)
(match_dup 1)))
(set (reg:P CA_REGNO)
(leu:P (match_dup 1)
(match_dup 2)))]
"mode == Pmode"
"@
subfc. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(parallel [(set (match_dup 0)
(minus:P (match_dup 2)
(match_dup 1)))
(set (reg:P CA_REGNO)
(leu:P (match_dup 1)
(match_dup 2)))])
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "subf3_carry"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(minus:P (match_operand:P 2 "reg_or_short_operand" "rI")
(match_operand:P 1 "gpc_reg_operand" "r")))
(set (reg:P CA_REGNO)
(leu:P (match_dup 1)
(match_dup 2)))]
""
"subf%I2c %0,%1,%2"
[(set_attr "type" "add")])
(define_insn "*subf3_imm_carry_0"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(neg:P (match_operand:P 1 "gpc_reg_operand" "r")))
(set (reg:P CA_REGNO)
(eq:P (match_dup 1)
(const_int 0)))]
""
"subfic %0,%1,0"
[(set_attr "type" "add")])
(define_insn "*subf3_imm_carry_m1"
[(set (match_operand:P 0 "gpc_reg_operand" "=r")
(not:P (match_operand:P 1 "gpc_reg_operand" "r")))
(set (reg:P CA_REGNO)
(const_int 1))]
""
"subfic %0,%1,-1"
[(set_attr "type" "add")])
(define_expand "subf3_carry_in"
[(parallel [
(set (match_operand:GPR 0 "gpc_reg_operand")
(plus:GPR (plus:GPR (not:GPR (match_operand:GPR 1 "gpc_reg_operand"))
(reg:GPR CA_REGNO))
(match_operand:GPR 2 "adde_operand")))
(clobber (reg:GPR CA_REGNO))])]
""
{
if (operands[2] == const0_rtx)
{
emit_insn (gen_subf3_carry_in_0 (operands[0], operands[1]));
DONE;
}
if (operands[2] == constm1_rtx)
{
emit_insn (gen_subf3_carry_in_m1 (operands[0], operands[1]));
DONE;
}
})
(define_insn "*subf3_carry_in_internal"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (plus:GPR (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r"))
(reg:GPR CA_REGNO))
(match_operand:GPR 2 "gpc_reg_operand" "r")))
(clobber (reg:GPR CA_REGNO))]
""
"subfe %0,%1,%2"
[(set_attr "type" "add")])
(define_insn "subf3_carry_in_0"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (not:GPR (match_operand:GPR 1 "gpc_reg_operand" "r"))
(reg:GPR CA_REGNO)))
(clobber (reg:GPR CA_REGNO))]
""
"subfze %0,%1"
[(set_attr "type" "add")])
(define_insn "subf3_carry_in_m1"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (minus:GPR (reg:GPR CA_REGNO)
(match_operand:GPR 1 "gpc_reg_operand" "r"))
(const_int -2)))
(clobber (reg:GPR CA_REGNO))]
""
"subfme %0,%1"
[(set_attr "type" "add")])
(define_insn "subf3_carry_in_xx"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (reg:GPR CA_REGNO)
(const_int -1)))
(clobber (reg:GPR CA_REGNO))]
""
"subfe %0,%0,%0"
[(set_attr "type" "add")])
(define_insn "neg2"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))]
""
"neg %0,%1"
[(set_attr "type" "add")])
(define_insn_and_split "*neg2_dot"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))]
"mode == Pmode"
"@
neg. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(neg:GPR (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*neg2_dot2"
[(set (match_operand:CC 2 "cc_reg_operand" "=x,?y")
(compare:CC (neg:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(neg:GPR (match_dup 1)))]
"mode == Pmode"
"@
neg. %0,%1
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[2], CCmode)"
[(set (match_dup 0)
(neg:GPR (match_dup 1)))
(set (match_dup 2)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "add")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "clz2"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(clz:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))]
""
"cntlz %0,%1"
[(set_attr "type" "cntlz")])
(define_expand "ctz2"
[(set (match_operand:GPR 0 "gpc_reg_operand")
(ctz:GPR (match_operand:GPR 1 "gpc_reg_operand")))]
""
{
if (TARGET_CTZ)
{
emit_insn (gen_ctz2_hw (operands[0], operands[1]));
DONE;
}
rtx tmp1 = gen_reg_rtx (mode);
rtx tmp2 = gen_reg_rtx (mode);
rtx tmp3 = gen_reg_rtx (mode);
if (TARGET_POPCNTD)
{
emit_insn (gen_add3 (tmp1, operands[1], constm1_rtx));
emit_insn (gen_one_cmpl2 (tmp2, operands[1]));
emit_insn (gen_and3 (tmp3, tmp1, tmp2));
emit_insn (gen_popcntd2 (operands[0], tmp3));
}
else
{
emit_insn (gen_neg2 (tmp1, operands[1]));
emit_insn (gen_and3 (tmp2, operands[1], tmp1));
emit_insn (gen_clz2 (tmp3, tmp2));
emit_insn (gen_sub3 (operands[0], GEN_INT ( - 1), tmp3));
}
DONE;
})
(define_insn "ctz2_hw"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(ctz:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))]
"TARGET_CTZ"
"cnttz %0,%1"
[(set_attr "type" "cntlz")])
(define_expand "ffs2"
[(set (match_operand:GPR 0 "gpc_reg_operand")
(ffs:GPR (match_operand:GPR 1 "gpc_reg_operand")))]
""
{
rtx tmp1 = gen_reg_rtx (mode);
rtx tmp2 = gen_reg_rtx (mode);
rtx tmp3 = gen_reg_rtx (mode);
emit_insn (gen_neg2 (tmp1, operands[1]));
emit_insn (gen_and3 (tmp2, operands[1], tmp1));
emit_insn (gen_clz2 (tmp3, tmp2));
emit_insn (gen_sub3 (operands[0], GEN_INT (), tmp3));
DONE;
})
(define_expand "popcount2"
[(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 "popcntb2"
[(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"
[(set_attr "type" "popcnt")])
(define_insn "popcntd2"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(popcount:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")))]
"TARGET_POPCNTD"
"popcnt %0,%1"
[(set_attr "type" "popcnt")])
(define_expand "parity2"
[(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;
})
(define_insn "parity2_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 %0,%1"
[(set_attr "type" "popcnt")])
(define_insn "cmpb3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(unspec:GPR [(match_operand:GPR 1 "gpc_reg_operand" "r")
(match_operand:GPR 2 "gpc_reg_operand" "r")] UNSPEC_CMPB))]
"TARGET_CMPB"
"cmpb %0,%1,%2"
[(set_attr "type" "cmp")])
;; Since the hardware zeros the upper part of the register, save generating the
;; AND immediate if we are converting to unsigned
(define_insn "*bswap2_extenddi"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(zero_extend:DI
(bswap:HSI (match_operand:HSI 1 "memory_operand" "Z"))))]
"TARGET_POWERPC64"
"lbrx %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"))))]
""
"lhbrx %0,%y1"
[(set_attr "length" "4")
(set_attr "type" "load")])
;; Separate the bswap patterns into load, store, and gpr<-gpr. This prevents
;; the register allocator from converting a gpr<-gpr swap into a store and then
;; load with byte swap, which can be slower than doing it in the registers. It
;; also prevents certain failures with the RELOAD register allocator.
(define_expand "bswap2"
[(use (match_operand:HSI 0 "reg_or_mem_operand"))
(use (match_operand:HSI 1 "reg_or_mem_operand"))]
""
{
rtx dest = operands[0];
rtx src = operands[1];
if (!REG_P (dest) && !REG_P (src))
src = force_reg (mode, src);
if (MEM_P (src))
emit_insn (gen_bswap2_load (dest, src));
else if (MEM_P (dest))
emit_insn (gen_bswap2_store (dest, src));
else
emit_insn (gen_bswap2_reg (dest, src));
DONE;
})
(define_insn "bswap2_load"
[(set (match_operand:HSI 0 "gpc_reg_operand" "=r")
(bswap:HSI (match_operand:HSI 1 "memory_operand" "Z")))]
""
"lbrx %0,%y1"
[(set_attr "type" "load")])
(define_insn "bswap2_store"
[(set (match_operand:HSI 0 "memory_operand" "=Z")
(bswap:HSI (match_operand:HSI 1 "gpc_reg_operand" "r")))]
""
"stbrx %1,%y0"
[(set_attr "type" "store")])
(define_insn_and_split "bswaphi2_reg"
[(set (match_operand:HI 0 "gpc_reg_operand" "=&r")
(bswap:HI
(match_operand:HI 1 "gpc_reg_operand" "r")))
(clobber (match_scratch:SI 2 "=&r"))]
""
"#"
"reload_completed"
[(set (match_dup 3)
(and:SI (lshiftrt:SI (match_dup 4)
(const_int 8))
(const_int 255)))
(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);
}
[(set_attr "length" "12")
(set_attr "type" "*")])
;; We are always BITS_BIG_ENDIAN, so the bit positions below in
;; zero_extract insns do not change for -mlittle.
(define_insn_and_split "bswapsi2_reg"
[(set (match_operand:SI 0 "gpc_reg_operand" "=&r")
(bswap:SI
(match_operand:SI 1 "gpc_reg_operand" "r")))]
""
"#"
"reload_completed"
[(set (match_dup 0) ; DABC
(rotate:SI (match_dup 1)
(const_int 24)))
(set (match_dup 0) ; DCBC
(ior:SI (and:SI (ashift:SI (match_dup 1)
(const_int 8))
(const_int 16711680))
(and:SI (match_dup 0)
(const_int -16711681))))
(set (match_dup 0) ; DCBA
(ior:SI (and:SI (lshiftrt:SI (match_dup 1)
(const_int 24))
(const_int 255))
(and:SI (match_dup 0)
(const_int -256))))]
"")
;; On systems with LDBRX/STDBRX generate the loads/stores directly, just like
;; we do for L{H,W}BRX and ST{H,W}BRX above. If not, we have to generate more
;; complex code.
(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 ""))])]
""
{
rtx dest = operands[0];
rtx src = operands[1];
if (!REG_P (dest) && !REG_P (src))
operands[1] = src = force_reg (DImode, src);
if (TARGET_POWERPC64 && TARGET_LDBRX)
{
if (MEM_P (src))
emit_insn (gen_bswapdi2_load (dest, src));
else if (MEM_P (dest))
emit_insn (gen_bswapdi2_store (dest, src));
else
emit_insn (gen_bswapdi2_reg (dest, src));
DONE;
}
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 (dest, src));
DONE;
}
})
;; Power7/cell has ldbrx/stdbrx, so use it directly
(define_insn "bswapdi2_load"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(bswap:DI (match_operand:DI 1 "memory_operand" "Z")))]
"TARGET_POWERPC64 && TARGET_LDBRX"
"ldbrx %0,%y1"
[(set_attr "type" "load")])
(define_insn "bswapdi2_store"
[(set (match_operand:DI 0 "memory_operand" "=Z")
(bswap:DI (match_operand:DI 1 "gpc_reg_operand" "r")))]
"TARGET_POWERPC64 && TARGET_LDBRX"
"stdbrx %1,%y0"
[(set_attr "type" "store")])
(define_insn "bswapdi2_reg"
[(set (match_operand:DI 0 "gpc_reg_operand" "=&r")
(bswap:DI (match_operand:DI 1 "gpc_reg_operand" "r")))
(clobber (match_scratch:DI 2 "=&r"))
(clobber (match_scratch:DI 3 "=&r"))]
"TARGET_POWERPC64 && TARGET_LDBRX"
"#"
[(set_attr "length" "36")])
;; 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"))]
"TARGET_POWERPC64 && !TARGET_LDBRX
&& (REG_P (operands[0]) || REG_P (operands[1]))
&& !(MEM_P (operands[0]) && MEM_VOLATILE_P (operands[0]))
&& !(MEM_P (operands[1]) && MEM_VOLATILE_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" ""))]
"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 op3_32 = simplify_gen_subreg (SImode, op3, DImode,
BYTES_BIG_ENDIAN ? 4 : 0);
rtx dest_32 = simplify_gen_subreg (SImode, dest, DImode,
BYTES_BIG_ENDIAN ? 4 : 0);
rtx addr1;
rtx addr2;
rtx word1;
rtx word2;
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);
}
word1 = change_address (src, SImode, addr1);
word2 = change_address (src, SImode, addr2);
if (BYTES_BIG_ENDIAN)
{
emit_insn (gen_bswapsi2 (op3_32, word2));
emit_insn (gen_bswapsi2 (dest_32, word1));
}
else
{
emit_insn (gen_bswapsi2 (op3_32, word1));
emit_insn (gen_bswapsi2 (dest_32, word2));
}
emit_insn (gen_ashldi3 (op3, op3, GEN_INT (32)));
emit_insn (gen_iordi3 (dest, dest, op3));
DONE;
}")
(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" ""))]
"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,
BYTES_BIG_ENDIAN ? 4 : 0);
rtx op3_si = simplify_gen_subreg (SImode, op3, DImode,
BYTES_BIG_ENDIAN ? 4 : 0);
rtx addr1;
rtx addr2;
rtx word1;
rtx word2;
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);
}
word1 = change_address (dest, SImode, addr1);
word2 = change_address (dest, SImode, addr2);
emit_insn (gen_lshrdi3 (op3, src, GEN_INT (32)));
if (BYTES_BIG_ENDIAN)
{
emit_insn (gen_bswapsi2 (word1, src_si));
emit_insn (gen_bswapsi2 (word2, op3_si));
}
else
{
emit_insn (gen_bswapsi2 (word2, src_si));
emit_insn (gen_bswapsi2 (word1, op3_si));
}
DONE;
}")
(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" ""))]
"TARGET_POWERPC64 && reload_completed"
[(const_int 0)]
"
{
rtx dest = operands[0];
rtx src = operands[1];
rtx op2 = operands[2];
rtx op3 = operands[3];
int lo_off = BYTES_BIG_ENDIAN ? 4 : 0;
rtx dest_si = simplify_gen_subreg (SImode, dest, DImode, lo_off);
rtx src_si = simplify_gen_subreg (SImode, src, DImode, lo_off);
rtx op2_si = simplify_gen_subreg (SImode, op2, DImode, lo_off);
rtx op3_si = simplify_gen_subreg (SImode, op3, DImode, lo_off);
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));
DONE;
}")
(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 dest1 = simplify_gen_subreg (SImode, dest, DImode, 0);
rtx dest2 = simplify_gen_subreg (SImode, dest, DImode, 4);
rtx addr1;
rtx addr2;
rtx word1;
rtx word2;
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
|| REGNO (XEXP (addr1, 1)) == REGNO (dest2))
{
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
|| REGNO (addr1) == REGNO (dest2))
{
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);
}
word1 = change_address (src, SImode, addr1);
word2 = change_address (src, SImode, addr2);
emit_insn (gen_bswapsi2 (dest2, word1));
/* The REGNO (dest2) tests above ensure that addr2 has not been trashed,
thus allowing us to omit an early clobber on the output. */
emit_insn (gen_bswapsi2 (dest1, word2));
DONE;
}")
(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 src1 = simplify_gen_subreg (SImode, src, DImode, 0);
rtx src2 = simplify_gen_subreg (SImode, src, DImode, 4);
rtx addr1;
rtx addr2;
rtx word1;
rtx word2;
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);
}
word1 = change_address (dest, SImode, addr1);
word2 = change_address (dest, SImode, addr2);
emit_insn (gen_bswapsi2 (word2, src1));
emit_insn (gen_bswapsi2 (word1, src2));
DONE;
}")
(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 src1 = simplify_gen_subreg (SImode, src, DImode, 0);
rtx src2 = simplify_gen_subreg (SImode, src, DImode, 4);
rtx dest1 = simplify_gen_subreg (SImode, dest, DImode, 0);
rtx dest2 = simplify_gen_subreg (SImode, dest, DImode, 4);
emit_insn (gen_bswapsi2 (dest1, src2));
emit_insn (gen_bswapsi2 (dest2, src1));
DONE;
}")
(define_insn "mul3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(mult:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
(match_operand:GPR 2 "reg_or_short_operand" "r,I")))]
""
"@
mull %0,%1,%2
mulli %0,%1,%2"
[(set_attr "type" "mul")
(set (attr "size")
(cond [(match_operand:GPR 2 "s8bit_cint_operand" "")
(const_string "8")
(match_operand:GPR 2 "short_cint_operand" "")
(const_string "16")]
(const_string "")))])
(define_insn_and_split "*mul3_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (mult:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "gpc_reg_operand" "r,r"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))]
"mode == Pmode && rs6000_gen_cell_microcode"
"@
mull. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(mult:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "mul")
(set_attr "size" "")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*mul3_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (mult:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "gpc_reg_operand" "r,r"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(mult:GPR (match_dup 1)
(match_dup 2)))]
"mode == Pmode && rs6000_gen_cell_microcode"
"@
mull. %0,%1,%2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(mult:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "mul")
(set_attr "size" "")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_expand "mul3_highpart"
[(set (match_operand:GPR 0 "gpc_reg_operand")
(subreg:GPR
(mult: (any_extend:
(match_operand:GPR 1 "gpc_reg_operand"))
(any_extend:
(match_operand:GPR 2 "gpc_reg_operand")))
0))]
""
{
if (mode == SImode && TARGET_POWERPC64)
{
emit_insn (gen_mulsi3_highpart_64 (operands[0], operands[1],
operands[2]));
DONE;
}
if (!WORDS_BIG_ENDIAN)
{
emit_insn (gen_mul3_highpart_le (operands[0], operands[1],
operands[2]));
DONE;
}
})
(define_insn "*mul3_highpart"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(subreg:GPR
(mult: (any_extend:
(match_operand:GPR 1 "gpc_reg_operand" "r"))
(any_extend:
(match_operand:GPR 2 "gpc_reg_operand" "r")))
0))]
"WORDS_BIG_ENDIAN && !(mode == SImode && TARGET_POWERPC64)"
"mulh %0,%1,%2"
[(set_attr "type" "mul")
(set_attr "size" "")])
(define_insn "mulsi3_highpart_le"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(subreg:SI
(mult:DI (any_extend:DI
(match_operand:SI 1 "gpc_reg_operand" "r"))
(any_extend:DI
(match_operand:SI 2 "gpc_reg_operand" "r")))
4))]
"!WORDS_BIG_ENDIAN && !TARGET_POWERPC64"
"mulhw %0,%1,%2"
[(set_attr "type" "mul")])
(define_insn "muldi3_highpart_le"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(subreg:DI
(mult:TI (any_extend:TI
(match_operand:DI 1 "gpc_reg_operand" "r"))
(any_extend:TI
(match_operand:DI 2 "gpc_reg_operand" "r")))
8))]
"!WORDS_BIG_ENDIAN && TARGET_POWERPC64"
"mulhd %0,%1,%2"
[(set_attr "type" "mul")
(set_attr "size" "64")])
(define_insn "mulsi3_highpart_64"
[(set (match_operand:SI 0 "gpc_reg_operand" "=r")
(truncate:SI
(lshiftrt:DI
(mult:DI (any_extend:DI
(match_operand:SI 1 "gpc_reg_operand" "r"))
(any_extend:DI
(match_operand:SI 2 "gpc_reg_operand" "r")))
(const_int 32))))]
"TARGET_POWERPC64"
"mulhw %0,%1,%2"
[(set_attr "type" "mul")])
(define_expand "mul3"
[(set (match_operand: 0 "gpc_reg_operand")
(mult: (any_extend:
(match_operand:GPR 1 "gpc_reg_operand"))
(any_extend:
(match_operand:GPR 2 "gpc_reg_operand"))))]
"!(mode == SImode && TARGET_POWERPC64)"
{
rtx l = gen_reg_rtx (mode);
rtx h = gen_reg_rtx (mode);
emit_insn (gen_mul3 (l, operands[1], operands[2]));
emit_insn (gen_mul3_highpart (h, operands[1], operands[2]));
emit_move_insn (gen_lowpart (mode, operands[0]), l);
emit_move_insn (gen_highpart (mode, operands[0]), h);
DONE;
})
(define_insn "*maddld4"
[(set (match_operand:DI 0 "gpc_reg_operand" "=r")
(plus:DI (mult:DI (match_operand:DI 1 "gpc_reg_operand" "r")
(match_operand:DI 2 "gpc_reg_operand" "r"))
(match_operand:DI 3 "gpc_reg_operand" "r")))]
"TARGET_MADDLD"
"maddld %0,%1,%2,%3"
[(set_attr "type" "mul")])
(define_insn "udiv3"
[(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")))]
""
"divu %0,%1,%2"
[(set_attr "type" "div")
(set_attr "size" "")])
;; For powers of two we can do sra[wd]i/addze for divide and then adjust for
;; modulus. If it isn't a power of two, force operands into register and do
;; a normal divide.
(define_expand "div3"
[(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 (CONST_INT_P (operands[2])
&& INTVAL (operands[2]) > 0
&& exact_log2 (INTVAL (operands[2])) >= 0)
{
emit_insn (gen_div3_sra (operands[0], operands[1], operands[2]));
DONE;
}
operands[2] = force_reg (mode, operands[2]);
})
(define_insn "*div3"
[(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")))]
""
"div %0,%1,%2"
[(set_attr "type" "div")
(set_attr "size" "")])
(define_insn "div3_sra"
[(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")))
(clobber (reg:GPR CA_REGNO))]
""
"srai %0,%1,%p2\;addze %0,%0"
[(set_attr "type" "two")
(set_attr "length" "8")])
(define_insn_and_split "*div3_sra_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (div:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "exact_log2_cint_operand" "N,N"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))
(clobber (reg:GPR CA_REGNO))]
"mode == Pmode"
"@
srai %0,%1,%p2\;addze. %0,%0
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(parallel [(set (match_dup 0)
(div:GPR (match_dup 1)
(match_dup 2)))
(clobber (reg:GPR CA_REGNO))])
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "two")
(set_attr "length" "8,12")
(set_attr "cell_micro" "not")])
(define_insn_and_split "*div3_sra_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (div:GPR (match_operand:GPR 1 "gpc_reg_operand" "r,r")
(match_operand:GPR 2 "exact_log2_cint_operand" "N,N"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(div:GPR (match_dup 1)
(match_dup 2)))
(clobber (reg:GPR CA_REGNO))]
"mode == Pmode"
"@
srai %0,%1,%p2\;addze. %0,%0
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(parallel [(set (match_dup 0)
(div:GPR (match_dup 1)
(match_dup 2)))
(clobber (reg:GPR CA_REGNO))])
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "two")
(set_attr "length" "8,12")
(set_attr "cell_micro" "not")])
(define_expand "mod3"
[(set (match_operand:GPR 0 "gpc_reg_operand")
(mod:GPR (match_operand:GPR 1 "gpc_reg_operand")
(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)
{
if (!TARGET_MODULO)
FAIL;
operands[2] = force_reg (mode, operands[2]);
}
else
{
temp1 = gen_reg_rtx (mode);
temp2 = gen_reg_rtx (mode);
emit_insn (gen_div3 (temp1, operands[1], operands[2]));
emit_insn (gen_ashl3 (temp2, temp1, GEN_INT (i)));
emit_insn (gen_sub3 (operands[0], operands[1], temp2));
DONE;
}
})
;; In order to enable using a peephole2 for combining div/mod to eliminate the
;; mod, prefer putting the result of mod into a different register
(define_insn "*mod3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
(mod:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
(match_operand:GPR 2 "gpc_reg_operand" "r")))]
"TARGET_MODULO"
"mods %0,%1,%2"
[(set_attr "type" "div")
(set_attr "size" "")])
(define_insn "umod3"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=&r")
(umod:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
(match_operand:GPR 2 "gpc_reg_operand" "r")))]
"TARGET_MODULO"
"modu %0,%1,%2"
[(set_attr "type" "div")
(set_attr "size" "")])
;; On machines with modulo support, do a combined div/mod the old fashioned
;; method, since the multiply/subtract is faster than doing the mod instruction
;; after a divide.
(define_peephole2
[(set (match_operand:GPR 0 "gpc_reg_operand" "")
(div:GPR (match_operand:GPR 1 "gpc_reg_operand" "")
(match_operand:GPR 2 "gpc_reg_operand" "")))
(set (match_operand:GPR 3 "gpc_reg_operand" "")
(mod:GPR (match_dup 1)
(match_dup 2)))]
"TARGET_MODULO
&& ! reg_mentioned_p (operands[0], operands[1])
&& ! reg_mentioned_p (operands[0], operands[2])
&& ! reg_mentioned_p (operands[3], operands[1])
&& ! reg_mentioned_p (operands[3], operands[2])"
[(set (match_dup 0)
(div:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(mult:GPR (match_dup 0)
(match_dup 2)))
(set (match_dup 3)
(minus:GPR (match_dup 1)
(match_dup 3)))])
(define_peephole2
[(set (match_operand:GPR 0 "gpc_reg_operand" "")
(udiv:GPR (match_operand:GPR 1 "gpc_reg_operand" "")
(match_operand:GPR 2 "gpc_reg_operand" "")))
(set (match_operand:GPR 3 "gpc_reg_operand" "")
(umod:GPR (match_dup 1)
(match_dup 2)))]
"TARGET_MODULO
&& ! reg_mentioned_p (operands[0], operands[1])
&& ! reg_mentioned_p (operands[0], operands[2])
&& ! reg_mentioned_p (operands[3], operands[1])
&& ! reg_mentioned_p (operands[3], operands[2])"
[(set (match_dup 0)
(udiv:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(mult:GPR (match_dup 0)
(match_dup 2)))
(set (match_dup 3)
(minus:GPR (match_dup 1)
(match_dup 3)))])
;; 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 "and3"
[(set (match_operand:SDI 0 "gpc_reg_operand" "")
(and:SDI (match_operand:SDI 1 "gpc_reg_operand" "")
(match_operand:SDI 2 "reg_or_cint_operand" "")))]
""
{
if (mode == DImode && !TARGET_POWERPC64)
{
rs6000_split_logical (operands, AND, false, false, false);
DONE;
}
if (CONST_INT_P (operands[2]))
{
if (rs6000_is_valid_and_mask (operands[2], mode))
{
emit_insn (gen_and3_mask (operands[0], operands[1], operands[2]));
DONE;
}
if (logical_const_operand (operands[2], mode)
&& rs6000_gen_cell_microcode)
{
emit_insn (gen_and3_imm (operands[0], operands[1], operands[2]));
DONE;
}
if (rs6000_is_valid_2insn_and (operands[2], mode))
{
rs6000_emit_2insn_and (mode, operands, true, 0);
DONE;
}
operands[2] = force_reg (mode, operands[2]);
}
})
(define_insn "and3_imm"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r")
(match_operand:GPR 2 "logical_const_operand" "n")))
(clobber (match_scratch:CC 3 "=x"))]
"rs6000_gen_cell_microcode
&& !rs6000_is_valid_and_mask (operands[2], mode)"
"andi%e2. %0,%1,%u2"
[(set_attr "type" "logical")
(set_attr "dot" "yes")])
(define_insn_and_split "*and3_imm_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,??y")
(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
(match_operand:GPR 2 "logical_const_operand" "n,n"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))
(clobber (match_scratch:CC 4 "=X,x"))]
"(mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
&& rs6000_gen_cell_microcode
&& !rs6000_is_valid_and_mask (operands[2], mode)"
"@
andi%e2. %0,%1,%u2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(parallel [(set (match_dup 0)
(and:GPR (match_dup 1)
(match_dup 2)))
(clobber (match_dup 4))])
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*and3_imm_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,??y")
(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
(match_operand:GPR 2 "logical_const_operand" "n,n"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(and:GPR (match_dup 1)
(match_dup 2)))
(clobber (match_scratch:CC 4 "=X,x"))]
"(mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
&& rs6000_gen_cell_microcode
&& !rs6000_is_valid_and_mask (operands[2], mode)"
"@
andi%e2. %0,%1,%u2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(parallel [(set (match_dup 0)
(and:GPR (match_dup 1)
(match_dup 2)))
(clobber (match_dup 4))])
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*and3_imm_mask_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,??y")
(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
(match_operand:GPR 2 "logical_const_operand" "n,n"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))]
"(mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
&& rs6000_gen_cell_microcode
&& rs6000_is_valid_and_mask (operands[2], mode)"
"@
andi%e2. %0,%1,%u2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(and:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*and3_imm_mask_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,??y")
(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
(match_operand:GPR 2 "logical_const_operand" "n,n"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(and:GPR (match_dup 1)
(match_dup 2)))]
"(mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
&& rs6000_gen_cell_microcode
&& rs6000_is_valid_and_mask (operands[2], mode)"
"@
andi%e2. %0,%1,%u2
#"
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(and:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "logical")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn "*and3_imm_dot_shifted"
[(set (match_operand:CC 3 "cc_reg_operand" "=x")
(compare:CC
(and:GPR
(lshiftrt:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r")
(match_operand:SI 4 "const_int_operand" "n"))
(match_operand:GPR 2 "const_int_operand" "n"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r"))]
"logical_const_operand (GEN_INT (UINTVAL (operands[2])
<< INTVAL (operands[4])),
DImode)
&& (mode == Pmode
|| (UINTVAL (operands[2]) << INTVAL (operands[4])) <= 0x7fffffff)
&& rs6000_gen_cell_microcode"
{
operands[2] = GEN_INT (UINTVAL (operands[2]) << INTVAL (operands[4]));
return "andi%e2. %0,%1,%u2";
}
[(set_attr "type" "logical")
(set_attr "dot" "yes")])
(define_insn "and3_mask"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r")
(match_operand:GPR 2 "const_int_operand" "n")))]
"rs6000_is_valid_and_mask (operands[2], mode)"
{
return rs6000_insn_for_and_mask (mode, operands, false);
}
[(set_attr "type" "shift")])
(define_insn_and_split "*and3_mask_dot"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
(match_operand:GPR 2 "const_int_operand" "n,n"))
(const_int 0)))
(clobber (match_scratch:GPR 0 "=r,r"))]
"(mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
&& rs6000_gen_cell_microcode
&& !logical_const_operand (operands[2], mode)
&& rs6000_is_valid_and_mask (operands[2], mode)"
{
if (which_alternative == 0)
return rs6000_insn_for_and_mask (mode, operands, true);
else
return "#";
}
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(and:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "shift")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*and3_mask_dot2"
[(set (match_operand:CC 3 "cc_reg_operand" "=x,?y")
(compare:CC (and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,r")
(match_operand:GPR 2 "const_int_operand" "n,n"))
(const_int 0)))
(set (match_operand:GPR 0 "gpc_reg_operand" "=r,r")
(and:GPR (match_dup 1)
(match_dup 2)))]
"(mode == Pmode || UINTVAL (operands[2]) <= 0x7fffffff)
&& rs6000_gen_cell_microcode
&& !logical_const_operand (operands[2], mode)
&& rs6000_is_valid_and_mask (operands[2], mode)"
{
if (which_alternative == 0)
return rs6000_insn_for_and_mask (mode, operands, true);
else
return "#";
}
"&& reload_completed && cc_reg_not_cr0_operand (operands[3], CCmode)"
[(set (match_dup 0)
(and:GPR (match_dup 1)
(match_dup 2)))
(set (match_dup 3)
(compare:CC (match_dup 0)
(const_int 0)))]
""
[(set_attr "type" "shift")
(set_attr "dot" "yes")
(set_attr "length" "4,8")])
(define_insn_and_split "*and3_2insn"
[(set (match_operand:GPR 0 "gpc_reg_operand" "=r")
(and:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r")
(match_operand:GPR 2 "const_int_operand" "n")))]
"rs6000_is_valid_2insn_and (operands[2], mode)
&& !(rs6000_is_valid_and_mask (operands[2], mode)
|| (logical_const_operand (operands[2], mode)
&& rs6000_gen_cell_microcode))"
"#"
"&& 1"
[(pc)]
{
rs6000_emit_2insn_and (