const MCAsmInfo *MAI = MF->getTarget().getMCAsmInfo();
const MCInstrDesc &MCID = MI.getDesc();
- if (MCID.getSize())
- return MCID.getSize();
switch (MI.getOpcode()) {
default:
- // pseudo-instruction sizes are zero.
- return 0;
+ // Return the size specified in .td file. If there's none, return 0, as we
+ // can't define a default size (Thumb1 instructions are 2 bytes, Thumb2
+ // instructions are 2-4 bytes, and ARM instructions are 4 bytes), in
+ // contrast to AArch64 instructions which have a default size of 4 bytes for
+ // example.
+ return MCID.getSize();
case TargetOpcode::BUNDLE:
return getInstBundleLength(MI);
- case ARM::MOVi16_ga_pcrel:
- case ARM::MOVTi16_ga_pcrel:
- case ARM::t2MOVi16_ga_pcrel:
- case ARM::t2MOVTi16_ga_pcrel:
- return 4;
- case ARM::MOVi32imm:
- case ARM::t2MOVi32imm:
- return 8;
case ARM::CONSTPOOL_ENTRY:
case ARM::JUMPTABLE_INSTS:
case ARM::JUMPTABLE_ADDRS:
// If this machine instr is a constant pool entry, its size is recorded as
// operand #2.
return MI.getOperand(2).getImm();
- case ARM::Int_eh_sjlj_longjmp:
- return 16;
- case ARM::tInt_eh_sjlj_longjmp:
- return 10;
- case ARM::tInt_WIN_eh_sjlj_longjmp:
- return 12;
- case ARM::Int_eh_sjlj_setjmp:
- case ARM::Int_eh_sjlj_setjmp_nofp:
- return 20;
- case ARM::tInt_eh_sjlj_setjmp:
- case ARM::t2Int_eh_sjlj_setjmp:
- case ARM::t2Int_eh_sjlj_setjmp_nofp:
- return 12;
case ARM::SPACE:
return MI.getOperand(1).getImm();
case ARM::INLINEASM:
Size = alignTo(Size, 4);
return Size;
}
- case ARM::SpeculationBarrierISBDSBEndBB:
- case ARM::t2SpeculationBarrierISBDSBEndBB:
- // This gets lowered to 2 4-byte instructions.
- return 8;
- case ARM::SpeculationBarrierSBEndBB:
- case ARM::t2SpeculationBarrierSBEndBB:
- // This gets lowered to 1 4-byte instructions.
- return 4;
}
}
(MOVi16 GPR:$Rd, imm0_65535_expr:$imm, pred:$p), 0>,
Requires<[IsARM, HasV6T2]>;
+// This gets lowered to a single 4-byte instructions
+let Size = 4 in
def MOVi16_ga_pcrel : PseudoInst<(outs GPR:$Rd),
(ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>,
Sched<[WriteALU]>;
let DecoderMethod = "DecodeArmMOVTWInstruction";
}
+// This gets lowered to a single 4-byte instructions
+let Size = 4 in
def MOVTi16_ga_pcrel : PseudoInst<(outs GPR:$Rd),
(ins GPR:$src, i32imm:$addr, pclabel:$id), IIC_iMOVi, []>,
Sched<[WriteALU]>;
//
// These are pseudo-instructions and are lowered to individual MC-insts, so
// no encoding information is necessary.
+// This gets lowered to an instruction sequence of 20 bytes
let Defs =
[ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR,
Q0, Q1, Q2, Q3, Q4, Q5, Q6, Q7, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15 ],
- hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1 in {
+ hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1, Size = 20 in {
def Int_eh_sjlj_setjmp : PseudoInst<(outs), (ins GPR:$src, GPR:$val),
NoItinerary,
[(set R0, (ARMeh_sjlj_setjmp GPR:$src, GPR:$val))]>,
Requires<[IsARM, HasVFP2]>;
}
+// This gets lowered to an instruction sequence of 20 bytes
let Defs =
[ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR ],
- hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1 in {
+ hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1, Size = 20 in {
def Int_eh_sjlj_setjmp_nofp : PseudoInst<(outs), (ins GPR:$src, GPR:$val),
NoItinerary,
[(set R0, (ARMeh_sjlj_setjmp GPR:$src, GPR:$val))]>,
Requires<[IsARM, NoVFP]>;
}
+// This gets lowered to an instruction sequence of 16 bytes
// FIXME: Non-IOS version(s)
-let isBarrier = 1, hasSideEffects = 1, isTerminator = 1,
+let isBarrier = 1, hasSideEffects = 1, isTerminator = 1, Size = 16,
Defs = [ R7, LR, SP ] in {
def Int_eh_sjlj_longjmp : PseudoInst<(outs), (ins GPR:$src, GPR:$scratch),
NoItinerary,
// This is a single pseudo instruction, the benefit is that it can be remat'd
// as a single unit instead of having to handle reg inputs.
// FIXME: Remove this when we can do generalized remat.
-let isReMaterializable = 1, isMoveImm = 1 in
+let isReMaterializable = 1, isMoveImm = 1, Size = 8 in
def MOVi32imm : PseudoInst<(outs GPR:$dst), (ins i32imm:$src), IIC_iMOVix2,
[(set GPR:$dst, (arm_i32imm:$src))]>,
Requires<[IsARM]>;
// SpeculationBarrierEndBB must only be used after an unconditional control
// flow, i.e. after a terminator for which isBarrier is True.
let hasSideEffects = 1, isCodeGenOnly = 1, isTerminator = 1, isBarrier = 1 in {
+ // This gets lowered to a pair of 4-byte instructions
+ let Size = 8 in
def SpeculationBarrierISBDSBEndBB
: PseudoInst<(outs), (ins), NoItinerary, []>, Sched<[]>;
+ // This gets lowered to a single 4-byte instructions
+ let Size = 4 in
def SpeculationBarrierSBEndBB
: PseudoInst<(outs), (ins), NoItinerary, []>, Sched<[]>;
}
// Defs. By doing so, we also cause the prologue/epilogue code to actively
// preserve all of the callee-saved registers, which is exactly what we want.
// $val is a scratch register for our use.
+// This gets lowered to an instruction sequence of 12 bytes
let Defs = [ R0, R1, R2, R3, R4, R5, R6, R7, R12, CPSR ],
- hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
+ hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1, Size = 12,
usesCustomInserter = 1 in
def tInt_eh_sjlj_setjmp : ThumbXI<(outs),(ins tGPR:$src, tGPR:$val),
AddrModeNone, 0, NoItinerary, "","",
[(set R0, (ARMeh_sjlj_setjmp tGPR:$src, tGPR:$val))]>;
+// This gets lowered to an instruction sequence of 10 bytes
// FIXME: Non-IOS version(s)
let isBarrier = 1, hasSideEffects = 1, isTerminator = 1, isCodeGenOnly = 1,
- Defs = [ R7, LR, SP ] in
+ Size = 10, Defs = [ R7, LR, SP ] in
def tInt_eh_sjlj_longjmp : XI<(outs), (ins tGPR:$src, tGPR:$scratch),
AddrModeNone, 0, IndexModeNone,
Pseudo, NoItinerary, "", "",
[(ARMeh_sjlj_longjmp tGPR:$src, tGPR:$scratch)]>,
Requires<[IsThumb,IsNotWindows]>;
+// This gets lowered to an instruction sequence of 12 bytes
// (Windows is Thumb2-only)
let isBarrier = 1, hasSideEffects = 1, isTerminator = 1, isCodeGenOnly = 1,
- Defs = [ R11, LR, SP ] in
+ Size = 12, Defs = [ R11, LR, SP ] in
def tInt_WIN_eh_sjlj_longjmp
: XI<(outs), (ins GPR:$src, GPR:$scratch), AddrModeNone, 0, IndexModeNone,
Pseudo, NoItinerary, "", "", [(ARMeh_sjlj_longjmp GPR:$src, GPR:$scratch)]>,
(t2MOVi16 rGPR:$Rd, imm256_65535_expr:$imm, pred:$p), 0>,
Requires<[IsThumb, HasV8MBaseline]>, Sched<[WriteALU]>;
+// This gets lowered to a single 4-byte instructions
+let Size = 4 in
def t2MOVi16_ga_pcrel : PseudoInst<(outs rGPR:$Rd),
(ins i32imm:$addr, pclabel:$id), IIC_iMOVi, []>,
Sched<[WriteALU]>;
let DecoderMethod = "DecodeT2MOVTWInstruction";
}
+// This gets lowered to a single 4-byte instructions
+let Size = 4 in
def t2MOVTi16_ga_pcrel : PseudoInst<(outs rGPR:$Rd),
(ins rGPR:$src, i32imm:$addr, pclabel:$id), IIC_iMOVi, []>,
Sched<[WriteALU]>, Requires<[IsThumb, HasV8MBaseline]>;
// doing so, we also cause the prologue/epilogue code to actively preserve
// all of the callee-saved registers, which is exactly what we want.
// $val is a scratch register for our use.
+// This gets lowered to an instruction sequence of 12 bytes
let Defs =
[ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR,
Q0, Q1, Q2, Q3, Q8, Q9, Q10, Q11, Q12, Q13, Q14, Q15],
- hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
+ hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1, Size = 12,
usesCustomInserter = 1 in {
def t2Int_eh_sjlj_setjmp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val),
AddrModeNone, 0, NoItinerary, "", "",
Requires<[IsThumb2, HasVFP2]>;
}
+// This gets lowered to an instruction sequence of 12 bytes
let Defs =
[ R0, R1, R2, R3, R4, R5, R6, R7, R8, R9, R10, R11, R12, LR, CPSR ],
- hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1,
+ hasSideEffects = 1, isBarrier = 1, isCodeGenOnly = 1, Size = 12,
usesCustomInserter = 1 in {
def t2Int_eh_sjlj_setjmp_nofp : Thumb2XI<(outs), (ins tGPR:$src, tGPR:$val),
AddrModeNone, 0, NoItinerary, "", "",
// 32-bit immediate using movw + movt.
// This is a single pseudo instruction to make it re-materializable.
// FIXME: Remove this when we can do generalized remat.
-let isReMaterializable = 1, isMoveImm = 1 in
+let isReMaterializable = 1, isMoveImm = 1, Size = 8 in
def t2MOVi32imm : PseudoInst<(outs rGPR:$dst), (ins i32imm:$src), IIC_iMOVix2,
[(set rGPR:$dst, (i32 imm:$src))]>,
Requires<[IsThumb, UseMovt]>;
// SpeculationBarrierEndBB must only be used after an unconditional control
// flow, i.e. after a terminator for which isBarrier is True.
let hasSideEffects = 1, isCodeGenOnly = 1, isTerminator = 1, isBarrier = 1 in {
+ // This gets lowered to a pair of 4-byte instructions
+ let Size = 8 in
def t2SpeculationBarrierISBDSBEndBB
: PseudoInst<(outs), (ins), NoItinerary, []>, Sched<[]>;
+ // This gets lowered to a single 4-byte instructions
+ let Size = 4 in
def t2SpeculationBarrierSBEndBB
: PseudoInst<(outs), (ins), NoItinerary, []>, Sched<[]>;
}
CodeGen
GlobalISel
MC
+ MIRParser
SelectionDAG
Support
Target
add_llvm_target_unittest(ARMTests
MachineInstrTest.cpp
+ InstSizes.cpp
)
--- /dev/null
+#include "ARMInstrInfo.h"
+#include "ARMSubtarget.h"
+#include "ARMTargetMachine.h"
+#include "llvm/CodeGen/MIRParser/MIRParser.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Support/TargetSelect.h"
+
+#include "gtest/gtest.h"
+
+using namespace llvm;
+
+namespace {
+/// The \p InputIRSnippet is only needed for things that can't be expressed in
+/// the \p InputMIRSnippet (global variables etc)
+/// TODO: Some of this might be useful for other architectures as well - extract
+/// the platform-independent parts somewhere they can be reused.
+void runChecks(
+ LLVMTargetMachine *TM, const ARMBaseInstrInfo *II,
+ const StringRef InputIRSnippet, const StringRef InputMIRSnippet,
+ unsigned Expected,
+ std::function<void(const ARMBaseInstrInfo &, MachineFunction &, unsigned &)>
+ Checks) {
+ LLVMContext Context;
+
+ auto MIRString = "--- |\n"
+ " declare void @sizes()\n" +
+ InputIRSnippet.str() +
+ "...\n"
+ "---\n"
+ "name: sizes\n"
+ "constants:\n"
+ " - id: 0\n"
+ " value: i32 12345678\n"
+ " alignment: 4\n"
+ "jumpTable:\n"
+ " kind: inline\n"
+ " entries:\n"
+ " - id: 0\n"
+ " blocks: [ '%bb.0' ]\n"
+ "body: |\n"
+ " bb.0:\n" +
+ InputMIRSnippet.str();
+
+ std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRString);
+ std::unique_ptr<MIRParser> MParser =
+ createMIRParser(std::move(MBuffer), Context);
+ ASSERT_TRUE(MParser);
+
+ std::unique_ptr<Module> M = MParser->parseIRModule();
+ ASSERT_TRUE(M);
+
+ M->setTargetTriple(TM->getTargetTriple().getTriple());
+ M->setDataLayout(TM->createDataLayout());
+
+ MachineModuleInfo MMI(TM);
+ bool Res = MParser->parseMachineFunctions(*M, MMI);
+ ASSERT_FALSE(Res);
+
+ auto F = M->getFunction("sizes");
+ ASSERT_TRUE(F != nullptr);
+ auto &MF = MMI.getOrCreateMachineFunction(*F);
+
+ Checks(*II, MF, Expected);
+}
+
+} // anonymous namespace
+
+TEST(InstSizes, PseudoInst) {
+ LLVMInitializeARMTargetInfo();
+ LLVMInitializeARMTarget();
+ LLVMInitializeARMTargetMC();
+
+ auto TT(Triple::normalize("thumbv8.1m.main-none-none-eabi"));
+ std::string Error;
+ const Target *T = TargetRegistry::lookupTarget(TT, Error);
+ if (!T) {
+ dbgs() << Error;
+ return;
+ }
+
+ TargetOptions Options;
+ auto TM = std::unique_ptr<LLVMTargetMachine>(
+ static_cast<LLVMTargetMachine *>(T->createTargetMachine(
+ TT, "generic", "", Options, None, None, CodeGenOpt::Default)));
+ ARMSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
+ std::string(TM->getTargetFeatureString()),
+ *static_cast<const ARMBaseTargetMachine *>(TM.get()), false);
+ const ARMBaseInstrInfo *II = ST.getInstrInfo();
+
+ auto cmpInstSize = [](const ARMBaseInstrInfo &II, MachineFunction &MF,
+ unsigned &Expected) {
+ auto I = MF.begin()->begin();
+ EXPECT_EQ(Expected, II.getInstSizeInBytes(*I));
+ };
+
+ runChecks(TM.get(), II, "",
+ " $r0 = MOVi16_ga_pcrel"
+ " target-flags(arm-lo16, arm-nonlazy) @sizes, 0\n",
+ 4u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " $r0 = MOVTi16_ga_pcrel $r0,"
+ " target-flags(arm-hi16, arm-nonlazy) @sizes, 0\n",
+ 4u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " $r0 = t2MOVi16_ga_pcrel"
+ " target-flags(arm-lo16, arm-nonlazy) @sizes, 0\n",
+ 4u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " $r0 = t2MOVTi16_ga_pcrel $r0,"
+ " target-flags(arm-hi16, arm-nonlazy) @sizes, 0\n",
+ 4u, cmpInstSize);
+
+ runChecks(TM.get(), II, "", " $r0 = MOVi32imm 2\n", 8u, cmpInstSize);
+
+ runChecks(TM.get(), II, "", " $r0 = t2MOVi32imm 2\n", 8u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " SpeculationBarrierISBDSBEndBB\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 8u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " t2SpeculationBarrierISBDSBEndBB\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 8u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " SpeculationBarrierSBEndBB\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 4u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " t2SpeculationBarrierSBEndBB\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 4u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " Int_eh_sjlj_longjmp $r0, $r1, implicit-def $r7,"
+ " implicit-def $lr, implicit-def $sp\n",
+ 16u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " tInt_eh_sjlj_longjmp $r0, $r1, implicit-def $r7,"
+ " implicit-def $lr, implicit-def $sp\n",
+ 10u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " tInt_WIN_eh_sjlj_longjmp $r0, $r1, implicit-def $r11,"
+ " implicit-def $lr, implicit-def $sp\n",
+ 12u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " Int_eh_sjlj_setjmp $r0, $r1, implicit-def $r0,"
+ " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
+ " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
+ " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
+ " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
+ " implicit-def $lr, implicit-def $cpsr, implicit-def $q0,"
+ " implicit-def $q1, implicit-def $q2, implicit-def $q3,"
+ " implicit-def $q4, implicit-def $q5, implicit-def $q6,"
+ " implicit-def $q7, implicit-def $q8, implicit-def $q9,"
+ " implicit-def $q10, implicit-def $q11, implicit-def $q12,"
+ " implicit-def $q13, implicit-def $q14, implicit-def $q15\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 20u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " Int_eh_sjlj_setjmp_nofp $r0, $r1, implicit-def $r0,"
+ " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
+ " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
+ " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
+ " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
+ " implicit-def $lr, implicit-def $cpsr\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 20u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " tInt_eh_sjlj_setjmp $r0, $r1, implicit-def $r0,"
+ " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
+ " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
+ " implicit-def $r7, implicit-def $r12, implicit-def $cpsr\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 12u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " t2Int_eh_sjlj_setjmp $r0, $r1, implicit-def $r0,"
+ " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
+ " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
+ " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
+ " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
+ " implicit-def $lr, implicit-def $cpsr, implicit-def $q0,"
+ " implicit-def $q1, implicit-def $q2, implicit-def $q3,"
+ " implicit-def $q8, implicit-def $q9, implicit-def $q10,"
+ " implicit-def $q11, implicit-def $q12, implicit-def $q13,"
+ " implicit-def $q14, implicit-def $q15\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 12u, cmpInstSize);
+
+ runChecks(TM.get(), II, "",
+ " t2Int_eh_sjlj_setjmp_nofp $r0, $r1, implicit-def $r0,"
+ " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
+ " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
+ " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
+ " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
+ " implicit-def $lr, implicit-def $cpsr\n"
+ " tBX_RET 14, $noreg, implicit $r0\n",
+ 12u, cmpInstSize);
+
+ runChecks(TM.get(), II, "", " CONSTPOOL_ENTRY 3, %const.0, 8\n", 8u,
+ cmpInstSize);
+
+ runChecks(TM.get(), II, "", " JUMPTABLE_ADDRS 0, %jump-table.0, 123\n", 123u,
+ cmpInstSize);
+
+ runChecks(TM.get(), II, "", " JUMPTABLE_INSTS 0, %jump-table.0, 456\n", 456u,
+ cmpInstSize);
+
+ runChecks(TM.get(), II, "", " JUMPTABLE_TBB 0, %jump-table.0, 789\n", 789u,
+ cmpInstSize);
+
+ runChecks(TM.get(), II, "", " JUMPTABLE_TBH 0, %jump-table.0, 188\n", 188u,
+ cmpInstSize);
+
+ runChecks(TM.get(), II, "", " $r0 = SPACE 40, undef $r0\n", 40u,
+ cmpInstSize);
+
+ runChecks(TM.get(), II, "", " INLINEASM &\"movs r0, #42\", 1\n", 6u,
+ cmpInstSize);
+
+ runChecks(TM.get(), II,
+ " define void @foo() {\n"
+ " entry:\n"
+ " ret void\n"
+ " }\n",
+ " INLINEASM_BR &\"b ${0:l}\", 1, 13, blockaddress(@foo, "
+ "%ir-block.entry)\n",
+ 6u, cmpInstSize);
+}
unittest("ARMTests") {
deps = [
+ "//llvm/lib/CodeGen/MIRParser",
"//llvm/lib/MC",
"//llvm/lib/Support",
"//llvm/lib/Target",
"//llvm/lib/Target/ARM/Utils",
]
include_dirs = [ "//llvm/lib/Target/ARM" ]
- sources = [ "MachineInstrTest.cpp" ]
+ sources = [ "MachineInstrTest.cpp", "InstSizes.cpp" ]
}