[clang][modules] Don't prevent translation of FW_Private includes when explicitly...
[llvm-project.git] / llvm / unittests / CodeGen / InstrRefLDVTest.cpp
blob5a050bc520362c2a5e786289e6efee1f63f25ddb
1 //===------------- llvm/unittest/CodeGen/InstrRefLDVTest.cpp --------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
9 #include "llvm/CodeGen/MIRParser/MIRParser.h"
10 #include "llvm/CodeGen/MachineDominators.h"
11 #include "llvm/CodeGen/MachineModuleInfo.h"
12 #include "llvm/CodeGen/TargetFrameLowering.h"
13 #include "llvm/CodeGen/TargetInstrInfo.h"
14 #include "llvm/CodeGen/TargetLowering.h"
15 #include "llvm/CodeGen/TargetRegisterInfo.h"
16 #include "llvm/CodeGen/TargetSubtargetInfo.h"
17 #include "llvm/IR/DIBuilder.h"
18 #include "llvm/IR/DebugInfoMetadata.h"
19 #include "llvm/IR/IRBuilder.h"
20 #include "llvm/MC/TargetRegistry.h"
21 #include "llvm/Support/MemoryBuffer.h"
22 #include "llvm/Support/TargetSelect.h"
23 #include "llvm/Target/TargetMachine.h"
24 #include "llvm/Target/TargetOptions.h"
26 #include "../lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h"
28 #include "gtest/gtest.h"
30 using namespace llvm;
31 using namespace LiveDebugValues;
33 // Include helper functions to ease the manipulation of MachineFunctions
34 #include "MFCommon.inc"
36 class InstrRefLDVTest : public testing::Test {
37 public:
38 friend class InstrRefBasedLDV;
39 using MLocTransferMap = InstrRefBasedLDV::MLocTransferMap;
41 LLVMContext Ctx;
42 std::unique_ptr<Module> Mod;
43 std::unique_ptr<TargetMachine> Machine;
44 std::unique_ptr<MachineFunction> MF;
45 std::unique_ptr<MachineDominatorTree> DomTree;
46 std::unique_ptr<MachineModuleInfo> MMI;
47 DICompileUnit *OurCU;
48 DIFile *OurFile;
49 DISubprogram *OurFunc;
50 DILexicalBlock *OurBlock, *AnotherBlock;
51 DISubprogram *ToInlineFunc;
52 DILexicalBlock *ToInlineBlock;
53 DILocalVariable *FuncVariable;
54 DIBasicType *LongInt;
55 DIExpression *EmptyExpr;
56 LiveDebugValues::OverlapMap Overlaps;
58 DebugLoc OutermostLoc, InBlockLoc, NotNestedBlockLoc, InlinedLoc;
60 MachineBasicBlock *MBB0, *MBB1, *MBB2, *MBB3, *MBB4;
62 std::unique_ptr<InstrRefBasedLDV> LDV;
63 std::unique_ptr<MLocTracker> MTracker;
64 std::unique_ptr<VLocTracker> VTracker;
66 SmallString<256> MIRStr;
68 InstrRefLDVTest() : Ctx(), Mod(std::make_unique<Module>("beehives", Ctx)) {}
70 void SetUp() {
71 // Boilerplate that creates a MachineFunction and associated blocks.
73 Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-"
74 "f80:128-n8:16:32:64-S128");
75 Triple TargetTriple("x86_64--");
76 std::string Error;
77 const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
78 if (!T)
79 GTEST_SKIP();
81 TargetOptions Options;
82 Machine = std::unique_ptr<TargetMachine>(T->createTargetMachine(
83 Triple::normalize("x86_64--"), "", "", Options, std::nullopt,
84 std::nullopt, CodeGenOptLevel::Aggressive));
86 auto Type = FunctionType::get(Type::getVoidTy(Ctx), false);
87 auto F =
88 Function::Create(Type, GlobalValue::ExternalLinkage, "Test", &*Mod);
90 unsigned FunctionNum = 42;
91 MMI = std::make_unique<MachineModuleInfo>((LLVMTargetMachine *)&*Machine);
92 const TargetSubtargetInfo &STI = *Machine->getSubtargetImpl(*F);
94 MF = std::make_unique<MachineFunction>(*F, (LLVMTargetMachine &)*Machine,
95 STI, FunctionNum, *MMI);
97 // Create metadata: CU, subprogram, some blocks and an inline function
98 // scope.
99 DIBuilder DIB(*Mod);
100 OurFile = DIB.createFile("xyzzy.c", "/cave");
101 OurCU =
102 DIB.createCompileUnit(dwarf::DW_LANG_C99, OurFile, "nou", false, "", 0);
103 auto OurSubT =
104 DIB.createSubroutineType(DIB.getOrCreateTypeArray(std::nullopt));
105 OurFunc =
106 DIB.createFunction(OurCU, "bees", "", OurFile, 1, OurSubT, 1,
107 DINode::FlagZero, DISubprogram::SPFlagDefinition);
108 F->setSubprogram(OurFunc);
109 OurBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 3);
110 AnotherBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 6);
111 ToInlineFunc =
112 DIB.createFunction(OurFile, "shoes", "", OurFile, 10, OurSubT, 10,
113 DINode::FlagZero, DISubprogram::SPFlagDefinition);
115 // Make some nested scopes.
116 OutermostLoc = DILocation::get(Ctx, 3, 1, OurFunc);
117 InBlockLoc = DILocation::get(Ctx, 4, 1, OurBlock);
118 InlinedLoc = DILocation::get(Ctx, 10, 1, ToInlineFunc, InBlockLoc.get());
120 // Make a scope that isn't nested within the others.
121 NotNestedBlockLoc = DILocation::get(Ctx, 4, 1, AnotherBlock);
123 LongInt = DIB.createBasicType("long", 64, llvm::dwarf::DW_ATE_unsigned);
124 FuncVariable = DIB.createAutoVariable(OurFunc, "lala", OurFile, 1, LongInt);
125 EmptyExpr = DIExpression::get(Ctx, {});
127 DIB.finalize();
130 Register getRegByName(const char *WantedName) {
131 auto *TRI = MF->getRegInfo().getTargetRegisterInfo();
132 // Slow, but works.
133 for (unsigned int I = 1; I < TRI->getNumRegs(); ++I) {
134 const char *Name = TRI->getName(I);
135 if (strcmp(WantedName, Name) == 0)
136 return I;
139 // If this ever fails, something is very wrong with this unit test.
140 llvm_unreachable("Can't find register by name");
143 InstrRefBasedLDV *setupLDVObj(MachineFunction *MF) {
144 // Create a new LDV object, and plug some relevant object ptrs into it.
145 LDV = std::make_unique<InstrRefBasedLDV>();
146 const TargetSubtargetInfo &STI = MF->getSubtarget();
147 LDV->TII = STI.getInstrInfo();
148 LDV->TRI = STI.getRegisterInfo();
149 LDV->TFI = STI.getFrameLowering();
150 LDV->MFI = &MF->getFrameInfo();
151 LDV->MRI = &MF->getRegInfo();
153 DomTree = std::make_unique<MachineDominatorTree>(*MF);
154 LDV->DomTree = &*DomTree;
156 // Future work: unit tests for mtracker / vtracker / ttracker.
158 // Setup things like the artifical block map, and BlockNo <=> RPO Order
159 // mappings.
160 LDV->initialSetup(*MF);
161 LDV->LS.initialize(*MF);
162 addMTracker(MF);
163 return &*LDV;
166 void addMTracker(MachineFunction *MF) {
167 ASSERT_TRUE(LDV);
168 // Add a machine-location-tracking object to LDV. Don't initialize any
169 // register locations within it though.
170 const TargetSubtargetInfo &STI = MF->getSubtarget();
171 MTracker = std::make_unique<MLocTracker>(
172 *MF, *LDV->TII, *LDV->TRI, *STI.getTargetLowering());
173 LDV->MTracker = &*MTracker;
176 void addVTracker() {
177 ASSERT_TRUE(LDV);
178 VTracker = std::make_unique<VLocTracker>(Overlaps, EmptyExpr);
179 LDV->VTracker = &*VTracker;
182 DbgOpID addValueDbgOp(ValueIDNum V) {
183 return LDV->DbgOpStore.insert(DbgOp(V));
185 DbgOpID addConstDbgOp(MachineOperand MO) {
186 return LDV->DbgOpStore.insert(DbgOp(MO));
189 // Some routines for bouncing into LDV,
190 void buildMLocValueMap(FuncValueTable &MInLocs, FuncValueTable &MOutLocs,
191 SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
192 LDV->buildMLocValueMap(*MF, MInLocs, MOutLocs, MLocTransfer);
195 void placeMLocPHIs(MachineFunction &MF,
196 SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks,
197 FuncValueTable &MInLocs,
198 SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
199 LDV->placeMLocPHIs(MF, AllBlocks, MInLocs, MLocTransfer);
202 bool
203 pickVPHILoc(SmallVectorImpl<DbgOpID> &OutValues, const MachineBasicBlock &MBB,
204 const InstrRefBasedLDV::LiveIdxT &LiveOuts,
205 FuncValueTable &MOutLocs,
206 const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
207 return LDV->pickVPHILoc(OutValues, MBB, LiveOuts, MOutLocs, BlockOrders);
210 bool vlocJoin(MachineBasicBlock &MBB, InstrRefBasedLDV::LiveIdxT &VLOCOutLocs,
211 SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore,
212 DbgValue &InLoc) {
213 return LDV->vlocJoin(MBB, VLOCOutLocs, BlocksToExplore, InLoc);
216 void buildVLocValueMap(const DILocation *DILoc,
217 const SmallSet<DebugVariable, 4> &VarsWeCareAbout,
218 SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks,
219 InstrRefBasedLDV::LiveInsT &Output, FuncValueTable &MOutLocs,
220 FuncValueTable &MInLocs,
221 SmallVectorImpl<VLocTracker> &AllTheVLocs) {
222 LDV->buildVLocValueMap(DILoc, VarsWeCareAbout, AssignBlocks, Output,
223 MOutLocs, MInLocs, AllTheVLocs);
226 void initValueArray(FuncValueTable &Nums, unsigned Blks, unsigned Locs) {
227 for (unsigned int I = 0; I < Blks; ++I)
228 for (unsigned int J = 0; J < Locs; ++J)
229 Nums[I][J] = ValueIDNum::EmptyValue;
232 void setupSingleBlock() {
233 // Add an entry block with nothing but 'ret void' in it.
234 Function &F = const_cast<llvm::Function &>(MF->getFunction());
235 auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
236 IRBuilder<> IRB(BB0);
237 IRB.CreateRetVoid();
238 MBB0 = MF->CreateMachineBasicBlock(BB0);
239 MF->insert(MF->end(), MBB0);
240 MF->RenumberBlocks();
242 setupLDVObj(&*MF);
245 void setupDiamondBlocks() {
246 // entry
247 // / \
248 // br1 br2
249 // \ /
250 // ret
251 llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
252 auto *BB0 = BasicBlock::Create(Ctx, "a", &F);
253 auto *BB1 = BasicBlock::Create(Ctx, "b", &F);
254 auto *BB2 = BasicBlock::Create(Ctx, "c", &F);
255 auto *BB3 = BasicBlock::Create(Ctx, "d", &F);
256 IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3);
257 IRB0.CreateBr(BB1);
258 IRB1.CreateBr(BB2);
259 IRB2.CreateBr(BB3);
260 IRB3.CreateRetVoid();
261 MBB0 = MF->CreateMachineBasicBlock(BB0);
262 MF->insert(MF->end(), MBB0);
263 MBB1 = MF->CreateMachineBasicBlock(BB1);
264 MF->insert(MF->end(), MBB1);
265 MBB2 = MF->CreateMachineBasicBlock(BB2);
266 MF->insert(MF->end(), MBB2);
267 MBB3 = MF->CreateMachineBasicBlock(BB3);
268 MF->insert(MF->end(), MBB3);
269 MBB0->addSuccessor(MBB1);
270 MBB0->addSuccessor(MBB2);
271 MBB1->addSuccessor(MBB3);
272 MBB2->addSuccessor(MBB3);
273 MF->RenumberBlocks();
275 setupLDVObj(&*MF);
278 void setupSimpleLoop() {
279 // entry
280 // |
281 // |/-----\
282 // loopblk |
283 // |\-----/
284 // |
285 // ret
286 llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
287 auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
288 auto *BB1 = BasicBlock::Create(Ctx, "loop", &F);
289 auto *BB2 = BasicBlock::Create(Ctx, "ret", &F);
290 IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2);
291 IRB0.CreateBr(BB1);
292 IRB1.CreateBr(BB2);
293 IRB2.CreateRetVoid();
294 MBB0 = MF->CreateMachineBasicBlock(BB0);
295 MF->insert(MF->end(), MBB0);
296 MBB1 = MF->CreateMachineBasicBlock(BB1);
297 MF->insert(MF->end(), MBB1);
298 MBB2 = MF->CreateMachineBasicBlock(BB2);
299 MF->insert(MF->end(), MBB2);
300 MBB0->addSuccessor(MBB1);
301 MBB1->addSuccessor(MBB2);
302 MBB1->addSuccessor(MBB1);
303 MF->RenumberBlocks();
305 setupLDVObj(&*MF);
308 void setupNestedLoops() {
309 // entry
310 // |
311 // loop1
312 // ^\
313 // | \ /-\
314 // | loop2 |
315 // | / \-/
316 // ^ /
317 // join
318 // |
319 // ret
320 llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
321 auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
322 auto *BB1 = BasicBlock::Create(Ctx, "loop1", &F);
323 auto *BB2 = BasicBlock::Create(Ctx, "loop2", &F);
324 auto *BB3 = BasicBlock::Create(Ctx, "join", &F);
325 auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
326 IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
327 IRB0.CreateBr(BB1);
328 IRB1.CreateBr(BB2);
329 IRB2.CreateBr(BB3);
330 IRB3.CreateBr(BB4);
331 IRB4.CreateRetVoid();
332 MBB0 = MF->CreateMachineBasicBlock(BB0);
333 MF->insert(MF->end(), MBB0);
334 MBB1 = MF->CreateMachineBasicBlock(BB1);
335 MF->insert(MF->end(), MBB1);
336 MBB2 = MF->CreateMachineBasicBlock(BB2);
337 MF->insert(MF->end(), MBB2);
338 MBB3 = MF->CreateMachineBasicBlock(BB3);
339 MF->insert(MF->end(), MBB3);
340 MBB4 = MF->CreateMachineBasicBlock(BB4);
341 MF->insert(MF->end(), MBB4);
342 MBB0->addSuccessor(MBB1);
343 MBB1->addSuccessor(MBB2);
344 MBB2->addSuccessor(MBB2);
345 MBB2->addSuccessor(MBB3);
346 MBB3->addSuccessor(MBB1);
347 MBB3->addSuccessor(MBB4);
348 MF->RenumberBlocks();
350 setupLDVObj(&*MF);
353 void setupNoDominatingLoop() {
354 // entry
355 // / \
356 // / \
357 // / \
358 // head1 head2
359 // ^ \ / ^
360 // ^ \ / ^
361 // \-joinblk -/
362 // |
363 // ret
364 llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
365 auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
366 auto *BB1 = BasicBlock::Create(Ctx, "head1", &F);
367 auto *BB2 = BasicBlock::Create(Ctx, "head2", &F);
368 auto *BB3 = BasicBlock::Create(Ctx, "joinblk", &F);
369 auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
370 IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
371 IRB0.CreateBr(BB1);
372 IRB1.CreateBr(BB2);
373 IRB2.CreateBr(BB3);
374 IRB3.CreateBr(BB4);
375 IRB4.CreateRetVoid();
376 MBB0 = MF->CreateMachineBasicBlock(BB0);
377 MF->insert(MF->end(), MBB0);
378 MBB1 = MF->CreateMachineBasicBlock(BB1);
379 MF->insert(MF->end(), MBB1);
380 MBB2 = MF->CreateMachineBasicBlock(BB2);
381 MF->insert(MF->end(), MBB2);
382 MBB3 = MF->CreateMachineBasicBlock(BB3);
383 MF->insert(MF->end(), MBB3);
384 MBB4 = MF->CreateMachineBasicBlock(BB4);
385 MF->insert(MF->end(), MBB4);
386 MBB0->addSuccessor(MBB1);
387 MBB0->addSuccessor(MBB2);
388 MBB1->addSuccessor(MBB3);
389 MBB2->addSuccessor(MBB3);
390 MBB3->addSuccessor(MBB1);
391 MBB3->addSuccessor(MBB2);
392 MBB3->addSuccessor(MBB4);
393 MF->RenumberBlocks();
395 setupLDVObj(&*MF);
398 void setupBadlyNestedLoops() {
399 // entry
400 // |
401 // loop1 -o
402 // | ^
403 // | ^
404 // loop2 -o
405 // | ^
406 // | ^
407 // loop3 -o
408 // |
409 // ret
411 // NB: the loop blocks self-loop, which is a bit too fiddly to draw on
412 // accurately.
413 llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
414 auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
415 auto *BB1 = BasicBlock::Create(Ctx, "loop1", &F);
416 auto *BB2 = BasicBlock::Create(Ctx, "loop2", &F);
417 auto *BB3 = BasicBlock::Create(Ctx, "loop3", &F);
418 auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
419 IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
420 IRB0.CreateBr(BB1);
421 IRB1.CreateBr(BB2);
422 IRB2.CreateBr(BB3);
423 IRB3.CreateBr(BB4);
424 IRB4.CreateRetVoid();
425 MBB0 = MF->CreateMachineBasicBlock(BB0);
426 MF->insert(MF->end(), MBB0);
427 MBB1 = MF->CreateMachineBasicBlock(BB1);
428 MF->insert(MF->end(), MBB1);
429 MBB2 = MF->CreateMachineBasicBlock(BB2);
430 MF->insert(MF->end(), MBB2);
431 MBB3 = MF->CreateMachineBasicBlock(BB3);
432 MF->insert(MF->end(), MBB3);
433 MBB4 = MF->CreateMachineBasicBlock(BB4);
434 MF->insert(MF->end(), MBB4);
435 MBB0->addSuccessor(MBB1);
436 MBB1->addSuccessor(MBB1);
437 MBB1->addSuccessor(MBB2);
438 MBB2->addSuccessor(MBB1);
439 MBB2->addSuccessor(MBB2);
440 MBB2->addSuccessor(MBB3);
441 MBB3->addSuccessor(MBB2);
442 MBB3->addSuccessor(MBB3);
443 MBB3->addSuccessor(MBB4);
444 MF->RenumberBlocks();
446 setupLDVObj(&*MF);
449 MachineFunction *readMIRBlock(const char *Input) {
450 MIRStr.clear();
451 StringRef S = Twine(Twine(R"MIR(
452 --- |
453 target triple = "x86_64-unknown-linux-gnu"
454 define void @test() { ret void }
457 name: test
458 tracksRegLiveness: true
459 stack:
460 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
461 stack-id: default, callee-saved-register: '', callee-saved-restored: true,
462 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
463 body: |
464 bb.0:
465 liveins: $rdi, $rsi
466 )MIR") + Twine(Input) + Twine("...\n"))
467 .toNullTerminatedStringRef(MIRStr);
470 // Clear the "test" function from MMI if it's still present.
471 if (Function *Fn = Mod->getFunction("test"))
472 MMI->deleteMachineFunctionFor(*Fn);
474 auto MemBuf = MemoryBuffer::getMemBuffer(S, "<input>");
475 auto MIRParse = createMIRParser(std::move(MemBuf), Ctx);
476 Mod = MIRParse->parseIRModule();
477 assert(Mod);
478 Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-"
479 "f80:128-n8:16:32:64-S128");
481 bool Result = MIRParse->parseMachineFunctions(*Mod, *MMI);
482 assert(!Result && "Failed to parse unit test machine function?");
483 (void)Result;
485 Function *Fn = Mod->getFunction("test");
486 assert(Fn && "Failed to parse a unit test module string?");
487 Fn->setSubprogram(OurFunc);
488 return MMI->getMachineFunction(*Fn);
491 void
492 produceMLocTransferFunction(MachineFunction &MF,
493 SmallVectorImpl<MLocTransferMap> &MLocTransfer,
494 unsigned MaxNumBlocks) {
495 LDV->produceMLocTransferFunction(MF, MLocTransfer, MaxNumBlocks);
498 std::pair<FuncValueTable, FuncValueTable>
499 allocValueTables(unsigned Blocks, unsigned Locs) {
500 FuncValueTable MOutLocs = std::make_unique<ValueTable[]>(Blocks);
501 FuncValueTable MInLocs = std::make_unique<ValueTable[]>(Blocks);
503 for (unsigned int I = 0; I < Blocks; ++I) {
504 MOutLocs[I] = std::make_unique<ValueIDNum[]>(Locs);
505 MInLocs[I] = std::make_unique<ValueIDNum[]>(Locs);
508 return std::make_pair(std::move(MOutLocs), std::move(MInLocs));
512 TEST_F(InstrRefLDVTest, MTransferDefs) {
513 MachineFunction *MF = readMIRBlock(
514 " $rax = MOV64ri 0\n"
515 " RET64 $rax\n");
516 setupLDVObj(MF);
518 // We should start with only SP tracked.
519 EXPECT_TRUE(MTracker->getNumLocs() == 1);
521 SmallVector<MLocTransferMap, 1> TransferMap;
522 TransferMap.resize(1);
523 produceMLocTransferFunction(*MF, TransferMap, 1);
525 // Code contains only one register write: that should assign to each of the
526 // aliasing registers. Test that all of them get locations, and have a
527 // corresponding def at the first instr in the function.
528 const char *RegNames[] = {"RAX", "HAX", "EAX", "AX", "AH", "AL"};
529 EXPECT_TRUE(MTracker->getNumLocs() == 7);
530 for (const char *RegName : RegNames) {
531 Register R = getRegByName(RegName);
532 ASSERT_TRUE(MTracker->isRegisterTracked(R));
533 LocIdx L = MTracker->getRegMLoc(R);
534 ValueIDNum V = MTracker->readReg(R);
535 // Value of this register should be: block zero, instruction 1, and the
536 // location it's defined in is itself.
537 ValueIDNum ToCmp(0, 1, L);
538 EXPECT_EQ(V, ToCmp);
541 // Do the same again, but with an aliasing write. This should write to all
542 // the same registers again, except $ah and $hax (the upper 8 bits of $ax
543 // and 32 bits of $rax resp.).
544 MF = readMIRBlock(
545 " $rax = MOV64ri 0\n"
546 " $al = MOV8ri 0\n"
547 " RET64 $rax\n");
548 setupLDVObj(MF);
549 TransferMap.clear();
550 TransferMap.resize(1);
551 produceMLocTransferFunction(*MF, TransferMap, 1);
553 auto TestRegSetSite = [&](const char *Name, unsigned InstrNum) {
554 Register R = getRegByName(Name);
555 ASSERT_TRUE(MTracker->isRegisterTracked(R));
556 LocIdx L = MTracker->getRegMLoc(R);
557 ValueIDNum V = MTracker->readMLoc(L);
558 ValueIDNum ToCmp(0, InstrNum, L);
559 EXPECT_EQ(V, ToCmp);
562 TestRegSetSite("AL", 2);
563 TestRegSetSite("AH", 1);
564 TestRegSetSite("AX", 2);
565 TestRegSetSite("EAX", 2);
566 TestRegSetSite("HAX", 1);
567 TestRegSetSite("RAX", 2);
569 // This call should:
570 // * Def rax via the implicit-def,
571 // * Clobber rsi/rdi and all their subregs, via the register mask
572 // * Same for rcx, despite it not being a use in the instr, it's in the mask
573 // * NOT clobber $rsp / $esp $ sp, LiveDebugValues deliberately ignores
574 // these.
575 // * NOT clobber $rbx, because it's non-volatile
576 // * Not track every other register in the machine, only those needed.
577 MF = readMIRBlock(
578 " $rax = MOV64ri 0\n" // instr 1
579 " $rbx = MOV64ri 0\n" // instr 2
580 " $rcx = MOV64ri 0\n" // instr 3
581 " $rdi = MOV64ri 0\n" // instr 4
582 " $rsi = MOV64ri 0\n" // instr 5
583 " CALL64r $rax, csr_64, implicit $rsp, implicit $ssp, implicit $rdi, implicit $rsi, implicit-def $rsp, implicit-def $ssp, implicit-def $rax, implicit-def $esp, implicit-def $sp\n\n\n\n" // instr 6
584 " RET64 $rax\n"); // instr 7
585 setupLDVObj(MF);
586 TransferMap.clear();
587 TransferMap.resize(1);
588 produceMLocTransferFunction(*MF, TransferMap, 1);
590 const char *RegsSetInCall[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX",
591 "DIL", "DIH", "DI", "EDI", "HDI", "RDI",
592 "SIL", "SIH", "SI", "ESI", "HSI", "RSI",
593 "CL", "CH", "CX", "ECX", "HCX", "RCX"};
594 for (const char *RegSetInCall : RegsSetInCall)
595 TestRegSetSite(RegSetInCall, 6);
597 const char *RegsLeftAlone[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
598 for (const char *RegLeftAlone : RegsLeftAlone)
599 TestRegSetSite(RegLeftAlone, 2);
601 // Stack pointer should be the live-in to the function, instruction zero.
602 TestRegSetSite("RSP", 0);
603 // These stack regs should not be tracked either. Nor the (fake) subregs.
604 EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("ESP")));
605 EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SP")));
606 EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPL")));
607 EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPH")));
608 EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("HSP")));
610 // Should only be tracking: 6 x {A, B, C, DI, SI} registers = 30,
611 // Plus RSP, SSP = 32.
612 EXPECT_EQ(32u, MTracker->getNumLocs());
615 // When we DBG_PHI something, we should track all its subregs.
616 MF = readMIRBlock(
617 " DBG_PHI $rdi, 0\n"
618 " RET64\n");
619 setupLDVObj(MF);
620 TransferMap.clear();
621 TransferMap.resize(1);
622 produceMLocTransferFunction(*MF, TransferMap, 1);
624 // All DI regs and RSP tracked.
625 EXPECT_EQ(7u, MTracker->getNumLocs());
627 // All the DI registers should have block live-in values, i.e. the argument
628 // to the function.
629 const char *DIRegs[] = {"DIL", "DIH", "DI", "EDI", "HDI", "RDI"};
630 for (const char *DIReg : DIRegs)
631 TestRegSetSite(DIReg, 0);
634 TEST_F(InstrRefLDVTest, MTransferMeta) {
635 // Meta instructions should not have any effect on register values.
636 SmallVector<MLocTransferMap, 1> TransferMap;
637 MachineFunction *MF = readMIRBlock(
638 " $rax = MOV64ri 0\n"
639 " $rax = IMPLICIT_DEF\n"
640 " $rax = KILL killed $rax\n"
641 " RET64 $rax\n");
642 setupLDVObj(MF);
643 TransferMap.clear();
644 TransferMap.resize(1);
645 produceMLocTransferFunction(*MF, TransferMap, 1);
647 LocIdx RaxLoc = MTracker->getRegMLoc(getRegByName("RAX"));
648 ValueIDNum V = MTracker->readMLoc(RaxLoc);
649 // Def of rax should be from instruction 1, i.e., unmodified.
650 ValueIDNum Cmp(0, 1, RaxLoc);
651 EXPECT_EQ(Cmp, V);
654 TEST_F(InstrRefLDVTest, MTransferCopies) {
655 SmallVector<MLocTransferMap, 1> TransferMap;
656 // This memory spill should be recognised, and a spill slot created.
657 MachineFunction *MF = readMIRBlock(
658 " $rax = MOV64ri 0\n"
659 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
660 " RET64 $rax\n");
661 setupLDVObj(MF);
662 TransferMap.clear();
663 TransferMap.resize(1);
664 produceMLocTransferFunction(*MF, TransferMap, 1);
666 // Check that the spill location contains the value defined in rax by
667 // instruction 1. The MIR header says -16 offset, but it's stored as -8;
668 // it's not completely clear why, but here we only care about correctly
669 // identifying the slot, not that all the surrounding data is correct.
670 SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
671 SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
672 unsigned SpillLocID = MTracker->getLocID(SpillNo, {64, 0});
673 LocIdx SpillLoc = MTracker->getSpillMLoc(SpillLocID);
674 ValueIDNum V = MTracker->readMLoc(SpillLoc);
675 Register RAX = getRegByName("RAX");
676 LocIdx RaxLoc = MTracker->getRegMLoc(RAX);
677 ValueIDNum Cmp(0, 1, RaxLoc);
678 EXPECT_EQ(V, Cmp);
680 // A spill and restore should be recognised.
681 MF = readMIRBlock(
682 " $rax = MOV64ri 0\n"
683 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
684 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
685 " RET64\n");
686 setupLDVObj(MF);
687 TransferMap.clear();
688 TransferMap.resize(1);
689 produceMLocTransferFunction(*MF, TransferMap, 1);
691 // Test that rbx contains rax from instruction 1.
692 RAX = getRegByName("RAX");
693 RaxLoc = MTracker->getRegMLoc(RAX);
694 Register RBX = getRegByName("RBX");
695 LocIdx RbxLoc = MTracker->getRegMLoc(RBX);
696 Cmp = ValueIDNum(0, 1, RaxLoc);
697 ValueIDNum RbxVal = MTracker->readMLoc(RbxLoc);
698 EXPECT_EQ(RbxVal, Cmp);
700 // Testing that all the subregisters are transferred happens in
701 // MTransferSubregSpills.
703 // Copies and x86 movs should be recognised and honoured. In addition, all
704 // of the subregisters should be copied across too.
705 MF = readMIRBlock(
706 " $rax = MOV64ri 0\n"
707 " $rcx = COPY $rax\n"
708 " $rbx = MOV64rr $rcx\n"
709 " RET64\n");
710 setupLDVObj(MF);
711 TransferMap.clear();
712 TransferMap.resize(1);
713 produceMLocTransferFunction(*MF, TransferMap, 1);
715 const char *ARegs[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
716 const char *BRegs[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
717 const char *CRegs[] = {"CL", "CH", "CX", "ECX", "HCX", "RCX"};
718 auto CheckReg = [&](unsigned int I) {
719 LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
720 LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
721 LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
722 ValueIDNum ARefVal(0, 1, A);
723 ValueIDNum AVal = MTracker->readMLoc(A);
724 ValueIDNum BVal = MTracker->readMLoc(B);
725 ValueIDNum CVal = MTracker->readMLoc(C);
726 EXPECT_EQ(ARefVal, AVal);
727 EXPECT_EQ(ARefVal, BVal);
728 EXPECT_EQ(ARefVal, CVal);
731 for (unsigned int I = 0; I < 6; ++I)
732 CheckReg(I);
734 // When we copy to a subregister, the super-register should be def'd too: it's
735 // value will have changed.
736 MF = readMIRBlock(
737 " $rax = MOV64ri 0\n"
738 " $ecx = COPY $eax\n"
739 " RET64\n");
740 setupLDVObj(MF);
741 TransferMap.clear();
742 TransferMap.resize(1);
743 produceMLocTransferFunction(*MF, TransferMap, 1);
745 // First four regs [al, ah, ax, eax] should be copied to *cx.
746 for (unsigned int I = 0; I < 4; ++I) {
747 LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
748 LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
749 ValueIDNum ARefVal(0, 1, A);
750 ValueIDNum AVal = MTracker->readMLoc(A);
751 ValueIDNum CVal = MTracker->readMLoc(C);
752 EXPECT_EQ(ARefVal, AVal);
753 EXPECT_EQ(ARefVal, CVal);
756 // But rcx should contain a value defined by the COPY.
757 LocIdx RcxLoc = MTracker->getRegMLoc(getRegByName("RCX"));
758 ValueIDNum RcxVal = MTracker->readMLoc(RcxLoc);
759 ValueIDNum RcxDefVal(0, 2, RcxLoc); // instr 2 -> the copy
760 EXPECT_EQ(RcxVal, RcxDefVal);
763 TEST_F(InstrRefLDVTest, MTransferSubregSpills) {
764 SmallVector<MLocTransferMap, 1> TransferMap;
765 MachineFunction *MF = readMIRBlock(
766 " $rax = MOV64ri 0\n"
767 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
768 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
769 " RET64\n");
770 setupLDVObj(MF);
771 TransferMap.clear();
772 TransferMap.resize(1);
773 produceMLocTransferFunction(*MF, TransferMap, 1);
775 // Check that all the subregs of rax and rbx contain the same values. One
776 // should completely transfer to the other.
777 const char *ARegs[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
778 const char *BRegs[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
779 for (unsigned int I = 0; I < 6; ++I) {
780 LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
781 LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
782 EXPECT_EQ(MTracker->readMLoc(A), MTracker->readMLoc(B));
785 // Explicitly check what's in the different subreg slots, on the stack.
786 // Pair up subreg idx fields with the corresponding subregister in $rax.
787 MLocTracker::StackSlotPos SubRegIdxes[] = {{8, 0}, {8, 8}, {16, 0}, {32, 0}, {64, 0}};
788 const char *SubRegNames[] = {"AL", "AH", "AX", "EAX", "RAX"};
789 for (unsigned int I = 0; I < 5; ++I) {
790 // Value number where it's defined,
791 LocIdx RegLoc = MTracker->getRegMLoc(getRegByName(SubRegNames[I]));
792 ValueIDNum DefNum(0, 1, RegLoc);
793 // Read the corresponding subreg field from the stack.
794 SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
795 SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
796 unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
797 LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
798 ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
799 EXPECT_EQ(DefNum, SpillValue);
802 // If we have exactly the same code, but we write $eax to the stack slot after
803 // $rax, then we should still have exactly the same output in the lower five
804 // subregisters. Storing $eax to the start of the slot will overwrite with the
805 // same values. $rax, as an aliasing register, should be reset to something
806 // else by that write.
807 // In theory, we could try and recognise that we're writing the _same_ values
808 // to the stack again, and so $rax doesn't need to be reset to something else.
809 // It seems vanishingly unlikely that LLVM would generate such code though,
810 // so the benefits would be small.
811 MF = readMIRBlock(
812 " $rax = MOV64ri 0\n"
813 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
814 " MOV32mr $rsp, 1, $noreg, 16, $noreg, $eax :: (store 4 into %stack.0)\n"
815 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
816 " RET64\n");
817 setupLDVObj(MF);
818 TransferMap.clear();
819 TransferMap.resize(1);
820 produceMLocTransferFunction(*MF, TransferMap, 1);
822 // Check lower five registers up to and include $eax == $ebx,
823 for (unsigned int I = 0; I < 5; ++I) {
824 LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
825 LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
826 EXPECT_EQ(MTracker->readMLoc(A), MTracker->readMLoc(B));
829 // $rbx should contain something else; today it's a def at the spill point
830 // of the 4 byte value.
831 SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
832 SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
833 unsigned SpillID = MTracker->getLocID(SpillNo, {64, 0});
834 LocIdx Spill64Loc = MTracker->getSpillMLoc(SpillID);
835 ValueIDNum DefAtSpill64(0, 3, Spill64Loc);
836 LocIdx RbxLoc = MTracker->getRegMLoc(getRegByName("RBX"));
837 EXPECT_EQ(MTracker->readMLoc(RbxLoc), DefAtSpill64);
839 // Same again, test that the lower four subreg slots on the stack are the
840 // value defined by $rax in instruction 1.
841 for (unsigned int I = 0; I < 4; ++I) {
842 // Value number where it's defined,
843 LocIdx RegLoc = MTracker->getRegMLoc(getRegByName(SubRegNames[I]));
844 ValueIDNum DefNum(0, 1, RegLoc);
845 // Read the corresponding subreg field from the stack.
846 SpillNo = *MTracker->getOrTrackSpillLoc(L);
847 SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
848 LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
849 ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
850 EXPECT_EQ(DefNum, SpillValue);
853 // Stack slot for $rax should be a different value, today it's EmptyValue.
854 ValueIDNum SpillValue = MTracker->readMLoc(Spill64Loc);
855 EXPECT_EQ(SpillValue, DefAtSpill64);
857 // If we write something to the stack, then over-write with some register
858 // from a completely different hierarchy, none of the "old" values should be
859 // readable.
860 // NB: slight hack, store 16 in to a 8 byte stack slot.
861 MF = readMIRBlock(
862 " $rax = MOV64ri 0\n"
863 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
864 " $xmm0 = IMPLICIT_DEF\n"
865 " MOVUPDmr $rsp, 1, $noreg, 16, $noreg, killed $xmm0 :: (store (s128) into %stack.0)\n"
866 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
867 " RET64\n");
868 setupLDVObj(MF);
869 TransferMap.clear();
870 TransferMap.resize(1);
871 produceMLocTransferFunction(*MF, TransferMap, 1);
873 for (unsigned int I = 0; I < 5; ++I) {
874 // Read subreg fields from the stack.
875 SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
876 unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
877 LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
878 ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
880 // Value should be defined by the spill-to-xmm0 instr, get value of a def
881 // at the point of the spill.
882 ValueIDNum SpillDef(0, 4, SpillLoc);
883 EXPECT_EQ(SpillValue, SpillDef);
886 // Read xmm0's position and ensure it has a value. Should be the live-in
887 // value to the block, as IMPLICIT_DEF isn't a real def.
888 SpillNo = *MTracker->getOrTrackSpillLoc(L);
889 SpillID = MTracker->getLocID(SpillNo, {128, 0});
890 LocIdx Spill128Loc = MTracker->getSpillMLoc(SpillID);
891 SpillValue = MTracker->readMLoc(Spill128Loc);
892 Register XMM0 = getRegByName("XMM0");
893 LocIdx Xmm0Loc = MTracker->getRegMLoc(XMM0);
894 EXPECT_EQ(ValueIDNum(0, 0, Xmm0Loc), SpillValue);
896 // What happens if we spill ah to the stack, then load al? It should find
897 // the same value.
898 MF = readMIRBlock(
899 " $rax = MOV64ri 0\n"
900 " MOV8mr $rsp, 1, $noreg, 16, $noreg, $ah :: (store 1 into %stack.0)\n"
901 " $al = MOV8rm $rsp, 1, $noreg, 0, $noreg :: (load 1 from %stack.0)\n"
902 " RET64\n");
903 setupLDVObj(MF);
904 TransferMap.clear();
905 TransferMap.resize(1);
906 produceMLocTransferFunction(*MF, TransferMap, 1);
908 Register AL = getRegByName("AL");
909 Register AH = getRegByName("AH");
910 LocIdx AlLoc = MTracker->getRegMLoc(AL);
911 LocIdx AhLoc = MTracker->getRegMLoc(AH);
912 ValueIDNum AHDef(0, 1, AhLoc);
913 ValueIDNum ALValue = MTracker->readMLoc(AlLoc);
914 EXPECT_EQ(ALValue, AHDef);
917 TEST_F(InstrRefLDVTest, MLocSingleBlock) {
918 // Test some very simple properties about interpreting the transfer function.
919 setupSingleBlock();
921 // We should start with a single location, the stack pointer.
922 ASSERT_TRUE(MTracker->getNumLocs() == 1);
923 LocIdx RspLoc(0);
925 // Set up live-in and live-out tables for this function: two locations (we
926 // add one later) in a single block.
927 FuncValueTable MOutLocs, MInLocs;
928 std::tie(MOutLocs, MInLocs) = allocValueTables(1, 2);
930 // Transfer function: nothing.
931 SmallVector<MLocTransferMap, 1> TransferFunc;
932 TransferFunc.resize(1);
934 // Try and build value maps...
935 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
937 // The result should be that RSP is marked as a live-in-PHI -- this represents
938 // an argument. And as there's no transfer function, the block live-out should
939 // be the same.
940 EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
941 EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
943 // Try again, this time initialising the in-locs to be defined by an
944 // instruction. The entry block should always be re-assigned to be the
945 // arguments.
946 initValueArray(MInLocs, 1, 2);
947 initValueArray(MOutLocs, 1, 2);
948 MInLocs[0][0] = ValueIDNum(0, 1, RspLoc);
949 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
950 EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
951 EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
953 // Now insert something into the transfer function to assign to the single
954 // machine location.
955 TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
956 initValueArray(MInLocs, 1, 2);
957 initValueArray(MOutLocs, 1, 2);
958 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
959 EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
960 EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
961 TransferFunc[0].clear();
963 // Add a new register to be tracked, and insert it into the transfer function
964 // as a copy. The output of $rax should be the live-in value of $rsp.
965 Register RAX = getRegByName("RAX");
966 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
967 TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
968 TransferFunc[0].insert({RaxLoc, ValueIDNum(0, 0, RspLoc)});
969 initValueArray(MInLocs, 1, 2);
970 initValueArray(MOutLocs, 1, 2);
971 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
972 EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
973 EXPECT_EQ(MInLocs[0][1], ValueIDNum(0, 0, RaxLoc));
974 EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
975 EXPECT_EQ(MOutLocs[0][1], ValueIDNum(0, 0, RspLoc)); // Rax contains RspLoc.
976 TransferFunc[0].clear();
979 TEST_F(InstrRefLDVTest, MLocDiamondBlocks) {
980 // Test that information flows from the entry block to two successors.
981 // entry
982 // / \
983 // br1 br2
984 // \ /
985 // ret
986 setupDiamondBlocks();
988 ASSERT_TRUE(MTracker->getNumLocs() == 1);
989 LocIdx RspLoc(0);
990 Register RAX = getRegByName("RAX");
991 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
993 FuncValueTable MInLocs, MOutLocs;
994 std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
996 // Transfer function: start with nothing.
997 SmallVector<MLocTransferMap, 1> TransferFunc;
998 TransferFunc.resize(4);
1000 // Name some values.
1001 unsigned EntryBlk = 0, BrBlk1 = 1, BrBlk2 = 2, RetBlk = 3;
1003 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1004 ValueIDNum RspDefInBlk0(EntryBlk, 1, RspLoc);
1005 ValueIDNum RspDefInBlk1(BrBlk1, 1, RspLoc);
1006 ValueIDNum RspDefInBlk2(BrBlk2, 1, RspLoc);
1007 ValueIDNum RspPHIInBlk3(RetBlk, 0, RspLoc);
1008 ValueIDNum RaxLiveInBlk1(BrBlk1, 0, RaxLoc);
1009 ValueIDNum RaxLiveInBlk2(BrBlk2, 0, RaxLoc);
1011 // With no transfer function, the live-in values to the entry block should
1012 // propagate to all live-outs and the live-ins to the two successor blocks.
1013 // IN ADDITION: this checks that the exit block doesn't get a PHI put in it.
1014 initValueArray(MInLocs, 4, 2);
1015 initValueArray(MOutLocs, 4, 2);
1016 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1017 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1018 EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1019 EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1020 EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1021 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1022 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1023 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1024 EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1025 // (Skipped writing out locations for $rax).
1027 // Check that a def of $rsp in the entry block will likewise reach all the
1028 // successors.
1029 TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1030 initValueArray(MInLocs, 4, 2);
1031 initValueArray(MOutLocs, 4, 2);
1032 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1033 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1034 EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1035 EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1036 EXPECT_EQ(MInLocs[3][0], RspDefInBlk0);
1037 EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1038 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk0);
1039 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk0);
1040 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk0);
1041 TransferFunc[0].clear();
1043 // Def in one branch of the diamond means that we need a PHI in the ret block
1044 TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1045 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1046 initValueArray(MInLocs, 4, 2);
1047 initValueArray(MOutLocs, 4, 2);
1048 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1049 // This value map: like above, where RspDefInBlk0 is propagated through one
1050 // branch of the diamond, but is def'ed in the live-outs of the other. The
1051 // ret / merging block should have a PHI in its live-ins.
1052 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1053 EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1054 EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1055 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1056 EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1057 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1058 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk0);
1059 EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1060 TransferFunc[0].clear();
1061 TransferFunc[1].clear();
1063 // If we have differeing defs in either side of the diamond, we should
1064 // continue to produce a PHI,
1065 TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1066 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1067 TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1068 initValueArray(MInLocs, 4, 2);
1069 initValueArray(MOutLocs, 4, 2);
1070 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1071 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1072 EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1073 EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1074 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1075 EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1076 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1077 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1078 EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1079 TransferFunc[0].clear();
1080 TransferFunc[1].clear();
1081 TransferFunc[2].clear();
1083 // If we have defs of the same value on either side of the branch, a PHI will
1084 // initially be created, however value propagation should then eliminate it.
1085 // Encode this by copying the live-in value to $rax, and copying it to $rsp
1086 // from $rax in each branch of the diamond. We don't allow the definition of
1087 // arbitary values in transfer functions.
1088 TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1089 TransferFunc[0].insert({RaxLoc, LiveInRsp});
1090 TransferFunc[1].insert({RspLoc, RaxLiveInBlk1});
1091 TransferFunc[2].insert({RspLoc, RaxLiveInBlk2});
1092 initValueArray(MInLocs, 4, 2);
1093 initValueArray(MOutLocs, 4, 2);
1094 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1095 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1096 EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1097 EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1098 EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1099 EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1100 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1101 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1102 EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1103 TransferFunc[0].clear();
1104 TransferFunc[1].clear();
1105 TransferFunc[2].clear();
1108 TEST_F(InstrRefLDVTest, MLocDiamondSpills) {
1109 // Test that defs in stack locations that require PHIs, cause PHIs to be
1110 // installed in aliasing locations. i.e., if there's a PHI in the lower
1111 // 8 bits of the stack, there should be PHIs for 16/32/64 bit locations
1112 // on the stack too.
1113 // Technically this isn't needed for accuracy: we should calculate PHIs
1114 // independently for each location. However, because there's an optimisation
1115 // that only places PHIs for the lower "interfering" parts of stack slots,
1116 // test for this behaviour.
1117 setupDiamondBlocks();
1119 ASSERT_TRUE(MTracker->getNumLocs() == 1);
1120 LocIdx RspLoc(0);
1122 // Create a stack location and ensure it's tracked.
1123 SpillLoc SL = {getRegByName("RSP"), StackOffset::getFixed(-8)};
1124 SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(SL);
1125 ASSERT_EQ(MTracker->getNumLocs(), 11u); // Tracks all possible stack locs.
1126 // Locations are: RSP, stack slots from 2^3 bits wide up to 2^9 for zmm regs,
1127 // then slots for sub_8bit_hi and sub_16bit_hi ({8, 8} and {16, 16}).
1128 // Finally, one for spilt fp80 registers.
1130 // Pick out the locations on the stack that various x86 regs would be written
1131 // to. HAX is the upper 16 bits of EAX.
1132 unsigned ALID = MTracker->getLocID(SpillNo, {8, 0});
1133 unsigned AHID = MTracker->getLocID(SpillNo, {8, 8});
1134 unsigned AXID = MTracker->getLocID(SpillNo, {16, 0});
1135 unsigned EAXID = MTracker->getLocID(SpillNo, {32, 0});
1136 unsigned HAXID = MTracker->getLocID(SpillNo, {16, 16});
1137 unsigned RAXID = MTracker->getLocID(SpillNo, {64, 0});
1138 LocIdx ALStackLoc = MTracker->getSpillMLoc(ALID);
1139 LocIdx AHStackLoc = MTracker->getSpillMLoc(AHID);
1140 LocIdx AXStackLoc = MTracker->getSpillMLoc(AXID);
1141 LocIdx EAXStackLoc = MTracker->getSpillMLoc(EAXID);
1142 LocIdx HAXStackLoc = MTracker->getSpillMLoc(HAXID);
1143 LocIdx RAXStackLoc = MTracker->getSpillMLoc(RAXID);
1144 // There are other locations, for things like xmm0, which we're going to
1145 // ignore here.
1147 FuncValueTable MInLocs, MOutLocs;
1148 std::tie(MInLocs, MOutLocs) = allocValueTables(4, 11);
1150 // Transfer function: start with nothing.
1151 SmallVector<MLocTransferMap, 1> TransferFunc;
1152 TransferFunc.resize(4);
1154 // Name some values.
1155 unsigned EntryBlk = 0, Blk1 = 1, RetBlk = 3;
1157 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1158 ValueIDNum ALLiveIn(EntryBlk, 0, ALStackLoc);
1159 ValueIDNum AHLiveIn(EntryBlk, 0, AHStackLoc);
1160 ValueIDNum HAXLiveIn(EntryBlk, 0, HAXStackLoc);
1161 ValueIDNum ALPHI(RetBlk, 0, ALStackLoc);
1162 ValueIDNum AXPHI(RetBlk, 0, AXStackLoc);
1163 ValueIDNum EAXPHI(RetBlk, 0, EAXStackLoc);
1164 ValueIDNum HAXPHI(RetBlk, 0, HAXStackLoc);
1165 ValueIDNum RAXPHI(RetBlk, 0, RAXStackLoc);
1167 ValueIDNum ALDefInBlk1(Blk1, 1, ALStackLoc);
1168 ValueIDNum HAXDefInBlk1(Blk1, 1, HAXStackLoc);
1170 SmallPtrSet<MachineBasicBlock *, 4> AllBlocks{MBB0, MBB1, MBB2, MBB3};
1172 // If we put defs into one side of the diamond, for AL and HAX, then we should
1173 // find all aliasing positions have PHIs placed. This isn't technically what
1174 // the transfer function says to do: but we're testing that the optimisation
1175 // to reduce IDF calculation does the right thing.
1176 // AH should not be def'd: it don't alias AL or HAX.
1178 // NB: we don't call buildMLocValueMap, because it will try to eliminate the
1179 // upper-slot PHIs, and succeed because of our slightly cooked transfer
1180 // function.
1181 TransferFunc[1].insert({ALStackLoc, ALDefInBlk1});
1182 TransferFunc[1].insert({HAXStackLoc, HAXDefInBlk1});
1183 initValueArray(MInLocs, 4, 11);
1184 placeMLocPHIs(*MF, AllBlocks, MInLocs, TransferFunc);
1185 EXPECT_EQ(MInLocs[3][ALStackLoc.asU64()], ALPHI);
1186 EXPECT_EQ(MInLocs[3][AXStackLoc.asU64()], AXPHI);
1187 EXPECT_EQ(MInLocs[3][EAXStackLoc.asU64()], EAXPHI);
1188 EXPECT_EQ(MInLocs[3][HAXStackLoc.asU64()], HAXPHI);
1189 EXPECT_EQ(MInLocs[3][RAXStackLoc.asU64()], RAXPHI);
1190 // AH should be left untouched,
1191 EXPECT_EQ(MInLocs[3][AHStackLoc.asU64()], ValueIDNum::EmptyValue);
1194 TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
1195 // entry
1196 // |
1197 // |/-----\
1198 // loopblk |
1199 // |\-----/
1200 // |
1201 // ret
1202 setupSimpleLoop();
1204 ASSERT_TRUE(MTracker->getNumLocs() == 1);
1205 LocIdx RspLoc(0);
1206 Register RAX = getRegByName("RAX");
1207 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1209 FuncValueTable MInLocs, MOutLocs;
1210 std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
1212 SmallVector<MLocTransferMap, 1> TransferFunc;
1213 TransferFunc.resize(3);
1215 // Name some values.
1216 unsigned EntryBlk = 0, LoopBlk = 1, RetBlk = 2;
1218 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1219 ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
1220 ValueIDNum RspDefInBlk1(LoopBlk, 1, RspLoc);
1221 ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1222 ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
1223 ValueIDNum RaxPHIInBlk2(RetBlk, 0, RaxLoc);
1225 // Begin test with all locations being live-through.
1226 initValueArray(MInLocs, 3, 2);
1227 initValueArray(MOutLocs, 3, 2);
1228 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1229 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1230 EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1231 EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1232 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1233 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1234 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1236 // Add a def of $rsp to the loop block: it should be in the live-outs, but
1237 // should cause a PHI to be placed in the live-ins. Test the transfer function
1238 // by copying that PHI into $rax in the loop, then back to $rsp in the ret
1239 // block.
1240 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1241 TransferFunc[1].insert({RaxLoc, RspPHIInBlk1});
1242 TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1243 initValueArray(MInLocs, 3, 2);
1244 initValueArray(MOutLocs, 3, 2);
1245 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1246 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1247 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1248 EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1249 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1250 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1251 EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
1252 // Check rax as well,
1253 EXPECT_EQ(MInLocs[0][1], LiveInRax);
1254 EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
1255 EXPECT_EQ(MInLocs[2][1], RspPHIInBlk1);
1256 EXPECT_EQ(MOutLocs[0][1], LiveInRax);
1257 EXPECT_EQ(MOutLocs[1][1], RspPHIInBlk1);
1258 EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
1259 TransferFunc[1].clear();
1260 TransferFunc[2].clear();
1262 // As with the diamond case, a PHI will be created if there's a (implicit)
1263 // def in the entry block and loop block; but should be value propagated away
1264 // if it copies in the same value. Copy live-in $rsp to $rax, then copy it
1265 // into $rsp in the loop. Encoded as copying the live-in $rax value in block 1
1266 // to $rsp.
1267 TransferFunc[0].insert({RaxLoc, LiveInRsp});
1268 TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1269 initValueArray(MInLocs, 3, 2);
1270 initValueArray(MOutLocs, 3, 2);
1271 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1272 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1273 EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1274 EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1275 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1276 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1277 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1278 // Check $rax's values.
1279 EXPECT_EQ(MInLocs[0][1], LiveInRax);
1280 EXPECT_EQ(MInLocs[1][1], LiveInRsp);
1281 EXPECT_EQ(MInLocs[2][1], LiveInRsp);
1282 EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
1283 EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
1284 EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
1285 TransferFunc[0].clear();
1286 TransferFunc[1].clear();
1289 TEST_F(InstrRefLDVTest, MLocNestedLoop) {
1290 // entry
1291 // |
1292 // loop1
1293 // ^\
1294 // | \ /-\
1295 // | loop2 |
1296 // | / \-/
1297 // ^ /
1298 // join
1299 // |
1300 // ret
1301 setupNestedLoops();
1303 ASSERT_TRUE(MTracker->getNumLocs() == 1);
1304 LocIdx RspLoc(0);
1305 Register RAX = getRegByName("RAX");
1306 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1308 FuncValueTable MInLocs, MOutLocs;
1309 std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
1311 SmallVector<MLocTransferMap, 1> TransferFunc;
1312 TransferFunc.resize(5);
1314 unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2, JoinBlk = 3;
1316 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1317 ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
1318 ValueIDNum RspDefInBlk1(Loop1Blk, 1, RspLoc);
1319 ValueIDNum RspPHIInBlk2(Loop2Blk, 0, RspLoc);
1320 ValueIDNum RspDefInBlk2(Loop2Blk, 1, RspLoc);
1321 ValueIDNum RspDefInBlk3(JoinBlk, 1, RspLoc);
1322 ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1323 ValueIDNum RaxPHIInBlk1(Loop1Blk, 0, RaxLoc);
1324 ValueIDNum RaxPHIInBlk2(Loop2Blk, 0, RaxLoc);
1326 // Like the other tests: first ensure that if there's nothing in the transfer
1327 // function, then everything is live-through (check $rsp).
1328 initValueArray(MInLocs, 5, 2);
1329 initValueArray(MOutLocs, 5, 2);
1330 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1331 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1332 EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1333 EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1334 EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1335 EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1336 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1337 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1338 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1339 EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1340 EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1342 // A def in the inner loop means we should get PHIs at the heads of both
1343 // loops. Live-outs of the last three blocks will be the def, as it dominates
1344 // those.
1345 TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1346 initValueArray(MInLocs, 5, 2);
1347 initValueArray(MOutLocs, 5, 2);
1348 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1349 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1350 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1351 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1352 EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1353 EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
1354 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1355 EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1356 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1357 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
1358 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
1359 TransferFunc[2].clear();
1361 // Adding a def to the outer loop header shouldn't affect this much -- the
1362 // live-out of block 1 changes.
1363 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1364 TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1365 initValueArray(MInLocs, 5, 2);
1366 initValueArray(MOutLocs, 5, 2);
1367 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1368 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1369 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1370 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1371 EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1372 EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
1373 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1374 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1375 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1376 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
1377 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
1378 TransferFunc[1].clear();
1379 TransferFunc[2].clear();
1381 // Likewise, putting a def in the outer loop tail shouldn't affect where
1382 // the PHIs go, and should propagate into the ret block.
1384 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1385 TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1386 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1387 initValueArray(MInLocs, 5, 2);
1388 initValueArray(MOutLocs, 5, 2);
1389 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1390 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1391 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1392 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1393 EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1394 EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1395 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1396 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1397 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1398 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1399 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1400 TransferFunc[1].clear();
1401 TransferFunc[2].clear();
1402 TransferFunc[3].clear();
1404 // However: if we don't def in the inner-loop, then we just have defs in the
1405 // head and tail of the outer loop. The inner loop should be live-through.
1406 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1407 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1408 initValueArray(MInLocs, 5, 2);
1409 initValueArray(MOutLocs, 5, 2);
1410 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1411 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1412 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1413 EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1414 EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1415 EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1416 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1417 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1418 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1419 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1420 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1421 TransferFunc[1].clear();
1422 TransferFunc[3].clear();
1424 // Check that this still works if we copy RspDefInBlk1 to $rax and then
1425 // copy it back into $rsp in the inner loop.
1426 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1427 TransferFunc[1].insert({RaxLoc, RspDefInBlk1});
1428 TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1429 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1430 initValueArray(MInLocs, 5, 2);
1431 initValueArray(MOutLocs, 5, 2);
1432 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1433 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1434 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1435 EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1436 EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1437 EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1438 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1439 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1440 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1441 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1442 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1443 // Look at raxes value in the relevant blocks,
1444 EXPECT_EQ(MInLocs[2][1], RspDefInBlk1);
1445 EXPECT_EQ(MOutLocs[1][1], RspDefInBlk1);
1446 TransferFunc[1].clear();
1447 TransferFunc[2].clear();
1448 TransferFunc[3].clear();
1450 // If we have a single def in the tail of the outer loop, that should produce
1451 // a PHI at the loop head, and be live-through the inner loop.
1452 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1453 initValueArray(MInLocs, 5, 2);
1454 initValueArray(MOutLocs, 5, 2);
1455 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1456 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1457 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1458 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk1);
1459 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk1);
1460 EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1461 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1462 EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1463 EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
1464 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1465 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1466 TransferFunc[3].clear();
1468 // And if we copy from $rsp to $rax in block 2, it should resolve to the PHI
1469 // in block 1, and we should keep that value in rax until the ret block.
1470 // There'll be a PHI in block 1 and 2, because we're putting a def in the
1471 // inner loop.
1472 TransferFunc[2].insert({RaxLoc, RspPHIInBlk2});
1473 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1474 initValueArray(MInLocs, 5, 2);
1475 initValueArray(MOutLocs, 5, 2);
1476 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1477 // Examining the values of rax,
1478 EXPECT_EQ(MInLocs[0][1], LiveInRax);
1479 EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
1480 EXPECT_EQ(MInLocs[2][1], RaxPHIInBlk2);
1481 EXPECT_EQ(MInLocs[3][1], RspPHIInBlk1);
1482 EXPECT_EQ(MInLocs[4][1], RspPHIInBlk1);
1483 EXPECT_EQ(MOutLocs[0][1], LiveInRax);
1484 EXPECT_EQ(MOutLocs[1][1], RaxPHIInBlk1);
1485 EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
1486 EXPECT_EQ(MOutLocs[3][1], RspPHIInBlk1);
1487 EXPECT_EQ(MOutLocs[4][1], RspPHIInBlk1);
1488 TransferFunc[2].clear();
1489 TransferFunc[3].clear();
1492 TEST_F(InstrRefLDVTest, MLocNoDominatingLoop) {
1493 // entry
1494 // / \
1495 // / \
1496 // / \
1497 // head1 head2
1498 // ^ \ / ^
1499 // ^ \ / ^
1500 // \-joinblk -/
1501 // |
1502 // ret
1503 setupNoDominatingLoop();
1505 ASSERT_TRUE(MTracker->getNumLocs() == 1);
1506 LocIdx RspLoc(0);
1507 Register RAX = getRegByName("RAX");
1508 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1510 FuncValueTable MInLocs, MOutLocs;
1511 std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
1513 SmallVector<MLocTransferMap, 1> TransferFunc;
1514 TransferFunc.resize(5);
1516 unsigned EntryBlk = 0, Head1Blk = 1, Head2Blk = 2, JoinBlk = 3;
1518 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1519 ValueIDNum RspPHIInBlk1(Head1Blk, 0, RspLoc);
1520 ValueIDNum RspDefInBlk1(Head1Blk, 1, RspLoc);
1521 ValueIDNum RspPHIInBlk2(Head2Blk, 0, RspLoc);
1522 ValueIDNum RspDefInBlk2(Head2Blk, 1, RspLoc);
1523 ValueIDNum RspPHIInBlk3(JoinBlk, 0, RspLoc);
1524 ValueIDNum RspDefInBlk3(JoinBlk, 1, RspLoc);
1525 ValueIDNum RaxPHIInBlk1(Head1Blk, 0, RaxLoc);
1526 ValueIDNum RaxPHIInBlk2(Head2Blk, 0, RaxLoc);
1528 // As ever, test that everything is live-through if there are no defs.
1529 initValueArray(MInLocs, 5, 2);
1530 initValueArray(MOutLocs, 5, 2);
1531 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1532 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1533 EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1534 EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1535 EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1536 EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1537 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1538 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1539 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1540 EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1541 EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1543 // Putting a def in the 'join' block will cause us to have two distinct
1544 // PHIs in each loop head, then on entry to the join block.
1545 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1546 initValueArray(MInLocs, 5, 2);
1547 initValueArray(MOutLocs, 5, 2);
1548 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1549 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1550 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1551 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1552 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1553 EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1554 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1555 EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1556 EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1557 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1558 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1559 TransferFunc[3].clear();
1561 // We should get the same behaviour if we put the def in either of the
1562 // loop heads -- it should force the other head to be a PHI.
1563 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1564 initValueArray(MInLocs, 5, 2);
1565 initValueArray(MOutLocs, 5, 2);
1566 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1567 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1568 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1569 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1570 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1571 EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
1572 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1573 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1574 EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1575 EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1576 EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
1577 TransferFunc[1].clear();
1579 // Check symmetry,
1580 TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1581 initValueArray(MInLocs, 5, 2);
1582 initValueArray(MOutLocs, 5, 2);
1583 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1584 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1585 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1586 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1587 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1588 EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
1589 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1590 EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1591 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1592 EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1593 EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
1594 TransferFunc[2].clear();
1596 // Test some scenarios where there _shouldn't_ be any PHIs created at heads.
1597 // These are those PHIs are created, but value propagation eliminates them.
1598 // For example, lets copy rsp-livein to $rsp inside each loop head, so that
1599 // there's no need for a PHI in the join block. Put a def of $rsp in block 3
1600 // to force PHIs elsewhere.
1601 TransferFunc[0].insert({RaxLoc, LiveInRsp});
1602 TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1603 TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1604 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1605 initValueArray(MInLocs, 5, 2);
1606 initValueArray(MOutLocs, 5, 2);
1607 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1608 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1609 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1610 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1611 EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1612 EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1613 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1614 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1615 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1616 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1617 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1618 TransferFunc[0].clear();
1619 TransferFunc[1].clear();
1620 TransferFunc[2].clear();
1621 TransferFunc[3].clear();
1623 // In fact, if we eliminate the def in block 3, none of those PHIs are
1624 // necessary, as we're just repeatedly copying LiveInRsp into $rsp. They
1625 // should all be value propagated out.
1626 TransferFunc[0].insert({RaxLoc, LiveInRsp});
1627 TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1628 TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1629 initValueArray(MInLocs, 5, 2);
1630 initValueArray(MOutLocs, 5, 2);
1631 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1632 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1633 EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1634 EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1635 EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1636 EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1637 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1638 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1639 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1640 EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1641 EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1642 TransferFunc[0].clear();
1643 TransferFunc[1].clear();
1644 TransferFunc[2].clear();
1647 TEST_F(InstrRefLDVTest, MLocBadlyNestedLoops) {
1648 // entry
1649 // |
1650 // loop1 -o
1651 // | ^
1652 // | ^
1653 // loop2 -o
1654 // | ^
1655 // | ^
1656 // loop3 -o
1657 // |
1658 // ret
1659 setupBadlyNestedLoops();
1661 ASSERT_TRUE(MTracker->getNumLocs() == 1);
1662 LocIdx RspLoc(0);
1663 Register RAX = getRegByName("RAX");
1664 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1666 FuncValueTable MInLocs, MOutLocs;
1667 std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
1669 SmallVector<MLocTransferMap, 1> TransferFunc;
1670 TransferFunc.resize(5);
1672 unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2, Loop3Blk = 3;
1674 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1675 ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
1676 ValueIDNum RspDefInBlk1(Loop1Blk, 1, RspLoc);
1677 ValueIDNum RspPHIInBlk2(Loop2Blk, 0, RspLoc);
1678 ValueIDNum RspPHIInBlk3(Loop3Blk, 0, RspLoc);
1679 ValueIDNum RspDefInBlk3(Loop3Blk, 1, RspLoc);
1680 ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1681 ValueIDNum RaxPHIInBlk3(Loop3Blk, 0, RaxLoc);
1683 // As ever, test that everything is live-through if there are no defs.
1684 initValueArray(MInLocs, 5, 2);
1685 initValueArray(MOutLocs, 5, 2);
1686 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1687 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1688 EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1689 EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1690 EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1691 EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1692 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1693 EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1694 EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1695 EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1696 EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1698 // A def in loop3 should cause PHIs in every loop block: they're all
1699 // reachable from each other.
1700 TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1701 initValueArray(MInLocs, 5, 2);
1702 initValueArray(MOutLocs, 5, 2);
1703 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1704 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1705 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1706 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1707 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1708 EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1709 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1710 EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1711 EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1712 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1713 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1714 TransferFunc[3].clear();
1716 // A def in loop1 should cause a PHI in loop1, but not the other blocks.
1717 // loop2 and loop3 are dominated by the def in loop1, so they should have
1718 // that value live-through.
1719 TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1720 initValueArray(MInLocs, 5, 2);
1721 initValueArray(MOutLocs, 5, 2);
1722 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1723 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1724 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1725 EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1726 EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1727 EXPECT_EQ(MInLocs[4][0], RspDefInBlk1);
1728 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1729 EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1730 EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1731 EXPECT_EQ(MOutLocs[3][0], RspDefInBlk1);
1732 EXPECT_EQ(MOutLocs[4][0], RspDefInBlk1);
1733 TransferFunc[1].clear();
1735 // As with earlier tricks: copy $rsp to $rax in the entry block, then $rax
1736 // to $rsp in block 3. The only def of $rsp is simply copying the same value
1737 // back into itself, and the value of $rsp is LiveInRsp all the way through.
1738 // PHIs should be created, then value-propagated away... however this
1739 // doesn't work in practice.
1740 // Consider the entry to loop3: we can determine that there's an incoming
1741 // PHI value from loop2, and LiveInRsp from the self-loop. This would still
1742 // justify having a PHI on entry to loop3. The only way to completely
1743 // value-propagate these PHIs away would be to speculatively explore what
1744 // PHIs could be eliminated and what that would lead to; which is
1745 // combinatorially complex.
1746 // Happily:
1747 // a) In this scenario, we always have a tracked location for LiveInRsp
1748 // anyway, so there's no loss in availability,
1749 // b) Only DBG_PHIs of a register would be vunlerable to this scenario, and
1750 // even then only if a true PHI became a DBG_PHI and was then optimised
1751 // through branch folding to no longer be at a CFG join,
1752 // c) The register allocator can spot this kind of redundant COPY easily,
1753 // and eliminate it.
1755 // This unit test left in as a reference for the limitations of this
1756 // approach. PHIs will be left in $rsp on entry to each block.
1757 TransferFunc[0].insert({RaxLoc, LiveInRsp});
1758 TransferFunc[3].insert({RspLoc, RaxPHIInBlk3});
1759 initValueArray(MInLocs, 5, 2);
1760 initValueArray(MOutLocs, 5, 2);
1761 buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1762 EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1763 EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1764 EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1765 EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1766 EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1767 EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1768 EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1769 EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1770 EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1771 EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1772 // Check $rax's value. It should have $rsps value from the entry block
1773 // onwards.
1774 EXPECT_EQ(MInLocs[0][1], LiveInRax);
1775 EXPECT_EQ(MInLocs[1][1], LiveInRsp);
1776 EXPECT_EQ(MInLocs[2][1], LiveInRsp);
1777 EXPECT_EQ(MInLocs[3][1], LiveInRsp);
1778 EXPECT_EQ(MInLocs[4][1], LiveInRsp);
1779 EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
1780 EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
1781 EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
1782 EXPECT_EQ(MOutLocs[3][1], LiveInRsp);
1783 EXPECT_EQ(MOutLocs[4][1], LiveInRsp);
1786 TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
1787 // entry
1788 // / \
1789 // br1 br2
1790 // \ /
1791 // ret
1792 setupDiamondBlocks();
1794 ASSERT_TRUE(MTracker->getNumLocs() == 1);
1795 LocIdx RspLoc(0);
1796 Register RAX = getRegByName("RAX");
1797 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1799 FuncValueTable MInLocs, MOutLocs;
1800 std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
1802 initValueArray(MOutLocs, 4, 2);
1804 unsigned EntryBlk = 0, Br2Blk = 2, RetBlk = 3;
1806 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1807 ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1808 ValueIDNum RspPHIInBlk2(Br2Blk, 0, RspLoc);
1809 ValueIDNum RspPHIInBlk3(RetBlk, 0, RspLoc);
1810 ValueIDNum RaxPHIInBlk3(RetBlk, 0, RaxLoc);
1811 DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
1812 DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
1813 DbgOpID RspPHIInBlk2ID = addValueDbgOp(RspPHIInBlk2);
1814 DbgOpID RspPHIInBlk3ID = addValueDbgOp(RspPHIInBlk3);
1815 DbgOpID RaxPHIInBlk3ID = addValueDbgOp(RaxPHIInBlk3);
1816 DbgOpID ConstZeroID = addConstDbgOp(MachineOperand::CreateImm(0));
1818 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
1819 DbgValueProperties EmptyProps(EmptyExpr, false, false);
1820 DIExpression *TwoOpExpr =
1821 DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
1822 1, dwarf::DW_OP_plus});
1823 DbgValueProperties TwoOpProps(TwoOpExpr, false, true);
1824 SmallVector<DbgValue, 32> VLiveOuts;
1825 VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef));
1826 InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
1827 VLiveOutIdx[MBB0] = &VLiveOuts[0];
1828 VLiveOutIdx[MBB1] = &VLiveOuts[1];
1829 VLiveOutIdx[MBB2] = &VLiveOuts[2];
1830 VLiveOutIdx[MBB3] = &VLiveOuts[3];
1832 SmallVector<const MachineBasicBlock *, 2> Preds;
1833 for (const auto *Pred : MBB3->predecessors())
1834 Preds.push_back(Pred);
1836 // Specify the live-outs around the joining block.
1837 MOutLocs[1][0] = LiveInRsp;
1838 MOutLocs[2][0] = LiveInRax;
1840 bool Result;
1841 SmallVector<DbgOpID> OutValues;
1843 // Simple case: join two distinct values on entry to the block.
1844 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1845 VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
1846 OutValues.clear();
1847 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1848 // Should have picked a PHI in $rsp in block 3.
1849 EXPECT_TRUE(Result);
1850 if (Result) {
1851 EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
1854 // If the incoming values are swapped between blocks, we should not
1855 // successfully join. The CFG merge would select the right values, but in
1856 // the wrong conditions.
1857 std::swap(VLiveOuts[1], VLiveOuts[2]);
1858 OutValues.clear();
1859 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1860 EXPECT_FALSE(Result);
1862 // Swap back,
1863 std::swap(VLiveOuts[1], VLiveOuts[2]);
1864 // Setting one of these to being a constant should prohibit merging.
1865 VLiveOuts[1].setDbgOpIDs(ConstZeroID);
1866 OutValues.clear();
1867 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1868 EXPECT_FALSE(Result);
1870 // Setting both to being identical constants should result in a valid join
1871 // with a constant value.
1872 VLiveOuts[2] = VLiveOuts[1];
1873 OutValues.clear();
1874 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1875 EXPECT_TRUE(Result);
1876 if (Result) {
1877 EXPECT_EQ(OutValues[0], ConstZeroID);
1880 // NoVals shouldn't join with anything else.
1881 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1882 VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::NoVal);
1883 OutValues.clear();
1884 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1885 EXPECT_FALSE(Result);
1887 // We might merge in another VPHI in such a join. Present pickVPHILoc with
1888 // such a scenario: first, where one incoming edge has a VPHI with no known
1889 // value. This represents an edge where there was a PHI value that can't be
1890 // found in the register file -- we can't subsequently find a PHI here.
1891 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1892 VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
1893 OutValues.clear();
1894 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1895 EXPECT_FALSE(Result);
1897 // However, if we know the value of the incoming VPHI, we can search for its
1898 // location. Use a PHI machine-value for doing this, as VPHIs should always
1899 // have PHI values, or they should have been eliminated.
1900 MOutLocs[2][0] = RspPHIInBlk2;
1901 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1902 VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
1903 VLiveOuts[2].setDbgOpIDs(RspPHIInBlk2ID); // Set location where PHI happens.
1904 OutValues.clear();
1905 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1906 EXPECT_TRUE(Result);
1907 if (Result) {
1908 EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
1911 // If that value isn't available from that block, don't join.
1912 MOutLocs[2][0] = LiveInRsp;
1913 OutValues.clear();
1914 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1915 EXPECT_FALSE(Result);
1917 // Check that we don't pick values when the properties disagree, for example
1918 // different indirectness or DIExpression.
1919 MOutLocs[2][0] = LiveInRax;
1920 DIExpression *NewExpr =
1921 DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
1922 DbgValueProperties PropsWithExpr(NewExpr, false, false);
1923 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1924 VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithExpr);
1925 OutValues.clear();
1926 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1927 EXPECT_FALSE(Result);
1929 DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
1930 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1931 VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
1932 OutValues.clear();
1933 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1934 EXPECT_FALSE(Result);
1936 // When we have operands with values [A, B] and [B, A], we do not necessarily
1937 // pick identical join locations for each operand if the locations of those
1938 // values differ between incoming basic blocks.
1939 MOutLocs[1][0] = LiveInRsp;
1940 MOutLocs[2][0] = LiveInRax;
1941 MOutLocs[1][1] = LiveInRax;
1942 MOutLocs[2][1] = LiveInRsp;
1943 DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
1944 DbgOpID Locs1[] = {LiveInRaxID, LiveInRspID};
1945 VLiveOuts[1] = DbgValue(Locs0, TwoOpProps);
1946 VLiveOuts[2] = DbgValue(Locs1, TwoOpProps);
1947 OutValues.clear();
1948 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1949 // Should have picked PHIs in block 3.
1950 EXPECT_TRUE(Result);
1951 if (Result) {
1952 EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
1953 EXPECT_EQ(OutValues[1], RaxPHIInBlk3ID);
1956 // When joining identical constants for an operand, we should simply keep that
1957 // constant while joining the remaining operands as normal.
1958 DbgOpID Locs2[] = {LiveInRspID, ConstZeroID};
1959 DbgOpID Locs3[] = {LiveInRaxID, ConstZeroID};
1960 VLiveOuts[1] = DbgValue(Locs2, TwoOpProps);
1961 VLiveOuts[2] = DbgValue(Locs3, TwoOpProps);
1962 OutValues.clear();
1963 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1964 EXPECT_TRUE(Result);
1965 if (Result) {
1966 EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
1967 EXPECT_EQ(OutValues[1], ConstZeroID);
1970 // If the debug values have different constants for the same operand, they
1971 // cannot be joined.
1972 DbgOpID ConstOneID = addConstDbgOp(MachineOperand::CreateImm(1));
1973 DbgOpID Locs4[] = {LiveInRaxID, ConstOneID};
1974 VLiveOuts[1] = DbgValue(Locs3, TwoOpProps);
1975 VLiveOuts[2] = DbgValue(Locs4, TwoOpProps);
1976 OutValues.clear();
1977 Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1978 EXPECT_FALSE(Result);
1981 TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
1982 setupSimpleLoop();
1983 // entry
1984 // |
1985 // |/-----\
1986 // loopblk |
1987 // |\-----/
1988 // |
1989 // ret
1991 ASSERT_TRUE(MTracker->getNumLocs() == 1);
1992 LocIdx RspLoc(0);
1993 Register RAX = getRegByName("RAX");
1994 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1996 FuncValueTable MInLocs, MOutLocs;
1997 std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
1999 initValueArray(MOutLocs, 3, 2);
2001 unsigned EntryBlk = 0, LoopBlk = 1;
2003 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
2004 ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
2005 ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
2006 ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
2007 DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2008 DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
2009 DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
2010 DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
2012 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2013 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2014 DIExpression *TwoOpExpr =
2015 DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
2016 1, dwarf::DW_OP_plus});
2017 DbgValueProperties TwoOpProps(TwoOpExpr, false, true);
2018 SmallVector<DbgValue, 32> VLiveOuts;
2019 VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef));
2020 InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2021 VLiveOutIdx[MBB0] = &VLiveOuts[0];
2022 VLiveOutIdx[MBB1] = &VLiveOuts[1];
2023 VLiveOutIdx[MBB2] = &VLiveOuts[2];
2025 SmallVector<const MachineBasicBlock *, 2> Preds;
2026 for (const auto *Pred : MBB1->predecessors())
2027 Preds.push_back(Pred);
2029 // Specify the live-outs around the joining block.
2030 MOutLocs[0][0] = LiveInRsp;
2031 MOutLocs[1][0] = LiveInRax;
2033 bool Result;
2034 SmallVector<DbgOpID> OutValues;
2036 // See that we can merge as normal on a backedge.
2037 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2038 VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2039 OutValues.clear();
2040 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2041 // Should have picked a PHI in $rsp in block 1.
2042 EXPECT_TRUE(Result);
2043 if (Result) {
2044 EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
2047 // And that, if the desired values aren't available, we don't merge.
2048 MOutLocs[1][0] = LiveInRsp;
2049 OutValues.clear();
2050 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2051 EXPECT_FALSE(Result);
2053 // Test the backedge behaviour: PHIs that feed back into themselves can
2054 // carry this variables value. Feed in LiveInRsp in both $rsp and $rax
2055 // from the entry block, but only put an appropriate backedge PHI in $rax.
2056 // Only the $rax location can form the correct PHI.
2057 MOutLocs[0][0] = LiveInRsp;
2058 MOutLocs[0][1] = LiveInRsp;
2059 MOutLocs[1][0] = RaxPHIInBlk1;
2060 MOutLocs[1][1] = RaxPHIInBlk1;
2061 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2062 // Crucially, a VPHI originating in this block:
2063 VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2064 OutValues.clear();
2065 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2066 EXPECT_TRUE(Result);
2067 if (Result) {
2068 EXPECT_EQ(OutValues[0], RaxPHIInBlk1ID);
2071 // Test that we can also find a location when joining a backedge PHI with
2072 // a variadic debug value.
2073 MOutLocs[1][0] = RspPHIInBlk1;
2074 MOutLocs[0][1] = LiveInRax;
2075 DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
2076 VLiveOuts[0] = DbgValue(Locs0, TwoOpProps);
2077 // Crucially, a VPHI originating in this block:
2078 VLiveOuts[1] = DbgValue(1, TwoOpProps, DbgValue::VPHI);
2079 OutValues.clear();
2080 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2081 EXPECT_TRUE(Result);
2082 if (Result) {
2083 EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
2084 EXPECT_EQ(OutValues[1], RaxPHIInBlk1ID);
2087 // Merging should not be permitted if there's a usable PHI on the backedge,
2088 // but it's in the wrong place. (Overwrite $rax).
2089 MOutLocs[1][1] = LiveInRax;
2090 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2091 OutValues.clear();
2092 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2093 EXPECT_FALSE(Result);
2095 // Additionally, if the VPHI coming back on the loop backedge isn't from
2096 // this block (block 1), we can't merge it.
2097 MOutLocs[1][1] = RaxPHIInBlk1;
2098 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2099 VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
2100 OutValues.clear();
2101 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2102 EXPECT_FALSE(Result);
2105 TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
2106 // Run some tests similar to pickVPHILocLoops, with more than one backedge,
2107 // and check that we merge correctly over many candidate locations.
2108 setupBadlyNestedLoops();
2109 // entry
2110 // |
2111 // loop1 -o
2112 // | ^
2113 // | ^
2114 // loop2 -o
2115 // | ^
2116 // | ^
2117 // loop3 -o
2118 // |
2119 // ret
2120 ASSERT_TRUE(MTracker->getNumLocs() == 1);
2121 LocIdx RspLoc(0);
2122 Register RAX = getRegByName("RAX");
2123 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2124 Register RBX = getRegByName("RBX");
2125 LocIdx RbxLoc = MTracker->lookupOrTrackRegister(RBX);
2127 FuncValueTable MInLocs, MOutLocs;
2128 std::tie(MInLocs, MOutLocs) = allocValueTables(5, 3);
2130 initValueArray(MOutLocs, 5, 3);
2132 unsigned EntryBlk = 0, Loop1Blk = 1;
2134 ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
2135 ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
2136 ValueIDNum LiveInRbx(EntryBlk, 0, RbxLoc);
2137 ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
2138 ValueIDNum RaxPHIInBlk1(Loop1Blk, 0, RaxLoc);
2139 ValueIDNum RbxPHIInBlk1(Loop1Blk, 0, RbxLoc);
2140 DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2141 DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
2142 DbgOpID LiveInRbxID = addValueDbgOp(LiveInRbx);
2143 DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
2144 addValueDbgOp(RaxPHIInBlk1);
2145 DbgOpID RbxPHIInBlk1ID = addValueDbgOp(RbxPHIInBlk1);
2147 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2148 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2149 SmallVector<DbgValue, 32> VLiveOuts;
2150 VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef));
2151 InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2152 VLiveOutIdx[MBB0] = &VLiveOuts[0];
2153 VLiveOutIdx[MBB1] = &VLiveOuts[1];
2154 VLiveOutIdx[MBB2] = &VLiveOuts[2];
2155 VLiveOutIdx[MBB3] = &VLiveOuts[3];
2156 VLiveOutIdx[MBB4] = &VLiveOuts[4];
2158 // We're going to focus on block 1.
2159 SmallVector<const MachineBasicBlock *, 2> Preds;
2160 for (const auto *Pred : MBB1->predecessors())
2161 Preds.push_back(Pred);
2163 // Specify the live-outs around the joining block. Incoming edges from the
2164 // entry block, self, and loop2.
2165 MOutLocs[0][0] = LiveInRsp;
2166 MOutLocs[1][0] = LiveInRax;
2167 MOutLocs[2][0] = LiveInRbx;
2169 bool Result;
2170 SmallVector<DbgOpID> OutValues;
2172 // See that we can merge as normal on a backedge.
2173 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2174 VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2175 VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
2176 OutValues.clear();
2177 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2178 // Should have picked a PHI in $rsp in block 1.
2179 EXPECT_TRUE(Result);
2180 if (Result) {
2181 EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
2184 // Check too that permuting the live-out locations prevents merging
2185 MOutLocs[0][0] = LiveInRax;
2186 MOutLocs[1][0] = LiveInRbx;
2187 MOutLocs[2][0] = LiveInRsp;
2188 OutValues.clear();
2189 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2190 EXPECT_FALSE(Result);
2192 MOutLocs[0][0] = LiveInRsp;
2193 MOutLocs[1][0] = LiveInRax;
2194 MOutLocs[2][0] = LiveInRbx;
2196 // Feeding a PHI back on one backedge shouldn't merge (block 1 self backedge
2197 // wants LiveInRax).
2198 MOutLocs[1][0] = RspPHIInBlk1;
2199 OutValues.clear();
2200 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2201 EXPECT_FALSE(Result);
2203 // If the variables value on that edge is a VPHI feeding into itself, that's
2204 // fine.
2205 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2206 VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2207 VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
2208 OutValues.clear();
2209 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2210 EXPECT_TRUE(Result);
2211 if (Result) {
2212 EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
2215 // Likewise: the other backedge being a VPHI from block 1 should be accepted.
2216 MOutLocs[2][0] = RspPHIInBlk1;
2217 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2218 VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2219 VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2220 OutValues.clear();
2221 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2222 EXPECT_TRUE(Result);
2223 if (Result) {
2224 EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
2227 // Here's where it becomes tricky: we should not merge if there are two
2228 // _distinct_ backedge PHIs. We can't have a PHI that happens in both rsp
2229 // and rax for example. We can only pick one location as the live-in.
2230 MOutLocs[2][0] = RaxPHIInBlk1;
2231 OutValues.clear();
2232 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2233 EXPECT_FALSE(Result);
2235 // The above test sources correct machine-PHI-value from two places. Now
2236 // try with one machine-PHI-value, but placed in two different locations
2237 // on the backedge. Again, we can't merge a location here, there's no
2238 // location that works on all paths.
2239 MOutLocs[0][0] = LiveInRsp;
2240 MOutLocs[1][0] = RspPHIInBlk1;
2241 MOutLocs[2][0] = LiveInRsp;
2242 MOutLocs[2][1] = RspPHIInBlk1;
2243 OutValues.clear();
2244 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2245 EXPECT_FALSE(Result);
2247 // Scatter various PHI values across the available locations. Only rbx (loc 2)
2248 // has the right value in both backedges -- that's the loc that should be
2249 // picked.
2250 MOutLocs[0][2] = LiveInRsp;
2251 MOutLocs[1][0] = RspPHIInBlk1;
2252 MOutLocs[1][1] = RaxPHIInBlk1;
2253 MOutLocs[1][2] = RbxPHIInBlk1;
2254 MOutLocs[2][0] = LiveInRsp;
2255 MOutLocs[2][1] = RspPHIInBlk1;
2256 MOutLocs[2][2] = RbxPHIInBlk1;
2257 OutValues.clear();
2258 Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2259 EXPECT_TRUE(Result);
2260 if (Result) {
2261 EXPECT_EQ(OutValues[0], RbxPHIInBlk1ID);
2265 TEST_F(InstrRefLDVTest, vlocJoinDiamond) {
2266 // entry
2267 // / \
2268 // br1 br2
2269 // \ /
2270 // ret
2271 setupDiamondBlocks();
2273 ASSERT_TRUE(MTracker->getNumLocs() == 1);
2274 LocIdx RspLoc(0);
2275 Register RAX = getRegByName("RAX");
2276 MTracker->lookupOrTrackRegister(RAX);
2278 DbgOpID LiveInRspID = DbgOpID(false, 0);
2279 DbgOpID LiveInRaxID = DbgOpID(false, 1);
2281 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2282 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2283 SmallVector<DbgValue, 32> VLiveOuts;
2284 VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef));
2285 InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2286 VLiveOutIdx[MBB0] = &VLiveOuts[0];
2287 VLiveOutIdx[MBB1] = &VLiveOuts[1];
2288 VLiveOutIdx[MBB2] = &VLiveOuts[2];
2289 VLiveOutIdx[MBB3] = &VLiveOuts[3];
2291 SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2292 AllBlocks.insert(MBB0);
2293 AllBlocks.insert(MBB1);
2294 AllBlocks.insert(MBB2);
2295 AllBlocks.insert(MBB3);
2297 SmallVector<const MachineBasicBlock *, 2> Preds;
2298 for (const auto *Pred : MBB3->predecessors())
2299 Preds.push_back(Pred);
2301 SmallSet<DebugVariable, 4> AllVars;
2302 AllVars.insert(Var);
2304 // vlocJoin is here to propagate incoming values, and eliminate PHIs. Start
2305 // off by propagating a value into the merging block, number 3.
2306 DbgValue JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
2307 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2308 VLiveOuts[2] = DbgValue(LiveInRspID, EmptyProps);
2309 bool Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2310 EXPECT_TRUE(Result); // Output locs should have changed.
2311 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2312 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2314 // And if we did it a second time, leaving the live-ins as it was, then
2315 // we should report no change.
2316 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2317 EXPECT_FALSE(Result);
2319 // If the live-in variable values are different, but there's no PHI placed
2320 // in this block, then just pick a location. It should be the first (in RPO)
2321 // predecessor to avoid being a backedge.
2322 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2323 VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
2324 JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
2325 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2326 EXPECT_TRUE(Result);
2327 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2328 // RPO is blocks 0 2 1 3, so LiveInRax is picked as the first predecessor
2329 // of this join.
2330 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRaxID);
2332 // No tests for whether vlocJoin will pass-through a variable with differing
2333 // expressions / properties. Those can only come about due to assignments; and
2334 // for any assignment at all, a PHI should have been placed at the dominance
2335 // frontier. We rely on the IDF calculator being accurate (which is OK,
2336 // because so does the rest of LLVM).
2338 // Try placing a PHI. With differing input values (LiveInRsp, LiveInRax),
2339 // this PHI should not be eliminated.
2340 JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
2341 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2342 // Expect no change.
2343 EXPECT_FALSE(Result);
2344 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2345 // This should not have been assigned a fixed value.
2346 EXPECT_EQ(JoinedLoc.getDbgOpID(0), DbgOpID::UndefID);
2347 EXPECT_EQ(JoinedLoc.BlockNo, 3);
2349 // Try a simple PHI elimination. Put a PHI in block 3, but LiveInRsp on both
2350 // incoming edges. Re-load in and out-locs with unrelated values; they're
2351 // irrelevant.
2352 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2353 VLiveOuts[2] = DbgValue(LiveInRspID, EmptyProps);
2354 JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
2355 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2356 EXPECT_TRUE(Result);
2357 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2358 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2360 // Try the same PHI elimination but with one incoming value being a VPHI
2361 // referring to the same value.
2362 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2363 VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
2364 VLiveOuts[2].setDbgOpIDs(LiveInRspID);
2365 JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
2366 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2367 EXPECT_TRUE(Result);
2368 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2369 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2371 // If the "current" live-in is a VPHI, but not a VPHI generated in the current
2372 // block, then it's the remains of an earlier value propagation. We should
2373 // value propagate through this merge. Even if the current incoming values
2374 // disagree, because we've previously determined any VPHI here is redundant.
2375 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2376 VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
2377 JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
2378 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2379 EXPECT_TRUE(Result);
2380 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2381 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRaxID); // from block 2
2383 // The above test, but test that we will install one value-propagated VPHI
2384 // over another.
2385 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2386 VLiveOuts[2] = DbgValue(0, EmptyProps, DbgValue::VPHI);
2387 JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
2388 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2389 EXPECT_TRUE(Result);
2390 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2391 EXPECT_EQ(JoinedLoc.BlockNo, 0);
2393 // We shouldn't eliminate PHIs when properties disagree.
2394 DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
2395 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2396 VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
2397 JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
2398 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2399 EXPECT_FALSE(Result);
2400 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2401 EXPECT_EQ(JoinedLoc.BlockNo, 3);
2403 // Even if properties disagree, we should still value-propagate if there's no
2404 // PHI to be eliminated. The disagreeing values should work themselves out,
2405 // seeing how we've determined no PHI is necessary.
2406 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2407 VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
2408 JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
2409 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2410 EXPECT_TRUE(Result);
2411 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2412 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2413 // Also check properties come from block 2, the first RPO predecessor to block
2414 // three.
2415 EXPECT_EQ(JoinedLoc.Properties, PropsWithIndirect);
2417 // Again, disagreeing properties, this time the expr, should cause a PHI to
2418 // not be eliminated.
2419 DIExpression *NewExpr =
2420 DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
2421 DbgValueProperties PropsWithExpr(NewExpr, false, false);
2422 VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2423 VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithExpr);
2424 JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
2425 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2426 EXPECT_FALSE(Result);
2428 // Try placing a PHI with variadic debug values. With differing input values
2429 // (LiveInRsp, LiveInRax), this PHI should not be eliminated.
2430 DIExpression *TwoOpExpr =
2431 DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
2432 1, dwarf::DW_OP_plus});
2433 DbgValueProperties TwoOpProps(TwoOpExpr, false, true);
2434 DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
2435 DbgOpID Locs1[] = {LiveInRaxID, LiveInRspID};
2436 JoinedLoc = DbgValue(3, TwoOpProps, DbgValue::VPHI);
2437 VLiveOuts[1] = DbgValue(Locs0, TwoOpProps);
2438 VLiveOuts[2] = DbgValue(Locs1, TwoOpProps);
2439 Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2440 // Expect no change.
2441 EXPECT_FALSE(Result);
2442 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2443 // This should not have been assigned a fixed value.
2444 EXPECT_EQ(JoinedLoc.getDbgOpID(0), DbgOpID::UndefID);
2445 EXPECT_EQ(JoinedLoc.BlockNo, 3);
2448 TEST_F(InstrRefLDVTest, vlocJoinLoops) {
2449 setupSimpleLoop();
2450 // entry
2451 // |
2452 // |/-----\
2453 // loopblk |
2454 // |\-----/
2455 // |
2456 // ret
2457 ASSERT_TRUE(MTracker->getNumLocs() == 1);
2458 LocIdx RspLoc(0);
2459 Register RAX = getRegByName("RAX");
2460 MTracker->lookupOrTrackRegister(RAX);
2462 DbgOpID LiveInRspID = DbgOpID(false, 0);
2463 DbgOpID LiveInRaxID = DbgOpID(false, 1);
2465 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2466 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2467 SmallVector<DbgValue, 32> VLiveOuts;
2468 VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef));
2469 InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2470 VLiveOutIdx[MBB0] = &VLiveOuts[0];
2471 VLiveOutIdx[MBB1] = &VLiveOuts[1];
2472 VLiveOutIdx[MBB2] = &VLiveOuts[2];
2474 SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2475 AllBlocks.insert(MBB0);
2476 AllBlocks.insert(MBB1);
2477 AllBlocks.insert(MBB2);
2479 SmallVector<const MachineBasicBlock *, 2> Preds;
2480 for (const auto *Pred : MBB1->predecessors())
2481 Preds.push_back(Pred);
2483 SmallSet<DebugVariable, 4> AllVars;
2484 AllVars.insert(Var);
2486 // Test some back-edge-specific behaviours of vloc join. Mostly: the fact that
2487 // VPHIs that arrive on backedges can be eliminated, despite having different
2488 // values to the predecessor.
2490 // First: when there's no VPHI placed already, propagate the live-in value of
2491 // the first RPO predecessor.
2492 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2493 VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2494 DbgValue JoinedLoc = DbgValue(LiveInRaxID, EmptyProps);
2495 bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2496 EXPECT_TRUE(Result);
2497 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2498 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2500 // If there is a VPHI: don't elimiante it if there are disagreeing values.
2501 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2502 VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2503 JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2504 Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2505 EXPECT_FALSE(Result);
2506 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2507 EXPECT_EQ(JoinedLoc.BlockNo, 1);
2509 // If we feed this VPHI back into itself though, we can eliminate it.
2510 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2511 VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2512 JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2513 Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2514 EXPECT_TRUE(Result);
2515 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2516 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2518 // Don't eliminate backedge VPHIs if the predecessors have different
2519 // properties.
2520 DIExpression *NewExpr =
2521 DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
2522 DbgValueProperties PropsWithExpr(NewExpr, false, false);
2523 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2524 VLiveOuts[1] = DbgValue(1, PropsWithExpr, DbgValue::VPHI);
2525 JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2526 Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2527 EXPECT_FALSE(Result);
2528 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2529 EXPECT_EQ(JoinedLoc.BlockNo, 1);
2531 // Backedges with VPHIs, but from the wrong block, shouldn't be eliminated.
2532 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2533 VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
2534 JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2535 Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2536 EXPECT_FALSE(Result);
2537 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2538 EXPECT_EQ(JoinedLoc.BlockNo, 1);
2541 TEST_F(InstrRefLDVTest, vlocJoinBadlyNestedLoops) {
2542 // Test PHI elimination in the presence of multiple backedges.
2543 setupBadlyNestedLoops();
2544 // entry
2545 // |
2546 // loop1 -o
2547 // | ^
2548 // | ^
2549 // loop2 -o
2550 // | ^
2551 // | ^
2552 // loop3 -o
2553 // |
2554 // ret
2555 ASSERT_TRUE(MTracker->getNumLocs() == 1);
2556 LocIdx RspLoc(0);
2557 Register RAX = getRegByName("RAX");
2558 MTracker->lookupOrTrackRegister(RAX);
2559 Register RBX = getRegByName("RBX");
2560 MTracker->lookupOrTrackRegister(RBX);
2562 DbgOpID LiveInRspID = DbgOpID(false, 0);
2563 DbgOpID LiveInRaxID = DbgOpID(false, 1);
2564 DbgOpID LiveInRbxID = DbgOpID(false, 2);
2566 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2567 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2568 SmallVector<DbgValue, 32> VLiveOuts;
2569 VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef));
2570 InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2571 VLiveOutIdx[MBB0] = &VLiveOuts[0];
2572 VLiveOutIdx[MBB1] = &VLiveOuts[1];
2573 VLiveOutIdx[MBB2] = &VLiveOuts[2];
2574 VLiveOutIdx[MBB3] = &VLiveOuts[3];
2575 VLiveOutIdx[MBB4] = &VLiveOuts[4];
2577 SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2578 AllBlocks.insert(MBB0);
2579 AllBlocks.insert(MBB1);
2580 AllBlocks.insert(MBB2);
2581 AllBlocks.insert(MBB3);
2582 AllBlocks.insert(MBB4);
2584 // We're going to focus on block 1.
2585 SmallVector<const MachineBasicBlock *, 3> Preds;
2586 for (const auto *Pred : MBB1->predecessors())
2587 Preds.push_back(Pred);
2589 SmallSet<DebugVariable, 4> AllVars;
2590 AllVars.insert(Var);
2592 // Test a normal VPHI isn't eliminated.
2593 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2594 VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2595 VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
2596 DbgValue JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2597 bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2598 EXPECT_FALSE(Result);
2599 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2600 EXPECT_EQ(JoinedLoc.BlockNo, 1);
2602 // Common VPHIs on backedges should merge.
2603 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2604 VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2605 VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2606 JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2607 Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2608 EXPECT_TRUE(Result);
2609 EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2610 EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2612 // They shouldn't merge if one of their properties is different.
2613 DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
2614 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2615 VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2616 VLiveOuts[2] = DbgValue(1, PropsWithIndirect, DbgValue::VPHI);
2617 JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2618 Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2619 EXPECT_FALSE(Result);
2620 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2621 EXPECT_EQ(JoinedLoc.BlockNo, 1);
2623 // VPHIs from different blocks should not merge.
2624 VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2625 VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2626 VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
2627 JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
2628 Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2629 EXPECT_FALSE(Result);
2630 EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2631 EXPECT_EQ(JoinedLoc.BlockNo, 1);
2634 // Above are tests for picking VPHI locations, and eliminating VPHIs. No
2635 // unit-tests are written for evaluating the transfer function as that's
2636 // pretty straight forwards, or applying VPHI-location-picking to live-ins.
2637 // Instead, pre-set some machine locations and apply buildVLocValueMap to the
2638 // existing CFG patterns.
2639 TEST_F(InstrRefLDVTest, VLocSingleBlock) {
2640 setupSingleBlock();
2642 ASSERT_TRUE(MTracker->getNumLocs() == 1);
2643 LocIdx RspLoc(0);
2645 FuncValueTable MInLocs, MOutLocs;
2646 std::tie(MInLocs, MOutLocs) = allocValueTables(1, 2);
2648 ValueIDNum LiveInRsp = ValueIDNum(0, 0, RspLoc);
2649 DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2650 MInLocs[0][0] = MOutLocs[0][0] = LiveInRsp;
2652 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2653 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2655 SmallSet<DebugVariable, 4> AllVars;
2656 AllVars.insert(Var);
2658 // Mild hack: rather than constructing machine instructions in each block
2659 // and creating lexical scopes across them, instead just tell
2660 // buildVLocValueMap that there's an assignment in every block. That makes
2661 // every block in scope.
2662 SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2663 AssignBlocks.insert(MBB0);
2665 SmallVector<VLocTracker, 1> VLocs;
2666 VLocs.resize(1, VLocTracker(Overlaps, EmptyExpr));
2668 InstrRefBasedLDV::LiveInsT Output;
2670 // Test that, with no assignments at all, no mappings are created for the
2671 // variable in this function.
2672 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2673 MOutLocs, MInLocs, VLocs);
2674 EXPECT_EQ(Output.size(), 0ul);
2676 // If we put an assignment in the transfer function, that should... well,
2677 // do nothing, because we don't store the live-outs.
2678 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2679 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2680 MOutLocs, MInLocs, VLocs);
2681 EXPECT_EQ(Output.size(), 0ul);
2683 // There is pretty much nothing else of interest to test with a single block.
2684 // It's not relevant to the SSA-construction parts of variable values.
2687 TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
2688 setupDiamondBlocks();
2689 // entry
2690 // / \
2691 // br1 br2
2692 // \ /
2693 // ret
2695 ASSERT_TRUE(MTracker->getNumLocs() == 1);
2696 LocIdx RspLoc(0);
2697 Register RAX = getRegByName("RAX");
2698 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2700 unsigned EntryBlk = 0, RetBlk = 3;
2702 ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
2703 ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
2704 ValueIDNum RspPHIInBlk3 = ValueIDNum(RetBlk, 0, RspLoc);
2705 DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2706 DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
2707 DbgOpID RspPHIInBlk3ID = addValueDbgOp(RspPHIInBlk3);
2709 FuncValueTable MInLocs, MOutLocs;
2710 std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
2712 initValueArray(MInLocs, 4, 2);
2713 initValueArray(MOutLocs, 4, 2);
2715 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2716 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2718 SmallSet<DebugVariable, 4> AllVars;
2719 AllVars.insert(Var);
2721 // Mild hack: rather than constructing machine instructions in each block
2722 // and creating lexical scopes across them, instead just tell
2723 // buildVLocValueMap that there's an assignment in every block. That makes
2724 // every block in scope.
2725 SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2726 AssignBlocks.insert(MBB0);
2727 AssignBlocks.insert(MBB1);
2728 AssignBlocks.insert(MBB2);
2729 AssignBlocks.insert(MBB3);
2731 SmallVector<VLocTracker, 1> VLocs;
2732 VLocs.resize(4, VLocTracker(Overlaps, EmptyExpr));
2734 InstrRefBasedLDV::LiveInsT Output;
2736 // Start off with LiveInRsp in every location.
2737 for (unsigned int I = 0; I < 4; ++I) {
2738 MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
2739 MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
2742 auto ClearOutputs = [&]() {
2743 for (auto &Elem : Output)
2744 Elem.clear();
2746 Output.resize(4);
2748 // No assignments -> no values.
2749 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2750 MOutLocs, MInLocs, VLocs);
2751 EXPECT_EQ(Output[0].size(), 0ul);
2752 EXPECT_EQ(Output[1].size(), 0ul);
2753 EXPECT_EQ(Output[2].size(), 0ul);
2754 EXPECT_EQ(Output[3].size(), 0ul);
2756 // An assignment in the end block should also not affect other blocks; or
2757 // produce any live-ins.
2758 VLocs[3].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2759 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2760 MOutLocs, MInLocs, VLocs);
2761 EXPECT_EQ(Output[0].size(), 0ul);
2762 EXPECT_EQ(Output[1].size(), 0ul);
2763 EXPECT_EQ(Output[2].size(), 0ul);
2764 EXPECT_EQ(Output[3].size(), 0ul);
2765 ClearOutputs();
2767 // Assignments in either of the side-of-diamond blocks should also not be
2768 // propagated anywhere.
2769 VLocs[3].Vars.clear();
2770 VLocs[2].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2771 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2772 MOutLocs, MInLocs, VLocs);
2773 EXPECT_EQ(Output[0].size(), 0ul);
2774 EXPECT_EQ(Output[1].size(), 0ul);
2775 EXPECT_EQ(Output[2].size(), 0ul);
2776 EXPECT_EQ(Output[3].size(), 0ul);
2777 VLocs[2].Vars.clear();
2778 ClearOutputs();
2780 VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2781 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2782 MOutLocs, MInLocs, VLocs);
2783 EXPECT_EQ(Output[0].size(), 0ul);
2784 EXPECT_EQ(Output[1].size(), 0ul);
2785 EXPECT_EQ(Output[2].size(), 0ul);
2786 EXPECT_EQ(Output[3].size(), 0ul);
2787 VLocs[1].Vars.clear();
2788 ClearOutputs();
2790 // However: putting an assignment in the first block should propagate variable
2791 // values through to all other blocks, as it dominates.
2792 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2793 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2794 MOutLocs, MInLocs, VLocs);
2795 EXPECT_EQ(Output[0].size(), 0ul);
2796 ASSERT_EQ(Output[1].size(), 1ul);
2797 ASSERT_EQ(Output[2].size(), 1ul);
2798 ASSERT_EQ(Output[3].size(), 1ul);
2799 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2800 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2801 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2802 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2803 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2804 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
2805 ClearOutputs();
2806 VLocs[0].Vars.clear();
2808 // Additionally, even if that value isn't available in the register file, it
2809 // should still be propagated, as buildVLocValueMap shouldn't care about
2810 // what's in the registers (except for PHIs).
2811 // values through to all other blocks, as it dominates.
2812 VLocs[0].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
2813 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2814 MOutLocs, MInLocs, VLocs);
2815 EXPECT_EQ(Output[0].size(), 0ul);
2816 ASSERT_EQ(Output[1].size(), 1ul);
2817 ASSERT_EQ(Output[2].size(), 1ul);
2818 ASSERT_EQ(Output[3].size(), 1ul);
2819 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2820 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRaxID);
2821 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2822 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
2823 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2824 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
2825 ClearOutputs();
2826 VLocs[0].Vars.clear();
2828 // We should get a live-in to the merging block, if there are two assigns of
2829 // the same value in either side of the diamond.
2830 VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2831 VLocs[2].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2832 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2833 MOutLocs, MInLocs, VLocs);
2834 EXPECT_EQ(Output[0].size(), 0ul);
2835 EXPECT_EQ(Output[1].size(), 0ul);
2836 EXPECT_EQ(Output[2].size(), 0ul);
2837 ASSERT_EQ(Output[3].size(), 1ul);
2838 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2839 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
2840 ClearOutputs();
2841 VLocs[1].Vars.clear();
2842 VLocs[2].Vars.clear();
2844 // If we assign a value in the entry block, then 'undef' on a branch, we
2845 // shouldn't have a live-in in the merge block.
2846 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2847 VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
2848 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2849 MOutLocs, MInLocs, VLocs);
2850 EXPECT_EQ(Output[0].size(), 0ul);
2851 ASSERT_EQ(Output[1].size(), 1ul);
2852 ASSERT_EQ(Output[2].size(), 1ul);
2853 EXPECT_EQ(Output[3].size(), 0ul);
2854 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2855 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2856 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2857 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2858 ClearOutputs();
2859 VLocs[0].Vars.clear();
2860 VLocs[1].Vars.clear();
2862 // Having different values joining into the merge block should mean we have
2863 // no live-in in that block. Block ones LiveInRax value doesn't appear as a
2864 // live-in anywhere, it's block internal.
2865 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2866 VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
2867 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2868 MOutLocs, MInLocs, VLocs);
2869 EXPECT_EQ(Output[0].size(), 0ul);
2870 ASSERT_EQ(Output[1].size(), 1ul);
2871 ASSERT_EQ(Output[2].size(), 1ul);
2872 EXPECT_EQ(Output[3].size(), 0ul);
2873 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2874 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2875 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2876 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2877 ClearOutputs();
2878 VLocs[0].Vars.clear();
2879 VLocs[1].Vars.clear();
2881 // But on the other hand, if there's a location in the register file where
2882 // those two values can be joined, do so.
2883 MOutLocs[1][0] = LiveInRax;
2884 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2885 VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
2886 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2887 MOutLocs, MInLocs, VLocs);
2888 EXPECT_EQ(Output[0].size(), 0ul);
2889 ASSERT_EQ(Output[1].size(), 1ul);
2890 ASSERT_EQ(Output[2].size(), 1ul);
2891 ASSERT_EQ(Output[3].size(), 1ul);
2892 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2893 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2894 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2895 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2896 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2897 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), RspPHIInBlk3ID);
2898 ClearOutputs();
2899 VLocs[0].Vars.clear();
2900 VLocs[1].Vars.clear();
2903 TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
2904 setupSimpleLoop();
2905 // entry
2906 // |
2907 // |/-----\
2908 // loopblk |
2909 // |\-----/
2910 // |
2911 // ret
2913 ASSERT_TRUE(MTracker->getNumLocs() == 1);
2914 LocIdx RspLoc(0);
2915 Register RAX = getRegByName("RAX");
2916 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2918 unsigned EntryBlk = 0, LoopBlk = 1;
2920 ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
2921 ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
2922 ValueIDNum RspPHIInBlk1 = ValueIDNum(LoopBlk, 0, RspLoc);
2923 ValueIDNum RspDefInBlk1 = ValueIDNum(LoopBlk, 1, RspLoc);
2924 ValueIDNum RaxPHIInBlk1 = ValueIDNum(LoopBlk, 0, RaxLoc);
2925 DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2926 DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
2927 DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
2928 DbgOpID RspDefInBlk1ID = addValueDbgOp(RspDefInBlk1);
2929 DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
2931 FuncValueTable MInLocs, MOutLocs;
2932 std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
2934 initValueArray(MInLocs, 3, 2);
2935 initValueArray(MOutLocs, 3, 2);
2937 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2938 DbgValueProperties EmptyProps(EmptyExpr, false, false);
2939 DIExpression *TwoOpExpr =
2940 DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
2941 1, dwarf::DW_OP_plus});
2942 DbgValueProperties VariadicProps(TwoOpExpr, false, true);
2944 SmallSet<DebugVariable, 4> AllVars;
2945 AllVars.insert(Var);
2947 SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2948 AssignBlocks.insert(MBB0);
2949 AssignBlocks.insert(MBB1);
2950 AssignBlocks.insert(MBB2);
2952 SmallVector<VLocTracker, 3> VLocs;
2953 VLocs.resize(3, VLocTracker(Overlaps, EmptyExpr));
2955 InstrRefBasedLDV::LiveInsT Output;
2957 // Start off with LiveInRsp in every location.
2958 for (unsigned int I = 0; I < 3; ++I) {
2959 MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
2960 MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
2963 auto ClearOutputs = [&]() {
2964 for (auto &Elem : Output)
2965 Elem.clear();
2967 Output.resize(3);
2969 // Easy starter: a dominating assign should propagate to all blocks.
2970 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
2971 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2972 MOutLocs, MInLocs, VLocs);
2973 EXPECT_EQ(Output[0].size(), 0ul);
2974 ASSERT_EQ(Output[1].size(), 1ul);
2975 ASSERT_EQ(Output[2].size(), 1ul);
2976 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2977 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2978 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2979 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2980 ClearOutputs();
2981 VLocs[0].Vars.clear();
2982 VLocs[1].Vars.clear();
2984 // A variadic assignment should behave the same.
2985 DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
2986 VLocs[0].Vars.insert({Var, DbgValue(Locs0, VariadicProps)});
2987 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output, MOutLocs,
2988 MInLocs, VLocs);
2989 EXPECT_EQ(Output[0].size(), 0ul);
2990 ASSERT_EQ(Output[1].size(), 1ul);
2991 ASSERT_EQ(Output[2].size(), 1ul);
2992 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2993 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2994 EXPECT_EQ(Output[1][0].second.getDbgOpID(1), LiveInRaxID);
2995 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2996 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2997 ClearOutputs();
2998 VLocs[0].Vars.clear();
2999 VLocs[1].Vars.clear();
3001 // Put an undef assignment in the loop. Should get no live-in value.
3002 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3003 VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
3004 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3005 MOutLocs, MInLocs, VLocs);
3006 EXPECT_EQ(Output[0].size(), 0ul);
3007 EXPECT_EQ(Output[1].size(), 0ul);
3008 EXPECT_EQ(Output[2].size(), 0ul);
3009 ClearOutputs();
3010 VLocs[0].Vars.clear();
3011 VLocs[1].Vars.clear();
3013 // Assignment of the same value should naturally join.
3014 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3015 VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3016 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3017 MOutLocs, MInLocs, VLocs);
3018 EXPECT_EQ(Output[0].size(), 0ul);
3019 ASSERT_EQ(Output[1].size(), 1ul);
3020 ASSERT_EQ(Output[2].size(), 1ul);
3021 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3022 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3023 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3024 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3025 ClearOutputs();
3026 VLocs[0].Vars.clear();
3027 VLocs[1].Vars.clear();
3029 // Assignment of different values shouldn't join with no machine PHI vals.
3030 // Will be live-in to exit block as it's dominated.
3031 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3032 VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
3033 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3034 MOutLocs, MInLocs, VLocs);
3035 EXPECT_EQ(Output[0].size(), 0ul);
3036 EXPECT_EQ(Output[1].size(), 0ul);
3037 ASSERT_EQ(Output[2].size(), 1ul);
3038 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3039 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
3040 ClearOutputs();
3041 VLocs[0].Vars.clear();
3042 VLocs[1].Vars.clear();
3044 // Install a completely unrelated PHI value, that we should not join on. Try
3045 // with unrelated assign in loop block again.
3046 MInLocs[1][0] = RspPHIInBlk1;
3047 MOutLocs[1][0] = RspDefInBlk1;
3048 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3049 VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
3050 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3051 MOutLocs, MInLocs, VLocs);
3052 EXPECT_EQ(Output[0].size(), 0ul);
3053 EXPECT_EQ(Output[1].size(), 0ul);
3054 ASSERT_EQ(Output[2].size(), 1ul);
3055 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3056 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
3057 ClearOutputs();
3058 VLocs[0].Vars.clear();
3059 VLocs[1].Vars.clear();
3061 // Now, if we assign RspDefInBlk1 in the loop block, we should be able to
3062 // find the appropriate PHI.
3063 MInLocs[1][0] = RspPHIInBlk1;
3064 MOutLocs[1][0] = RspDefInBlk1;
3065 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3066 VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1ID, EmptyProps)});
3067 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3068 MOutLocs, MInLocs, VLocs);
3069 EXPECT_EQ(Output[0].size(), 0ul);
3070 ASSERT_EQ(Output[1].size(), 1ul);
3071 ASSERT_EQ(Output[2].size(), 1ul);
3072 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3073 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3074 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3075 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
3076 ClearOutputs();
3077 VLocs[0].Vars.clear();
3078 VLocs[1].Vars.clear();
3080 // If the PHI happens in a different location, the live-in should happen
3081 // there.
3082 MInLocs[1][0] = LiveInRsp;
3083 MOutLocs[1][0] = LiveInRsp;
3084 MInLocs[1][1] = RaxPHIInBlk1;
3085 MOutLocs[1][1] = RspDefInBlk1;
3086 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3087 VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1ID, EmptyProps)});
3088 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3089 MOutLocs, MInLocs, VLocs);
3090 EXPECT_EQ(Output[0].size(), 0ul);
3091 ASSERT_EQ(Output[1].size(), 1ul);
3092 ASSERT_EQ(Output[2].size(), 1ul);
3093 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3094 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RaxPHIInBlk1ID);
3095 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3096 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
3097 ClearOutputs();
3098 VLocs[0].Vars.clear();
3099 VLocs[1].Vars.clear();
3101 // The PHI happening in both places should be handled too. Exactly where
3102 // isn't important, but if the location picked changes, this test will let
3103 // you know.
3104 MInLocs[1][0] = RaxPHIInBlk1;
3105 MOutLocs[1][0] = RspDefInBlk1;
3106 MInLocs[1][1] = RaxPHIInBlk1;
3107 MOutLocs[1][1] = RspDefInBlk1;
3108 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3109 VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1ID, EmptyProps)});
3110 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3111 MOutLocs, MInLocs, VLocs);
3112 EXPECT_EQ(Output[0].size(), 0ul);
3113 ASSERT_EQ(Output[1].size(), 1ul);
3114 ASSERT_EQ(Output[2].size(), 1ul);
3115 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3116 // Today, the first register is picked.
3117 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3118 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3119 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
3120 ClearOutputs();
3121 VLocs[0].Vars.clear();
3122 VLocs[1].Vars.clear();
3124 // If the loop block looked a bit like this:
3125 // %0 = PHI %1, %2
3126 // [...]
3127 // DBG_VALUE %0
3128 // Then with instr-ref it becomes:
3129 // DBG_PHI %0
3130 // [...]
3131 // DBG_INSTR_REF
3132 // And we would be feeding a machine PHI-value back around the loop. However:
3133 // this does not mean we can eliminate the variable value PHI and use the
3134 // variable value from the entry block: they are distinct values that must be
3135 // joined at some location by the control flow.
3136 // [This test input would never occur naturally, the machine-PHI would be
3137 // eliminated]
3138 MInLocs[1][0] = RspPHIInBlk1;
3139 MOutLocs[1][0] = RspPHIInBlk1;
3140 MInLocs[1][1] = LiveInRax;
3141 MOutLocs[1][1] = LiveInRax;
3142 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3143 VLocs[1].Vars.insert({Var, DbgValue(RspPHIInBlk1ID, EmptyProps)});
3144 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3145 MOutLocs, MInLocs, VLocs);
3146 EXPECT_EQ(Output[0].size(), 0ul);
3147 ASSERT_EQ(Output[1].size(), 1ul);
3148 ASSERT_EQ(Output[2].size(), 1ul);
3149 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3150 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3151 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3152 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3153 ClearOutputs();
3154 VLocs[0].Vars.clear();
3155 VLocs[1].Vars.clear();
3157 // Test that we can eliminate PHIs. A PHI will be placed at the loop head
3158 // because there's a def in it.
3159 MInLocs[1][0] = LiveInRsp;
3160 MOutLocs[1][0] = LiveInRsp;
3161 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3162 VLocs[1].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3163 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3164 MOutLocs, MInLocs, VLocs);
3165 EXPECT_EQ(Output[0].size(), 0ul);
3166 ASSERT_EQ(Output[1].size(), 1ul);
3167 ASSERT_EQ(Output[2].size(), 1ul);
3168 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3169 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3170 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3171 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3172 ClearOutputs();
3173 VLocs[0].Vars.clear();
3174 VLocs[1].Vars.clear();
3177 // test phi elimination with the nested situation
3178 TEST_F(InstrRefLDVTest, VLocNestedLoop) {
3179 // entry
3180 // |
3181 // loop1
3182 // ^\
3183 // | \ /-\
3184 // | loop2 |
3185 // | / \-/
3186 // ^ /
3187 // join
3188 // |
3189 // ret
3190 setupNestedLoops();
3192 ASSERT_TRUE(MTracker->getNumLocs() == 1);
3193 LocIdx RspLoc(0);
3194 Register RAX = getRegByName("RAX");
3195 LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
3197 unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2;
3199 ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
3200 ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
3201 ValueIDNum RspPHIInBlk1 = ValueIDNum(Loop1Blk, 0, RspLoc);
3202 ValueIDNum RspPHIInBlk2 = ValueIDNum(Loop2Blk, 0, RspLoc);
3203 ValueIDNum RspDefInBlk2 = ValueIDNum(Loop2Blk, 1, RspLoc);
3204 DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
3205 DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
3206 DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
3207 DbgOpID RspPHIInBlk2ID = addValueDbgOp(RspPHIInBlk2);
3208 DbgOpID RspDefInBlk2ID = addValueDbgOp(RspDefInBlk2);
3210 FuncValueTable MInLocs, MOutLocs;
3211 std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
3213 initValueArray(MInLocs, 5, 2);
3214 initValueArray(MOutLocs, 5, 2);
3216 DebugVariable Var(FuncVariable, std::nullopt, nullptr);
3217 DbgValueProperties EmptyProps(EmptyExpr, false, false);
3219 SmallSet<DebugVariable, 4> AllVars;
3220 AllVars.insert(Var);
3222 SmallPtrSet<MachineBasicBlock *, 5> AssignBlocks;
3223 AssignBlocks.insert(MBB0);
3224 AssignBlocks.insert(MBB1);
3225 AssignBlocks.insert(MBB2);
3226 AssignBlocks.insert(MBB3);
3227 AssignBlocks.insert(MBB4);
3229 SmallVector<VLocTracker, 5> VLocs;
3230 VLocs.resize(5, VLocTracker(Overlaps, EmptyExpr));
3232 InstrRefBasedLDV::LiveInsT Output;
3234 // Start off with LiveInRsp in every location.
3235 for (unsigned int I = 0; I < 5; ++I) {
3236 MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
3237 MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
3240 auto ClearOutputs = [&]() {
3241 for (auto &Elem : Output)
3242 Elem.clear();
3244 Output.resize(5);
3246 // A dominating assign should propagate to all blocks.
3247 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3248 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3249 MOutLocs, MInLocs, VLocs);
3250 EXPECT_EQ(Output[0].size(), 0ul);
3251 ASSERT_EQ(Output[1].size(), 1ul);
3252 ASSERT_EQ(Output[2].size(), 1ul);
3253 ASSERT_EQ(Output[3].size(), 1ul);
3254 ASSERT_EQ(Output[4].size(), 1ul);
3255 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3256 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3257 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3258 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3259 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3260 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
3261 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3262 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRspID);
3263 ClearOutputs();
3264 VLocs[0].Vars.clear();
3266 // Test that an assign in the inner loop causes unresolved PHIs at the heads
3267 // of both loops, and no output location. Dominated blocks do get values.
3268 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3269 VLocs[2].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
3270 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3271 MOutLocs, MInLocs, VLocs);
3272 EXPECT_EQ(Output[0].size(), 0ul);
3273 EXPECT_EQ(Output[1].size(), 0ul);
3274 EXPECT_EQ(Output[2].size(), 0ul);
3275 ASSERT_EQ(Output[3].size(), 1ul);
3276 ASSERT_EQ(Output[4].size(), 1ul);
3277 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3278 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3279 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3280 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3281 ClearOutputs();
3282 VLocs[0].Vars.clear();
3283 VLocs[2].Vars.clear();
3285 // Same test, but with no assignment in block 0. We should still get values
3286 // in dominated blocks.
3287 VLocs[2].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
3288 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3289 MOutLocs, MInLocs, VLocs);
3290 EXPECT_EQ(Output[0].size(), 0ul);
3291 EXPECT_EQ(Output[1].size(), 0ul);
3292 EXPECT_EQ(Output[2].size(), 0ul);
3293 ASSERT_EQ(Output[3].size(), 1ul);
3294 ASSERT_EQ(Output[4].size(), 1ul);
3295 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3296 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3297 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3298 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3299 ClearOutputs();
3300 VLocs[2].Vars.clear();
3302 // Similarly, assignments in the outer loop gives location to dominated
3303 // blocks, but no PHI locations are found at the outer loop head.
3304 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3305 VLocs[3].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
3306 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3307 MOutLocs, MInLocs, VLocs);
3308 EXPECT_EQ(Output[0].size(), 0ul);
3309 EXPECT_EQ(Output[1].size(), 0ul);
3310 EXPECT_EQ(Output[2].size(), 0ul);
3311 EXPECT_EQ(Output[3].size(), 0ul);
3312 ASSERT_EQ(Output[4].size(), 1ul);
3313 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3314 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3315 ClearOutputs();
3316 VLocs[0].Vars.clear();
3317 VLocs[3].Vars.clear();
3319 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3320 VLocs[1].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
3321 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3322 MOutLocs, MInLocs, VLocs);
3323 EXPECT_EQ(Output[0].size(), 0ul);
3324 EXPECT_EQ(Output[1].size(), 0ul);
3325 ASSERT_EQ(Output[2].size(), 1ul);
3326 ASSERT_EQ(Output[3].size(), 1ul);
3327 ASSERT_EQ(Output[4].size(), 1ul);
3328 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3329 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
3330 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3331 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3332 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3333 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3334 ClearOutputs();
3335 VLocs[0].Vars.clear();
3336 VLocs[1].Vars.clear();
3338 // With an assignment of the same value in the inner loop, we should work out
3339 // that all PHIs can be eliminated and the same value is live-through the
3340 // whole function.
3341 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3342 VLocs[2].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3343 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3344 MOutLocs, MInLocs, VLocs);
3345 EXPECT_EQ(Output[0].size(), 0ul);
3346 EXPECT_EQ(Output[1].size(), 1ul);
3347 EXPECT_EQ(Output[2].size(), 1ul);
3348 ASSERT_EQ(Output[3].size(), 1ul);
3349 ASSERT_EQ(Output[4].size(), 1ul);
3350 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3351 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3352 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3353 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3354 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3355 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
3356 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3357 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRspID);
3358 ClearOutputs();
3359 VLocs[0].Vars.clear();
3360 VLocs[2].Vars.clear();
3362 // If we have an assignment in the inner loop, and a PHI for it at the inner
3363 // loop head, we could find a live-in location for the inner loop. But because
3364 // the outer loop has no PHI, we can't find a variable value for outer loop
3365 // head, so can't have a live-in value for the inner loop head.
3366 MInLocs[2][0] = RspPHIInBlk2;
3367 MOutLocs[2][0] = LiveInRax;
3368 // NB: all other machine locations are LiveInRsp, disallowing a PHI in block
3369 // one. Even though RspPHIInBlk2 isn't available later in the function, we
3370 // should still produce a live-in value. The fact it's unavailable is a
3371 // different concern.
3372 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3373 VLocs[2].Vars.insert({Var, DbgValue(LiveInRaxID, EmptyProps)});
3374 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3375 MOutLocs, MInLocs, VLocs);
3376 EXPECT_EQ(Output[0].size(), 0ul);
3377 EXPECT_EQ(Output[1].size(), 0ul);
3378 EXPECT_EQ(Output[2].size(), 0ul);
3379 ASSERT_EQ(Output[3].size(), 1ul);
3380 ASSERT_EQ(Output[4].size(), 1ul);
3381 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3382 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3383 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3384 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3385 ClearOutputs();
3386 VLocs[0].Vars.clear();
3387 VLocs[2].Vars.clear();
3389 // Have an assignment in inner loop that can have a PHI resolved; and add a
3390 // machine value PHI to the outer loop head, so that we can find a location
3391 // all the way through the function.
3392 MInLocs[1][0] = RspPHIInBlk1;
3393 MOutLocs[1][0] = RspPHIInBlk1;
3394 MInLocs[2][0] = RspPHIInBlk2;
3395 MOutLocs[2][0] = RspDefInBlk2;
3396 MInLocs[3][0] = RspDefInBlk2;
3397 MOutLocs[3][0] = RspDefInBlk2;
3398 VLocs[0].Vars.insert({Var, DbgValue(LiveInRspID, EmptyProps)});
3399 VLocs[2].Vars.insert({Var, DbgValue(RspDefInBlk2ID, EmptyProps)});
3400 buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3401 MOutLocs, MInLocs, VLocs);
3402 EXPECT_EQ(Output[0].size(), 0ul);
3403 ASSERT_EQ(Output[1].size(), 1ul);
3404 ASSERT_EQ(Output[2].size(), 1ul);
3405 ASSERT_EQ(Output[3].size(), 1ul);
3406 ASSERT_EQ(Output[4].size(), 1ul);
3407 EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3408 EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3409 EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3410 EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspPHIInBlk2ID);
3411 EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3412 EXPECT_EQ(Output[3][0].second.getDbgOpID(0), RspDefInBlk2ID);
3413 EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3414 EXPECT_EQ(Output[4][0].second.getDbgOpID(0), RspDefInBlk2ID);
3415 ClearOutputs();
3416 VLocs[0].Vars.clear();
3417 VLocs[2].Vars.clear();