diff options
Diffstat (limited to 'contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td')
-rw-r--r-- | contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td | 1493 |
1 files changed, 1493 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td new file mode 100644 index 0000000..63b4581 --- /dev/null +++ b/contrib/llvm/lib/Target/PowerPC/PPCInstrInfo.td @@ -0,0 +1,1493 @@ +//===- PPCInstrInfo.td - The PowerPC Instruction Set -------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This file describes the subset of the 32-bit PowerPC instruction set, as used +// by the PowerPC instruction selector. +// +//===----------------------------------------------------------------------===// + +include "PPCInstrFormats.td" + +//===----------------------------------------------------------------------===// +// PowerPC specific type constraints. +// +def SDT_PPCstfiwx : SDTypeProfile<0, 2, [ // stfiwx + SDTCisVT<0, f64>, SDTCisPtrTy<1> +]>; +def SDT_PPCCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; +def SDT_PPCCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, + SDTCisVT<1, i32> ]>; +def SDT_PPCvperm : SDTypeProfile<1, 3, [ + SDTCisVT<3, v16i8>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2> +]>; + +def SDT_PPCvcmp : SDTypeProfile<1, 3, [ + SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisVT<3, i32> +]>; + +def SDT_PPCcondbr : SDTypeProfile<0, 3, [ + SDTCisVT<0, i32>, SDTCisVT<2, OtherVT> +]>; + +def SDT_PPClbrx : SDTypeProfile<1, 2, [ + SDTCisVT<0, i32>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT> +]>; +def SDT_PPCstbrx : SDTypeProfile<0, 3, [ + SDTCisVT<0, i32>, SDTCisPtrTy<1>, SDTCisVT<2, OtherVT> +]>; + +def SDT_PPClarx : SDTypeProfile<1, 1, [ + SDTCisInt<0>, SDTCisPtrTy<1> +]>; +def SDT_PPCstcx : SDTypeProfile<0, 2, [ + SDTCisInt<0>, SDTCisPtrTy<1> +]>; + +def SDT_PPCTC_ret : SDTypeProfile<0, 2, [ + SDTCisPtrTy<0>, SDTCisVT<1, i32> +]>; + +def SDT_PPCnop : SDTypeProfile<0, 0, []>; + +//===----------------------------------------------------------------------===// +// PowerPC specific DAG Nodes. +// + +def PPCfcfid : SDNode<"PPCISD::FCFID" , SDTFPUnaryOp, []>; +def PPCfctidz : SDNode<"PPCISD::FCTIDZ", SDTFPUnaryOp, []>; +def PPCfctiwz : SDNode<"PPCISD::FCTIWZ", SDTFPUnaryOp, []>; +def PPCstfiwx : SDNode<"PPCISD::STFIWX", SDT_PPCstfiwx, + [SDNPHasChain, SDNPMayStore]>; + +// This sequence is used for long double->int conversions. It changes the +// bits in the FPSCR which is not modelled. +def PPCmffs : SDNode<"PPCISD::MFFS", SDTypeProfile<1, 0, [SDTCisVT<0, f64>]>, + [SDNPOutFlag]>; +def PPCmtfsb0 : SDNode<"PPCISD::MTFSB0", SDTypeProfile<0, 1, [SDTCisInt<0>]>, + [SDNPInFlag, SDNPOutFlag]>; +def PPCmtfsb1 : SDNode<"PPCISD::MTFSB1", SDTypeProfile<0, 1, [SDTCisInt<0>]>, + [SDNPInFlag, SDNPOutFlag]>; +def PPCfaddrtz: SDNode<"PPCISD::FADDRTZ", SDTFPBinOp, + [SDNPInFlag, SDNPOutFlag]>; +def PPCmtfsf : SDNode<"PPCISD::MTFSF", SDTypeProfile<1, 3, + [SDTCisVT<0, f64>, SDTCisInt<1>, SDTCisVT<2, f64>, + SDTCisVT<3, f64>]>, + [SDNPInFlag]>; + +def PPCfsel : SDNode<"PPCISD::FSEL", + // Type constraint for fsel. + SDTypeProfile<1, 3, [SDTCisSameAs<0, 2>, SDTCisSameAs<0, 3>, + SDTCisFP<0>, SDTCisVT<1, f64>]>, []>; + +def PPChi : SDNode<"PPCISD::Hi", SDTIntBinOp, []>; +def PPClo : SDNode<"PPCISD::Lo", SDTIntBinOp, []>; +def PPCtoc_entry: SDNode<"PPCISD::TOC_ENTRY", SDTIntBinOp, [SDNPMayLoad]>; +def PPCvmaddfp : SDNode<"PPCISD::VMADDFP", SDTFPTernaryOp, []>; +def PPCvnmsubfp : SDNode<"PPCISD::VNMSUBFP", SDTFPTernaryOp, []>; + +def PPCvperm : SDNode<"PPCISD::VPERM", SDT_PPCvperm, []>; + +// These nodes represent the 32-bit PPC shifts that operate on 6-bit shift +// amounts. These nodes are generated by the multi-precision shift code. +def PPCsrl : SDNode<"PPCISD::SRL" , SDTIntShiftOp>; +def PPCsra : SDNode<"PPCISD::SRA" , SDTIntShiftOp>; +def PPCshl : SDNode<"PPCISD::SHL" , SDTIntShiftOp>; + +def PPCextsw_32 : SDNode<"PPCISD::EXTSW_32" , SDTIntUnaryOp>; +def PPCstd_32 : SDNode<"PPCISD::STD_32" , SDTStore, + [SDNPHasChain, SDNPMayStore]>; + +// These are target-independent nodes, but have target-specific formats. +def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_PPCCallSeqStart, + [SDNPHasChain, SDNPOutFlag]>; +def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_PPCCallSeqEnd, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; + +def SDT_PPCCall : SDTypeProfile<0, -1, [SDTCisInt<0>]>; +def PPCcall_Darwin : SDNode<"PPCISD::CALL_Darwin", SDT_PPCCall, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + SDNPVariadic]>; +def PPCcall_SVR4 : SDNode<"PPCISD::CALL_SVR4", SDT_PPCCall, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + SDNPVariadic]>; +def PPCnop : SDNode<"PPCISD::NOP", SDT_PPCnop, [SDNPInFlag, SDNPOutFlag]>; +def PPCload : SDNode<"PPCISD::LOAD", SDTypeProfile<1, 1, []>, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; +def PPCload_toc : SDNode<"PPCISD::LOAD_TOC", SDTypeProfile<0, 1, []>, + [SDNPHasChain, SDNPInFlag, SDNPOutFlag]>; +def PPCtoc_restore : SDNode<"PPCISD::TOC_RESTORE", SDTypeProfile<0, 0, []>, + [SDNPHasChain, SDNPInFlag, SDNPOutFlag]>; +def PPCmtctr : SDNode<"PPCISD::MTCTR", SDT_PPCCall, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag]>; +def PPCbctrl_Darwin : SDNode<"PPCISD::BCTRL_Darwin", SDTNone, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + SDNPVariadic]>; + +def PPCbctrl_SVR4 : SDNode<"PPCISD::BCTRL_SVR4", SDTNone, + [SDNPHasChain, SDNPOptInFlag, SDNPOutFlag, + SDNPVariadic]>; + +def retflag : SDNode<"PPCISD::RET_FLAG", SDTNone, + [SDNPHasChain, SDNPOptInFlag, SDNPVariadic]>; + +def PPCtc_return : SDNode<"PPCISD::TC_RETURN", SDT_PPCTC_ret, + [SDNPHasChain, SDNPOptInFlag, SDNPVariadic]>; + +def PPCvcmp : SDNode<"PPCISD::VCMP" , SDT_PPCvcmp, []>; +def PPCvcmp_o : SDNode<"PPCISD::VCMPo", SDT_PPCvcmp, [SDNPOutFlag]>; + +def PPCcondbranch : SDNode<"PPCISD::COND_BRANCH", SDT_PPCcondbr, + [SDNPHasChain, SDNPOptInFlag]>; + +def PPClbrx : SDNode<"PPCISD::LBRX", SDT_PPClbrx, + [SDNPHasChain, SDNPMayLoad]>; +def PPCstbrx : SDNode<"PPCISD::STBRX", SDT_PPCstbrx, + [SDNPHasChain, SDNPMayStore]>; + +// Instructions to support atomic operations +def PPClarx : SDNode<"PPCISD::LARX", SDT_PPClarx, + [SDNPHasChain, SDNPMayLoad]>; +def PPCstcx : SDNode<"PPCISD::STCX", SDT_PPCstcx, + [SDNPHasChain, SDNPMayStore]>; + +// Instructions to support dynamic alloca. +def SDTDynOp : SDTypeProfile<1, 2, []>; +def PPCdynalloc : SDNode<"PPCISD::DYNALLOC", SDTDynOp, [SDNPHasChain]>; + +//===----------------------------------------------------------------------===// +// PowerPC specific transformation functions and pattern fragments. +// + +def SHL32 : SDNodeXForm<imm, [{ + // Transformation function: 31 - imm + return getI32Imm(31 - N->getZExtValue()); +}]>; + +def SRL32 : SDNodeXForm<imm, [{ + // Transformation function: 32 - imm + return N->getZExtValue() ? getI32Imm(32 - N->getZExtValue()) : getI32Imm(0); +}]>; + +def LO16 : SDNodeXForm<imm, [{ + // Transformation function: get the low 16 bits. + return getI32Imm((unsigned short)N->getZExtValue()); +}]>; + +def HI16 : SDNodeXForm<imm, [{ + // Transformation function: shift the immediate value down into the low bits. + return getI32Imm((unsigned)N->getZExtValue() >> 16); +}]>; + +def HA16 : SDNodeXForm<imm, [{ + // Transformation function: shift the immediate value down into the low bits. + signed int Val = N->getZExtValue(); + return getI32Imm((Val - (signed short)Val) >> 16); +}]>; +def MB : SDNodeXForm<imm, [{ + // Transformation function: get the start bit of a mask + unsigned mb = 0, me; + (void)isRunOfOnes((unsigned)N->getZExtValue(), mb, me); + return getI32Imm(mb); +}]>; + +def ME : SDNodeXForm<imm, [{ + // Transformation function: get the end bit of a mask + unsigned mb, me = 0; + (void)isRunOfOnes((unsigned)N->getZExtValue(), mb, me); + return getI32Imm(me); +}]>; +def maskimm32 : PatLeaf<(imm), [{ + // maskImm predicate - True if immediate is a run of ones. + unsigned mb, me; + if (N->getValueType(0) == MVT::i32) + return isRunOfOnes((unsigned)N->getZExtValue(), mb, me); + else + return false; +}]>; + +def immSExt16 : PatLeaf<(imm), [{ + // immSExt16 predicate - True if the immediate fits in a 16-bit sign extended + // field. Used by instructions like 'addi'. + if (N->getValueType(0) == MVT::i32) + return (int32_t)N->getZExtValue() == (short)N->getZExtValue(); + else + return (int64_t)N->getZExtValue() == (short)N->getZExtValue(); +}]>; +def immZExt16 : PatLeaf<(imm), [{ + // immZExt16 predicate - True if the immediate fits in a 16-bit zero extended + // field. Used by instructions like 'ori'. + return (uint64_t)N->getZExtValue() == (unsigned short)N->getZExtValue(); +}], LO16>; + +// imm16Shifted* - These match immediates where the low 16-bits are zero. There +// are two forms: imm16ShiftedSExt and imm16ShiftedZExt. These two forms are +// identical in 32-bit mode, but in 64-bit mode, they return true if the +// immediate fits into a sign/zero extended 32-bit immediate (with the low bits +// clear). +def imm16ShiftedZExt : PatLeaf<(imm), [{ + // imm16ShiftedZExt predicate - True if only bits in the top 16-bits of the + // immediate are set. Used by instructions like 'xoris'. + return (N->getZExtValue() & ~uint64_t(0xFFFF0000)) == 0; +}], HI16>; + +def imm16ShiftedSExt : PatLeaf<(imm), [{ + // imm16ShiftedSExt predicate - True if only bits in the top 16-bits of the + // immediate are set. Used by instructions like 'addis'. Identical to + // imm16ShiftedZExt in 32-bit mode. + if (N->getZExtValue() & 0xFFFF) return false; + if (N->getValueType(0) == MVT::i32) + return true; + // For 64-bit, make sure it is sext right. + return N->getZExtValue() == (uint64_t)(int)N->getZExtValue(); +}], HI16>; + + +//===----------------------------------------------------------------------===// +// PowerPC Flag Definitions. + +class isPPC64 { bit PPC64 = 1; } +class isDOT { + list<Register> Defs = [CR0]; + bit RC = 1; +} + +class RegConstraint<string C> { + string Constraints = C; +} +class NoEncode<string E> { + string DisableEncoding = E; +} + + +//===----------------------------------------------------------------------===// +// PowerPC Operand Definitions. + +def s5imm : Operand<i32> { + let PrintMethod = "printS5ImmOperand"; +} +def u5imm : Operand<i32> { + let PrintMethod = "printU5ImmOperand"; +} +def u6imm : Operand<i32> { + let PrintMethod = "printU6ImmOperand"; +} +def s16imm : Operand<i32> { + let PrintMethod = "printS16ImmOperand"; +} +def u16imm : Operand<i32> { + let PrintMethod = "printU16ImmOperand"; +} +def s16immX4 : Operand<i32> { // Multiply imm by 4 before printing. + let PrintMethod = "printS16X4ImmOperand"; +} +def target : Operand<OtherVT> { + let PrintMethod = "printBranchOperand"; +} +def calltarget : Operand<iPTR> { + let PrintMethod = "printCallOperand"; +} +def aaddr : Operand<iPTR> { + let PrintMethod = "printAbsAddrOperand"; +} +def piclabel: Operand<iPTR> { + let PrintMethod = "printPICLabel"; +} +def symbolHi: Operand<i32> { + let PrintMethod = "printSymbolHi"; +} +def symbolLo: Operand<i32> { + let PrintMethod = "printSymbolLo"; +} +def crbitm: Operand<i8> { + let PrintMethod = "printcrbitm"; +} +// Address operands +def memri : Operand<iPTR> { + let PrintMethod = "printMemRegImm"; + let MIOperandInfo = (ops i32imm:$imm, ptr_rc:$reg); +} +def memrr : Operand<iPTR> { + let PrintMethod = "printMemRegReg"; + let MIOperandInfo = (ops ptr_rc, ptr_rc); +} +def memrix : Operand<iPTR> { // memri where the imm is shifted 2 bits. + let PrintMethod = "printMemRegImmShifted"; + let MIOperandInfo = (ops i32imm:$imm, ptr_rc:$reg); +} +def tocentry : Operand<iPTR> { + let PrintMethod = "printTOCEntryLabel"; + let MIOperandInfo = (ops i32imm:$imm); +} + +// PowerPC Predicate operand. 20 = (0<<5)|20 = always, CR0 is a dummy reg +// that doesn't matter. +def pred : PredicateOperand<OtherVT, (ops imm, CRRC), + (ops (i32 20), (i32 zero_reg))> { + let PrintMethod = "printPredicateOperand"; +} + +// Define PowerPC specific addressing mode. +def iaddr : ComplexPattern<iPTR, 2, "SelectAddrImm", [], []>; +def xaddr : ComplexPattern<iPTR, 2, "SelectAddrIdx", [], []>; +def xoaddr : ComplexPattern<iPTR, 2, "SelectAddrIdxOnly",[], []>; +def ixaddr : ComplexPattern<iPTR, 2, "SelectAddrImmShift", [], []>; // "std" + +/// This is just the offset part of iaddr, used for preinc. +def iaddroff : ComplexPattern<iPTR, 1, "SelectAddrImmOffs", [], []>; + +//===----------------------------------------------------------------------===// +// PowerPC Instruction Predicate Definitions. +def FPContractions : Predicate<"!NoExcessFPPrecision">; +def In32BitMode : Predicate<"!PPCSubTarget.isPPC64()">; +def In64BitMode : Predicate<"PPCSubTarget.isPPC64()">; + + +//===----------------------------------------------------------------------===// +// PowerPC Instruction Definitions. + +// Pseudo-instructions: + +let hasCtrlDep = 1 in { +let Defs = [R1], Uses = [R1] in { +def ADJCALLSTACKDOWN : Pseudo<(outs), (ins u16imm:$amt), + "${:comment} ADJCALLSTACKDOWN", + [(callseq_start timm:$amt)]>; +def ADJCALLSTACKUP : Pseudo<(outs), (ins u16imm:$amt1, u16imm:$amt2), + "${:comment} ADJCALLSTACKUP", + [(callseq_end timm:$amt1, timm:$amt2)]>; +} + +def UPDATE_VRSAVE : Pseudo<(outs GPRC:$rD), (ins GPRC:$rS), + "UPDATE_VRSAVE $rD, $rS", []>; +} + +let Defs = [R1], Uses = [R1] in +def DYNALLOC : Pseudo<(outs GPRC:$result), (ins GPRC:$negsize, memri:$fpsi), + "${:comment} DYNALLOC $result, $negsize, $fpsi", + [(set GPRC:$result, + (PPCdynalloc GPRC:$negsize, iaddr:$fpsi))]>; + +// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after +// instruction selection into a branch sequence. +let usesCustomInserter = 1, // Expanded after instruction selection. + PPC970_Single = 1 in { + def SELECT_CC_I4 : Pseudo<(outs GPRC:$dst), (ins CRRC:$cond, GPRC:$T, GPRC:$F, + i32imm:$BROPC), "${:comment} SELECT_CC PSEUDO!", + []>; + def SELECT_CC_I8 : Pseudo<(outs G8RC:$dst), (ins CRRC:$cond, G8RC:$T, G8RC:$F, + i32imm:$BROPC), "${:comment} SELECT_CC PSEUDO!", + []>; + def SELECT_CC_F4 : Pseudo<(outs F4RC:$dst), (ins CRRC:$cond, F4RC:$T, F4RC:$F, + i32imm:$BROPC), "${:comment} SELECT_CC PSEUDO!", + []>; + def SELECT_CC_F8 : Pseudo<(outs F8RC:$dst), (ins CRRC:$cond, F8RC:$T, F8RC:$F, + i32imm:$BROPC), "${:comment} SELECT_CC PSEUDO!", + []>; + def SELECT_CC_VRRC: Pseudo<(outs VRRC:$dst), (ins CRRC:$cond, VRRC:$T, VRRC:$F, + i32imm:$BROPC), "${:comment} SELECT_CC PSEUDO!", + []>; +} + +// SPILL_CR - Indicate that we're dumping the CR register, so we'll need to +// scavenge a register for it. +def SPILL_CR : Pseudo<(outs), (ins GPRC:$cond, memri:$F), + "${:comment} SPILL_CR $cond $F", []>; + +let isTerminator = 1, isBarrier = 1, PPC970_Unit = 7 in { + let isReturn = 1, Uses = [LR, RM] in + def BLR : XLForm_2_br<19, 16, 0, (outs), (ins pred:$p), + "b${p:cc}lr ${p:reg}", BrB, + [(retflag)]>; + let isBranch = 1, isIndirectBranch = 1, Uses = [CTR] in + def BCTR : XLForm_2_ext<19, 528, 20, 0, 0, (outs), (ins), "bctr", BrB, []>; +} + +let Defs = [LR] in + def MovePCtoLR : Pseudo<(outs), (ins piclabel:$label), "bl $label", []>, + PPC970_Unit_BRU; + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7 in { + let isBarrier = 1 in { + def B : IForm<18, 0, 0, (outs), (ins target:$dst), + "b $dst", BrB, + [(br bb:$dst)]>; + } + + // BCC represents an arbitrary conditional branch on a predicate. + // FIXME: should be able to write a pattern for PPCcondbranch, but can't use + // a two-value operand where a dag node expects two operands. :( + def BCC : BForm<16, 0, 0, (outs), (ins pred:$cond, target:$dst), + "b${cond:cc} ${cond:reg}, $dst" + /*[(PPCcondbranch CRRC:$crS, imm:$opc, bb:$dst)]*/>; +} + +// Darwin ABI Calls. +let isCall = 1, PPC970_Unit = 7, + // All calls clobber the non-callee saved registers... + Defs = [R0,R2,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12, + F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,F13, + V0,V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16,V17,V18,V19, + LR,CTR, + CR0,CR1,CR5,CR6,CR7,CARRY] in { + // Convenient aliases for call instructions + let Uses = [RM] in { + def BL_Darwin : IForm<18, 0, 1, + (outs), (ins calltarget:$func, variable_ops), + "bl $func", BrB, []>; // See Pat patterns below. + def BLA_Darwin : IForm<18, 1, 1, + (outs), (ins aaddr:$func, variable_ops), + "bla $func", BrB, [(PPCcall_Darwin (i32 imm:$func))]>; + } + let Uses = [CTR, RM] in { + def BCTRL_Darwin : XLForm_2_ext<19, 528, 20, 0, 1, + (outs), (ins variable_ops), + "bctrl", BrB, + [(PPCbctrl_Darwin)]>, Requires<[In32BitMode]>; + } +} + +// SVR4 ABI Calls. +let isCall = 1, PPC970_Unit = 7, + // All calls clobber the non-callee saved registers... + Defs = [R0,R3,R4,R5,R6,R7,R8,R9,R10,R11,R12, + F0,F1,F2,F3,F4,F5,F6,F7,F8,F9,F10,F11,F12,F13, + V0,V1,V2,V3,V4,V5,V6,V7,V8,V9,V10,V11,V12,V13,V14,V15,V16,V17,V18,V19, + LR,CTR, + CR0,CR1,CR5,CR6,CR7,CARRY] in { + // Convenient aliases for call instructions + let Uses = [RM] in { + def BL_SVR4 : IForm<18, 0, 1, + (outs), (ins calltarget:$func, variable_ops), + "bl $func", BrB, []>; // See Pat patterns below. + def BLA_SVR4 : IForm<18, 1, 1, + (outs), (ins aaddr:$func, variable_ops), + "bla $func", BrB, + [(PPCcall_SVR4 (i32 imm:$func))]>; + } + let Uses = [CTR, RM] in { + def BCTRL_SVR4 : XLForm_2_ext<19, 528, 20, 0, 1, + (outs), (ins variable_ops), + "bctrl", BrB, + [(PPCbctrl_SVR4)]>, Requires<[In32BitMode]>; + } +} + + +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in +def TCRETURNdi :Pseudo< (outs), + (ins calltarget:$dst, i32imm:$offset, variable_ops), + "#TC_RETURNd $dst $offset", + []>; + + +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in +def TCRETURNai :Pseudo<(outs), (ins aaddr:$func, i32imm:$offset, variable_ops), + "#TC_RETURNa $func $offset", + [(PPCtc_return (i32 imm:$func), imm:$offset)]>; + +let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1, Uses = [RM] in +def TCRETURNri : Pseudo<(outs), (ins CTRRC:$dst, i32imm:$offset, variable_ops), + "#TC_RETURNr $dst $offset", + []>; + + +let isTerminator = 1, isBarrier = 1, PPC970_Unit = 7, isBranch = 1, + isIndirectBranch = 1, isCall = 1, isReturn = 1, Uses = [CTR, RM] in +def TAILBCTR : XLForm_2_ext<19, 528, 20, 0, 0, (outs), (ins), "bctr", BrB, []>, + Requires<[In32BitMode]>; + + + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7, + isBarrier = 1, isCall = 1, isReturn = 1, Uses = [RM] in +def TAILB : IForm<18, 0, 0, (outs), (ins calltarget:$dst), + "b $dst", BrB, + []>; + + +let isBranch = 1, isTerminator = 1, hasCtrlDep = 1, PPC970_Unit = 7, + isBarrier = 1, isCall = 1, isReturn = 1, Uses = [RM] in +def TAILBA : IForm<18, 0, 0, (outs), (ins aaddr:$dst), + "ba $dst", BrB, + []>; + + +// DCB* instructions. +def DCBA : DCB_Form<758, 0, (outs), (ins memrr:$dst), + "dcba $dst", LdStDCBF, [(int_ppc_dcba xoaddr:$dst)]>, + PPC970_DGroup_Single; +def DCBF : DCB_Form<86, 0, (outs), (ins memrr:$dst), + "dcbf $dst", LdStDCBF, [(int_ppc_dcbf xoaddr:$dst)]>, + PPC970_DGroup_Single; +def DCBI : DCB_Form<470, 0, (outs), (ins memrr:$dst), + "dcbi $dst", LdStDCBF, [(int_ppc_dcbi xoaddr:$dst)]>, + PPC970_DGroup_Single; +def DCBST : DCB_Form<54, 0, (outs), (ins memrr:$dst), + "dcbst $dst", LdStDCBF, [(int_ppc_dcbst xoaddr:$dst)]>, + PPC970_DGroup_Single; +def DCBT : DCB_Form<278, 0, (outs), (ins memrr:$dst), + "dcbt $dst", LdStDCBF, [(int_ppc_dcbt xoaddr:$dst)]>, + PPC970_DGroup_Single; +def DCBTST : DCB_Form<246, 0, (outs), (ins memrr:$dst), + "dcbtst $dst", LdStDCBF, [(int_ppc_dcbtst xoaddr:$dst)]>, + PPC970_DGroup_Single; +def DCBZ : DCB_Form<1014, 0, (outs), (ins memrr:$dst), + "dcbz $dst", LdStDCBF, [(int_ppc_dcbz xoaddr:$dst)]>, + PPC970_DGroup_Single; +def DCBZL : DCB_Form<1014, 1, (outs), (ins memrr:$dst), + "dcbzl $dst", LdStDCBF, [(int_ppc_dcbzl xoaddr:$dst)]>, + PPC970_DGroup_Single; + +// Atomic operations +let usesCustomInserter = 1 in { + let Uses = [CR0] in { + def ATOMIC_LOAD_ADD_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_ADD_I8 PSEUDO!", + [(set GPRC:$dst, (atomic_load_add_8 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_SUB_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_SUB_I8 PSEUDO!", + [(set GPRC:$dst, (atomic_load_sub_8 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_AND_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_AND_I8 PSEUDO!", + [(set GPRC:$dst, (atomic_load_and_8 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_OR_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_OR_I8 PSEUDO!", + [(set GPRC:$dst, (atomic_load_or_8 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_XOR_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_XOR_I8 PSEUDO!", + [(set GPRC:$dst, (atomic_load_xor_8 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_NAND_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_NAND_I8 PSEUDO!", + [(set GPRC:$dst, (atomic_load_nand_8 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_ADD_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_ADD_I16 PSEUDO!", + [(set GPRC:$dst, (atomic_load_add_16 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_SUB_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_SUB_I16 PSEUDO!", + [(set GPRC:$dst, (atomic_load_sub_16 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_AND_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_AND_I16 PSEUDO!", + [(set GPRC:$dst, (atomic_load_and_16 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_OR_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_OR_I16 PSEUDO!", + [(set GPRC:$dst, (atomic_load_or_16 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_XOR_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_XOR_I16 PSEUDO!", + [(set GPRC:$dst, (atomic_load_xor_16 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_NAND_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_NAND_I16 PSEUDO!", + [(set GPRC:$dst, (atomic_load_nand_16 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_ADD_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_ADD_I32 PSEUDO!", + [(set GPRC:$dst, (atomic_load_add_32 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_SUB_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_SUB_I32 PSEUDO!", + [(set GPRC:$dst, (atomic_load_sub_32 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_AND_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_AND_I32 PSEUDO!", + [(set GPRC:$dst, (atomic_load_and_32 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_OR_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_OR_I32 PSEUDO!", + [(set GPRC:$dst, (atomic_load_or_32 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_XOR_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_XOR_I32 PSEUDO!", + [(set GPRC:$dst, (atomic_load_xor_32 xoaddr:$ptr, GPRC:$incr))]>; + def ATOMIC_LOAD_NAND_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$incr), + "${:comment} ATOMIC_LOAD_NAND_I32 PSEUDO!", + [(set GPRC:$dst, (atomic_load_nand_32 xoaddr:$ptr, GPRC:$incr))]>; + + def ATOMIC_CMP_SWAP_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$old, GPRC:$new), + "${:comment} ATOMIC_CMP_SWAP_I8 PSEUDO!", + [(set GPRC:$dst, + (atomic_cmp_swap_8 xoaddr:$ptr, GPRC:$old, GPRC:$new))]>; + def ATOMIC_CMP_SWAP_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$old, GPRC:$new), + "${:comment} ATOMIC_CMP_SWAP_I16 PSEUDO!", + [(set GPRC:$dst, + (atomic_cmp_swap_16 xoaddr:$ptr, GPRC:$old, GPRC:$new))]>; + def ATOMIC_CMP_SWAP_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$old, GPRC:$new), + "${:comment} ATOMIC_CMP_SWAP_I32 PSEUDO!", + [(set GPRC:$dst, + (atomic_cmp_swap_32 xoaddr:$ptr, GPRC:$old, GPRC:$new))]>; + + def ATOMIC_SWAP_I8 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$new), + "${:comment} ATOMIC_SWAP_I8 PSEUDO!", + [(set GPRC:$dst, (atomic_swap_8 xoaddr:$ptr, GPRC:$new))]>; + def ATOMIC_SWAP_I16 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$new), + "${:comment} ATOMIC_SWAP_I16 PSEUDO!", + [(set GPRC:$dst, (atomic_swap_16 xoaddr:$ptr, GPRC:$new))]>; + def ATOMIC_SWAP_I32 : Pseudo< + (outs GPRC:$dst), (ins memrr:$ptr, GPRC:$new), + "${:comment} ATOMIC_SWAP_I32 PSEUDO!", + [(set GPRC:$dst, (atomic_swap_32 xoaddr:$ptr, GPRC:$new))]>; + } +} + +// Instructions to support atomic operations +def LWARX : XForm_1<31, 20, (outs GPRC:$rD), (ins memrr:$src), + "lwarx $rD, $src", LdStLWARX, + [(set GPRC:$rD, (PPClarx xoaddr:$src))]>; + +let Defs = [CR0] in +def STWCX : XForm_1<31, 150, (outs), (ins GPRC:$rS, memrr:$dst), + "stwcx. $rS, $dst", LdStSTWCX, + [(PPCstcx GPRC:$rS, xoaddr:$dst)]>, + isDOT; + +let isTerminator = 1, isBarrier = 1, hasCtrlDep = 1 in +def TRAP : XForm_24<31, 4, (outs), (ins), "trap", LdStGeneral, [(trap)]>; + +//===----------------------------------------------------------------------===// +// PPC32 Load Instructions. +// + +// Unindexed (r+i) Loads. +let canFoldAsLoad = 1, PPC970_Unit = 2 in { +def LBZ : DForm_1<34, (outs GPRC:$rD), (ins memri:$src), + "lbz $rD, $src", LdStGeneral, + [(set GPRC:$rD, (zextloadi8 iaddr:$src))]>; +def LHA : DForm_1<42, (outs GPRC:$rD), (ins memri:$src), + "lha $rD, $src", LdStLHA, + [(set GPRC:$rD, (sextloadi16 iaddr:$src))]>, + PPC970_DGroup_Cracked; +def LHZ : DForm_1<40, (outs GPRC:$rD), (ins memri:$src), + "lhz $rD, $src", LdStGeneral, + [(set GPRC:$rD, (zextloadi16 iaddr:$src))]>; +def LWZ : DForm_1<32, (outs GPRC:$rD), (ins memri:$src), + "lwz $rD, $src", LdStGeneral, + [(set GPRC:$rD, (load iaddr:$src))]>; + +def LFS : DForm_1<48, (outs F4RC:$rD), (ins memri:$src), + "lfs $rD, $src", LdStLFDU, + [(set F4RC:$rD, (load iaddr:$src))]>; +def LFD : DForm_1<50, (outs F8RC:$rD), (ins memri:$src), + "lfd $rD, $src", LdStLFD, + [(set F8RC:$rD, (load iaddr:$src))]>; + + +// Unindexed (r+i) Loads with Update (preinc). +let mayLoad = 1 in { +def LBZU : DForm_1<35, (outs GPRC:$rD, ptr_rc:$ea_result), (ins memri:$addr), + "lbzu $rD, $addr", LdStGeneral, + []>, RegConstraint<"$addr.reg = $ea_result">, + NoEncode<"$ea_result">; + +def LHAU : DForm_1<43, (outs GPRC:$rD, ptr_rc:$ea_result), (ins memri:$addr), + "lhau $rD, $addr", LdStGeneral, + []>, RegConstraint<"$addr.reg = $ea_result">, + NoEncode<"$ea_result">; + +def LHZU : DForm_1<41, (outs GPRC:$rD, ptr_rc:$ea_result), (ins memri:$addr), + "lhzu $rD, $addr", LdStGeneral, + []>, RegConstraint<"$addr.reg = $ea_result">, + NoEncode<"$ea_result">; + +def LWZU : DForm_1<33, (outs GPRC:$rD, ptr_rc:$ea_result), (ins memri:$addr), + "lwzu $rD, $addr", LdStGeneral, + []>, RegConstraint<"$addr.reg = $ea_result">, + NoEncode<"$ea_result">; + +def LFSU : DForm_1<49, (outs F4RC:$rD, ptr_rc:$ea_result), (ins memri:$addr), + "lfs $rD, $addr", LdStLFDU, + []>, RegConstraint<"$addr.reg = $ea_result">, + NoEncode<"$ea_result">; + +def LFDU : DForm_1<51, (outs F8RC:$rD, ptr_rc:$ea_result), (ins memri:$addr), + "lfd $rD, $addr", LdStLFD, + []>, RegConstraint<"$addr.reg = $ea_result">, + NoEncode<"$ea_result">; +} +} + +// Indexed (r+r) Loads. +// +let canFoldAsLoad = 1, PPC970_Unit = 2 in { +def LBZX : XForm_1<31, 87, (outs GPRC:$rD), (ins memrr:$src), + "lbzx $rD, $src", LdStGeneral, + [(set GPRC:$rD, (zextloadi8 xaddr:$src))]>; +def LHAX : XForm_1<31, 343, (outs GPRC:$rD), (ins memrr:$src), + "lhax $rD, $src", LdStLHA, + [(set GPRC:$rD, (sextloadi16 xaddr:$src))]>, + PPC970_DGroup_Cracked; +def LHZX : XForm_1<31, 279, (outs GPRC:$rD), (ins memrr:$src), + "lhzx $rD, $src", LdStGeneral, + [(set GPRC:$rD, (zextloadi16 xaddr:$src))]>; +def LWZX : XForm_1<31, 23, (outs GPRC:$rD), (ins memrr:$src), + "lwzx $rD, $src", LdStGeneral, + [(set GPRC:$rD, (load xaddr:$src))]>; + + +def LHBRX : XForm_1<31, 790, (outs GPRC:$rD), (ins memrr:$src), + "lhbrx $rD, $src", LdStGeneral, + [(set GPRC:$rD, (PPClbrx xoaddr:$src, i16))]>; +def LWBRX : XForm_1<31, 534, (outs GPRC:$rD), (ins memrr:$src), + "lwbrx $rD, $src", LdStGeneral, + [(set GPRC:$rD, (PPClbrx xoaddr:$src, i32))]>; + +def LFSX : XForm_25<31, 535, (outs F4RC:$frD), (ins memrr:$src), + "lfsx $frD, $src", LdStLFDU, + [(set F4RC:$frD, (load xaddr:$src))]>; +def LFDX : XForm_25<31, 599, (outs F8RC:$frD), (ins memrr:$src), + "lfdx $frD, $src", LdStLFDU, + [(set F8RC:$frD, (load xaddr:$src))]>; +} + +//===----------------------------------------------------------------------===// +// PPC32 Store Instructions. +// + +// Unindexed (r+i) Stores. +let PPC970_Unit = 2 in { +def STB : DForm_1<38, (outs), (ins GPRC:$rS, memri:$src), + "stb $rS, $src", LdStGeneral, + [(truncstorei8 GPRC:$rS, iaddr:$src)]>; +def STH : DForm_1<44, (outs), (ins GPRC:$rS, memri:$src), + "sth $rS, $src", LdStGeneral, + [(truncstorei16 GPRC:$rS, iaddr:$src)]>; +def STW : DForm_1<36, (outs), (ins GPRC:$rS, memri:$src), + "stw $rS, $src", LdStGeneral, + [(store GPRC:$rS, iaddr:$src)]>; +def STFS : DForm_1<52, (outs), (ins F4RC:$rS, memri:$dst), + "stfs $rS, $dst", LdStUX, + [(store F4RC:$rS, iaddr:$dst)]>; +def STFD : DForm_1<54, (outs), (ins F8RC:$rS, memri:$dst), + "stfd $rS, $dst", LdStUX, + [(store F8RC:$rS, iaddr:$dst)]>; +} + +// Unindexed (r+i) Stores with Update (preinc). +let PPC970_Unit = 2 in { +def STBU : DForm_1<39, (outs ptr_rc:$ea_res), (ins GPRC:$rS, + symbolLo:$ptroff, ptr_rc:$ptrreg), + "stbu $rS, $ptroff($ptrreg)", LdStGeneral, + [(set ptr_rc:$ea_res, + (pre_truncsti8 GPRC:$rS, ptr_rc:$ptrreg, + iaddroff:$ptroff))]>, + RegConstraint<"$ptrreg = $ea_res">, NoEncode<"$ea_res">; +def STHU : DForm_1<45, (outs ptr_rc:$ea_res), (ins GPRC:$rS, + symbolLo:$ptroff, ptr_rc:$ptrreg), + "sthu $rS, $ptroff($ptrreg)", LdStGeneral, + [(set ptr_rc:$ea_res, + (pre_truncsti16 GPRC:$rS, ptr_rc:$ptrreg, + iaddroff:$ptroff))]>, + RegConstraint<"$ptrreg = $ea_res">, NoEncode<"$ea_res">; +def STWU : DForm_1<37, (outs ptr_rc:$ea_res), (ins GPRC:$rS, + symbolLo:$ptroff, ptr_rc:$ptrreg), + "stwu $rS, $ptroff($ptrreg)", LdStGeneral, + [(set ptr_rc:$ea_res, (pre_store GPRC:$rS, ptr_rc:$ptrreg, + iaddroff:$ptroff))]>, + RegConstraint<"$ptrreg = $ea_res">, NoEncode<"$ea_res">; +def STFSU : DForm_1<37, (outs ptr_rc:$ea_res), (ins F4RC:$rS, + symbolLo:$ptroff, ptr_rc:$ptrreg), + "stfsu $rS, $ptroff($ptrreg)", LdStGeneral, + [(set ptr_rc:$ea_res, (pre_store F4RC:$rS, ptr_rc:$ptrreg, + iaddroff:$ptroff))]>, + RegConstraint<"$ptrreg = $ea_res">, NoEncode<"$ea_res">; +def STFDU : DForm_1<37, (outs ptr_rc:$ea_res), (ins F8RC:$rS, + symbolLo:$ptroff, ptr_rc:$ptrreg), + "stfdu $rS, $ptroff($ptrreg)", LdStGeneral, + [(set ptr_rc:$ea_res, (pre_store F8RC:$rS, ptr_rc:$ptrreg, + iaddroff:$ptroff))]>, + RegConstraint<"$ptrreg = $ea_res">, NoEncode<"$ea_res">; +} + + +// Indexed (r+r) Stores. +// +let PPC970_Unit = 2 in { +def STBX : XForm_8<31, 215, (outs), (ins GPRC:$rS, memrr:$dst), + "stbx $rS, $dst", LdStGeneral, + [(truncstorei8 GPRC:$rS, xaddr:$dst)]>, + PPC970_DGroup_Cracked; +def STHX : XForm_8<31, 407, (outs), (ins GPRC:$rS, memrr:$dst), + "sthx $rS, $dst", LdStGeneral, + [(truncstorei16 GPRC:$rS, xaddr:$dst)]>, + PPC970_DGroup_Cracked; +def STWX : XForm_8<31, 151, (outs), (ins GPRC:$rS, memrr:$dst), + "stwx $rS, $dst", LdStGeneral, + [(store GPRC:$rS, xaddr:$dst)]>, + PPC970_DGroup_Cracked; + +let mayStore = 1 in { +def STWUX : XForm_8<31, 183, (outs), (ins GPRC:$rS, GPRC:$rA, GPRC:$rB), + "stwux $rS, $rA, $rB", LdStGeneral, + []>; +} +def STHBRX: XForm_8<31, 918, (outs), (ins GPRC:$rS, memrr:$dst), + "sthbrx $rS, $dst", LdStGeneral, + [(PPCstbrx GPRC:$rS, xoaddr:$dst, i16)]>, + PPC970_DGroup_Cracked; +def STWBRX: XForm_8<31, 662, (outs), (ins GPRC:$rS, memrr:$dst), + "stwbrx $rS, $dst", LdStGeneral, + [(PPCstbrx GPRC:$rS, xoaddr:$dst, i32)]>, + PPC970_DGroup_Cracked; + +def STFIWX: XForm_28<31, 983, (outs), (ins F8RC:$frS, memrr:$dst), + "stfiwx $frS, $dst", LdStUX, + [(PPCstfiwx F8RC:$frS, xoaddr:$dst)]>; + +def STFSX : XForm_28<31, 663, (outs), (ins F4RC:$frS, memrr:$dst), + "stfsx $frS, $dst", LdStUX, + [(store F4RC:$frS, xaddr:$dst)]>; +def STFDX : XForm_28<31, 727, (outs), (ins F8RC:$frS, memrr:$dst), + "stfdx $frS, $dst", LdStUX, + [(store F8RC:$frS, xaddr:$dst)]>; +} + +def SYNC : XForm_24_sync<31, 598, (outs), (ins), + "sync", LdStSync, + [(int_ppc_sync)]>; + +//===----------------------------------------------------------------------===// +// PPC32 Arithmetic Instructions. +// + +let PPC970_Unit = 1 in { // FXU Operations. +def ADDI : DForm_2<14, (outs GPRC:$rD), (ins GPRC:$rA, s16imm:$imm), + "addi $rD, $rA, $imm", IntGeneral, + [(set GPRC:$rD, (add GPRC:$rA, immSExt16:$imm))]>; +let Defs = [CARRY] in { +def ADDIC : DForm_2<12, (outs GPRC:$rD), (ins GPRC:$rA, s16imm:$imm), + "addic $rD, $rA, $imm", IntGeneral, + [(set GPRC:$rD, (addc GPRC:$rA, immSExt16:$imm))]>, + PPC970_DGroup_Cracked; +def ADDICo : DForm_2<13, (outs GPRC:$rD), (ins GPRC:$rA, s16imm:$imm), + "addic. $rD, $rA, $imm", IntGeneral, + []>; +} +def ADDIS : DForm_2<15, (outs GPRC:$rD), (ins GPRC:$rA, symbolHi:$imm), + "addis $rD, $rA, $imm", IntGeneral, + [(set GPRC:$rD, (add GPRC:$rA, imm16ShiftedSExt:$imm))]>; +def LA : DForm_2<14, (outs GPRC:$rD), (ins GPRC:$rA, symbolLo:$sym), + "la $rD, $sym($rA)", IntGeneral, + [(set GPRC:$rD, (add GPRC:$rA, + (PPClo tglobaladdr:$sym, 0)))]>; +def MULLI : DForm_2< 7, (outs GPRC:$rD), (ins GPRC:$rA, s16imm:$imm), + "mulli $rD, $rA, $imm", IntMulLI, + [(set GPRC:$rD, (mul GPRC:$rA, immSExt16:$imm))]>; +let Defs = [CARRY] in { +def SUBFIC : DForm_2< 8, (outs GPRC:$rD), (ins GPRC:$rA, s16imm:$imm), + "subfic $rD, $rA, $imm", IntGeneral, + [(set GPRC:$rD, (subc immSExt16:$imm, GPRC:$rA))]>; +} + +let isReMaterializable = 1 in { + def LI : DForm_2_r0<14, (outs GPRC:$rD), (ins symbolLo:$imm), + "li $rD, $imm", IntGeneral, + [(set GPRC:$rD, immSExt16:$imm)]>; + def LIS : DForm_2_r0<15, (outs GPRC:$rD), (ins symbolHi:$imm), + "lis $rD, $imm", IntGeneral, + [(set GPRC:$rD, imm16ShiftedSExt:$imm)]>; +} +} + +let PPC970_Unit = 1 in { // FXU Operations. +def ANDIo : DForm_4<28, (outs GPRC:$dst), (ins GPRC:$src1, u16imm:$src2), + "andi. $dst, $src1, $src2", IntGeneral, + [(set GPRC:$dst, (and GPRC:$src1, immZExt16:$src2))]>, + isDOT; +def ANDISo : DForm_4<29, (outs GPRC:$dst), (ins GPRC:$src1, u16imm:$src2), + "andis. $dst, $src1, $src2", IntGeneral, + [(set GPRC:$dst, (and GPRC:$src1,imm16ShiftedZExt:$src2))]>, + isDOT; +def ORI : DForm_4<24, (outs GPRC:$dst), (ins GPRC:$src1, u16imm:$src2), + "ori $dst, $src1, $src2", IntGeneral, + [(set GPRC:$dst, (or GPRC:$src1, immZExt16:$src2))]>; +def ORIS : DForm_4<25, (outs GPRC:$dst), (ins GPRC:$src1, u16imm:$src2), + "oris $dst, $src1, $src2", IntGeneral, + [(set GPRC:$dst, (or GPRC:$src1, imm16ShiftedZExt:$src2))]>; +def XORI : DForm_4<26, (outs GPRC:$dst), (ins GPRC:$src1, u16imm:$src2), + "xori $dst, $src1, $src2", IntGeneral, + [(set GPRC:$dst, (xor GPRC:$src1, immZExt16:$src2))]>; +def XORIS : DForm_4<27, (outs GPRC:$dst), (ins GPRC:$src1, u16imm:$src2), + "xoris $dst, $src1, $src2", IntGeneral, + [(set GPRC:$dst, (xor GPRC:$src1,imm16ShiftedZExt:$src2))]>; +def NOP : DForm_4_zero<24, (outs), (ins), "nop", IntGeneral, + []>; +def CMPWI : DForm_5_ext<11, (outs CRRC:$crD), (ins GPRC:$rA, s16imm:$imm), + "cmpwi $crD, $rA, $imm", IntCompare>; +def CMPLWI : DForm_6_ext<10, (outs CRRC:$dst), (ins GPRC:$src1, u16imm:$src2), + "cmplwi $dst, $src1, $src2", IntCompare>; +} + + +let PPC970_Unit = 1 in { // FXU Operations. +def NAND : XForm_6<31, 476, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "nand $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (not (and GPRC:$rS, GPRC:$rB)))]>; +def AND : XForm_6<31, 28, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "and $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (and GPRC:$rS, GPRC:$rB))]>; +def ANDC : XForm_6<31, 60, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "andc $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (and GPRC:$rS, (not GPRC:$rB)))]>; +def OR : XForm_6<31, 444, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "or $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (or GPRC:$rS, GPRC:$rB))]>; +def NOR : XForm_6<31, 124, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "nor $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (not (or GPRC:$rS, GPRC:$rB)))]>; +def ORC : XForm_6<31, 412, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "orc $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (or GPRC:$rS, (not GPRC:$rB)))]>; +def EQV : XForm_6<31, 284, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "eqv $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (not (xor GPRC:$rS, GPRC:$rB)))]>; +def XOR : XForm_6<31, 316, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "xor $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (xor GPRC:$rS, GPRC:$rB))]>; +def SLW : XForm_6<31, 24, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "slw $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (PPCshl GPRC:$rS, GPRC:$rB))]>; +def SRW : XForm_6<31, 536, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "srw $rA, $rS, $rB", IntGeneral, + [(set GPRC:$rA, (PPCsrl GPRC:$rS, GPRC:$rB))]>; +let Defs = [CARRY] in { +def SRAW : XForm_6<31, 792, (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB), + "sraw $rA, $rS, $rB", IntShift, + [(set GPRC:$rA, (PPCsra GPRC:$rS, GPRC:$rB))]>; +} +} + +let PPC970_Unit = 1 in { // FXU Operations. +let Defs = [CARRY] in { +def SRAWI : XForm_10<31, 824, (outs GPRC:$rA), (ins GPRC:$rS, u5imm:$SH), + "srawi $rA, $rS, $SH", IntShift, + [(set GPRC:$rA, (sra GPRC:$rS, (i32 imm:$SH)))]>; +} +def CNTLZW : XForm_11<31, 26, (outs GPRC:$rA), (ins GPRC:$rS), + "cntlzw $rA, $rS", IntGeneral, + [(set GPRC:$rA, (ctlz GPRC:$rS))]>; +def EXTSB : XForm_11<31, 954, (outs GPRC:$rA), (ins GPRC:$rS), + "extsb $rA, $rS", IntGeneral, + [(set GPRC:$rA, (sext_inreg GPRC:$rS, i8))]>; +def EXTSH : XForm_11<31, 922, (outs GPRC:$rA), (ins GPRC:$rS), + "extsh $rA, $rS", IntGeneral, + [(set GPRC:$rA, (sext_inreg GPRC:$rS, i16))]>; + +def CMPW : XForm_16_ext<31, 0, (outs CRRC:$crD), (ins GPRC:$rA, GPRC:$rB), + "cmpw $crD, $rA, $rB", IntCompare>; +def CMPLW : XForm_16_ext<31, 32, (outs CRRC:$crD), (ins GPRC:$rA, GPRC:$rB), + "cmplw $crD, $rA, $rB", IntCompare>; +} +let PPC970_Unit = 3 in { // FPU Operations. +//def FCMPO : XForm_17<63, 32, (outs CRRC:$crD), (ins FPRC:$fA, FPRC:$fB), +// "fcmpo $crD, $fA, $fB", FPCompare>; +def FCMPUS : XForm_17<63, 0, (outs CRRC:$crD), (ins F4RC:$fA, F4RC:$fB), + "fcmpu $crD, $fA, $fB", FPCompare>; +def FCMPUD : XForm_17<63, 0, (outs CRRC:$crD), (ins F8RC:$fA, F8RC:$fB), + "fcmpu $crD, $fA, $fB", FPCompare>; + +let Uses = [RM] in { + def FCTIWZ : XForm_26<63, 15, (outs F8RC:$frD), (ins F8RC:$frB), + "fctiwz $frD, $frB", FPGeneral, + [(set F8RC:$frD, (PPCfctiwz F8RC:$frB))]>; + def FRSP : XForm_26<63, 12, (outs F4RC:$frD), (ins F8RC:$frB), + "frsp $frD, $frB", FPGeneral, + [(set F4RC:$frD, (fround F8RC:$frB))]>; + def FSQRT : XForm_26<63, 22, (outs F8RC:$frD), (ins F8RC:$frB), + "fsqrt $frD, $frB", FPSqrt, + [(set F8RC:$frD, (fsqrt F8RC:$frB))]>; + def FSQRTS : XForm_26<59, 22, (outs F4RC:$frD), (ins F4RC:$frB), + "fsqrts $frD, $frB", FPSqrt, + [(set F4RC:$frD, (fsqrt F4RC:$frB))]>; + } +} + +/// FMR is split into 2 versions, one for 4/8 byte FP, and one for extending. +/// +/// Note that these are defined as pseudo-ops on the PPC970 because they are +/// often coalesced away and we don't want the dispatch group builder to think +/// that they will fill slots (which could cause the load of a LSU reject to +/// sneak into a d-group with a store). +def FMR : XForm_26<63, 72, (outs F4RC:$frD), (ins F4RC:$frB), + "fmr $frD, $frB", FPGeneral, + []>, // (set F4RC:$frD, F4RC:$frB) + PPC970_Unit_Pseudo; +def FMRSD : XForm_26<63, 72, (outs F8RC:$frD), (ins F4RC:$frB), + "fmr $frD, $frB", FPGeneral, + [(set F8RC:$frD, (fextend F4RC:$frB))]>, + PPC970_Unit_Pseudo; + +let PPC970_Unit = 3 in { // FPU Operations. +// These are artificially split into two different forms, for 4/8 byte FP. +def FABSS : XForm_26<63, 264, (outs F4RC:$frD), (ins F4RC:$frB), + "fabs $frD, $frB", FPGeneral, + [(set F4RC:$frD, (fabs F4RC:$frB))]>; +def FABSD : XForm_26<63, 264, (outs F8RC:$frD), (ins F8RC:$frB), + "fabs $frD, $frB", FPGeneral, + [(set F8RC:$frD, (fabs F8RC:$frB))]>; +def FNABSS : XForm_26<63, 136, (outs F4RC:$frD), (ins F4RC:$frB), + "fnabs $frD, $frB", FPGeneral, + [(set F4RC:$frD, (fneg (fabs F4RC:$frB)))]>; +def FNABSD : XForm_26<63, 136, (outs F8RC:$frD), (ins F8RC:$frB), + "fnabs $frD, $frB", FPGeneral, + [(set F8RC:$frD, (fneg (fabs F8RC:$frB)))]>; +def FNEGS : XForm_26<63, 40, (outs F4RC:$frD), (ins F4RC:$frB), + "fneg $frD, $frB", FPGeneral, + [(set F4RC:$frD, (fneg F4RC:$frB))]>; +def FNEGD : XForm_26<63, 40, (outs F8RC:$frD), (ins F8RC:$frB), + "fneg $frD, $frB", FPGeneral, + [(set F8RC:$frD, (fneg F8RC:$frB))]>; +} + + +// XL-Form instructions. condition register logical ops. +// +def MCRF : XLForm_3<19, 0, (outs CRRC:$BF), (ins CRRC:$BFA), + "mcrf $BF, $BFA", BrMCR>, + PPC970_DGroup_First, PPC970_Unit_CRU; + +def CREQV : XLForm_1<19, 289, (outs CRBITRC:$CRD), + (ins CRBITRC:$CRA, CRBITRC:$CRB), + "creqv $CRD, $CRA, $CRB", BrCR, + []>; + +def CROR : XLForm_1<19, 449, (outs CRBITRC:$CRD), + (ins CRBITRC:$CRA, CRBITRC:$CRB), + "cror $CRD, $CRA, $CRB", BrCR, + []>; + +def CRSET : XLForm_1_ext<19, 289, (outs CRBITRC:$dst), (ins), + "creqv $dst, $dst, $dst", BrCR, + []>; + +// XFX-Form instructions. Instructions that deal with SPRs. +// +let Uses = [CTR] in { +def MFCTR : XFXForm_1_ext<31, 339, 9, (outs GPRC:$rT), (ins), + "mfctr $rT", SprMFSPR>, + PPC970_DGroup_First, PPC970_Unit_FXU; +} +let Defs = [CTR], Pattern = [(PPCmtctr GPRC:$rS)] in { +def MTCTR : XFXForm_7_ext<31, 467, 9, (outs), (ins GPRC:$rS), + "mtctr $rS", SprMTSPR>, + PPC970_DGroup_First, PPC970_Unit_FXU; +} + +let Defs = [LR] in { +def MTLR : XFXForm_7_ext<31, 467, 8, (outs), (ins GPRC:$rS), + "mtlr $rS", SprMTSPR>, + PPC970_DGroup_First, PPC970_Unit_FXU; +} +let Uses = [LR] in { +def MFLR : XFXForm_1_ext<31, 339, 8, (outs GPRC:$rT), (ins), + "mflr $rT", SprMFSPR>, + PPC970_DGroup_First, PPC970_Unit_FXU; +} + +// Move to/from VRSAVE: despite being a SPR, the VRSAVE register is renamed like +// a GPR on the PPC970. As such, copies in and out have the same performance +// characteristics as an OR instruction. +def MTVRSAVE : XFXForm_7_ext<31, 467, 256, (outs), (ins GPRC:$rS), + "mtspr 256, $rS", IntGeneral>, + PPC970_DGroup_Single, PPC970_Unit_FXU; +def MFVRSAVE : XFXForm_1_ext<31, 339, 256, (outs GPRC:$rT), (ins), + "mfspr $rT, 256", IntGeneral>, + PPC970_DGroup_First, PPC970_Unit_FXU; + +def MTCRF : XFXForm_5<31, 144, (outs), (ins crbitm:$FXM, GPRC:$rS), + "mtcrf $FXM, $rS", BrMCRX>, + PPC970_MicroCode, PPC970_Unit_CRU; + +// This is a pseudo for MFCR, which implicitly uses all 8 of its subregisters; +// declaring that here gives the local register allocator problems with this: +// vreg = MCRF CR0 +// MFCR <kill of whatever preg got assigned to vreg> +// while not declaring it breaks DeadMachineInstructionElimination. +// As it turns out, in all cases where we currently use this, +// we're only interested in one subregister of it. Represent this in the +// instruction to keep the register allocator from becoming confused. +def MFCRpseud: XFXForm_3<31, 19, (outs GPRC:$rT), (ins crbitm:$FXM), + "mfcr $rT ${:comment} $FXM", SprMFCR>, + PPC970_MicroCode, PPC970_Unit_CRU; +def MFOCRF: XFXForm_5a<31, 19, (outs GPRC:$rT), (ins crbitm:$FXM), + "mfcr $rT, $FXM", SprMFCR>, + PPC970_DGroup_First, PPC970_Unit_CRU; + +// Instructions to manipulate FPSCR. Only long double handling uses these. +// FPSCR is not modelled; we use the SDNode Flag to keep things in order. + +let Uses = [RM], Defs = [RM] in { + def MTFSB0 : XForm_43<63, 70, (outs), (ins u5imm:$FM), + "mtfsb0 $FM", IntMTFSB0, + [(PPCmtfsb0 (i32 imm:$FM))]>, + PPC970_DGroup_Single, PPC970_Unit_FPU; + def MTFSB1 : XForm_43<63, 38, (outs), (ins u5imm:$FM), + "mtfsb1 $FM", IntMTFSB0, + [(PPCmtfsb1 (i32 imm:$FM))]>, + PPC970_DGroup_Single, PPC970_Unit_FPU; + // MTFSF does not actually produce an FP result. We pretend it copies + // input reg B to the output. If we didn't do this it would look like the + // instruction had no outputs (because we aren't modelling the FPSCR) and + // it would be deleted. + def MTFSF : XFLForm<63, 711, (outs F8RC:$FRA), + (ins i32imm:$FM, F8RC:$rT, F8RC:$FRB), + "mtfsf $FM, $rT", "$FRB = $FRA", IntMTFSB0, + [(set F8RC:$FRA, (PPCmtfsf (i32 imm:$FM), + F8RC:$rT, F8RC:$FRB))]>, + PPC970_DGroup_Single, PPC970_Unit_FPU; +} +let Uses = [RM] in { + def MFFS : XForm_42<63, 583, (outs F8RC:$rT), (ins), + "mffs $rT", IntMFFS, + [(set F8RC:$rT, (PPCmffs))]>, + PPC970_DGroup_Single, PPC970_Unit_FPU; + def FADDrtz: AForm_2<63, 21, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRB), + "fadd $FRT, $FRA, $FRB", FPGeneral, + [(set F8RC:$FRT, (PPCfaddrtz F8RC:$FRA, F8RC:$FRB))]>, + PPC970_DGroup_Single, PPC970_Unit_FPU; +} + + +let PPC970_Unit = 1 in { // FXU Operations. + +// XO-Form instructions. Arithmetic instructions that can set overflow bit +// +def ADD4 : XOForm_1<31, 266, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "add $rT, $rA, $rB", IntGeneral, + [(set GPRC:$rT, (add GPRC:$rA, GPRC:$rB))]>; +let Defs = [CARRY] in { +def ADDC : XOForm_1<31, 10, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "addc $rT, $rA, $rB", IntGeneral, + [(set GPRC:$rT, (addc GPRC:$rA, GPRC:$rB))]>, + PPC970_DGroup_Cracked; +} +def DIVW : XOForm_1<31, 491, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "divw $rT, $rA, $rB", IntDivW, + [(set GPRC:$rT, (sdiv GPRC:$rA, GPRC:$rB))]>, + PPC970_DGroup_First, PPC970_DGroup_Cracked; +def DIVWU : XOForm_1<31, 459, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "divwu $rT, $rA, $rB", IntDivW, + [(set GPRC:$rT, (udiv GPRC:$rA, GPRC:$rB))]>, + PPC970_DGroup_First, PPC970_DGroup_Cracked; +def MULHW : XOForm_1<31, 75, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "mulhw $rT, $rA, $rB", IntMulHW, + [(set GPRC:$rT, (mulhs GPRC:$rA, GPRC:$rB))]>; +def MULHWU : XOForm_1<31, 11, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "mulhwu $rT, $rA, $rB", IntMulHWU, + [(set GPRC:$rT, (mulhu GPRC:$rA, GPRC:$rB))]>; +def MULLW : XOForm_1<31, 235, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "mullw $rT, $rA, $rB", IntMulHW, + [(set GPRC:$rT, (mul GPRC:$rA, GPRC:$rB))]>; +def SUBF : XOForm_1<31, 40, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "subf $rT, $rA, $rB", IntGeneral, + [(set GPRC:$rT, (sub GPRC:$rB, GPRC:$rA))]>; +let Defs = [CARRY] in { +def SUBFC : XOForm_1<31, 8, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "subfc $rT, $rA, $rB", IntGeneral, + [(set GPRC:$rT, (subc GPRC:$rB, GPRC:$rA))]>, + PPC970_DGroup_Cracked; +} +def NEG : XOForm_3<31, 104, 0, (outs GPRC:$rT), (ins GPRC:$rA), + "neg $rT, $rA", IntGeneral, + [(set GPRC:$rT, (ineg GPRC:$rA))]>; +let Uses = [CARRY], Defs = [CARRY] in { +def ADDE : XOForm_1<31, 138, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "adde $rT, $rA, $rB", IntGeneral, + [(set GPRC:$rT, (adde GPRC:$rA, GPRC:$rB))]>; +def ADDME : XOForm_3<31, 234, 0, (outs GPRC:$rT), (ins GPRC:$rA), + "addme $rT, $rA", IntGeneral, + [(set GPRC:$rT, (adde GPRC:$rA, -1))]>; +def ADDZE : XOForm_3<31, 202, 0, (outs GPRC:$rT), (ins GPRC:$rA), + "addze $rT, $rA", IntGeneral, + [(set GPRC:$rT, (adde GPRC:$rA, 0))]>; +def SUBFE : XOForm_1<31, 136, 0, (outs GPRC:$rT), (ins GPRC:$rA, GPRC:$rB), + "subfe $rT, $rA, $rB", IntGeneral, + [(set GPRC:$rT, (sube GPRC:$rB, GPRC:$rA))]>; +def SUBFME : XOForm_3<31, 232, 0, (outs GPRC:$rT), (ins GPRC:$rA), + "subfme $rT, $rA", IntGeneral, + [(set GPRC:$rT, (sube -1, GPRC:$rA))]>; +def SUBFZE : XOForm_3<31, 200, 0, (outs GPRC:$rT), (ins GPRC:$rA), + "subfze $rT, $rA", IntGeneral, + [(set GPRC:$rT, (sube 0, GPRC:$rA))]>; +} +} + +// A-Form instructions. Most of the instructions executed in the FPU are of +// this type. +// +let PPC970_Unit = 3 in { // FPU Operations. +let Uses = [RM] in { + def FMADD : AForm_1<63, 29, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRC, F8RC:$FRB), + "fmadd $FRT, $FRA, $FRC, $FRB", FPFused, + [(set F8RC:$FRT, (fadd (fmul F8RC:$FRA, F8RC:$FRC), + F8RC:$FRB))]>, + Requires<[FPContractions]>; + def FMADDS : AForm_1<59, 29, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRC, F4RC:$FRB), + "fmadds $FRT, $FRA, $FRC, $FRB", FPGeneral, + [(set F4RC:$FRT, (fadd (fmul F4RC:$FRA, F4RC:$FRC), + F4RC:$FRB))]>, + Requires<[FPContractions]>; + def FMSUB : AForm_1<63, 28, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRC, F8RC:$FRB), + "fmsub $FRT, $FRA, $FRC, $FRB", FPFused, + [(set F8RC:$FRT, (fsub (fmul F8RC:$FRA, F8RC:$FRC), + F8RC:$FRB))]>, + Requires<[FPContractions]>; + def FMSUBS : AForm_1<59, 28, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRC, F4RC:$FRB), + "fmsubs $FRT, $FRA, $FRC, $FRB", FPGeneral, + [(set F4RC:$FRT, (fsub (fmul F4RC:$FRA, F4RC:$FRC), + F4RC:$FRB))]>, + Requires<[FPContractions]>; + def FNMADD : AForm_1<63, 31, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRC, F8RC:$FRB), + "fnmadd $FRT, $FRA, $FRC, $FRB", FPFused, + [(set F8RC:$FRT, (fneg (fadd (fmul F8RC:$FRA, F8RC:$FRC), + F8RC:$FRB)))]>, + Requires<[FPContractions]>; + def FNMADDS : AForm_1<59, 31, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRC, F4RC:$FRB), + "fnmadds $FRT, $FRA, $FRC, $FRB", FPGeneral, + [(set F4RC:$FRT, (fneg (fadd (fmul F4RC:$FRA, F4RC:$FRC), + F4RC:$FRB)))]>, + Requires<[FPContractions]>; + def FNMSUB : AForm_1<63, 30, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRC, F8RC:$FRB), + "fnmsub $FRT, $FRA, $FRC, $FRB", FPFused, + [(set F8RC:$FRT, (fneg (fsub (fmul F8RC:$FRA, F8RC:$FRC), + F8RC:$FRB)))]>, + Requires<[FPContractions]>; + def FNMSUBS : AForm_1<59, 30, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRC, F4RC:$FRB), + "fnmsubs $FRT, $FRA, $FRC, $FRB", FPGeneral, + [(set F4RC:$FRT, (fneg (fsub (fmul F4RC:$FRA, F4RC:$FRC), + F4RC:$FRB)))]>, + Requires<[FPContractions]>; +} +// FSEL is artificially split into 4 and 8-byte forms for the result. To avoid +// having 4 of these, force the comparison to always be an 8-byte double (code +// should use an FMRSD if the input comparison value really wants to be a float) +// and 4/8 byte forms for the result and operand type.. +def FSELD : AForm_1<63, 23, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRC, F8RC:$FRB), + "fsel $FRT, $FRA, $FRC, $FRB", FPGeneral, + [(set F8RC:$FRT, (PPCfsel F8RC:$FRA,F8RC:$FRC,F8RC:$FRB))]>; +def FSELS : AForm_1<63, 23, + (outs F4RC:$FRT), (ins F8RC:$FRA, F4RC:$FRC, F4RC:$FRB), + "fsel $FRT, $FRA, $FRC, $FRB", FPGeneral, + [(set F4RC:$FRT, (PPCfsel F8RC:$FRA,F4RC:$FRC,F4RC:$FRB))]>; +let Uses = [RM] in { + def FADD : AForm_2<63, 21, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRB), + "fadd $FRT, $FRA, $FRB", FPGeneral, + [(set F8RC:$FRT, (fadd F8RC:$FRA, F8RC:$FRB))]>; + def FADDS : AForm_2<59, 21, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRB), + "fadds $FRT, $FRA, $FRB", FPGeneral, + [(set F4RC:$FRT, (fadd F4RC:$FRA, F4RC:$FRB))]>; + def FDIV : AForm_2<63, 18, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRB), + "fdiv $FRT, $FRA, $FRB", FPDivD, + [(set F8RC:$FRT, (fdiv F8RC:$FRA, F8RC:$FRB))]>; + def FDIVS : AForm_2<59, 18, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRB), + "fdivs $FRT, $FRA, $FRB", FPDivS, + [(set F4RC:$FRT, (fdiv F4RC:$FRA, F4RC:$FRB))]>; + def FMUL : AForm_3<63, 25, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRB), + "fmul $FRT, $FRA, $FRB", FPFused, + [(set F8RC:$FRT, (fmul F8RC:$FRA, F8RC:$FRB))]>; + def FMULS : AForm_3<59, 25, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRB), + "fmuls $FRT, $FRA, $FRB", FPGeneral, + [(set F4RC:$FRT, (fmul F4RC:$FRA, F4RC:$FRB))]>; + def FSUB : AForm_2<63, 20, + (outs F8RC:$FRT), (ins F8RC:$FRA, F8RC:$FRB), + "fsub $FRT, $FRA, $FRB", FPGeneral, + [(set F8RC:$FRT, (fsub F8RC:$FRA, F8RC:$FRB))]>; + def FSUBS : AForm_2<59, 20, + (outs F4RC:$FRT), (ins F4RC:$FRA, F4RC:$FRB), + "fsubs $FRT, $FRA, $FRB", FPGeneral, + [(set F4RC:$FRT, (fsub F4RC:$FRA, F4RC:$FRB))]>; + } +} + +let PPC970_Unit = 1 in { // FXU Operations. +// M-Form instructions. rotate and mask instructions. +// +let isCommutable = 1 in { +// RLWIMI can be commuted if the rotate amount is zero. +def RLWIMI : MForm_2<20, + (outs GPRC:$rA), (ins GPRC:$rSi, GPRC:$rS, u5imm:$SH, u5imm:$MB, + u5imm:$ME), "rlwimi $rA, $rS, $SH, $MB, $ME", IntRotate, + []>, PPC970_DGroup_Cracked, RegConstraint<"$rSi = $rA">, + NoEncode<"$rSi">; +} +def RLWINM : MForm_2<21, + (outs GPRC:$rA), (ins GPRC:$rS, u5imm:$SH, u5imm:$MB, u5imm:$ME), + "rlwinm $rA, $rS, $SH, $MB, $ME", IntGeneral, + []>; +def RLWINMo : MForm_2<21, + (outs GPRC:$rA), (ins GPRC:$rS, u5imm:$SH, u5imm:$MB, u5imm:$ME), + "rlwinm. $rA, $rS, $SH, $MB, $ME", IntGeneral, + []>, isDOT, PPC970_DGroup_Cracked; +def RLWNM : MForm_2<23, + (outs GPRC:$rA), (ins GPRC:$rS, GPRC:$rB, u5imm:$MB, u5imm:$ME), + "rlwnm $rA, $rS, $rB, $MB, $ME", IntGeneral, + []>; +} + + +//===----------------------------------------------------------------------===// +// PowerPC Instruction Patterns +// + +// Arbitrary immediate support. Implement in terms of LIS/ORI. +def : Pat<(i32 imm:$imm), + (ORI (LIS (HI16 imm:$imm)), (LO16 imm:$imm))>; + +// Implement the 'not' operation with the NOR instruction. +def NOT : Pat<(not GPRC:$in), + (NOR GPRC:$in, GPRC:$in)>; + +// ADD an arbitrary immediate. +def : Pat<(add GPRC:$in, imm:$imm), + (ADDIS (ADDI GPRC:$in, (LO16 imm:$imm)), (HA16 imm:$imm))>; +// OR an arbitrary immediate. +def : Pat<(or GPRC:$in, imm:$imm), + (ORIS (ORI GPRC:$in, (LO16 imm:$imm)), (HI16 imm:$imm))>; +// XOR an arbitrary immediate. +def : Pat<(xor GPRC:$in, imm:$imm), + (XORIS (XORI GPRC:$in, (LO16 imm:$imm)), (HI16 imm:$imm))>; +// SUBFIC +def : Pat<(sub immSExt16:$imm, GPRC:$in), + (SUBFIC GPRC:$in, imm:$imm)>; + +// SHL/SRL +def : Pat<(shl GPRC:$in, (i32 imm:$imm)), + (RLWINM GPRC:$in, imm:$imm, 0, (SHL32 imm:$imm))>; +def : Pat<(srl GPRC:$in, (i32 imm:$imm)), + (RLWINM GPRC:$in, (SRL32 imm:$imm), imm:$imm, 31)>; + +// ROTL +def : Pat<(rotl GPRC:$in, GPRC:$sh), + (RLWNM GPRC:$in, GPRC:$sh, 0, 31)>; +def : Pat<(rotl GPRC:$in, (i32 imm:$imm)), + (RLWINM GPRC:$in, imm:$imm, 0, 31)>; + +// RLWNM +def : Pat<(and (rotl GPRC:$in, GPRC:$sh), maskimm32:$imm), + (RLWNM GPRC:$in, GPRC:$sh, (MB maskimm32:$imm), (ME maskimm32:$imm))>; + +// Calls +def : Pat<(PPCcall_Darwin (i32 tglobaladdr:$dst)), + (BL_Darwin tglobaladdr:$dst)>; +def : Pat<(PPCcall_Darwin (i32 texternalsym:$dst)), + (BL_Darwin texternalsym:$dst)>; +def : Pat<(PPCcall_SVR4 (i32 tglobaladdr:$dst)), + (BL_SVR4 tglobaladdr:$dst)>; +def : Pat<(PPCcall_SVR4 (i32 texternalsym:$dst)), + (BL_SVR4 texternalsym:$dst)>; + + +def : Pat<(PPCtc_return (i32 tglobaladdr:$dst), imm:$imm), + (TCRETURNdi tglobaladdr:$dst, imm:$imm)>; + +def : Pat<(PPCtc_return (i32 texternalsym:$dst), imm:$imm), + (TCRETURNdi texternalsym:$dst, imm:$imm)>; + +def : Pat<(PPCtc_return CTRRC:$dst, imm:$imm), + (TCRETURNri CTRRC:$dst, imm:$imm)>; + + + +// Hi and Lo for Darwin Global Addresses. +def : Pat<(PPChi tglobaladdr:$in, 0), (LIS tglobaladdr:$in)>; +def : Pat<(PPClo tglobaladdr:$in, 0), (LI tglobaladdr:$in)>; +def : Pat<(PPChi tconstpool:$in, 0), (LIS tconstpool:$in)>; +def : Pat<(PPClo tconstpool:$in, 0), (LI tconstpool:$in)>; +def : Pat<(PPChi tjumptable:$in, 0), (LIS tjumptable:$in)>; +def : Pat<(PPClo tjumptable:$in, 0), (LI tjumptable:$in)>; +def : Pat<(PPChi tblockaddress:$in, 0), (LIS tblockaddress:$in)>; +def : Pat<(PPClo tblockaddress:$in, 0), (LI tblockaddress:$in)>; +def : Pat<(add GPRC:$in, (PPChi tglobaladdr:$g, 0)), + (ADDIS GPRC:$in, tglobaladdr:$g)>; +def : Pat<(add GPRC:$in, (PPChi tconstpool:$g, 0)), + (ADDIS GPRC:$in, tconstpool:$g)>; +def : Pat<(add GPRC:$in, (PPChi tjumptable:$g, 0)), + (ADDIS GPRC:$in, tjumptable:$g)>; +def : Pat<(add GPRC:$in, (PPChi tblockaddress:$g, 0)), + (ADDIS GPRC:$in, tblockaddress:$g)>; + +// Fused negative multiply subtract, alternate pattern +def : Pat<(fsub F8RC:$B, (fmul F8RC:$A, F8RC:$C)), + (FNMSUB F8RC:$A, F8RC:$C, F8RC:$B)>, + Requires<[FPContractions]>; +def : Pat<(fsub F4RC:$B, (fmul F4RC:$A, F4RC:$C)), + (FNMSUBS F4RC:$A, F4RC:$C, F4RC:$B)>, + Requires<[FPContractions]>; + +// Standard shifts. These are represented separately from the real shifts above +// so that we can distinguish between shifts that allow 5-bit and 6-bit shift +// amounts. +def : Pat<(sra GPRC:$rS, GPRC:$rB), + (SRAW GPRC:$rS, GPRC:$rB)>; +def : Pat<(srl GPRC:$rS, GPRC:$rB), + (SRW GPRC:$rS, GPRC:$rB)>; +def : Pat<(shl GPRC:$rS, GPRC:$rB), + (SLW GPRC:$rS, GPRC:$rB)>; + +def : Pat<(zextloadi1 iaddr:$src), + (LBZ iaddr:$src)>; +def : Pat<(zextloadi1 xaddr:$src), + (LBZX xaddr:$src)>; +def : Pat<(extloadi1 iaddr:$src), + (LBZ iaddr:$src)>; +def : Pat<(extloadi1 xaddr:$src), + (LBZX xaddr:$src)>; +def : Pat<(extloadi8 iaddr:$src), + (LBZ iaddr:$src)>; +def : Pat<(extloadi8 xaddr:$src), + (LBZX xaddr:$src)>; +def : Pat<(extloadi16 iaddr:$src), + (LHZ iaddr:$src)>; +def : Pat<(extloadi16 xaddr:$src), + (LHZX xaddr:$src)>; +def : Pat<(extloadf32 iaddr:$src), + (FMRSD (LFS iaddr:$src))>; +def : Pat<(extloadf32 xaddr:$src), + (FMRSD (LFSX xaddr:$src))>; + +// Memory barriers +def : Pat<(membarrier (i32 imm /*ll*/), + (i32 imm /*ls*/), + (i32 imm /*sl*/), + (i32 imm /*ss*/), + (i32 imm /*device*/)), + (SYNC)>; + +include "PPCInstrAltivec.td" +include "PPCInstr64Bit.td" |