;; Machine description for IBM RISC System 6000 (POWER) for GNU C compiler
;; Copyright (C) 1990-2020 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)
(FIRST_ALTIVEC_REGNO 64)
(LAST_ALTIVEC_REGNO 95)
(LR_REGNO 96)
(CTR_REGNO 97)
(CA_REGNO 98)
(ARG_POINTER_REGNUM 99)
(CR0_REGNO 100)
(CR1_REGNO 101)
(CR2_REGNO 102)
(CR3_REGNO 103)
(CR4_REGNO 104)
(CR5_REGNO 105)
(CR6_REGNO 106)
(CR7_REGNO 107)
(MAX_CR_REGNO 107)
(VRSAVE_REGNO 108)
(VSCR_REGNO 109)
(FRAME_POINTER_REGNUM 110)
])
;;
;; UNSPEC usage
;;
(define_c_enum "unspec"
[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_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_TLS_GET_ADDR
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_TLSTLS_PCREL
UNSPEC_FIX_TRUNC_TF ; fadd, rounding towards zero
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_ADD_ROUND_TO_ODD
UNSPEC_SUB_ROUND_TO_ODD
UNSPEC_MUL_ROUND_TO_ODD
UNSPEC_DIV_ROUND_TO_ODD
UNSPEC_FMA_ROUND_TO_ODD
UNSPEC_SQRT_ROUND_TO_ODD
UNSPEC_TRUNC_ROUND_TO_ODD
UNSPEC_SIGNBIT
UNSPEC_SF_FROM_SI
UNSPEC_SI_FROM_SF
UNSPEC_PLTSEQ
UNSPEC_PLT16_HA
])
;;
;; 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_MFFSL ; Move from FPSCR light instruction version
UNSPECV_MFFSCRN ; Move from FPSCR float rounding mode
UNSPECV_MFFSCDRN ; Move from FPSCR decimal float rounding mode
UNSPECV_MTFSF ; Move to FPSCR Fields 8 to 15
UNSPECV_MTFSF_HI ; Move to FPSCR Fields 0 to 7
UNSPECV_MTFSB0 ; Set FPSCR Field bit to 0
UNSPECV_MTFSB1 ; Set FPSCR Field bit to 1
UNSPECV_SPLIT_STACK_RETURN ; A camouflaged return
UNSPECV_SPEC_BARRIER ; Speculation barrier
UNSPECV_PLT16_LO
UNSPECV_PLT_PCREL
])
; The three different kinds of epilogue.
(define_enum "epilogue_type" [normal sibcall eh_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,mfcr,mfcrf,mtcr,
fpcompare,fp,fpsimple,dmul,qmul,sdiv,ddiv,ssqrt,dsqrt,
vecsimple,veccomplex,vecdiv,veccmp,veccmpsimple,vecperm,
vecfloat,vecfdiv,vecdouble,mffgpr,mftgpr,crypto,
veclogical,veccmpfx,vecexts,vecmove,
htm,htmsimple,dfp,mma"
(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"))
;; What is the insn_cost for this insn? The target hook can still override
;; this. For optimizing for size the "length" attribute is used instead.
(define_attr "cost" "" (const_int 0))
;; 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 cr_logical instruction have three operands? That is, BT != BB.
(define_attr "cr_logical_3op" "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"))
;; Whether an insn is a prefixed insn, and an initial 'p' should be printed
;; before the instruction. A prefixed instruction has a prefix instruction
;; word that extends the immediate value of the instructions from 12-16 bits to
;; 34 bits. The macro ASM_OUTPUT_OPCODE emits a leading 'p' for prefixed
;; insns. The default "length" attribute will also be adjusted by default to
;; be 12 bytes.
(define_attr "prefixed" "no,yes"
(cond [(ior (match_test "!TARGET_PREFIXED")
(match_test "!NONJUMP_INSN_P (insn)"))
(const_string "no")
(eq_attr "type" "load,fpload,vecload")
(if_then_else (match_test "prefixed_load_p (insn)")
(const_string "yes")
(const_string "no"))
(eq_attr "type" "store,fpstore,vecstore")
(if_then_else (match_test "prefixed_store_p (insn)")
(const_string "yes")
(const_string "no"))
(eq_attr "type" "integer,add")
(if_then_else (match_test "prefixed_paddi_p (insn)")
(const_string "yes")
(const_string "no"))]
(const_string "no")))
;; Return the number of real hardware instructions in a combined insn. If it
;; is 0, just use the length / 4.
(define_attr "num_insns" "" (const_int 0))
;; If an insn is prefixed, return the maximum number of prefixed instructions
;; in the insn. The macro ADJUST_INSN_LENGTH uses this number to adjust the
;; insn length.
(define_attr "max_prefixed_insns" "" (const_int 1))
;; Length of the instruction (in bytes). This length does not consider the
;; length for prefixed instructions. The macro ADJUST_INSN_LENGTH will adjust
;; the length if there are prefixed instructions.
;;
;; While it might be tempting to use num_insns to calculate the length, it can
;; be problematical unless all insn lengths are adjusted to use num_insns
;; (i.e. if num_insns is 0, it will get the length, which in turn will get
;; num_insns and recurse).
(define_attr "length" "" (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,power10,
rs64a,mpccore,cell,ppca2,titan"
(const (symbol_ref "(enum attr_cpu) rs6000_tune")))
;; The ISA we implement.
(define_attr "isa" "any,p5,p6,p7,p7v,p8v,p9v,p9kf,p9tf,p10"
(const_string "any"))
;; Is this alternative enabled for the current CPU/ISA/etc.?
(define_attr "enabled" ""
(cond
[(eq_attr "isa" "any")
(const_int 1)
(and (eq_attr "isa" "p5")
(match_test "TARGET_POPCNTB"))
(const_int 1)
(and (eq_attr "isa" "p6")
(match_test "TARGET_CMPB"))
(const_int 1)
(and (eq_attr "isa" "p7")
(match_test "TARGET_POPCNTD"))
(const_int 1)
(and (eq_attr "isa" "p7v")
(match_test "TARGET_VSX"))
(const_int 1)
(and (eq_attr "isa" "p8v")
(match_test "TARGET_P8_VECTOR"))
(const_int 1)
(and (eq_attr "isa" "p9v")
(match_test "TARGET_P9_VECTOR"))
(const_int 1)
(and (eq_attr "isa" "p9kf")
(match_test "TARGET_FLOAT128_TYPE"))
(const_int 1)
(and (eq_attr "isa" "p9tf")
(match_test "FLOAT128_VECTOR_P (TFmode)"))
(const_int 1)
(and (eq_attr "isa" "p10")
(match_test "TARGET_POWER10"))
(const_int 1)
] (const_int 0)))
;; 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 "power10.md")
(include "cell.md")
(include "a2.md")
(include "titan.md")
(include "predicates.md")
(include "constraints.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")])
; And again, for patterns that need two (potentially) different integer modes.
(define_mode_iterator GPR2 [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])
; 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")
(DF "TARGET_HARD_FLOAT")
(TF "TARGET_HARD_FLOAT && TARGET_LONG_DOUBLE_128")
(IF "TARGET_HARD_FLOAT && 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")
(DF "TARGET_HARD_FLOAT || VECTOR_UNIT_VSX_P (DFmode)")
(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")])
(define_mode_iterator FMOVE128_FPR [(TF "FLOAT128_2REG_P (TFmode)")
(IF "FLOAT128_2REG_P (IFmode)")
(TD "TARGET_HARD_FLOAT")])
; Iterators for 128 bit types for direct move
(define_mode_iterator FMOVE128_GPR [TI
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])
; Iterators for converting to/from TFmode
(define_mode_iterator IFKF [IF KF])
; Constraints for moving IF/KFmode.
(define_mode_attr IFKF_reg [(IF "d") (KF "wa")])
; 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")
(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 "wa") (DD "wn")])
; Definitions for 64-bit direct move
(define_mode_attr f64_dm [(DF "wa") (DD "d")])
; Definitions for 64-bit use of altivec registers
(define_mode_attr f64_av [(DF "v") (DD "wn")])
; Definitions for 64-bit access to ISA 3.0 (power9) vector
(define_mode_attr f64_p9 [(DF "v") (DD "wn")])
; These modes do not fit in integer registers in 32-bit mode.
(define_mode_iterator DIFD [DI DF DD])
; Iterator for reciprocal estimate instructions
(define_mode_iterator RECIPF [SF DF V4SF V2DF])
; SFmode or DFmode.
(define_mode_iterator SFDF [SF DF])
; And again, for when we need two FP modes in a pattern.
(define_mode_iterator SFDF2 [SF DF])
; A generic s/d attribute, for sp/dp for example.
(define_mode_attr sd [(SF "s") (DF "d")
(V4SF "s") (V2DF "d")])
; "s" or nothing, for fmuls/fmul for example.
(define_mode_attr s [(SF "s") (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 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 "wa") (DF "wa") (DI "wa")])
; Which isa is needed for those float instructions?
(define_mode_attr Fisa [(SF "p8v") (DF "*") (DI "*")])
; FRE/FRES support
(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")
(SF "32") (DF "64")])
; DImode bits
(define_mode_attr dbits [(QI "56") (HI "48") (SI "32")])
;; 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 "wa")
(TF "f")
(TD "f")
(V4SF "wa")
(V2DF "wa")])
(define_mode_attr rreg2 [(SF "f")
(DF "d")])
(define_mode_attr SI_CONVERT_FP [(SF "TARGET_FCFIDS")
(DF "TARGET_FCFID")])
;; 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,wa,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,wa,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,wa,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,wa,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
POI PXI])
;; 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 "TARGET_P8_VECTOR")
(DI "TARGET_POWERPC64")])
(include "darwin.md")
;; 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,wa,^v")
(zero_extend:EXTQI (match_operand:QI 1 "reg_or_mem_operand" "m,r,?Z,v")))]
""
"@
lbz%U1%X1 %0,%1
rlwinm %0,%1,0,0xff
lxsibzx %x0,%y1
vextractub %0,%1,7"
[(set_attr "type" "load,shift,fpload,vecperm")
(set_attr "isa" "*,*,p9v,p9v")])
(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"))]
""
"@
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)))]
""
"@
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,wa,^v")
(zero_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "m,r,?Z,v")))]
""
"@
lhz%U1%X1 %0,%1
rlwinm %0,%1,0,0xffff
lxsihzx %x0,%y1
vextractuh %0,%1,6"
[(set_attr "type" "load,shift,fpload,vecperm")
(set_attr "isa" "*,*,p9v,p9v")])
(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"))]
""
"@
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)))]
""
"@
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,d,wa,wa,r,wa")
(zero_extend:EXTSI (match_operand:SI 1 "reg_or_mem_operand" "m,r,?Z,?Z,r,wa,wa")))]
""
"@
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")
(set_attr "isa" "*,*,p7,p8v,p8v,p8v,p9v")])
(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"))]
""
"@
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)))]
""
"@
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,?*v")
(sign_extend:EXTQI (match_operand:QI 1 "gpc_reg_operand" "r,?*v")))]
""
"@
extsb %0,%1
vextsb2d %0,%1"
[(set_attr "type" "exts,vecperm")
(set_attr "isa" "*,p9v")])
(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"))]
""
"@
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)))]
""
"@
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,?*v,?*v")
(sign_extend:EXTHI (match_operand:HI 1 "reg_or_mem_operand" "m,r,Z,v")))]
""
"@
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" "*,*,8,*")
(set_attr "isa" "*,*,p9v,p9v")])
(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_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"))]
""
"@
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)))]
""
"@
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, d, wa, wa, v, v, wr")
(sign_extend:EXTSI (match_operand:SI 1 "lwa_operand"
"YZ, r, Z, Z, r, v, v, ?wa")))]
""
"@
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,mftgpr")
(set_attr "sign_extend" "yes")
(set_attr "length" "*,*,*,*,*,*,8,8")
(set_attr "isa" "*,*,p6,p8v,p8v,p9v,p8v,p8v")])
(define_split
[(set (match_operand:EXTSI 0 "int_reg_operand")
(sign_extend:EXTSI (match_operand:SI 1 "vsx_register_operand")))]
"TARGET_DIRECT_MOVE_64BIT && reload_completed"
[(set (match_dup 2)
(match_dup 1))
(set (match_dup 0)
(sign_extend:DI (match_dup 2)))]
{
operands[2] = gen_rtx_REG (SImode, reg_or_subregno (operands[0]));
})
(define_split
[(set (match_operand:DI 0 "altivec_register_operand")
(sign_extend:DI (match_operand:SI 1 "altivec_register_operand")))]
"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 (BYTES_BIG_ENDIAN)
{
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"))]
""
"@
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)))]
""
"@
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))]
"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
|| !CONST_INT_P (align)
|| 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,r")
(plus:GPR (match_operand:GPR 1 "gpc_reg_operand" "%r,b,b,b")
(match_operand:GPR 2 "add_operand" "r,I,L,eI")))]
""
"@
add %0,%1,%2
addi %0,%1,%2
addis %0,%1,%v2
addi %0,%1,%2"
[(set_attr "type" "add")
(set_attr "isa" "*,*,*,p10")])
(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_internal2"
[(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))
(match_operand:GPR 2 "gpc_reg_operand" "r")))
(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"
"@
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"
"@
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 "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 "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))
{
src = rs6000_force_indexed_or_indirect_mem (src);
emit_insn (gen_bswap2_load (dest, src));
}
else if (MEM_P (dest))
{
dest = rs6000_force_indexed_or_indirect_mem (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,wa")
(bswap:HI
(match_operand:HI 1 "gpc_reg_operand" "r,wa")))
(clobber (match_scratch:SI 2 "=&r,X"))]
""
"@
#
xxbrh %x0,%x1"
"reload_completed && int_reg_operand (operands[0], HImode)"
[(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,4")
(set_attr "type" "*,vecperm")
(set_attr "isa" "*,p9v")])
;; 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,wa")
(bswap:SI
(match_operand:SI 1 "gpc_reg_operand" "r,wa")))]
""
"@
#
xxbrw %x0,%x1"
"reload_completed && int_reg_operand (operands[0], SImode)"
[(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))))]
""
[(set_attr "length" "12,4")
(set_attr "type" "*,vecperm")
(set_attr "isa" "*,p9v")])
;; 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))
{
src = rs6000_force_indexed_or_indirect_mem (src);
emit_insn (gen_bswapdi2_load (dest, src));
}
else if (MEM_P (dest))
{
dest = rs6000_force_indexed_or_indirect_mem (dest);
emit_insn (gen_bswapdi2_store (dest, src));
}
else if (TARGET_P9_VECTOR)
emit_insn (gen_bswapdi2_xxbrd (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_xxbrd"
[(set (match_operand:DI 0 "gpc_reg_operand" "=wa")
(bswap:DI (match_operand:DI 1 "gpc_reg_operand" "wa")))]
"TARGET_P9_VECTOR"
"xxbrd %x0,%x1"
[(set_attr "type" "vecperm")
(set_attr "isa" "p9v")])
(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 && !TARGET_P9_VECTOR"
"#"
[(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 && !TARGET_P9_VECTOR && 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"
"@
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"
"@
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:GPR 0 "gpc_reg_operand" "=r")
(plus:GPR (mult:GPR (match_operand:GPR 1 "gpc_reg_operand" "r")
(match_operand:GPR 2 "gpc_reg_operand" "r"))
(match_operand:GPR 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 (!CONST_INT_P (operands[2])
|| 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))
{
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_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_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_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_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_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)"
{
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)
&& !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)
&& !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],