blob: b74908411dafdada207cf0b944d0a6014f6f71e5 [file] [log] [blame]
NAKAMURA Takumic1857d12016-02-18 07:37:17 +00001#include "gtest/gtest.h"
Matthias Braun3199c4e2016-05-02 23:05:48 +00002#include "llvm/ADT/STLExtras.h"
3#include "llvm/CodeGen/LiveIntervalAnalysis.h"
4#include "llvm/CodeGen/MIRParser/MIRParser.h"
5#include "llvm/CodeGen/MachineFunction.h"
Matthias Braun3199c4e2016-05-02 23:05:48 +00006#include "llvm/CodeGen/MachineRegisterInfo.h"
7#include "llvm/CodeGen/Passes.h"
8#include "llvm/Support/MemoryBuffer.h"
9#include "llvm/Support/SourceMgr.h"
10#include "llvm/Support/TargetRegistry.h"
11#include "llvm/Support/TargetSelect.h"
12#include "llvm/Target/TargetMachine.h"
13#include "llvm/Target/TargetOptions.h"
14#include "llvm/Target/TargetRegisterInfo.h"
15#include "llvm/IR/LegacyPassManager.h"
NAKAMURA Takumic1857d12016-02-18 07:37:17 +000016
Matthias Braun3199c4e2016-05-02 23:05:48 +000017using namespace llvm;
18
19namespace llvm {
20 void initializeTestPassPass(PassRegistry &);
21}
22
23namespace {
24
25void initLLVM() {
26 InitializeAllTargets();
27 InitializeAllTargetMCs();
28 InitializeAllAsmPrinters();
29 InitializeAllAsmParsers();
30
31 PassRegistry *Registry = PassRegistry::getPassRegistry();
32 initializeCore(*Registry);
33 initializeCodeGen(*Registry);
34}
35
36/// Create a TargetMachine. As we lack a dedicated always available target for
37/// unittests, we go for "x86_64" which should be available in most builds.
38std::unique_ptr<TargetMachine> createTargetMachine() {
39 Triple TargetTriple("x86_64--");
40 std::string Error;
41 const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
42 if (!T)
43 return nullptr;
44
45 TargetOptions Options;
46 return std::unique_ptr<TargetMachine>(
47 T->createTargetMachine("x86_64", "", "", Options, Reloc::Default,
48 CodeModel::Default, CodeGenOpt::Aggressive));
49}
50
51std::unique_ptr<Module> parseMIR(LLVMContext &Context,
52 legacy::PassManagerBase &PM, std::unique_ptr<MIRParser> &MIR,
53 const TargetMachine &TM, StringRef MIRCode, const char *FuncName) {
54 SMDiagnostic Diagnostic;
55 std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode);
56 MIR = createMIRParser(std::move(MBuffer), Context);
57 if (!MIR)
58 return nullptr;
59
60 std::unique_ptr<Module> M = MIR->parseLLVMModule();
61 if (!M)
62 return nullptr;
63
64 M->setDataLayout(TM.createDataLayout());
65
66 Function *F = M->getFunction(FuncName);
67 if (!F)
68 return nullptr;
69
Matthias Braun47cf9182016-05-10 01:32:40 +000070 const LLVMTargetMachine &LLVMTM = static_cast<const LLVMTargetMachine&>(TM);
71 LLVMTM.addMachineModuleInfo(PM);
72 LLVMTM.addMachineFunctionAnalysis(PM, MIR.get());
Matthias Braun3199c4e2016-05-02 23:05:48 +000073
74 return M;
75}
76
77typedef std::function<void(MachineFunction&,LiveIntervals&)> LiveIntervalTest;
78
79struct TestPass : public MachineFunctionPass {
80 static char ID;
81 TestPass() : MachineFunctionPass(ID) {
82 // We should never call this but always use PM.add(new TestPass(...))
83 abort();
84 }
85 TestPass(LiveIntervalTest T) : MachineFunctionPass(ID), T(T) {
86 initializeTestPassPass(*PassRegistry::getPassRegistry());
87 }
88
89 bool runOnMachineFunction(MachineFunction &MF) override {
90 LiveIntervals &LIS = getAnalysis<LiveIntervals>();
91 T(MF, LIS);
92 EXPECT_TRUE(MF.verify(this));
93 return true;
94 }
95
96 void getAnalysisUsage(AnalysisUsage &AU) const override {
97 AU.setPreservesAll();
98 AU.addRequired<LiveIntervals>();
99 AU.addPreserved<LiveIntervals>();
100 MachineFunctionPass::getAnalysisUsage(AU);
101 }
102private:
103 LiveIntervalTest T;
104};
105
106/**
107 * Move instruction number \p From in front of instruction number \p To and
108 * update affected liveness intervals with LiveIntervalAnalysis::handleMove().
109 */
110static void testHandleMove(MachineFunction &MF, LiveIntervals &LIS,
111 unsigned From, unsigned To) {
112 MachineBasicBlock &MBB = MF.front();
113
114 unsigned I = 0;
115 MachineInstr *FromInstr = nullptr;
116 MachineInstr *ToInstr = nullptr;
117 for (MachineInstr &MI : MBB) {
118 if (I == From)
119 FromInstr = &MI;
120 if (I == To)
121 ToInstr = &MI;
122 ++I;
123 }
124 assert(FromInstr != nullptr && ToInstr != nullptr);
125
126 MBB.splice(ToInstr->getIterator(), &MBB, FromInstr->getIterator());
127 LIS.handleMove(*FromInstr, true);
128}
129
130static void liveIntervalTest(StringRef MIRFunc, LiveIntervalTest T) {
131 LLVMContext Context;
132 std::unique_ptr<TargetMachine> TM = createTargetMachine();
133 // This test is designed for the X86 backend; stop if it is not available.
134 if (!TM)
135 return;
136
137 legacy::PassManager PM;
138
139 SmallString<160> S;
140 StringRef MIRString = (Twine(
141"---\n"
142"...\n"
143"name: func\n"
144"registers:\n"
145" - { id: 0, class: gr64 }\n"
146"body: |\n"
147" bb.0:\n"
148 ) + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(S);
149 std::unique_ptr<MIRParser> MIR;
150 std::unique_ptr<Module> M = parseMIR(Context, PM, MIR, *TM, MIRString,
151 "func");
152
153 PM.add(new TestPass(T));
154
155 PM.run(*M);
156}
157
158} // End of anonymous namespace.
159
160char TestPass::ID = 0;
161INITIALIZE_PASS(TestPass, "testpass", "testpass", false, false)
162
163TEST(LiveIntervalTest, MoveUpDef) {
164 // Value defined.
165 liveIntervalTest(
166" NOOP\n"
167" NOOP\n"
168" early-clobber %0 = IMPLICIT_DEF\n"
169" RETQ %0\n",
170 [](MachineFunction &MF, LiveIntervals &LIS) {
171 testHandleMove(MF, LIS, 2, 1);
172 });
173}
174
175TEST(LiveIntervalTest, MoveUpRedef) {
176 liveIntervalTest(
177" %0 = IMPLICIT_DEF\n"
178" NOOP\n"
179" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
180" RETQ %0\n",
181 [](MachineFunction &MF, LiveIntervals &LIS) {
182 testHandleMove(MF, LIS, 2, 1);
183 });
184}
185
186TEST(LiveIntervalTest, MoveUpEarlyDef) {
187 liveIntervalTest(
188" NOOP\n"
189" NOOP\n"
190" early-clobber %0 = IMPLICIT_DEF\n"
191" RETQ %0\n",
192 [](MachineFunction &MF, LiveIntervals &LIS) {
193 testHandleMove(MF, LIS, 2, 1);
194 });
195}
196
197TEST(LiveIntervalTest, MoveUpEarlyRedef) {
198 liveIntervalTest(
199" %0 = IMPLICIT_DEF\n"
200" NOOP\n"
201" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
202" RETQ %0\n",
203 [](MachineFunction &MF, LiveIntervals &LIS) {
204 testHandleMove(MF, LIS, 2, 1);
205 });
206}
207
208TEST(LiveIntervalTest, MoveUpKill) {
209 liveIntervalTest(
210" %0 = IMPLICIT_DEF\n"
211" NOOP\n"
212" NOOP implicit %0\n",
213 [](MachineFunction &MF, LiveIntervals &LIS) {
214 testHandleMove(MF, LIS, 2, 1);
215 });
216}
217
218TEST(LiveIntervalTest, MoveUpKillFollowing) {
219 liveIntervalTest(
220" %0 = IMPLICIT_DEF\n"
221" NOOP\n"
222" NOOP implicit %0\n"
223" RETQ %0\n",
224 [](MachineFunction &MF, LiveIntervals &LIS) {
225 testHandleMove(MF, LIS, 2, 1);
226 });
227}
228
229// TODO: Construct a situation where we have intervals following a hole
230// while still having connected components.
231
232TEST(LiveIntervalTest, MoveDownDef) {
233 // Value defined.
234 liveIntervalTest(
235" NOOP\n"
236" early-clobber %0 = IMPLICIT_DEF\n"
237" NOOP\n"
238" RETQ %0\n",
239 [](MachineFunction &MF, LiveIntervals &LIS) {
240 testHandleMove(MF, LIS, 1, 2);
241 });
242}
243
244TEST(LiveIntervalTest, MoveDownRedef) {
245 liveIntervalTest(
246" %0 = IMPLICIT_DEF\n"
247" %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
248" NOOP\n"
249" RETQ %0\n",
250 [](MachineFunction &MF, LiveIntervals &LIS) {
251 testHandleMove(MF, LIS, 1, 2);
252 });
253}
254
255TEST(LiveIntervalTest, MoveDownEarlyDef) {
256 liveIntervalTest(
257" NOOP\n"
258" early-clobber %0 = IMPLICIT_DEF\n"
259" NOOP\n"
260" RETQ %0\n",
261 [](MachineFunction &MF, LiveIntervals &LIS) {
262 testHandleMove(MF, LIS, 1, 2);
263 });
264}
265
266TEST(LiveIntervalTest, MoveDownEarlyRedef) {
267 liveIntervalTest(
268" %0 = IMPLICIT_DEF\n"
269" early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)\n"
270" NOOP\n"
271" RETQ %0\n",
272 [](MachineFunction &MF, LiveIntervals &LIS) {
273 testHandleMove(MF, LIS, 1, 2);
274 });
275}
276
277TEST(LiveIntervalTest, MoveDownKill) {
278 liveIntervalTest(
279" %0 = IMPLICIT_DEF\n"
280" NOOP implicit %0\n"
281" NOOP\n",
282 [](MachineFunction &MF, LiveIntervals &LIS) {
283 testHandleMove(MF, LIS, 1, 2);
284 });
285}
286
287TEST(LiveIntervalTest, MoveDownKillFollowing) {
288 liveIntervalTest(
289" %0 = IMPLICIT_DEF\n"
290" NOOP\n"
291" NOOP implicit %0\n"
292" RETQ %0\n",
293 [](MachineFunction &MF, LiveIntervals &LIS) {
294 testHandleMove(MF, LIS, 1, 2);
295 });
296}
297
Matthias Braun71474e82016-05-06 21:47:41 +0000298TEST(LiveIntervalTest, MoveUndefUse) {
299 liveIntervalTest(
300" %0 = IMPLICIT_DEF\n"
301" NOOP implicit undef %0\n"
302" NOOP implicit %0\n"
303" NOOP\n",
304 [](MachineFunction &MF, LiveIntervals &LIS) {
305 testHandleMove(MF, LIS, 1, 3);
306 });
307}
308
Matthias Braun3199c4e2016-05-02 23:05:48 +0000309int main(int argc, char **argv) {
310 ::testing::InitGoogleTest(&argc, argv);
311 initLLVM();
312 return RUN_ALL_TESTS();
NAKAMURA Takumic1857d12016-02-18 07:37:17 +0000313}