aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Target/ARM/ARMInstrInfo.td
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/ARM/ARMInstrInfo.td')
-rw-r--r--llvm/lib/Target/ARM/ARMInstrInfo.td282
1 files changed, 162 insertions, 120 deletions
diff --git a/llvm/lib/Target/ARM/ARMInstrInfo.td b/llvm/lib/Target/ARM/ARMInstrInfo.td
index c6bcad8e2a82..2a3a4e91eee4 100644
--- a/llvm/lib/Target/ARM/ARMInstrInfo.td
+++ b/llvm/lib/Target/ARM/ARMInstrInfo.td
@@ -14,6 +14,12 @@
// ARM specific DAG Nodes.
//
+/// Value type used for "condition code" operands.
+defvar CondCodeVT = i32;
+
+/// Value type used for "flags" operands / results (either CPSR or FPSCR_NZCV).
+defvar FlagsVT = i32;
+
// Type profiles.
def SDT_ARMCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32>,
SDTCisVT<1, i32> ]>;
@@ -26,12 +32,19 @@ def SDT_ARMSaveCallPC : SDTypeProfile<0, 1, []>;
def SDT_ARMcall : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>;
-def SDT_ARMCMov : SDTypeProfile<1, 3,
- [SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>,
- SDTCisVT<3, i32>]>;
+def SDT_ARMCMov : SDTypeProfile<1, 4, [
+ /* any */ // result
+ SDTCisSameAs<1, 0>, // value on false
+ SDTCisSameAs<2, 0>, // value on true
+ SDTCisVT<3, CondCodeVT>, // condition code
+ SDTCisVT<4, FlagsVT>, // in flags
+]>;
-def SDT_ARMBrcond : SDTypeProfile<0, 2,
- [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>]>;
+def SDT_ARMBrcond : SDTypeProfile<0, 2, [
+ SDTCisVT<0, OtherVT>, // target basic block
+ SDTCisVT<1, CondCodeVT>, // condition code
+ SDTCisVT<2, FlagsVT>, // in flags
+]>;
def SDT_ARMBrJT : SDTypeProfile<0, 2,
[SDTCisPtrTy<0>, SDTCisVT<1, i32>]>;
@@ -50,7 +63,11 @@ def SDT_ARMAnd : SDTypeProfile<1, 2,
[SDTCisVT<0, i32>, SDTCisVT<1, i32>,
SDTCisVT<2, i32>]>;
-def SDT_ARMCmp : SDTypeProfile<0, 2, [SDTCisSameAs<0, 1>]>;
+def SDT_ARMCmp : SDTypeProfile<1, 2, [
+ SDTCisVT<0, FlagsVT>, // out flags
+ SDTCisInt<1>, // lhs
+ SDTCisSameAs<2, 1> // rhs
+]>;
def SDT_ARMPICAdd : SDTypeProfile<1, 2, [SDTCisSameAs<0, 1>,
SDTCisPtrTy<1>, SDTCisVT<2, i32>]>;
@@ -77,6 +94,18 @@ def SDT_ARMMEMCPY : SDTypeProfile<2, 3, [SDTCisVT<0, i32>, SDTCisVT<1, i32>,
SDTCisVT<2, i32>, SDTCisVT<3, i32>,
SDTCisVT<4, i32>]>;
+def SDTIntUnaryOpWithFlagsOut : SDTypeProfile<2, 1, [
+ SDTCisInt<0>, // result
+ SDTCisVT<1, FlagsVT>, // out flags
+ SDTCisSameAs<2, 0> // operand
+]>;
+
+def SDTIntUnaryOpWithFlagsIn : SDTypeProfile<1, 2, [
+ SDTCisInt<0>, // result
+ SDTCisSameAs<1, 0>, // operand
+ SDTCisVT<1, FlagsVT> // in flags
+]>;
+
def SDTBinaryArithWithFlags : SDTypeProfile<2, 2,
[SDTCisSameAs<0, 2>,
SDTCisSameAs<0, 3>,
@@ -109,15 +138,17 @@ def ARMSmlaldx : SDNode<"ARMISD::SMLALDX", SDT_LongMac>;
def ARMSmlsld : SDNode<"ARMISD::SMLSLD", SDT_LongMac>;
def ARMSmlsldx : SDNode<"ARMISD::SMLSLDX", SDT_LongMac>;
-def SDT_ARMCSel : SDTypeProfile<1, 3,
- [SDTCisSameAs<0, 1>,
- SDTCisSameAs<0, 2>,
- SDTCisInt<3>,
- SDTCisVT<3, i32>]>;
+def SDT_ARMCSel : SDTypeProfile<1, 4, [
+ /* any */ // result
+ SDTCisSameAs<1, 0>, // lhs
+ SDTCisSameAs<2, 0>, // rhs
+ SDTCisVT<3, CondCodeVT>, // condition code
+ SDTCisVT<3, FlagsVT> // in flags
+]>;
-def ARMcsinv : SDNode<"ARMISD::CSINV", SDT_ARMCSel, [SDNPOptInGlue]>;
-def ARMcsneg : SDNode<"ARMISD::CSNEG", SDT_ARMCSel, [SDNPOptInGlue]>;
-def ARMcsinc : SDNode<"ARMISD::CSINC", SDT_ARMCSel, [SDNPOptInGlue]>;
+def ARMcsinv : SDNode<"ARMISD::CSINV", SDT_ARMCSel>;
+def ARMcsneg : SDNode<"ARMISD::CSNEG", SDT_ARMCSel>;
+def ARMcsinc : SDNode<"ARMISD::CSINC", SDT_ARMCSel>;
def SDT_MulHSR : SDTypeProfile<1, 3, [SDTCisVT<0,i32>,
SDTCisSameAs<0, 1>,
@@ -158,15 +189,13 @@ def ARMseretglue : SDNode<"ARMISD::SERET_GLUE", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
def ARMintretglue : SDNode<"ARMISD::INTRET_GLUE", SDT_ARMcall,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
-def ARMcmov : SDNode<"ARMISD::CMOV", SDT_ARMCMov,
- [SDNPInGlue]>;
+def ARMcmov : SDNode<"ARMISD::CMOV", SDT_ARMCMov>;
def ARMssat : SDNode<"ARMISD::SSAT", SDTIntSatNoShOp, []>;
def ARMusat : SDNode<"ARMISD::USAT", SDTIntSatNoShOp, []>;
-def ARMbrcond : SDNode<"ARMISD::BRCOND", SDT_ARMBrcond,
- [SDNPHasChain, SDNPInGlue, SDNPOutGlue]>;
+def ARMbrcond : SDNode<"ARMISD::BRCOND", SDT_ARMBrcond, [SDNPHasChain]>;
def ARMbrjt : SDNode<"ARMISD::BR_JT", SDT_ARMBrJT,
[SDNPHasChain]>;
@@ -176,14 +205,11 @@ def ARMbr2jt : SDNode<"ARMISD::BR2_JT", SDT_ARMBr2JT,
def ARMBcci64 : SDNode<"ARMISD::BCC_i64", SDT_ARMBCC_i64,
[SDNPHasChain]>;
-def ARMcmp : SDNode<"ARMISD::CMP", SDT_ARMCmp,
- [SDNPOutGlue]>;
+def ARMcmp : SDNode<"ARMISD::CMP", SDT_ARMCmp>;
-def ARMcmn : SDNode<"ARMISD::CMN", SDT_ARMCmp,
- [SDNPOutGlue]>;
+def ARMcmn : SDNode<"ARMISD::CMN", SDT_ARMCmp>;
-def ARMcmpZ : SDNode<"ARMISD::CMPZ", SDT_ARMCmp,
- [SDNPOutGlue, SDNPCommutative]>;
+def ARMcmpZ : SDNode<"ARMISD::CMPZ", SDT_ARMCmp, [SDNPCommutative]>;
def ARMpic_add : SDNode<"ARMISD::PIC_ADD", SDT_ARMPICAdd>;
@@ -191,9 +217,9 @@ def ARMasrl : SDNode<"ARMISD::ASRL", SDT_ARMIntShiftParts, []>;
def ARMlsrl : SDNode<"ARMISD::LSRL", SDT_ARMIntShiftParts, []>;
def ARMlsll : SDNode<"ARMISD::LSLL", SDT_ARMIntShiftParts, []>;
-def ARMsrl_glue : SDNode<"ARMISD::SRL_GLUE", SDTIntUnaryOp, [SDNPOutGlue]>;
-def ARMsra_glue : SDNode<"ARMISD::SRA_GLUE", SDTIntUnaryOp, [SDNPOutGlue]>;
-def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOp, [SDNPInGlue ]>;
+def ARMlsrs1 : SDNode<"ARMISD::LSRS1", SDTIntUnaryOpWithFlagsOut>;
+def ARMasrs1 : SDNode<"ARMISD::ASRS1", SDTIntUnaryOpWithFlagsOut>;
+def ARMrrx : SDNode<"ARMISD::RRX" , SDTIntUnaryOpWithFlagsIn>;
def ARMaddc : SDNode<"ARMISD::ADDC", SDTBinaryArithWithFlags,
[SDNPCommutative]>;
@@ -371,12 +397,14 @@ def ARMVCCElse : PatLeaf<(i32 2)>;
// imm_neg_XFORM - Return the negation of an i32 immediate value.
def imm_neg_XFORM : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(-(int)N->getZExtValue(), SDLoc(N), MVT::i32);
+ return CurDAG->getSignedTargetConstant(-(int)N->getZExtValue(), SDLoc(N),
+ MVT::i32);
}]>;
// imm_not_XFORM - Return the complement of a i32 immediate value.
def imm_not_XFORM : SDNodeXForm<imm, [{
- return CurDAG->getTargetConstant(~(int)N->getZExtValue(), SDLoc(N), MVT::i32);
+ return CurDAG->getSignedTargetConstant(~(int)N->getZExtValue(), SDLoc(N),
+ MVT::i32);
}]>;
def gi_imm_not_XFORM : GICustomOperandRenderer<"renderInvertedImm">,
GISDNodeXFormEquiv<imm_not_XFORM>;
@@ -1197,25 +1225,25 @@ def PostIdxRegShiftedAsmOperand : AsmOperandClass {
let ParserMethod = "parsePostIdxReg";
}
def am2offset_reg : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode2OffsetReg",
- [], [SDNPWantRoot]> {
+ ComplexPattern<i32, 2, "SelectAddrMode2OffsetReg"> {
let EncoderMethod = "getAddrMode2OffsetOpValue";
let PrintMethod = "printAddrMode2OffsetOperand";
// When using this for assembly, it's always as a post-index offset.
let ParserMatchClass = PostIdxRegShiftedAsmOperand;
let MIOperandInfo = (ops GPRnopc, i32imm);
+ let WantsRoot = true;
}
// FIXME: am2offset_imm should only need the immediate, not the GPR. Having
// the GPR is purely vestigal at this point.
def AM2OffsetImmAsmOperand : AsmOperandClass { let Name = "AM2OffsetImm"; }
def am2offset_imm : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode2OffsetImm",
- [], [SDNPWantRoot]> {
+ ComplexPattern<i32, 2, "SelectAddrMode2OffsetImm"> {
let EncoderMethod = "getAddrMode2OffsetOpValue";
let PrintMethod = "printAddrMode2OffsetOperand";
let ParserMatchClass = AM2OffsetImmAsmOperand;
let MIOperandInfo = (ops GPRnopc, i32imm);
+ let WantsRoot = true;
}
@@ -1247,13 +1275,12 @@ def AM3OffsetAsmOperand : AsmOperandClass {
let Name = "AM3Offset";
let ParserMethod = "parseAM3Offset";
}
-def am3offset : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode3Offset",
- [], [SDNPWantRoot]> {
+def am3offset : MemOperand, ComplexPattern<i32, 2, "SelectAddrMode3Offset"> {
let EncoderMethod = "getAddrMode3OffsetOpValue";
let PrintMethod = "printAddrMode3OffsetOperand";
let ParserMatchClass = AM3OffsetAsmOperand;
let MIOperandInfo = (ops GPR, i32imm);
+ let WantsRoot = true;
}
// ldstm_mode := {ia, ib, da, db}
@@ -1300,40 +1327,39 @@ def addrmode5fp16 : AddrMode5FP16 {
// addrmode6 := reg with optional alignment
//
def AddrMode6AsmOperand : AsmOperandClass { let Name = "AlignedMemory"; }
-def addrmode6 : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{
+def addrmode6 : MemOperand, ComplexPattern<i32, 2, "SelectAddrMode6"> {
let PrintMethod = "printAddrMode6Operand";
let MIOperandInfo = (ops GPR:$addr, i32imm:$align);
let EncoderMethod = "getAddrMode6AddressOpValue";
let DecoderMethod = "DecodeAddrMode6Operand";
let ParserMatchClass = AddrMode6AsmOperand;
+ let WantsParent = true;
}
-def am6offset : MemOperand,
- ComplexPattern<i32, 1, "SelectAddrMode6Offset",
- [], [SDNPWantRoot]> {
+def am6offset : MemOperand, ComplexPattern<i32, 1, "SelectAddrMode6Offset"> {
let PrintMethod = "printAddrMode6OffsetOperand";
let MIOperandInfo = (ops GPR);
let EncoderMethod = "getAddrMode6OffsetOpValue";
let DecoderMethod = "DecodeGPRRegisterClass";
+ let WantsRoot = true;
}
// Special version of addrmode6 to handle alignment encoding for VST1/VLD1
// (single element from one lane) for size 32.
-def addrmode6oneL32 : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{
+def addrmode6oneL32 : MemOperand, ComplexPattern<i32, 2, "SelectAddrMode6"> {
let PrintMethod = "printAddrMode6Operand";
let MIOperandInfo = (ops GPR:$addr, i32imm);
let EncoderMethod = "getAddrMode6OneLane32AddressOpValue";
+ let WantsParent = true;
}
// Base class for addrmode6 with specific alignment restrictions.
-class AddrMode6Align : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{
+class AddrMode6Align : MemOperand, ComplexPattern<i32, 2, "SelectAddrMode6"> {
let PrintMethod = "printAddrMode6Operand";
let MIOperandInfo = (ops GPR:$addr, i32imm:$align);
let EncoderMethod = "getAddrMode6AddressOpValue";
let DecoderMethod = "DecodeAddrMode6Operand";
+ let WantsParent = true;
}
// Special version of addrmode6 to handle no allowed alignment encoding for
@@ -1404,22 +1430,23 @@ def addrmode6align64or128or256 : AddrMode6Align {
// Special version of addrmode6 to handle alignment encoding for VLD-dup
// instructions, specifically VLD4-dup.
-def addrmode6dup : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{
+def addrmode6dup : MemOperand, ComplexPattern<i32, 2, "SelectAddrMode6"> {
let PrintMethod = "printAddrMode6Operand";
let MIOperandInfo = (ops GPR:$addr, i32imm);
let EncoderMethod = "getAddrMode6DupAddressOpValue";
// FIXME: This is close, but not quite right. The alignment specifier is
// different.
let ParserMatchClass = AddrMode6AsmOperand;
+ let WantsParent = true;
}
// Base class for addrmode6dup with specific alignment restrictions.
class AddrMode6DupAlign : MemOperand,
- ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{
+ ComplexPattern<i32, 2, "SelectAddrMode6"> {
let PrintMethod = "printAddrMode6Operand";
let MIOperandInfo = (ops GPR:$addr, i32imm);
let EncoderMethod = "getAddrMode6DupAddressOpValue";
+ let WantsParent = true;
}
// Special version of addrmode6 to handle no allowed alignment encoding for
@@ -1759,7 +1786,7 @@ multiclass AI1_cmp_irs<bits<4> opcod, string opc,
string rrDecoderMethod = ""> {
def ri : AI1<opcod, (outs), (ins GPR:$Rn, mod_imm:$imm), DPFrm, iii,
opc, "\t$Rn, $imm",
- [(opnode GPR:$Rn, mod_imm:$imm)]>,
+ [(set CPSR, (opnode GPR:$Rn, mod_imm:$imm))]>,
Sched<[WriteCMP, ReadALU]> {
bits<4> Rn;
bits<12> imm;
@@ -1773,7 +1800,7 @@ multiclass AI1_cmp_irs<bits<4> opcod, string opc,
}
def rr : AI1<opcod, (outs), (ins GPR:$Rn, GPR:$Rm), DPFrm, iir,
opc, "\t$Rn, $Rm",
- [(opnode GPR:$Rn, GPR:$Rm)]>,
+ [(set CPSR, (opnode GPR:$Rn, GPR:$Rm))]>,
Sched<[WriteCMP, ReadALU, ReadALU]> {
bits<4> Rn;
bits<4> Rm;
@@ -1791,7 +1818,7 @@ multiclass AI1_cmp_irs<bits<4> opcod, string opc,
def rsi : AI1<opcod, (outs),
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm, iis,
opc, "\t$Rn, $shift",
- [(opnode GPR:$Rn, so_reg_imm:$shift)]>,
+ [(set CPSR, (opnode GPR:$Rn, so_reg_imm:$shift))]>,
Sched<[WriteCMPsi, ReadALU]> {
bits<4> Rn;
bits<12> shift;
@@ -1808,7 +1835,7 @@ multiclass AI1_cmp_irs<bits<4> opcod, string opc,
def rsr : AI1<opcod, (outs),
(ins GPRnopc:$Rn, so_reg_reg:$shift), DPSoRegRegFrm, iis,
opc, "\t$Rn, $shift",
- [(opnode GPRnopc:$Rn, so_reg_reg:$shift)]>,
+ [(set CPSR, (opnode GPRnopc:$Rn, so_reg_reg:$shift))]>,
Sched<[WriteCMPsr, ReadALU]> {
bits<4> Rn;
bits<12> shift;
@@ -2376,13 +2403,13 @@ def UDF : AInoP<(outs), (ins imm0_65535:$imm16), MiscFrm, NoItinerary,
* - In ARM: UDF #60896;
* - In Thumb: UDF #254 followed by a branch-to-self.
*/
-let isBarrier = 1, isTerminator = 1 in
+let isTrap = 1 in
def TRAPNaCl : AXI<(outs), (ins), MiscFrm, NoItinerary,
"trap", [(trap)]>,
Requires<[IsARM,UseNaClTrap]> {
let Inst = 0xe7fedef0;
}
-let isBarrier = 1, isTerminator = 1 in
+let isTrap = 1 in
def TRAP : AXI<(outs), (ins), MiscFrm, NoItinerary,
"trap", [(trap)]>,
Requires<[IsARM,DontUseNaClTrap]> {
@@ -3293,7 +3320,7 @@ def STRH_preidx: ARMPseudoInst<(outs GPR:$Rn_wb),
}
-
+let mayStore = 1, hasSideEffects = 0 in {
def STRH_PRE : AI3ldstidx<0b1011, 0, 1, (outs GPR:$Rn_wb),
(ins GPR:$Rt, addrmode3_pre:$addr), IndexModePre,
StMiscFrm, IIC_iStore_bh_ru,
@@ -3325,6 +3352,7 @@ def STRH_POST : AI3ldstidx<0b1011, 0, 0, (outs GPR:$Rn_wb),
let Inst{3-0} = offset{3-0}; // imm3_0/Rm
let DecoderMethod = "DecodeAddrMode3Instruction";
}
+} // mayStore = 1, hasSideEffects = 0
let mayStore = 1, hasSideEffects = 0, hasExtraSrcRegAllocReq = 1 in {
def STRD_PRE : AI3ldstidx<0b1111, 0, 1, (outs GPR:$Rn_wb),
@@ -3360,6 +3388,8 @@ def STRD_POST: AI3ldstidx<0b1111, 0, 0, (outs GPR:$Rn_wb),
// STRT, STRBT, and STRHT
+let mayStore = 1, hasSideEffects = 0 in {
+
def STRBT_POST_REG : AI2ldstidx<0, 1, 0, (outs GPR:$Rn_wb),
(ins GPR:$Rt, addr_offset_none:$addr, am2offset_reg:$offset),
IndexModePost, StFrm, IIC_iStore_bh_ru,
@@ -3400,7 +3430,6 @@ def STRBT_POST
: ARMAsmPseudo<"strbt${q} $Rt, $addr",
(ins GPR:$Rt, addr_offset_none:$addr, pred:$q)>;
-let mayStore = 1, hasSideEffects = 0 in {
def STRT_POST_REG : AI2ldstidx<0, 0, 0, (outs GPR:$Rn_wb),
(ins GPR:$Rt, addr_offset_none:$addr, am2offset_reg:$offset),
IndexModePost, StFrm, IIC_iStore_ru,
@@ -3436,7 +3465,6 @@ def STRT_POST_IMM
let Inst{11-0} = offset{11-0};
let DecoderMethod = "DecodeAddrMode2IdxInstruction";
}
-}
def STRT_POST
: ARMAsmPseudo<"strt${q} $Rt, $addr",
@@ -3465,7 +3493,6 @@ multiclass AI3strT<bits<4> op, string opc> {
}
}
-
defm STRHT : AI3strT<0b1011, "strht">;
def STL : AIstrrel<0b00, (outs), (ins GPR:$Rt, addr_offset_none:$addr),
@@ -3475,6 +3502,8 @@ def STLB : AIstrrel<0b10, (outs), (ins GPR:$Rt, addr_offset_none:$addr),
def STLH : AIstrrel<0b11, (outs), (ins GPR:$Rt, addr_offset_none:$addr),
NoItinerary, "stlh", "\t$Rt, $addr", []>;
+} // mayStore = 1, hasSideEffects = 0
+
//===----------------------------------------------------------------------===//
// Load / store multiple Instructions.
//
@@ -3728,20 +3757,17 @@ def : ARMPat<(or GPR:$src, 0xffff0000), (MOVTi16 GPR:$src, 0xffff)>,
Requires<[IsARM, HasV6T2]>;
let Uses = [CPSR] in
-def RRX: PseudoInst<(outs GPR:$Rd), (ins GPR:$Rm), IIC_iMOVsi,
- [(set GPR:$Rd, (ARMrrx GPR:$Rm))]>, UnaryDP,
- Requires<[IsARM]>, Sched<[WriteALU]>;
-
-// These aren't really mov instructions, but we have to define them this way
-// due to glue operands.
+def RRX : PseudoInst<(outs GPR:$Rd), (ins GPR:$Rm), IIC_iMOVsi,
+ [(set GPR:$Rd, (ARMrrx GPR:$Rm, CPSR))]>,
+ UnaryDP, Requires<[IsARM]>, Sched<[WriteALU]>;
let Defs = [CPSR] in {
-def MOVsrl_glue : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi,
- [(set GPR:$dst, (ARMsrl_glue GPR:$src))]>, UnaryDP,
- Sched<[WriteALU]>, Requires<[IsARM]>;
-def MOVsra_glue : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi,
- [(set GPR:$dst, (ARMsra_glue GPR:$src))]>, UnaryDP,
- Sched<[WriteALU]>, Requires<[IsARM]>;
+ def LSRs1 : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi,
+ [(set GPR:$dst, CPSR, (ARMlsrs1 GPR:$src))]>,
+ UnaryDP, Sched<[WriteALU]>, Requires<[IsARM]>;
+ def ASRs1 : PseudoInst<(outs GPR:$dst), (ins GPR:$src), IIC_iMOVsi,
+ [(set GPR:$dst, CPSR, (ARMasrs1 GPR:$src))]>,
+ UnaryDP, Sched<[WriteALU]>, Requires<[IsARM]>;
}
//===----------------------------------------------------------------------===//
@@ -4741,6 +4767,7 @@ def : ARMV6Pat<(int_arm_smusdx GPRnopc:$Rn, GPRnopc:$Rm),
//===----------------------------------------------------------------------===//
// Division Instructions (ARMv7-A with virtualization extension)
//
+let TwoOperandAliasConstraint = "$Rn = $Rd" in {
def SDIV : ADivA1I<0b001, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), IIC_iDIV,
"sdiv", "\t$Rd, $Rn, $Rm",
[(set GPR:$Rd, (sdiv GPR:$Rn, GPR:$Rm))]>,
@@ -4752,6 +4779,7 @@ def UDIV : ADivA1I<0b011, (outs GPR:$Rd), (ins GPR:$Rn, GPR:$Rm), IIC_iDIV,
[(set GPR:$Rd, (udiv GPR:$Rn, GPR:$Rm))]>,
Requires<[IsARM, HasDivideInARM]>,
Sched<[WriteDIV]>;
+}
//===----------------------------------------------------------------------===//
// Misc. Arithmetic Instructions.
@@ -4929,7 +4957,7 @@ def : ARMPat<(ARMcmpZ so_reg_reg:$rhs, 0),
let isCompare = 1, Defs = [CPSR] in {
def CMNri : AI1<0b1011, (outs), (ins GPR:$Rn, mod_imm:$imm), DPFrm, IIC_iCMPi,
"cmn", "\t$Rn, $imm",
- [(ARMcmn GPR:$Rn, mod_imm:$imm)]>,
+ [(set CPSR, (ARMcmn GPR:$Rn, mod_imm:$imm))]>,
Sched<[WriteCMP, ReadALU]> {
bits<4> Rn;
bits<12> imm;
@@ -4945,8 +4973,8 @@ def CMNri : AI1<0b1011, (outs), (ins GPR:$Rn, mod_imm:$imm), DPFrm, IIC_iCMPi,
// CMN register-register/shift
def CMNzrr : AI1<0b1011, (outs), (ins GPR:$Rn, GPR:$Rm), DPFrm, IIC_iCMPr,
"cmn", "\t$Rn, $Rm",
- [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
- GPR:$Rn, GPR:$Rm)]>, Sched<[WriteCMP, ReadALU, ReadALU]> {
+ [(set CPSR, (BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
+ GPR:$Rn, GPR:$Rm))]>, Sched<[WriteCMP, ReadALU, ReadALU]> {
bits<4> Rn;
bits<4> Rm;
let isCommutable = 1;
@@ -4963,8 +4991,8 @@ def CMNzrr : AI1<0b1011, (outs), (ins GPR:$Rn, GPR:$Rm), DPFrm, IIC_iCMPr,
def CMNzrsi : AI1<0b1011, (outs),
(ins GPR:$Rn, so_reg_imm:$shift), DPSoRegImmFrm, IIC_iCMPsr,
"cmn", "\t$Rn, $shift",
- [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
- GPR:$Rn, so_reg_imm:$shift)]>,
+ [(set CPSR, (BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
+ GPR:$Rn, so_reg_imm:$shift))]>,
Sched<[WriteCMPsi, ReadALU]> {
bits<4> Rn;
bits<12> shift;
@@ -4982,8 +5010,8 @@ def CMNzrsi : AI1<0b1011, (outs),
def CMNzrsr : AI1<0b1011, (outs),
(ins GPRnopc:$Rn, so_reg_reg:$shift), DPSoRegRegFrm, IIC_iCMPsr,
"cmn", "\t$Rn, $shift",
- [(BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
- GPRnopc:$Rn, so_reg_reg:$shift)]>,
+ [(set CPSR, (BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>
+ GPRnopc:$Rn, so_reg_reg:$shift))]>,
Sched<[WriteCMPsr, ReadALU]> {
bits<4> Rn;
bits<12> shift;
@@ -5038,65 +5066,74 @@ let hasSideEffects = 0 in {
let isCommutable = 1, isSelect = 1 in
def MOVCCr : ARMPseudoInst<(outs GPR:$Rd),
- (ins GPR:$false, GPR:$Rm, cmovpred:$p),
- 4, IIC_iCMOVr,
- [(set GPR:$Rd, (ARMcmov GPR:$false, GPR:$Rm,
- cmovpred:$p))]>,
+ (ins GPR:$false, GPR:$Rm, pred:$p),
+ 4, IIC_iCMOVr, []>,
RegConstraint<"$false = $Rd">, Sched<[WriteALU]>;
def MOVCCsi : ARMPseudoInst<(outs GPR:$Rd),
- (ins GPR:$false, so_reg_imm:$shift, cmovpred:$p),
- 4, IIC_iCMOVsr,
- [(set GPR:$Rd,
- (ARMcmov GPR:$false, so_reg_imm:$shift,
- cmovpred:$p))]>,
+ (ins GPR:$false, so_reg_imm:$shift, pred:$p),
+ 4, IIC_iCMOVsr, []>,
RegConstraint<"$false = $Rd">, Sched<[WriteALU]>;
def MOVCCsr : ARMPseudoInst<(outs GPR:$Rd),
- (ins GPR:$false, so_reg_reg:$shift, cmovpred:$p),
- 4, IIC_iCMOVsr,
- [(set GPR:$Rd, (ARMcmov GPR:$false, so_reg_reg:$shift,
- cmovpred:$p))]>,
+ (ins GPR:$false, so_reg_reg:$shift, pred:$p),
+ 4, IIC_iCMOVsr, []>,
RegConstraint<"$false = $Rd">, Sched<[WriteALU]>;
let isMoveImm = 1 in
def MOVCCi16
: ARMPseudoInst<(outs GPR:$Rd),
- (ins GPR:$false, imm0_65535_expr:$imm, cmovpred:$p),
- 4, IIC_iMOVi,
- [(set GPR:$Rd, (ARMcmov GPR:$false, imm0_65535:$imm,
- cmovpred:$p))]>,
+ (ins GPR:$false, imm0_65535_expr:$imm, pred:$p),
+ 4, IIC_iMOVi, []>,
RegConstraint<"$false = $Rd">, Requires<[IsARM, HasV6T2]>,
Sched<[WriteALU]>;
let isMoveImm = 1 in
def MOVCCi : ARMPseudoInst<(outs GPR:$Rd),
- (ins GPR:$false, mod_imm:$imm, cmovpred:$p),
- 4, IIC_iCMOVi,
- [(set GPR:$Rd, (ARMcmov GPR:$false, mod_imm:$imm,
- cmovpred:$p))]>,
+ (ins GPR:$false, mod_imm:$imm, pred:$p),
+ 4, IIC_iCMOVi, []>,
RegConstraint<"$false = $Rd">, Sched<[WriteALU]>;
// Two instruction predicate mov immediate.
let isMoveImm = 1 in
def MOVCCi32imm
: ARMPseudoInst<(outs GPR:$Rd),
- (ins GPR:$false, i32imm:$src, cmovpred:$p),
- 8, IIC_iCMOVix2,
- [(set GPR:$Rd, (ARMcmov GPR:$false, imm:$src,
- cmovpred:$p))]>,
+ (ins GPR:$false, i32imm:$src, pred:$p),
+ 8, IIC_iCMOVix2, []>,
RegConstraint<"$false = $Rd">, Requires<[IsARM, HasV6T2]>;
let isMoveImm = 1 in
def MVNCCi : ARMPseudoInst<(outs GPR:$Rd),
- (ins GPR:$false, mod_imm:$imm, cmovpred:$p),
- 4, IIC_iCMOVi,
- [(set GPR:$Rd, (ARMcmov GPR:$false, mod_imm_not:$imm,
- cmovpred:$p))]>,
+ (ins GPR:$false, mod_imm:$imm, pred:$p),
+ 4, IIC_iCMOVi, []>,
RegConstraint<"$false = $Rd">, Sched<[WriteALU]>;
} // hasSideEffects
+// The following patterns have to be defined out-of-line because the number
+// of instruction operands does not match the number of SDNode operands
+// (`pred` counts as one operand).
+
+def : ARMPat<(ARMcmov i32:$false, i32:$Rm, imm:$cc, CPSR),
+ (MOVCCr $false, $Rm, imm:$cc, CPSR)>;
+
+def : ARMPat<(ARMcmov i32:$false, so_reg_imm:$shift, imm:$cc, CPSR),
+ (MOVCCsi $false, so_reg_imm:$shift, imm:$cc, CPSR)>;
+
+def : ARMPat<(ARMcmov i32:$false, so_reg_reg:$shift, imm:$cc, CPSR),
+ (MOVCCsr $false, so_reg_reg:$shift, imm:$cc, CPSR)>;
+
+def : ARMV6T2Pat<(ARMcmov i32:$false, imm0_65535:$imm, imm:$cc, CPSR),
+ (MOVCCi16 $false, imm0_65535:$imm, imm:$cc, CPSR)>;
+
+def : ARMPat<(ARMcmov i32:$false, mod_imm:$imm, imm:$cc, CPSR),
+ (MOVCCi $false, mod_imm:$imm, imm:$cc, CPSR)>;
+
+def : ARMPat<(ARMcmov i32:$false, mod_imm_not:$imm, imm:$cc, CPSR),
+ (MVNCCi $false, mod_imm_not:$imm, imm:$cc, CPSR)>;
+
+def : ARMV6T2Pat<(ARMcmov i32:$false, imm:$src, imm:$cc, CPSR),
+ (MOVCCi32imm $false, imm:$src, imm:$cc, CPSR)>;
//===----------------------------------------------------------------------===//
// Atomic operations intrinsics
@@ -5597,15 +5634,19 @@ multiclass LdSt2Cop<bit load, bit Dbit, string asm, list<dag> pattern> {
}
}
+let mayLoad = 1 in {
defm LDC : LdStCop <1, 0, "ldc", [(int_arm_ldc timm:$cop, timm:$CRd, addrmode5:$addr)]>;
defm LDCL : LdStCop <1, 1, "ldcl", [(int_arm_ldcl timm:$cop, timm:$CRd, addrmode5:$addr)]>;
defm LDC2 : LdSt2Cop<1, 0, "ldc2", [(int_arm_ldc2 timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>;
defm LDC2L : LdSt2Cop<1, 1, "ldc2l", [(int_arm_ldc2l timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>;
+}
+let mayStore = 1 in {
defm STC : LdStCop <0, 0, "stc", [(int_arm_stc timm:$cop, timm:$CRd, addrmode5:$addr)]>;
defm STCL : LdStCop <0, 1, "stcl", [(int_arm_stcl timm:$cop, timm:$CRd, addrmode5:$addr)]>;
defm STC2 : LdSt2Cop<0, 0, "stc2", [(int_arm_stc2 timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>;
defm STC2L : LdSt2Cop<0, 1, "stc2l", [(int_arm_stc2l timm:$cop, timm:$CRd, addrmode5:$addr)]>, Requires<[IsARM,PreV8]>;
+}
} // DecoderNamespace = "CoProc"
@@ -6507,8 +6548,21 @@ def CMP_SWAP_32 : PseudoInst<(outs GPR:$Rd, GPR:$temp),
(ins GPR:$addr, GPR:$desired, GPR:$new),
NoItinerary, []>, Sched<[]>;
-def CMP_SWAP_64 : PseudoInst<(outs GPRPair:$Rd, GPR:$temp),
- (ins GPR:$addr, GPRPair:$desired, GPRPair:$new),
+// The addr_temp and addr_temp_out operands are logically a pair of GPR
+// operands:
+// * addr is an input, holding the address to swap.
+// * temp is a earlyclobber output, used internally in the expansion of the
+// pseudo-inst.
+// These are combined into one GPRPair operand to ensure that register
+// allocation always succeeds. In the worst case there are only 4 GPRPair
+// registers available, of which this instruction needs 3 for the other
+// operands. If these operands weren't combined they would also use two GPR
+// registers, which could overlap with two different GPRPairs, causing
+// allocation to fail. With them combined, we need to allocate 4 GPRPairs,
+// which will always succeed.
+let Constraints = "@earlyclobber $Rd,$addr_temp_out = $addr_temp" in
+def CMP_SWAP_64 : PseudoInst<(outs GPRPair:$Rd, GPRPair:$addr_temp_out),
+ (ins GPRPair:$addr_temp, GPRPair:$desired, GPRPair:$new),
NoItinerary, []>, Sched<[]>;
}
@@ -6534,15 +6588,3 @@ let isPseudo = 1 in {
let isTerminator = 1 in
def SEH_EpilogEnd : PseudoInst<(outs), (ins), NoItinerary, []>, Sched<[]>;
}
-
-
-//===----------------------------------------------------------------------===//
-// Pseudo Instructions for use when early-clobber is defined and Greedy Register
-// Allocation is used. This ensures the constraint is used properly.
-//===----------------------------------------------------------------------===//
-let isCodeGenOnly = 1, hasNoSchedulingInfo = 1 in {
- def PseudoARMInitUndefMQPR : PseudoInst<(outs MQPR:$vd), (ins), NoItinerary, []>;
- def PseudoARMInitUndefSPR : PseudoInst<(outs SPR:$sd), (ins), NoItinerary, []>;
- def PseudoARMInitUndefDPR_VFP2 : PseudoInst<(outs DPR_VFP2:$dd), (ins), NoItinerary, []>;
- def PseudoARMInitUndefGPR : PseudoInst<(outs GPR:$rd), (ins), NoItinerary, []>;
-}