// FIXME: Eventually this will be just "hasV6T2Ops".
def UseMovt : Predicate<"Subtarget->useMovt()">;
def DontUseMovt : Predicate<"!Subtarget->useMovt()">;
-def UseVMLx : Predicate<"Subtarget->useVMLx()">;
+def UseFPVMLx : Predicate<"Subtarget->useFPVMLx()">;
//===----------------------------------------------------------------------===//
// ARM Flag Definitions.
return CurDAG->ComputeNumSignBits(SDValue(N,0)) >= 17;
}]>;
-/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
-/// e.g., 0xf000ffff
-def bf_inv_mask_imm : Operand<i32>,
- PatLeaf<(imm), [{
- return ARM::isBitFieldInvertedMask(N->getZExtValue());
-}] > {
- let EncoderMethod = "getBitfieldInvertedMaskOpValue";
- let PrintMethod = "printBitfieldInvMaskImmOperand";
-}
-
/// Split a 32-bit immediate into two 16 bit parts.
def hi16 : SDNodeXForm<imm, [{
return CurDAG->getTargetConstant((uint32_t)N->getZExtValue() >> 16, MVT::i32);
return N->hasOneUse();
}]>;
+// An 'fmul' node with a single use.
+def fmul_su : PatFrag<(ops node:$lhs, node:$rhs), (fmul node:$lhs, node:$rhs),[{
+ return N->hasOneUse();
+}]>;
+
+// An 'fadd' node which checks for single non-hazardous use.
+def fadd_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fadd node:$lhs, node:$rhs),[{
+ return hasNoVMLxHazardUse(N);
+}]>;
+
+// An 'fsub' node which checks for single non-hazardous use.
+def fsub_mlx : PatFrag<(ops node:$lhs, node:$rhs),(fsub node:$lhs, node:$rhs),[{
+ return hasNoVMLxHazardUse(N);
+}]>;
+
//===----------------------------------------------------------------------===//
// Operand Definitions.
//
let EncoderMethod = "getBranchTargetOpValue";
}
+def uncondbrtarget : Operand<OtherVT> {
+ let EncoderMethod = "getUnconditionalBranchTargetOpValue";
+}
+
// Call target.
def bltarget : Operand<i32> {
// Encoded the same as branch targets.
let PrintMethod = "printPCLabel";
}
+// ADR instruction labels.
+def adrlabel : Operand<i32> {
+ let EncoderMethod = "getAdrLabelOpValue";
+}
+
def neon_vcvt_imm32 : Operand<i32> {
let EncoderMethod = "getNEONVcvtImm32OpValue";
}
let EncoderMethod = "getMovtImmOpValue";
}
+/// bf_inv_mask_imm predicate - An AND mask to clear an arbitrary width bitfield
+/// e.g., 0xf000ffff
+def bf_inv_mask_imm : Operand<i32>,
+ PatLeaf<(imm), [{
+ return ARM::isBitFieldInvertedMask(N->getZExtValue());
+}] > {
+ let EncoderMethod = "getBitfieldInvertedMaskOpValue";
+ let PrintMethod = "printBitfieldInvMaskImmOperand";
+}
+
// Define ARM specific addressing modes.
//
def addrmode2 : Operand<i32>,
ComplexPattern<i32, 3, "SelectAddrMode2", []> {
- string EncoderMethod = "getAddrMode2OpValue";
+ let EncoderMethod = "getAddrMode2OpValue";
let PrintMethod = "printAddrMode2Operand";
let MIOperandInfo = (ops GPR:$base, GPR:$offsreg, i32imm:$offsimm);
}
def am2offset : Operand<i32>,
ComplexPattern<i32, 2, "SelectAddrMode2Offset",
[], [SDNPWantRoot]> {
- string EncoderMethod = "getAddrMode2OffsetOpValue";
+ let EncoderMethod = "getAddrMode2OffsetOpValue";
let PrintMethod = "printAddrMode2OffsetOperand";
let MIOperandInfo = (ops GPR, i32imm);
}
let EncoderMethod = "getAddrMode6OffsetOpValue";
}
+// Special version of addrmode6 to handle alignment encoding for VLD-dup
+// instructions, specifically VLD4-dup.
+def addrmode6dup : Operand<i32>,
+ ComplexPattern<i32, 2, "SelectAddrMode6", [], [SDNPWantParent]>{
+ let PrintMethod = "printAddrMode6Operand";
+ let MIOperandInfo = (ops GPR:$addr, i32imm);
+ let EncoderMethod = "getAddrMode6DupAddressOpValue";
+}
+
// addrmodepc := pc + reg
//
def addrmodepc : Operand<i32>,
// LEApcrel - Load a pc-relative address into a register without offending the
// assembler.
-let neverHasSideEffects = 1 in {
-let isReMaterializable = 1 in
-// FIXME: We want one cannonical LEApcrel instruction and to express one or
-// both of these as pseudo-instructions that get expanded to it.
-def LEApcrel : AXI1<0, (outs GPR:$Rd), (ins i32imm:$label, pred:$p),
- MiscFrm, IIC_iALUi,
- "adr$p\t$Rd, #$label", []>;
-
-} // neverHasSideEffects
-def LEApcrelJT : AXI1<0b0100, (outs GPR:$Rd),
- (ins i32imm:$label, nohash_imm:$id, pred:$p),
- MiscFrm, IIC_iALUi,
- "adr$p\t$Rd, #${label}_${id}", []> {
- bits<4> p;
+let neverHasSideEffects = 1, isReMaterializable = 1 in
+// The 'adr' mnemonic encodes differently if the label is before or after
+// the instruction. The {24-21} opcode bits are set by the fixup, as we don't
+// know until then which form of the instruction will be used.
+def ADR : AI1<0, (outs GPR:$Rd), (ins adrlabel:$label),
+ MiscFrm, IIC_iALUi, "adr", "\t$Rd, #$label", []> {
bits<4> Rd;
- let Inst{31-28} = p;
+ bits<12> label;
let Inst{27-25} = 0b001;
let Inst{20} = 0;
let Inst{19-16} = 0b1111;
let Inst{15-12} = Rd;
- // FIXME: Add label encoding/fixup
+ let Inst{11-0} = label;
}
+def LEApcrel : ARMPseudoInst<(outs GPR:$Rd), (ins i32imm:$label, pred:$p),
+ Size4Bytes, IIC_iALUi, []>;
+
+def LEApcrelJT : ARMPseudoInst<(outs GPR:$Rd),
+ (ins i32imm:$label, nohash_imm:$id, pred:$p),
+ Size4Bytes, IIC_iALUi, []>;
//===----------------------------------------------------------------------===//
// Control Flow Instructions.
// Indirect branches
let isBranch = 1, isTerminator = 1, isBarrier = 1, isIndirectBranch = 1 in {
// ARMV4T and above
- def BRIND : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "bx\t$dst",
+ def BX : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "bx\t$dst",
[(brind GPR:$dst)]>,
Requires<[IsARM, HasV4T]> {
bits<4> dst;
}
// ARMV4 only
- def MOVPCRX : AXI<(outs), (ins GPR:$dst), BrMiscFrm, IIC_Br, "mov\tpc, $dst",
- [(brind GPR:$dst)]>,
- Requires<[IsARM, NoV4T]> {
- bits<4> dst;
- let Inst{31-4} = 0b1110000110100000111100000000;
- let Inst{3-0} = dst;
- }
+ // FIXME: We would really like to define this as a vanilla ARMPat like:
+ // ARMPat<(brind GPR:$dst), (MOVr PC, GPR:$dst)>
+ // With that, however, we can't set isBranch, isTerminator, etc..
+ def MOVPCRX : ARMPseudoInst<(outs), (ins GPR:$dst),
+ Size4Bytes, IIC_Br, [(brind GPR:$dst)]>,
+ Requires<[IsARM, NoV4T]>;
}
// All calls clobber the non-callee saved registers. SP is marked as
// ARMv4T
// Note: Restrict $func to the tGPR regclass to prevent it being in LR.
- // FIXME: x2 insn patterns like this need to be pseudo instructions.
- def BX : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
- IIC_Br, "mov\tlr, pc\n\tbx\t$func",
- [(ARMcall_nolink tGPR:$func)]>,
- Requires<[IsARM, HasV4T, IsNotDarwin]> {
- bits<4> func;
- let Inst{27-4} = 0b000100101111111111110001;
- let Inst{3-0} = func;
- }
+ def BX_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops),
+ Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>,
+ Requires<[IsARM, HasV4T, IsNotDarwin]>;
// ARMv4
- def BMOVPCRX : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
- IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func",
- [(ARMcall_nolink tGPR:$func)]>,
- Requires<[IsARM, NoV4T, IsNotDarwin]> {
- bits<4> func;
- let Inst{27-4} = 0b000110100000111100000000;
- let Inst{3-0} = func;
- }
+ def BMOVPCRX_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops),
+ Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>,
+ Requires<[IsARM, NoV4T, IsNotDarwin]>;
}
let isCall = 1,
// ARMv4T
// Note: Restrict $func to the tGPR regclass to prevent it being in LR.
- def BXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
- IIC_Br, "mov\tlr, pc\n\tbx\t$func",
- [(ARMcall_nolink tGPR:$func)]>,
- Requires<[IsARM, HasV4T, IsDarwin]> {
- bits<4> func;
- let Inst{27-4} = 0b000100101111111111110001;
- let Inst{3-0} = func;
- }
+ def BXr9_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops),
+ Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>,
+ Requires<[IsARM, HasV4T, IsDarwin]>;
// ARMv4
- def BMOVPCRXr9 : ABXIx2<(outs), (ins tGPR:$func, variable_ops),
- IIC_Br, "mov\tlr, pc\n\tmov\tpc, $func",
- [(ARMcall_nolink tGPR:$func)]>,
- Requires<[IsARM, NoV4T, IsDarwin]> {
- bits<4> func;
- let Inst{27-4} = 0b000110100000111100000000;
- let Inst{3-0} = func;
- }
+ def BMOVPCRXr9_CALL : ARMPseudoInst<(outs), (ins tGPR:$func, variable_ops),
+ Size8Bytes, IIC_Br, [(ARMcall_nolink tGPR:$func)]>,
+ Requires<[IsARM, NoV4T, IsDarwin]>;
}
// Tail calls.
// FIXME: These should probably be xformed into the non-TC versions of the
// instructions as part of MC lowering.
+// FIXME: These seem to be used for both Thumb and ARM instruction selection.
+// Thumb should have its own version since the instruction is actually
+// different, even though the mnemonic is the same.
let isCall = 1, isTerminator = 1, isReturn = 1, isBarrier = 1 in {
// Darwin versions.
let Defs = [R0, R1, R2, R3, R9, R12,
D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26,
D27, D28, D29, D30, D31, PC],
Uses = [SP] in {
- def TCRETURNdi : AInoP<(outs), (ins i32imm:$dst, variable_ops),
- Pseudo, IIC_Br,
- "@TC_RETURN","\t$dst", []>, Requires<[IsDarwin]>;
+ def TCRETURNdi : PseudoInst<(outs), (ins i32imm:$dst, variable_ops),
+ IIC_Br, []>, Requires<[IsDarwin]>;
- def TCRETURNri : AInoP<(outs), (ins tcGPR:$dst, variable_ops),
- Pseudo, IIC_Br,
- "@TC_RETURN","\t$dst", []>, Requires<[IsDarwin]>;
+ def TCRETURNri : PseudoInst<(outs), (ins tcGPR:$dst, variable_ops),
+ IIC_Br, []>, Requires<[IsDarwin]>;
def TAILJMPd : ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops),
IIC_Br, "b\t$dst @ TAILCALL",
- []>, Requires<[IsDarwin]>;
+ []>, Requires<[IsARM, IsDarwin]>;
def TAILJMPdt: ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops),
IIC_Br, "b.w\t$dst @ TAILCALL",
- []>, Requires<[IsDarwin]>;
+ []>, Requires<[IsThumb, IsDarwin]>;
def TAILJMPr : AXI<(outs), (ins tcGPR:$dst, variable_ops),
BrMiscFrm, IIC_Br, "bx\t$dst @ TAILCALL",
D16, D17, D18, D19, D20, D21, D22, D23, D24, D25, D26,
D27, D28, D29, D30, D31, PC],
Uses = [SP] in {
- def TCRETURNdiND : AInoP<(outs), (ins i32imm:$dst, variable_ops),
- Pseudo, IIC_Br,
- "@TC_RETURN","\t$dst", []>, Requires<[IsNotDarwin]>;
+ def TCRETURNdiND : PseudoInst<(outs), (ins i32imm:$dst, variable_ops),
+ IIC_Br, []>, Requires<[IsNotDarwin]>;
- def TCRETURNriND : AInoP<(outs), (ins tcGPR:$dst, variable_ops),
- Pseudo, IIC_Br,
- "@TC_RETURN","\t$dst", []>, Requires<[IsNotDarwin]>;
+ def TCRETURNriND : PseudoInst<(outs), (ins tcGPR:$dst, variable_ops),
+ IIC_Br, []>, Requires<[IsNotDarwin]>;
def TAILJMPdND : ABXI<0b1010, (outs), (ins brtarget:$dst, variable_ops),
IIC_Br, "b\t$dst @ TAILCALL",
// FIXME: Should pc be an implicit operand like PICADD, etc?
let isReturn = 1, isTerminator = 1, isBarrier = 1, mayLoad = 1,
hasExtraDefRegAllocReq = 1, isCodeGenOnly = 1 in
+// FIXME: Should be a pseudo-instruction.
def LDMIA_RET : AXI4<(outs GPR:$wb), (ins GPR:$Rn, pred:$p,
reglist:$regs, variable_ops),
IndexModeUpd, LdStMulFrm, IIC_iLoad_mBr,
IIC_iCMPi, IIC_iCMPr, IIC_iCMPsr,
BinOpFrag<(ARMcmp node:$LHS, node:$RHS)>>;
+// ARMcmpZ can re-use the above instruction definitions.
+def : ARMPat<(ARMcmpZ GPR:$src, so_imm:$imm),
+ (CMPri GPR:$src, so_imm:$imm)>;
+def : ARMPat<(ARMcmpZ GPR:$src, GPR:$rhs),
+ (CMPrr GPR:$src, GPR:$rhs)>;
+def : ARMPat<(ARMcmpZ GPR:$src, so_reg:$rhs),
+ (CMPrs GPR:$src, so_reg:$rhs)>;
+
// FIXME: We have to be careful when using the CMN instruction and comparison
// with 0. One would expect these two pieces of code should give identical
// results:
IIC_iTSTi, IIC_iTSTr, IIC_iTSTsr,
BinOpFrag<(ARMcmpZ (xor_su node:$LHS, node:$RHS), 0)>, 1>;
-defm CMPz : AI1_cmp_irs<0b1010, "cmp",
- IIC_iCMPi, IIC_iCMPr, IIC_iCMPsr,
- BinOpFrag<(ARMcmpZ node:$LHS, node:$RHS)>>;
defm CMNz : AI1_cmp_irs<0b1011, "cmn",
IIC_iCMPi, IIC_iCMPr, IIC_iCMPsr,
BinOpFrag<(ARMcmpZ node:$LHS,(ineg node:$RHS))>>;
//
// __aeabi_read_tp preserves the registers r1-r3.
-// FIXME: This needs to be a pseudo of some sort so that we can get the
-// encoding right, complete with fixup for the aeabi_read_tp function.
+// This is a pseudo inst so that we can get the encoding right,
+// complete with fixup for the aeabi_read_tp function.
let isCall = 1,
Defs = [R0, R12, LR, CPSR], Uses = [SP] in {
- def TPsoft : ABXI<0b1011, (outs), (ins), IIC_Br,
- "bl\t__aeabi_read_tp",
+ def TPsoft : PseudoInst<(outs), (ins), IIC_Br,
[(set R0, ARMthread_pointer)]>;
}