1#include "llvm/ADT/STLExtras.h"
2#include "llvm/CodeGen/LiveIntervals.h"
3#include "llvm/CodeGen/LiveVariables.h"
4#include "llvm/CodeGen/MIRParser/MIRParser.h"
5#include "llvm/CodeGen/MachineFunction.h"
6#include "llvm/CodeGen/MachineModuleInfo.h"
7#include "llvm/CodeGen/TargetRegisterInfo.h"
8#include "llvm/CodeGen/TargetSubtargetInfo.h"
9#include "llvm/IR/LegacyPassManager.h"
10#include "llvm/InitializePasses.h"
11#include "llvm/MC/TargetRegistry.h"
12#include "llvm/Support/MemoryBuffer.h"
13#include "llvm/Support/SourceMgr.h"
14#include "llvm/Support/TargetSelect.h"
15#include "llvm/Target/TargetMachine.h"
16#include "llvm/Target/TargetOptions.h"
17#include "gtest/gtest.h"
18
19#include "../lib/CodeGen/RegisterCoalescer.h"
20
21using namespace llvm;
22
23namespace llvm {
24 void initializeTestPassPass(PassRegistry &);
25}
26
27namespace {
28
29void initLLVM() {
30 InitializeAllTargets();
31 InitializeAllTargetMCs();
32 InitializeAllAsmPrinters();
33 InitializeAllAsmParsers();
34
35 PassRegistry *Registry = PassRegistry::getPassRegistry();
36 initializeCore(*Registry);
37 initializeCodeGen(*Registry);
38}
39
40/// Create a TargetMachine. As we lack a dedicated always available target for
41/// unittests, we go for "AMDGPU" to be able to test normal and subregister
42/// liveranges.
43std::unique_ptr<LLVMTargetMachine> createTargetMachine() {
44 Triple TargetTriple("amdgcn--");
45 std::string Error;
46 const Target *T = TargetRegistry::lookupTarget(ArchName: "", TheTriple&: TargetTriple, Error);
47 if (!T)
48 return nullptr;
49
50 TargetOptions Options;
51 return std::unique_ptr<LLVMTargetMachine>(static_cast<LLVMTargetMachine *>(
52 T->createTargetMachine(TT: "AMDGPU", CPU: "gfx900", Features: "", Options, RM: std::nullopt,
53 CM: std::nullopt, OL: CodeGenOptLevel::Aggressive)));
54}
55
56std::unique_ptr<Module> parseMIR(LLVMContext &Context,
57 legacy::PassManagerBase &PM, std::unique_ptr<MIRParser> &MIR,
58 const LLVMTargetMachine &TM, StringRef MIRCode, const char *FuncName) {
59 SMDiagnostic Diagnostic;
60 std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(InputData: MIRCode);
61 MIR = createMIRParser(Contents: std::move(MBuffer), Context);
62 if (!MIR)
63 return nullptr;
64
65 std::unique_ptr<Module> M = MIR->parseIRModule();
66 if (!M)
67 return nullptr;
68
69 M->setDataLayout(TM.createDataLayout());
70
71 MachineModuleInfoWrapperPass *MMIWP = new MachineModuleInfoWrapperPass(&TM);
72 if (MIR->parseMachineFunctions(M&: *M, MMI&: MMIWP->getMMI()))
73 return nullptr;
74 PM.add(P: MMIWP);
75
76 return M;
77}
78
79struct TestPass : public MachineFunctionPass {
80 static char ID;
81 TestPass() : MachineFunctionPass(ID) {}
82};
83
84template <typename AnalysisType>
85struct TestPassT : public TestPass {
86
87 typedef std::function<void(MachineFunction&,AnalysisType&)> TestFx;
88
89 TestPassT() {
90 // We should never call this but always use PM.add(new TestPass(...))
91 abort();
92 }
93 TestPassT(TestFx T, bool ShouldPass)
94 : T(T), ShouldPass(ShouldPass) {
95 initializeTestPassPass(*PassRegistry::getPassRegistry());
96 }
97
98 bool runOnMachineFunction(MachineFunction &MF) override {
99 AnalysisType &A = getAnalysis<AnalysisType>();
100 T(MF, A);
101 EXPECT_EQ(MF.verify(this, /* Banner */ nullptr, /* AbortOnError */ false),
102 ShouldPass);
103 return true;
104 }
105
106 void getAnalysisUsage(AnalysisUsage &AU) const override {
107 AU.setPreservesAll();
108 AU.addRequired<AnalysisType>();
109 AU.addPreserved<AnalysisType>();
110 MachineFunctionPass::getAnalysisUsage(AU);
111 }
112private:
113 TestFx T;
114 bool ShouldPass;
115};
116
117static MachineInstr &getMI(MachineFunction &MF, unsigned At,
118 unsigned BlockNum) {
119 MachineBasicBlock &MBB = *MF.getBlockNumbered(N: BlockNum);
120
121 unsigned I = 0;
122 for (MachineInstr &MI : MBB) {
123 if (I == At)
124 return MI;
125 ++I;
126 }
127 llvm_unreachable("Instruction not found");
128}
129
130/**
131 * Move instruction number \p From in front of instruction number \p To and
132 * update affected liveness intervals with LiveIntervalAnalysis::handleMove().
133 */
134static void testHandleMove(MachineFunction &MF, LiveIntervals &LIS,
135 unsigned From, unsigned To, unsigned BlockNum = 0) {
136 MachineInstr &FromInstr = getMI(MF, At: From, BlockNum);
137 MachineInstr &ToInstr = getMI(MF, At: To, BlockNum);
138
139 MachineBasicBlock &MBB = *FromInstr.getParent();
140 MBB.splice(Where: ToInstr.getIterator(), Other: &MBB, From: FromInstr.getIterator());
141 LIS.handleMove(MI&: FromInstr, UpdateFlags: true);
142}
143
144/**
145 * Move instructions numbered \p From inclusive through instruction number
146 * \p To into a newly formed bundle and update affected liveness intervals
147 * with LiveIntervalAnalysis::handleMoveIntoNewBundle().
148 */
149static void testHandleMoveIntoNewBundle(MachineFunction &MF, LiveIntervals &LIS,
150 unsigned From, unsigned To,
151 unsigned BlockNum = 0) {
152 MachineInstr &FromInstr = getMI(MF, At: From, BlockNum);
153 MachineInstr &ToInstr = getMI(MF, At: To, BlockNum);
154 MachineBasicBlock &MBB = *FromInstr.getParent();
155 MachineBasicBlock::instr_iterator I = FromInstr.getIterator();
156
157 // Build bundle
158 finalizeBundle(MBB, FirstMI: I, LastMI: std::next(x: ToInstr.getIterator()));
159 MF.getProperties().reset(P: MachineFunctionProperties::Property::IsSSA);
160
161 // Update LiveIntervals
162 MachineBasicBlock::instr_iterator BundleStart = std::prev(x: I);
163 LIS.handleMoveIntoNewBundle(BundleStart&: *BundleStart, UpdateFlags: true);
164}
165
166/**
167 * Split block numbered \p BlockNum at instruction \p SplitAt using
168 * MachineBasicBlock::splitAt updating liveness intervals.
169 */
170static void testSplitAt(MachineFunction &MF, LiveIntervals &LIS,
171 unsigned SplitAt, unsigned BlockNum) {
172 MachineInstr &SplitInstr = getMI(MF, At: SplitAt, BlockNum);
173 MachineBasicBlock &MBB = *SplitInstr.getParent();
174
175 // Split block and update live intervals
176 MBB.splitAt(SplitInst&: SplitInstr, UpdateLiveIns: false, LIS: &LIS);
177}
178
179/**
180 * Helper function to test for interference between a hard register and a
181 * virtual register live ranges.
182 */
183static bool checkRegUnitInterference(LiveIntervals &LIS,
184 const TargetRegisterInfo &TRI,
185 const LiveInterval &VirtReg,
186 MCRegister PhysReg) {
187 if (VirtReg.empty())
188 return false;
189 CoalescerPair CP(VirtReg.reg(), PhysReg, TRI);
190
191 for (MCRegUnit Unit : TRI.regunits(Reg: PhysReg)) {
192 const LiveRange &UnitRange = LIS.getRegUnit(Unit);
193 if (VirtReg.overlaps(Other: UnitRange, CP, *LIS.getSlotIndexes()))
194 return true;
195 }
196 return false;
197}
198
199template <typename AnalysisType>
200static void doTest(StringRef MIRFunc,
201 typename TestPassT<AnalysisType>::TestFx T,
202 bool ShouldPass = true) {
203 LLVMContext Context;
204 std::unique_ptr<LLVMTargetMachine> TM = createTargetMachine();
205 // This test is designed for the X86 backend; stop if it is not available.
206 if (!TM)
207 return;
208
209 legacy::PassManager PM;
210 std::unique_ptr<MIRParser> MIR;
211 std::unique_ptr<Module> M = parseMIR(Context, PM, MIR, TM: *TM, MIRCode: MIRFunc, FuncName: "func");
212 ASSERT_TRUE(M);
213
214 PM.add(P: new TestPassT<AnalysisType>(T, ShouldPass));
215
216 PM.run(M&: *M);
217}
218
219static void liveIntervalTest(StringRef MIRFunc,
220 TestPassT<LiveIntervals>::TestFx T,
221 bool ShouldPass = true) {
222 SmallString<160> S;
223 StringRef MIRString = (Twine(R"MIR(
224---
225...
226name: func
227registers:
228 - { id: 0, class: sreg_64 }
229body: |
230 bb.0:
231)MIR") + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(Out&: S);
232
233 doTest<LiveIntervals>(MIRFunc: MIRString, T, ShouldPass);
234}
235
236static void liveVariablesTest(StringRef MIRFunc,
237 TestPassT<LiveVariables>::TestFx T,
238 bool ShouldPass = true) {
239 SmallString<160> S;
240 StringRef MIRString = (Twine(R"MIR(
241---
242...
243name: func
244tracksRegLiveness: true
245registers:
246 - { id: 0, class: sreg_64 }
247body: |
248 bb.0:
249)MIR") + Twine(MIRFunc) + Twine("...\n")).toNullTerminatedStringRef(Out&: S);
250 doTest<LiveVariables>(MIRFunc: MIRString, T, ShouldPass);
251}
252
253} // End of anonymous namespace.
254
255char TestPass::ID = 0;
256INITIALIZE_PASS(TestPass, "testpass", "testpass", false, false)
257
258TEST(LiveIntervalTest, MoveUpDef) {
259 // Value defined.
260 liveIntervalTest(MIRFunc: R"MIR(
261 S_NOP 0
262 S_NOP 0
263 early-clobber %0 = IMPLICIT_DEF
264 S_NOP 0, implicit %0
265)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
266 testHandleMove(MF, LIS, From: 2, To: 1);
267 });
268}
269
270TEST(LiveIntervalTest, MoveUpRedef) {
271 liveIntervalTest(MIRFunc: R"MIR(
272 %0 = IMPLICIT_DEF
273 S_NOP 0
274 %0 = IMPLICIT_DEF implicit %0(tied-def 0)
275 S_NOP 0, implicit %0
276)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
277 testHandleMove(MF, LIS, From: 2, To: 1);
278 });
279}
280
281TEST(LiveIntervalTest, MoveUpEarlyDef) {
282 liveIntervalTest(MIRFunc: R"MIR(
283 S_NOP 0
284 S_NOP 0
285 early-clobber %0 = IMPLICIT_DEF
286 S_NOP 0, implicit %0
287)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
288 testHandleMove(MF, LIS, From: 2, To: 1);
289 });
290}
291
292TEST(LiveIntervalTest, MoveUpEarlyRedef) {
293 liveIntervalTest(MIRFunc: R"MIR(
294 %0 = IMPLICIT_DEF
295 S_NOP 0
296 early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)
297 S_NOP 0, implicit %0
298)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
299 testHandleMove(MF, LIS, From: 2, To: 1);
300 });
301}
302
303TEST(LiveIntervalTest, MoveUpKill) {
304 liveIntervalTest(MIRFunc: R"MIR(
305 %0 = IMPLICIT_DEF
306 S_NOP 0
307 S_NOP 0, implicit %0
308)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
309 testHandleMove(MF, LIS, From: 2, To: 1);
310 });
311}
312
313TEST(LiveIntervalTest, MoveUpKillFollowing) {
314 liveIntervalTest(MIRFunc: R"MIR(
315 %0 = IMPLICIT_DEF
316 S_NOP 0
317 S_NOP 0, implicit %0
318 S_NOP 0, implicit %0
319)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
320 testHandleMove(MF, LIS, From: 2, To: 1);
321 });
322}
323
324// TODO: Construct a situation where we have intervals following a hole
325// while still having connected components.
326
327TEST(LiveIntervalTest, MoveDownDef) {
328 // Value defined.
329 liveIntervalTest(MIRFunc: R"MIR(
330 S_NOP 0
331 early-clobber %0 = IMPLICIT_DEF
332 S_NOP 0
333 S_NOP 0, implicit %0
334)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
335 testHandleMove(MF, LIS, From: 1, To: 2);
336 });
337}
338
339TEST(LiveIntervalTest, MoveDownRedef) {
340 liveIntervalTest(MIRFunc: R"MIR(
341 %0 = IMPLICIT_DEF
342 %0 = IMPLICIT_DEF implicit %0(tied-def 0)
343 S_NOP 0
344 S_NOP 0, implicit %0
345)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
346 testHandleMove(MF, LIS, From: 1, To: 2);
347 });
348}
349
350TEST(LiveIntervalTest, MoveDownEarlyDef) {
351 liveIntervalTest(MIRFunc: R"MIR(
352 S_NOP 0
353 early-clobber %0 = IMPLICIT_DEF
354 S_NOP 0
355 S_NOP 0, implicit %0
356)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
357 testHandleMove(MF, LIS, From: 1, To: 2);
358 });
359}
360
361TEST(LiveIntervalTest, MoveDownEarlyRedef) {
362 liveIntervalTest(MIRFunc: R"MIR(
363 %0 = IMPLICIT_DEF
364 early-clobber %0 = IMPLICIT_DEF implicit %0(tied-def 0)
365 S_NOP 0
366 S_NOP 0, implicit %0
367)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
368 testHandleMove(MF, LIS, From: 1, To: 2);
369 });
370}
371
372TEST(LiveIntervalTest, MoveDownKill) {
373 liveIntervalTest(MIRFunc: R"MIR(
374 %0 = IMPLICIT_DEF
375 S_NOP 0, implicit %0
376 S_NOP 0
377)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
378 testHandleMove(MF, LIS, From: 1, To: 2);
379 });
380}
381
382TEST(LiveIntervalTest, MoveDownKillFollowing) {
383 liveIntervalTest(MIRFunc: R"MIR(
384 %0 = IMPLICIT_DEF
385 S_NOP 0
386 S_NOP 0, implicit %0
387 S_NOP 0, implicit %0
388)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
389 testHandleMove(MF, LIS, From: 1, To: 2);
390 });
391}
392
393TEST(LiveIntervalTest, MoveUndefUse) {
394 liveIntervalTest(MIRFunc: R"MIR(
395 %0 = IMPLICIT_DEF
396 S_NOP 0, implicit undef %0
397 S_NOP 0, implicit %0
398 S_NOP 0
399)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
400 testHandleMove(MF, LIS, From: 1, To: 3);
401 });
402}
403
404TEST(LiveIntervalTest, MoveUpValNos) {
405 // handleMoveUp() had a bug where it would reuse the value number of the
406 // destination segment, even though we have no guarantee that this valno
407 // wasn't used in other segments.
408 liveIntervalTest(MIRFunc: R"MIR(
409 successors: %bb.1, %bb.2
410 %0 = IMPLICIT_DEF
411 S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc
412 S_BRANCH %bb.1
413 bb.2:
414 S_NOP 0, implicit %0
415 bb.1:
416 successors: %bb.2
417 %0 = IMPLICIT_DEF implicit %0(tied-def 0)
418 %0 = IMPLICIT_DEF implicit %0(tied-def 0)
419 %0 = IMPLICIT_DEF implicit %0(tied-def 0)
420 S_BRANCH %bb.2
421)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
422 testHandleMove(MF, LIS, From: 2, To: 0, BlockNum: 2);
423 });
424}
425
426TEST(LiveIntervalTest, MoveOverUndefUse0) {
427 // findLastUseBefore() used by handleMoveUp() must ignore undef operands.
428 liveIntervalTest(MIRFunc: R"MIR(
429 %0 = IMPLICIT_DEF
430 S_NOP 0
431 S_NOP 0, implicit undef %0
432 %0 = IMPLICIT_DEF implicit %0(tied-def 0)
433)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
434 testHandleMove(MF, LIS, From: 3, To: 1);
435 });
436}
437
438TEST(LiveIntervalTest, MoveOverUndefUse1) {
439 // findLastUseBefore() used by handleMoveUp() must ignore undef operands.
440 liveIntervalTest(MIRFunc: R"MIR(
441 $sgpr0 = IMPLICIT_DEF
442 S_NOP 0
443 S_NOP 0, implicit undef $sgpr0
444 $sgpr0 = IMPLICIT_DEF implicit $sgpr0(tied-def 0)
445)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
446 testHandleMove(MF, LIS, From: 3, To: 1);
447 });
448}
449
450TEST(LiveIntervalTest, SubRegMoveDown) {
451 // Subregister ranges can have holes inside a basic block. Check for a
452 // movement of the form 32->150 in a liverange [16, 32) [100,200).
453 liveIntervalTest(MIRFunc: R"MIR(
454 successors: %bb.1, %bb.2
455 %0 = IMPLICIT_DEF
456 S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc
457 S_BRANCH %bb.1
458 bb.2:
459 successors: %bb.1
460 S_NOP 0, implicit %0.sub0
461 S_NOP 0, implicit %0.sub1
462 S_NOP 0
463 undef %0.sub0 = IMPLICIT_DEF
464 %0.sub1 = IMPLICIT_DEF
465 bb.1:
466 S_NOP 0, implicit %0
467)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
468 // Scheduler behaviour: Clear def,read-undef flag and move.
469 MachineInstr &MI = getMI(MF, At: 3, /*BlockNum=*/1);
470 MI.getOperand(i: 0).setIsUndef(false);
471 testHandleMove(MF, LIS, From: 1, To: 4, /*BlockNum=*/1);
472 });
473}
474
475TEST(LiveIntervalTest, SubRegMoveUp) {
476 // handleMoveUp had a bug not updating valno of segment incoming to bb.2
477 // after swapping subreg definitions.
478 liveIntervalTest(MIRFunc: R"MIR(
479 successors: %bb.1, %bb.2
480 undef %0.sub0 = IMPLICIT_DEF
481 %0.sub1 = IMPLICIT_DEF
482 S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc
483 S_BRANCH %bb.1
484 bb.1:
485 S_NOP 0, implicit %0.sub1
486 bb.2:
487 S_NOP 0, implicit %0.sub1
488)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
489 testHandleMove(MF, LIS, From: 1, To: 0);
490 });
491}
492
493TEST(LiveIntervalTest, DeadSubRegMoveUp) {
494 // handleMoveUp had a bug where moving a dead subreg def into the middle of
495 // an earlier segment resulted in an invalid live range.
496 liveIntervalTest(MIRFunc: R"MIR(
497 undef %125.sub0:vreg_128 = V_MOV_B32_e32 0, implicit $exec
498 %125.sub1:vreg_128 = COPY %125.sub0
499 %125.sub2:vreg_128 = COPY %125.sub0
500 undef %51.sub0:vreg_128 = V_MOV_B32_e32 898625526, implicit $exec
501 %51.sub1:vreg_128 = COPY %51.sub0
502 %51.sub2:vreg_128 = COPY %51.sub0
503 %52:vgpr_32 = V_MOV_B32_e32 986714345, implicit $exec
504 %54:vgpr_32 = V_MOV_B32_e32 1742342378, implicit $exec
505 %57:vgpr_32 = V_MOV_B32_e32 3168768712, implicit $exec
506 %59:vgpr_32 = V_MOV_B32_e32 1039972644, implicit $exec
507 %60:vgpr_32 = nofpexcept V_MAD_F32_e64 0, %52, 0, undef %61:vgpr_32, 0, %59, 0, 0, implicit $mode, implicit $exec
508 %63:vgpr_32 = nofpexcept V_ADD_F32_e32 %51.sub3, undef %64:vgpr_32, implicit $mode, implicit $exec
509 dead %66:vgpr_32 = nofpexcept V_MAD_F32_e64 0, %60, 0, undef %67:vgpr_32, 0, %125.sub2, 0, 0, implicit $mode, implicit $exec
510 undef %124.sub1:vreg_128 = nofpexcept V_MAD_F32_e64 0, %57, 0, undef %70:vgpr_32, 0, %125.sub1, 0, 0, implicit $mode, implicit $exec
511 %124.sub0:vreg_128 = nofpexcept V_MAD_F32_e64 0, %54, 0, undef %73:vgpr_32, 0, %125.sub0, 0, 0, implicit $mode, implicit $exec
512 dead undef %125.sub3:vreg_128 = nofpexcept V_MAC_F32_e32 %63, undef %76:vgpr_32, %125.sub3, implicit $mode, implicit $exec
513)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
514 testHandleMove(MF, LIS, From: 15, To: 12);
515 });
516}
517
518TEST(LiveIntervalTest, EarlyClobberSubRegMoveUp) {
519 // handleMoveUp had a bug where moving an early-clobber subreg def into the
520 // middle of an earlier segment resulted in an invalid live range.
521 liveIntervalTest(MIRFunc: R"MIR(
522 %4:sreg_32 = IMPLICIT_DEF
523 %6:sreg_32 = IMPLICIT_DEF
524 undef early-clobber %9.sub0:sreg_64 = STRICT_WWM %4:sreg_32, implicit $exec
525 %5:sreg_32 = S_FLBIT_I32_B32 %9.sub0:sreg_64
526 early-clobber %9.sub1:sreg_64 = STRICT_WWM %6:sreg_32, implicit $exec
527 %7:sreg_32 = S_FLBIT_I32_B32 %9.sub1:sreg_64
528)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
529 testHandleMove(MF, LIS, From: 4, To: 3);
530 });
531}
532
533TEST(LiveIntervalTest, TestMoveSubRegDefAcrossUseDef) {
534 liveIntervalTest(MIRFunc: R"MIR(
535 %1:vreg_64 = IMPLICIT_DEF
536
537 bb.1:
538 %2:vgpr_32 = V_MOV_B32_e32 2, implicit $exec
539 %3:vgpr_32 = V_ADD_U32_e32 %2, %1.sub0, implicit $exec
540 undef %1.sub0:vreg_64 = V_ADD_U32_e32 %2, %2, implicit $exec
541 %1.sub1:vreg_64 = COPY %2
542 S_NOP 0, implicit %1.sub1
543 S_BRANCH %bb.1
544
545)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
546 MachineInstr &UndefSubregDef = getMI(MF, At: 2, BlockNum: 1);
547 // The scheduler clears undef from subregister defs before moving
548 UndefSubregDef.getOperand(i: 0).setIsUndef(false);
549 testHandleMove(MF, LIS, From: 3, To: 1, BlockNum: 1);
550 });
551}
552
553TEST(LiveIntervalTest, TestMoveSubRegDefAcrossUseDefMulti) {
554 liveIntervalTest(MIRFunc: R"MIR(
555 %1:vreg_96 = IMPLICIT_DEF
556
557 bb.1:
558 %2:vgpr_32 = V_MOV_B32_e32 2, implicit $exec
559 %3:vgpr_32 = V_ADD_U32_e32 %2, %1.sub0, implicit $exec
560 undef %1.sub0:vreg_96 = V_ADD_U32_e32 %2, %2, implicit $exec
561 %1.sub1:vreg_96 = COPY %2
562 %1.sub2:vreg_96 = COPY %2
563 S_NOP 0, implicit %1.sub1, implicit %1.sub2
564 S_BRANCH %bb.1
565
566)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
567 MachineInstr &UndefSubregDef = getMI(MF, At: 2, BlockNum: 1);
568 // The scheduler clears undef from subregister defs before moving
569 UndefSubregDef.getOperand(i: 0).setIsUndef(false);
570 testHandleMove(MF, LIS, From: 4, To: 1, BlockNum: 1);
571 });
572}
573
574TEST(LiveIntervalTest, TestMoveSubRegUseAcrossMainRangeHole) {
575 liveIntervalTest(MIRFunc: R"MIR(
576 %1:sgpr_128 = IMPLICIT_DEF
577 bb.1:
578 %2:sgpr_32 = COPY %1.sub2
579 %3:sgpr_32 = COPY %1.sub1
580 %1.sub2 = COPY %2
581 undef %1.sub0 = IMPLICIT_DEF
582 %1.sub2 = IMPLICIT_DEF
583 S_CBRANCH_SCC1 %bb.1, implicit undef $scc
584 S_BRANCH %bb.2
585 bb.2:
586)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
587 MachineInstr &MI = getMI(MF, At: 3, /*BlockNum=*/1);
588 MI.getOperand(i: 0).setIsUndef(false);
589 testHandleMove(MF, LIS, From: 4, To: 3, BlockNum: 1);
590 testHandleMove(MF, LIS, From: 1, To: 4, BlockNum: 1);
591 });
592}
593
594TEST(LiveIntervalTest, TestMoveSubRegsOfOneReg) {
595 liveIntervalTest(MIRFunc: R"MIR(
596 INLINEASM &"", 0, 1835018, def undef %4.sub0:vreg_64, 1835018, def undef %4.sub1:vreg_64
597 %1:vreg_64 = COPY %4
598 undef %2.sub0:vreg_64 = V_MOV_B32_e32 0, implicit $exec
599 %2.sub1:vreg_64 = COPY %2.sub0
600 %3:vreg_64 = COPY %2
601)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
602 testHandleMove(MF, LIS, From: 1, To: 4);
603 testHandleMove(MF, LIS, From: 0, To: 3);
604 });
605}
606
607TEST(LiveIntervalTest, BundleUse) {
608 liveIntervalTest(MIRFunc: R"MIR(
609 %0 = IMPLICIT_DEF
610 S_NOP 0
611 S_NOP 0, implicit %0
612 S_NOP 0
613)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
614 testHandleMoveIntoNewBundle(MF, LIS, From: 1, To: 2);
615 });
616}
617
618TEST(LiveIntervalTest, BundleDef) {
619 liveIntervalTest(MIRFunc: R"MIR(
620 %0 = IMPLICIT_DEF
621 S_NOP 0
622 S_NOP 0, implicit %0
623 S_NOP 0
624)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
625 testHandleMoveIntoNewBundle(MF, LIS, From: 0, To: 1);
626 });
627}
628
629TEST(LiveIntervalTest, BundleRedef) {
630 liveIntervalTest(MIRFunc: R"MIR(
631 %0 = IMPLICIT_DEF
632 S_NOP 0
633 %0 = IMPLICIT_DEF implicit %0(tied-def 0)
634 S_NOP 0, implicit %0
635)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
636 testHandleMoveIntoNewBundle(MF, LIS, From: 1, To: 2);
637 });
638}
639
640TEST(LiveIntervalTest, BundleInternalUse) {
641 liveIntervalTest(MIRFunc: R"MIR(
642 %0 = IMPLICIT_DEF
643 S_NOP 0
644 S_NOP 0, implicit %0
645 S_NOP 0
646)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
647 testHandleMoveIntoNewBundle(MF, LIS, From: 0, To: 2);
648 });
649}
650
651TEST(LiveIntervalTest, BundleUndefUse) {
652 liveIntervalTest(MIRFunc: R"MIR(
653 %0 = IMPLICIT_DEF
654 S_NOP 0
655 S_NOP 0, implicit undef %0
656 S_NOP 0
657)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
658 testHandleMoveIntoNewBundle(MF, LIS, From: 1, To: 2);
659 });
660}
661
662TEST(LiveIntervalTest, BundleSubRegUse) {
663 liveIntervalTest(MIRFunc: R"MIR(
664 successors: %bb.1, %bb.2
665 undef %0.sub0 = IMPLICIT_DEF
666 %0.sub1 = IMPLICIT_DEF
667 S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc
668 S_BRANCH %bb.1
669 bb.1:
670 S_NOP 0
671 S_NOP 0, implicit %0.sub1
672 bb.2:
673 S_NOP 0, implicit %0.sub1
674)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
675 testHandleMoveIntoNewBundle(MF, LIS, From: 0, To: 1, BlockNum: 1);
676 });
677}
678
679TEST(LiveIntervalTest, BundleSubRegDef) {
680 liveIntervalTest(MIRFunc: R"MIR(
681 successors: %bb.1, %bb.2
682 undef %0.sub0 = IMPLICIT_DEF
683 %0.sub1 = IMPLICIT_DEF
684 S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc
685 S_BRANCH %bb.1
686 bb.1:
687 S_NOP 0
688 S_NOP 0, implicit %0.sub1
689 bb.2:
690 S_NOP 0, implicit %0.sub1
691)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
692 testHandleMoveIntoNewBundle(MF, LIS, From: 0, To: 1, BlockNum: 0);
693 });
694}
695
696TEST(LiveIntervalTest, SplitAtOneInstruction) {
697 liveIntervalTest(MIRFunc: R"MIR(
698 successors: %bb.1
699 %0 = IMPLICIT_DEF
700 S_BRANCH %bb.1
701 bb.1:
702 S_NOP 0
703)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
704 testSplitAt(MF, LIS, SplitAt: 1, BlockNum: 0);
705 });
706}
707
708TEST(LiveIntervalTest, SplitAtMultiInstruction) {
709 liveIntervalTest(MIRFunc: R"MIR(
710 successors: %bb.1
711 %0 = IMPLICIT_DEF
712 S_NOP 0
713 S_NOP 0
714 S_NOP 0
715 S_NOP 0
716 S_BRANCH %bb.1
717 bb.1:
718 S_NOP 0
719)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
720 testSplitAt(MF, LIS, SplitAt: 0, BlockNum: 0);
721 });
722}
723
724TEST(LiveIntervalTest, RepairIntervals) {
725 liveIntervalTest(MIRFunc: R"MIR(
726 %1:sgpr_32 = IMPLICIT_DEF
727 dead %2:sgpr_32 = COPY undef %3.sub0:sgpr_128
728 undef %4.sub2:sgpr_128 = COPY %1:sgpr_32
729 %5:sgpr_32 = COPY %4.sub2:sgpr_128
730)MIR", T: [](MachineFunction &MF, LiveIntervals &LIS) {
731 MachineInstr &Instr1 = getMI(MF, At: 1, BlockNum: 0);
732 MachineInstr &Instr2 = getMI(MF, At: 2, BlockNum: 0);
733 MachineInstr &Instr3 = getMI(MF, At: 3, BlockNum: 0);
734 LIS.RemoveMachineInstrFromMaps(MI&: Instr2);
735 MachineBasicBlock *MBB = Instr1.getParent();
736 SmallVector<Register> OrigRegs{
737 Instr1.getOperand(i: 0).getReg(),
738 Instr2.getOperand(i: 0).getReg(),
739 Instr2.getOperand(i: 1).getReg(),
740 };
741 LIS.repairIntervalsInRange(MBB, Begin: Instr2, End: Instr3, OrigRegs);
742 });
743}
744
745TEST(LiveIntervalTest, AdjacentIntervals) {
746 liveIntervalTest(
747 MIRFunc: R"MIR(
748 successors: %bb.1, %bb.2
749
750 $vgpr1 = IMPLICIT_DEF
751 S_NOP 0, implicit $vgpr1
752 %1:vgpr_32 = IMPLICIT_DEF
753 %2:vgpr_32 = IMPLICIT_DEF
754 S_CBRANCH_VCCNZ %bb.2, implicit undef $vcc
755 S_BRANCH %bb.1
756 bb.1:
757 $vgpr0, dead renamable $vcc = V_ADD_CO_U32_e64 %1, %2, 0, implicit $exec
758 S_NOP 0, implicit $vgpr0
759 S_BRANCH %bb.3
760 bb.2:
761 $vgpr0 = IMPLICIT_DEF
762 $vgpr1, dead renamable $vcc = V_ADD_CO_U32_e64 %1, %2, 0, implicit $exec
763 S_NOP 0, implicit $vgpr0, implicit $vgpr1
764 S_BRANCH %bb.3
765 bb.3:
766)MIR",
767 T: [](MachineFunction &MF, LiveIntervals &LIS) {
768 const auto &R1 =
769 LIS.getInterval(Reg: getMI(MF, At: 2, BlockNum: 0).getOperand(i: 0).getReg());
770 const auto &R2 =
771 LIS.getInterval(Reg: getMI(MF, At: 3, BlockNum: 0).getOperand(i: 0).getReg());
772 MCRegister V1 = getMI(MF, At: 1, BlockNum: 2).getOperand(i: 0).getReg().asMCReg();
773
774 ASSERT_FALSE(checkRegUnitInterference(
775 LIS, *MF.getSubtarget().getRegisterInfo(), R1, V1));
776 ASSERT_FALSE(checkRegUnitInterference(
777 LIS, *MF.getSubtarget().getRegisterInfo(), R2, V1));
778 });
779}
780
781TEST(LiveIntervalTest, LiveThroughSegments) {
782 liveIntervalTest(
783 MIRFunc: R"MIR(
784 %0 = IMPLICIT_DEF
785 S_BRANCH %bb.2
786 bb.1:
787 S_NOP 0, implicit %0
788 S_ENDPGM 0
789 bb.2:
790 S_BRANCH %bb.1
791)MIR",
792 T: [](MachineFunction &MF, LiveIntervals &LIS) {
793 MachineInstr &ImpDef = getMI(MF, At: 0, BlockNum: 0);
794 MachineInstr &Nop = getMI(MF, At: 0, BlockNum: 1);
795 LiveInterval &LI = LIS.getInterval(Reg: ImpDef.getOperand(i: 0).getReg());
796 SlotIndex OrigIdx = LIS.getInstructionIndex(Instr: ImpDef).getRegSlot();
797 LiveInterval::iterator FirstSeg = LI.FindSegmentContaining(Idx: OrigIdx);
798
799 // %0 is live through bb.2. Move its def into bb.1 and update LIS but do
800 // not remove the segment for bb.2. This should cause machine
801 // verification to fail.
802 LIS.RemoveMachineInstrFromMaps(MI&: ImpDef);
803 ImpDef.moveBefore(MovePos: &Nop);
804 LIS.InsertMachineInstrInMaps(MI&: ImpDef);
805
806 SlotIndex NewIdx = LIS.getInstructionIndex(Instr: ImpDef).getRegSlot();
807 FirstSeg->start = NewIdx;
808 FirstSeg->valno->def = NewIdx;
809 },
810 ShouldPass: false);
811}
812
813TEST(LiveVariablesTest, recomputeForSingleDefVirtReg_handle_undef1) {
814 liveVariablesTest(MIRFunc: R"MIR(
815 %0 = IMPLICIT_DEF
816 S_NOP 0, implicit %0
817 S_NOP 0, implicit undef %0
818)MIR", T: [](MachineFunction &MF, LiveVariables &LV) {
819 auto &FirstNop = getMI(MF, At: 1, BlockNum: 0);
820 auto &SecondNop = getMI(MF, At: 2, BlockNum: 0);
821 EXPECT_TRUE(FirstNop.getOperand(1).isKill());
822 EXPECT_FALSE(SecondNop.getOperand(1).isKill());
823
824 Register R = Register::index2VirtReg(Index: 0);
825 LV.recomputeForSingleDefVirtReg(Reg: R);
826
827 EXPECT_TRUE(FirstNop.getOperand(1).isKill());
828 EXPECT_FALSE(SecondNop.getOperand(1).isKill());
829 });
830}
831
832TEST(LiveVariablesTest, recomputeForSingleDefVirtReg_handle_undef2) {
833 liveVariablesTest(MIRFunc: R"MIR(
834 %0 = IMPLICIT_DEF
835 S_NOP 0, implicit %0
836 S_NOP 0, implicit undef %0, implicit %0
837)MIR", T: [](MachineFunction &MF, LiveVariables &LV) {
838 auto &FirstNop = getMI(MF, At: 1, BlockNum: 0);
839 auto &SecondNop = getMI(MF, At: 2, BlockNum: 0);
840 EXPECT_FALSE(FirstNop.getOperand(1).isKill());
841 EXPECT_FALSE(SecondNop.getOperand(1).isKill());
842 EXPECT_TRUE(SecondNop.getOperand(2).isKill());
843
844 Register R = Register::index2VirtReg(Index: 0);
845 LV.recomputeForSingleDefVirtReg(Reg: R);
846
847 EXPECT_FALSE(FirstNop.getOperand(1).isKill());
848 EXPECT_FALSE(SecondNop.getOperand(1).isKill());
849 EXPECT_TRUE(SecondNop.getOperand(2).isKill());
850 });
851}
852
853int main(int argc, char **argv) {
854 ::testing::InitGoogleTest(argc: &argc, argv);
855 initLLVM();
856 return RUN_ALL_TESTS();
857}
858

source code of llvm/unittests/MI/LiveIntervalTest.cpp