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