1 #include "ARMInstrInfo.h"
2 #include "ARMSubtarget.h"
3 #include "ARMTargetMachine.h"
4 #include "llvm/CodeGen/MIRParser/MIRParser.h"
5 #include "llvm/CodeGen/MachineModuleInfo.h"
6 #include "llvm/MC/TargetRegistry.h"
7 #include "llvm/Support/MemoryBuffer.h"
8 #include "llvm/Support/TargetSelect.h"
9 
10 #include "gtest/gtest.h"
11 
12 using namespace llvm;
13 
14 namespace {
15 /// The \p InputIRSnippet is only needed for things that can't be expressed in
16 /// the \p InputMIRSnippet (global variables etc)
17 /// TODO: Some of this might be useful for other architectures as well - extract
18 ///       the platform-independent parts somewhere they can be reused.
runChecks(LLVMTargetMachine * TM,const ARMBaseInstrInfo * II,const StringRef InputIRSnippet,const StringRef InputMIRSnippet,unsigned Expected,std::function<void (const ARMBaseInstrInfo &,MachineFunction &,unsigned &)> Checks)19 void runChecks(
20     LLVMTargetMachine *TM, const ARMBaseInstrInfo *II,
21     const StringRef InputIRSnippet, const StringRef InputMIRSnippet,
22     unsigned Expected,
23     std::function<void(const ARMBaseInstrInfo &, MachineFunction &, unsigned &)>
24         Checks) {
25   LLVMContext Context;
26 
27   auto MIRString = "--- |\n"
28                    "  declare void @sizes()\n" +
29                    InputIRSnippet.str() +
30                    "...\n"
31                    "---\n"
32                    "name: sizes\n"
33                    "constants:\n"
34                    "  - id:        0\n"
35                    "    value:     i32 12345678\n"
36                    "    alignment: 4\n"
37                    "jumpTable:\n"
38                    "  kind:    inline\n"
39                    "  entries:\n"
40                    "    - id:     0\n"
41                    "      blocks: [ '%bb.0' ]\n"
42                    "body: |\n"
43                    "  bb.0:\n" +
44                    InputMIRSnippet.str();
45 
46   std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRString);
47   std::unique_ptr<MIRParser> MParser =
48       createMIRParser(std::move(MBuffer), Context);
49   ASSERT_TRUE(MParser);
50 
51   std::unique_ptr<Module> M = MParser->parseIRModule();
52   ASSERT_TRUE(M);
53 
54   M->setTargetTriple(TM->getTargetTriple().getTriple());
55   M->setDataLayout(TM->createDataLayout());
56 
57   MachineModuleInfo MMI(TM);
58   bool Res = MParser->parseMachineFunctions(*M, MMI);
59   ASSERT_FALSE(Res);
60 
61   auto F = M->getFunction("sizes");
62   ASSERT_TRUE(F != nullptr);
63   auto &MF = MMI.getOrCreateMachineFunction(*F);
64 
65   Checks(*II, MF, Expected);
66 }
67 
68 } // anonymous namespace
69 
TEST(InstSizes,PseudoInst)70 TEST(InstSizes, PseudoInst) {
71   LLVMInitializeARMTargetInfo();
72   LLVMInitializeARMTarget();
73   LLVMInitializeARMTargetMC();
74 
75   auto TT(Triple::normalize("thumbv8.1m.main-none-none-eabi"));
76   std::string Error;
77   const Target *T = TargetRegistry::lookupTarget(TT, Error);
78   if (!T) {
79     dbgs() << Error;
80     return;
81   }
82 
83   TargetOptions Options;
84   auto TM = std::unique_ptr<LLVMTargetMachine>(
85       static_cast<LLVMTargetMachine *>(T->createTargetMachine(
86           TT, "generic", "", Options, None, None, CodeGenOpt::Default)));
87   ARMSubtarget ST(TM->getTargetTriple(), std::string(TM->getTargetCPU()),
88                   std::string(TM->getTargetFeatureString()),
89                   *static_cast<const ARMBaseTargetMachine *>(TM.get()), false);
90   const ARMBaseInstrInfo *II = ST.getInstrInfo();
91 
92   auto cmpInstSize = [](const ARMBaseInstrInfo &II, MachineFunction &MF,
93                         unsigned &Expected) {
94     auto I = MF.begin()->begin();
95     EXPECT_EQ(Expected, II.getInstSizeInBytes(*I));
96   };
97 
98   runChecks(TM.get(), II, "",
99             "    $r0 = MOVi16_ga_pcrel"
100             " target-flags(arm-lo16, arm-nonlazy) @sizes, 0\n",
101             4u, cmpInstSize);
102 
103   runChecks(TM.get(), II, "",
104             "    $r0 = MOVTi16_ga_pcrel $r0,"
105             " target-flags(arm-hi16, arm-nonlazy) @sizes, 0\n",
106             4u, cmpInstSize);
107 
108   runChecks(TM.get(), II, "",
109             "    $r0 = t2MOVi16_ga_pcrel"
110             " target-flags(arm-lo16, arm-nonlazy) @sizes, 0\n",
111             4u, cmpInstSize);
112 
113   runChecks(TM.get(), II, "",
114             "    $r0 = t2MOVTi16_ga_pcrel $r0,"
115             " target-flags(arm-hi16, arm-nonlazy) @sizes, 0\n",
116             4u, cmpInstSize);
117 
118   runChecks(TM.get(), II, "", "    $r0 = MOVi32imm 2\n", 8u, cmpInstSize);
119 
120   runChecks(TM.get(), II, "", "    $r0 = t2MOVi32imm 2\n", 8u, cmpInstSize);
121 
122   runChecks(TM.get(), II, "",
123             "    SpeculationBarrierISBDSBEndBB\n"
124             "    tBX_RET 14, $noreg, implicit $r0\n",
125             8u, cmpInstSize);
126 
127   runChecks(TM.get(), II, "",
128             "    t2SpeculationBarrierISBDSBEndBB\n"
129             "    tBX_RET 14, $noreg, implicit $r0\n",
130             8u, cmpInstSize);
131 
132   runChecks(TM.get(), II, "",
133             "    SpeculationBarrierSBEndBB\n"
134             "    tBX_RET 14, $noreg, implicit $r0\n",
135             4u, cmpInstSize);
136 
137   runChecks(TM.get(), II, "",
138             "    t2SpeculationBarrierSBEndBB\n"
139             "    tBX_RET 14, $noreg, implicit $r0\n",
140             4u, cmpInstSize);
141 
142   runChecks(TM.get(), II, "",
143             "    Int_eh_sjlj_longjmp $r0, $r1, implicit-def $r7,"
144             " implicit-def $lr, implicit-def $sp\n",
145             16u, cmpInstSize);
146 
147   runChecks(TM.get(), II, "",
148             "    tInt_eh_sjlj_longjmp $r0, $r1, implicit-def $r7,"
149             " implicit-def $lr, implicit-def $sp\n",
150             10u, cmpInstSize);
151 
152   runChecks(TM.get(), II, "",
153             "    tInt_WIN_eh_sjlj_longjmp $r0, $r1, implicit-def $r11,"
154             " implicit-def $lr, implicit-def $sp\n",
155             12u, cmpInstSize);
156 
157   runChecks(TM.get(), II, "",
158             "    Int_eh_sjlj_setjmp $r0, $r1, implicit-def $r0,"
159             " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
160             " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
161             " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
162             " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
163             " implicit-def $lr, implicit-def $cpsr, implicit-def $q0,"
164             " implicit-def $q1, implicit-def $q2, implicit-def $q3,"
165             " implicit-def $q4, implicit-def $q5, implicit-def $q6,"
166             " implicit-def $q7, implicit-def $q8, implicit-def $q9,"
167             " implicit-def $q10, implicit-def $q11, implicit-def $q12,"
168             " implicit-def $q13, implicit-def $q14, implicit-def $q15\n"
169             "    tBX_RET 14, $noreg, implicit $r0\n",
170             20u, cmpInstSize);
171 
172   runChecks(TM.get(), II, "",
173             "    Int_eh_sjlj_setjmp_nofp $r0, $r1, implicit-def $r0,"
174             " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
175             " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
176             " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
177             " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
178             " implicit-def $lr, implicit-def $cpsr\n"
179             "    tBX_RET 14, $noreg, implicit $r0\n",
180             20u, cmpInstSize);
181 
182   runChecks(TM.get(), II, "",
183             "    tInt_eh_sjlj_setjmp $r0, $r1, implicit-def $r0,"
184             " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
185             " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
186             " implicit-def $r7, implicit-def $r12, implicit-def $cpsr\n"
187             "    tBX_RET 14, $noreg, implicit $r0\n",
188             12u, cmpInstSize);
189 
190   runChecks(TM.get(), II, "",
191             "    t2Int_eh_sjlj_setjmp $r0, $r1, implicit-def $r0,"
192             " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
193             " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
194             " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
195             " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
196             " implicit-def $lr, implicit-def $cpsr, implicit-def $q0,"
197             " implicit-def $q1, implicit-def $q2, implicit-def $q3,"
198             " implicit-def $q8, implicit-def $q9, implicit-def $q10,"
199             " implicit-def $q11, implicit-def $q12, implicit-def $q13,"
200             " implicit-def $q14, implicit-def $q15\n"
201             "    tBX_RET 14, $noreg, implicit $r0\n",
202             12u, cmpInstSize);
203 
204   runChecks(TM.get(), II, "",
205             "    t2Int_eh_sjlj_setjmp_nofp $r0, $r1, implicit-def $r0,"
206             " implicit-def $r1, implicit-def $r2, implicit-def $r3,"
207             " implicit-def $r4, implicit-def $r5, implicit-def $r6,"
208             " implicit-def $r7, implicit-def $r8, implicit-def $r9,"
209             " implicit-def $r10, implicit-def $r11, implicit-def $r12,"
210             " implicit-def $lr, implicit-def $cpsr\n"
211             "    tBX_RET 14, $noreg, implicit $r0\n",
212             12u, cmpInstSize);
213 
214   runChecks(TM.get(), II, "", "  CONSTPOOL_ENTRY 3, %const.0, 8\n", 8u,
215             cmpInstSize);
216 
217   runChecks(TM.get(), II, "", "  JUMPTABLE_ADDRS 0, %jump-table.0, 123\n", 123u,
218             cmpInstSize);
219 
220   runChecks(TM.get(), II, "", "  JUMPTABLE_INSTS 0, %jump-table.0, 456\n", 456u,
221             cmpInstSize);
222 
223   runChecks(TM.get(), II, "", "  JUMPTABLE_TBB 0, %jump-table.0, 789\n", 789u,
224             cmpInstSize);
225 
226   runChecks(TM.get(), II, "", "  JUMPTABLE_TBH 0, %jump-table.0, 188\n", 188u,
227             cmpInstSize);
228 
229   runChecks(TM.get(), II, "", "  $r0 = SPACE 40, undef $r0\n", 40u,
230             cmpInstSize);
231 
232   runChecks(TM.get(), II, "", "  INLINEASM &\"movs  r0, #42\", 1\n", 6u,
233             cmpInstSize);
234 
235   runChecks(TM.get(), II,
236             "  define void @foo() {\n"
237             "  entry:\n"
238             "    ret void\n"
239             "  }\n",
240             "  INLINEASM_BR &\"b ${0:l}\", 1, 13, blockaddress(@foo, "
241             "%ir-block.entry)\n",
242             6u, cmpInstSize);
243 }
244