1 //===------------- llvm/unittest/CodeGen/InstrRefLDVTest.cpp --------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "llvm/CodeGen/CodeGenTargetMachineImpl.h"
10 #include "llvm/CodeGen/MIRParser/MIRParser.h"
11 #include "llvm/CodeGen/MachineDominators.h"
12 #include "llvm/CodeGen/MachineModuleInfo.h"
13 #include "llvm/CodeGen/TargetFrameLowering.h"
14 #include "llvm/CodeGen/TargetInstrInfo.h"
15 #include "llvm/CodeGen/TargetLowering.h"
16 #include "llvm/CodeGen/TargetRegisterInfo.h"
17 #include "llvm/CodeGen/TargetSubtargetInfo.h"
18 #include "llvm/IR/DIBuilder.h"
19 #include "llvm/IR/DebugInfoMetadata.h"
20 #include "llvm/IR/IRBuilder.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/MC/TargetRegistry.h"
23 #include "llvm/Support/MemoryBuffer.h"
24 #include "llvm/Support/TargetSelect.h"
25 #include "llvm/Target/TargetOptions.h"
27 #include "../lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h"
29 #include "gtest/gtest.h"
32 using namespace LiveDebugValues
;
34 // Include helper functions to ease the manipulation of MachineFunctions
35 #include "MFCommon.inc"
37 class InstrRefLDVTest
: public testing::Test
{
39 friend class InstrRefBasedLDV
;
40 using MLocTransferMap
= InstrRefBasedLDV::MLocTransferMap
;
43 std::unique_ptr
<Module
> Mod
;
44 std::unique_ptr
<TargetMachine
> Machine
;
45 std::unique_ptr
<MachineFunction
> MF
;
46 std::unique_ptr
<MachineDominatorTree
> DomTree
;
47 std::unique_ptr
<MachineModuleInfo
> MMI
;
50 DISubprogram
*OurFunc
;
51 DILexicalBlock
*OurBlock
, *AnotherBlock
;
52 DISubprogram
*ToInlineFunc
;
53 DILexicalBlock
*ToInlineBlock
;
54 DILocalVariable
*FuncVariable
;
56 DIExpression
*EmptyExpr
;
57 LiveDebugValues::OverlapMap Overlaps
;
58 LiveDebugValues::DebugVariableMap DVMap
;
60 DebugLoc OutermostLoc
, InBlockLoc
, NotNestedBlockLoc
, InlinedLoc
;
62 MachineBasicBlock
*MBB0
, *MBB1
, *MBB2
, *MBB3
, *MBB4
;
64 std::unique_ptr
<InstrRefBasedLDV
> LDV
;
65 std::unique_ptr
<MLocTracker
> MTracker
;
66 std::unique_ptr
<VLocTracker
> VTracker
;
68 SmallString
<256> MIRStr
;
70 InstrRefLDVTest() : Ctx(), Mod(std::make_unique
<Module
>("beehives", Ctx
)) {}
73 // Boilerplate that creates a MachineFunction and associated blocks.
75 Mod
->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-"
76 "f80:128-n8:16:32:64-S128");
77 Triple
TargetTriple("x86_64--");
79 const Target
*T
= TargetRegistry::lookupTarget("", TargetTriple
, Error
);
83 TargetOptions Options
;
84 Machine
= std::unique_ptr
<TargetMachine
>(T
->createTargetMachine(
85 Triple::normalize("x86_64--"), "", "", Options
, std::nullopt
,
86 std::nullopt
, CodeGenOptLevel::Aggressive
));
88 auto Type
= FunctionType::get(Type::getVoidTy(Ctx
), false);
90 Function::Create(Type
, GlobalValue::ExternalLinkage
, "Test", &*Mod
);
92 unsigned FunctionNum
= 42;
93 MMI
= std::make_unique
<MachineModuleInfo
>(Machine
.get());
94 const TargetSubtargetInfo
&STI
= *Machine
->getSubtargetImpl(*F
);
96 MF
= std::make_unique
<MachineFunction
>(*F
, *Machine
, STI
, MMI
->getContext(),
99 // Create metadata: CU, subprogram, some blocks and an inline function
102 OurFile
= DIB
.createFile("xyzzy.c", "/cave");
104 DIB
.createCompileUnit(dwarf::DW_LANG_C99
, OurFile
, "nou", false, "", 0);
105 auto OurSubT
= DIB
.createSubroutineType(DIB
.getOrCreateTypeArray({}));
107 DIB
.createFunction(OurCU
, "bees", "", OurFile
, 1, OurSubT
, 1,
108 DINode::FlagZero
, DISubprogram::SPFlagDefinition
);
109 F
->setSubprogram(OurFunc
);
110 OurBlock
= DIB
.createLexicalBlock(OurFunc
, OurFile
, 2, 3);
111 AnotherBlock
= DIB
.createLexicalBlock(OurFunc
, OurFile
, 2, 6);
113 DIB
.createFunction(OurFile
, "shoes", "", OurFile
, 10, OurSubT
, 10,
114 DINode::FlagZero
, DISubprogram::SPFlagDefinition
);
116 // Make some nested scopes.
117 OutermostLoc
= DILocation::get(Ctx
, 3, 1, OurFunc
);
118 InBlockLoc
= DILocation::get(Ctx
, 4, 1, OurBlock
);
119 InlinedLoc
= DILocation::get(Ctx
, 10, 1, ToInlineFunc
, InBlockLoc
.get());
121 // Make a scope that isn't nested within the others.
122 NotNestedBlockLoc
= DILocation::get(Ctx
, 4, 1, AnotherBlock
);
124 LongInt
= DIB
.createBasicType("long", 64, llvm::dwarf::DW_ATE_unsigned
);
125 FuncVariable
= DIB
.createAutoVariable(OurFunc
, "lala", OurFile
, 1, LongInt
);
126 EmptyExpr
= DIExpression::get(Ctx
, {});
131 Register
getRegByName(const char *WantedName
) {
132 auto *TRI
= MF
->getRegInfo().getTargetRegisterInfo();
134 for (unsigned int I
= 1; I
< TRI
->getNumRegs(); ++I
) {
135 const char *Name
= TRI
->getName(I
);
136 if (strcmp(WantedName
, Name
) == 0)
140 // If this ever fails, something is very wrong with this unit test.
141 llvm_unreachable("Can't find register by name");
144 InstrRefBasedLDV
*setupLDVObj(MachineFunction
*MF
) {
145 // Create a new LDV object, and plug some relevant object ptrs into it.
146 LDV
= std::make_unique
<InstrRefBasedLDV
>();
147 const TargetSubtargetInfo
&STI
= MF
->getSubtarget();
148 LDV
->TII
= STI
.getInstrInfo();
149 LDV
->TRI
= STI
.getRegisterInfo();
150 LDV
->TFI
= STI
.getFrameLowering();
151 LDV
->MFI
= &MF
->getFrameInfo();
152 LDV
->MRI
= &MF
->getRegInfo();
154 DomTree
= std::make_unique
<MachineDominatorTree
>(*MF
);
155 LDV
->DomTree
= &*DomTree
;
157 // Future work: unit tests for mtracker / vtracker / ttracker.
159 // Setup things like the artifical block map, and BlockNo <=> RPO Order
161 LDV
->initialSetup(*MF
);
162 LDV
->LS
.initialize(*MF
);
167 void addMTracker(MachineFunction
*MF
) {
169 // Add a machine-location-tracking object to LDV. Don't initialize any
170 // register locations within it though.
171 const TargetSubtargetInfo
&STI
= MF
->getSubtarget();
172 MTracker
= std::make_unique
<MLocTracker
>(
173 *MF
, *LDV
->TII
, *LDV
->TRI
, *STI
.getTargetLowering());
174 LDV
->MTracker
= &*MTracker
;
179 VTracker
= std::make_unique
<VLocTracker
>(DVMap
, Overlaps
, EmptyExpr
);
180 LDV
->VTracker
= &*VTracker
;
183 DbgOpID
addValueDbgOp(ValueIDNum V
) {
184 return LDV
->DbgOpStore
.insert(DbgOp(V
));
186 DbgOpID
addConstDbgOp(MachineOperand MO
) {
187 return LDV
->DbgOpStore
.insert(DbgOp(MO
));
190 // Some routines for bouncing into LDV,
191 void buildMLocValueMap(FuncValueTable
&MInLocs
, FuncValueTable
&MOutLocs
,
192 SmallVectorImpl
<MLocTransferMap
> &MLocTransfer
) {
193 LDV
->buildMLocValueMap(*MF
, MInLocs
, MOutLocs
, MLocTransfer
);
196 void placeMLocPHIs(MachineFunction
&MF
,
197 SmallPtrSetImpl
<MachineBasicBlock
*> &AllBlocks
,
198 FuncValueTable
&MInLocs
,
199 SmallVectorImpl
<MLocTransferMap
> &MLocTransfer
) {
200 LDV
->placeMLocPHIs(MF
, AllBlocks
, MInLocs
, MLocTransfer
);
204 pickVPHILoc(SmallVectorImpl
<DbgOpID
> &OutValues
, const MachineBasicBlock
&MBB
,
205 const InstrRefBasedLDV::LiveIdxT
&LiveOuts
,
206 FuncValueTable
&MOutLocs
,
207 const SmallVectorImpl
<const MachineBasicBlock
*> &BlockOrders
) {
208 return LDV
->pickVPHILoc(OutValues
, MBB
, LiveOuts
, MOutLocs
, BlockOrders
);
211 bool vlocJoin(MachineBasicBlock
&MBB
, InstrRefBasedLDV::LiveIdxT
&VLOCOutLocs
,
212 SmallPtrSet
<const MachineBasicBlock
*, 8> &BlocksToExplore
,
214 return LDV
->vlocJoin(MBB
, VLOCOutLocs
, BlocksToExplore
, InLoc
);
217 void buildVLocValueMap(const DILocation
*DILoc
,
218 const SmallSet
<DebugVariableID
, 4> &VarsWeCareAbout
,
219 SmallPtrSetImpl
<MachineBasicBlock
*> &AssignBlocks
,
220 InstrRefBasedLDV::LiveInsT
&Output
, FuncValueTable
&MOutLocs
,
221 FuncValueTable
&MInLocs
,
222 SmallVectorImpl
<VLocTracker
> &AllTheVLocs
) {
223 LDV
->buildVLocValueMap(DILoc
, VarsWeCareAbout
, AssignBlocks
, Output
,
224 MOutLocs
, MInLocs
, AllTheVLocs
);
227 void initValueArray(FuncValueTable
&Nums
, unsigned Blks
, unsigned Locs
) {
228 for (unsigned int I
= 0; I
< Blks
; ++I
)
229 for (unsigned int J
= 0; J
< Locs
; ++J
)
230 Nums
[I
][J
] = ValueIDNum::EmptyValue
;
233 void setupSingleBlock() {
234 // Add an entry block with nothing but 'ret void' in it.
235 Function
&F
= const_cast<llvm::Function
&>(MF
->getFunction());
236 auto *BB0
= BasicBlock::Create(Ctx
, "entry", &F
);
237 IRBuilder
<> IRB(BB0
);
239 MBB0
= MF
->CreateMachineBasicBlock(BB0
);
240 MF
->insert(MF
->end(), MBB0
);
241 MF
->RenumberBlocks();
246 void setupDiamondBlocks() {
252 llvm::Function
&F
= const_cast<llvm::Function
&>(MF
->getFunction());
253 auto *BB0
= BasicBlock::Create(Ctx
, "a", &F
);
254 auto *BB1
= BasicBlock::Create(Ctx
, "b", &F
);
255 auto *BB2
= BasicBlock::Create(Ctx
, "c", &F
);
256 auto *BB3
= BasicBlock::Create(Ctx
, "d", &F
);
257 IRBuilder
<> IRB0(BB0
), IRB1(BB1
), IRB2(BB2
), IRB3(BB3
);
261 IRB3
.CreateRetVoid();
262 MBB0
= MF
->CreateMachineBasicBlock(BB0
);
263 MF
->insert(MF
->end(), MBB0
);
264 MBB1
= MF
->CreateMachineBasicBlock(BB1
);
265 MF
->insert(MF
->end(), MBB1
);
266 MBB2
= MF
->CreateMachineBasicBlock(BB2
);
267 MF
->insert(MF
->end(), MBB2
);
268 MBB3
= MF
->CreateMachineBasicBlock(BB3
);
269 MF
->insert(MF
->end(), MBB3
);
270 MBB0
->addSuccessor(MBB1
);
271 MBB0
->addSuccessor(MBB2
);
272 MBB1
->addSuccessor(MBB3
);
273 MBB2
->addSuccessor(MBB3
);
274 MF
->RenumberBlocks();
279 void setupSimpleLoop() {
287 llvm::Function
&F
= const_cast<llvm::Function
&>(MF
->getFunction());
288 auto *BB0
= BasicBlock::Create(Ctx
, "entry", &F
);
289 auto *BB1
= BasicBlock::Create(Ctx
, "loop", &F
);
290 auto *BB2
= BasicBlock::Create(Ctx
, "ret", &F
);
291 IRBuilder
<> IRB0(BB0
), IRB1(BB1
), IRB2(BB2
);
294 IRB2
.CreateRetVoid();
295 MBB0
= MF
->CreateMachineBasicBlock(BB0
);
296 MF
->insert(MF
->end(), MBB0
);
297 MBB1
= MF
->CreateMachineBasicBlock(BB1
);
298 MF
->insert(MF
->end(), MBB1
);
299 MBB2
= MF
->CreateMachineBasicBlock(BB2
);
300 MF
->insert(MF
->end(), MBB2
);
301 MBB0
->addSuccessor(MBB1
);
302 MBB1
->addSuccessor(MBB2
);
303 MBB1
->addSuccessor(MBB1
);
304 MF
->RenumberBlocks();
309 void setupNestedLoops() {
321 llvm::Function
&F
= const_cast<llvm::Function
&>(MF
->getFunction());
322 auto *BB0
= BasicBlock::Create(Ctx
, "entry", &F
);
323 auto *BB1
= BasicBlock::Create(Ctx
, "loop1", &F
);
324 auto *BB2
= BasicBlock::Create(Ctx
, "loop2", &F
);
325 auto *BB3
= BasicBlock::Create(Ctx
, "join", &F
);
326 auto *BB4
= BasicBlock::Create(Ctx
, "ret", &F
);
327 IRBuilder
<> IRB0(BB0
), IRB1(BB1
), IRB2(BB2
), IRB3(BB3
), IRB4(BB4
);
332 IRB4
.CreateRetVoid();
333 MBB0
= MF
->CreateMachineBasicBlock(BB0
);
334 MF
->insert(MF
->end(), MBB0
);
335 MBB1
= MF
->CreateMachineBasicBlock(BB1
);
336 MF
->insert(MF
->end(), MBB1
);
337 MBB2
= MF
->CreateMachineBasicBlock(BB2
);
338 MF
->insert(MF
->end(), MBB2
);
339 MBB3
= MF
->CreateMachineBasicBlock(BB3
);
340 MF
->insert(MF
->end(), MBB3
);
341 MBB4
= MF
->CreateMachineBasicBlock(BB4
);
342 MF
->insert(MF
->end(), MBB4
);
343 MBB0
->addSuccessor(MBB1
);
344 MBB1
->addSuccessor(MBB2
);
345 MBB2
->addSuccessor(MBB2
);
346 MBB2
->addSuccessor(MBB3
);
347 MBB3
->addSuccessor(MBB1
);
348 MBB3
->addSuccessor(MBB4
);
349 MF
->RenumberBlocks();
354 void setupNoDominatingLoop() {
365 llvm::Function
&F
= const_cast<llvm::Function
&>(MF
->getFunction());
366 auto *BB0
= BasicBlock::Create(Ctx
, "entry", &F
);
367 auto *BB1
= BasicBlock::Create(Ctx
, "head1", &F
);
368 auto *BB2
= BasicBlock::Create(Ctx
, "head2", &F
);
369 auto *BB3
= BasicBlock::Create(Ctx
, "joinblk", &F
);
370 auto *BB4
= BasicBlock::Create(Ctx
, "ret", &F
);
371 IRBuilder
<> IRB0(BB0
), IRB1(BB1
), IRB2(BB2
), IRB3(BB3
), IRB4(BB4
);
376 IRB4
.CreateRetVoid();
377 MBB0
= MF
->CreateMachineBasicBlock(BB0
);
378 MF
->insert(MF
->end(), MBB0
);
379 MBB1
= MF
->CreateMachineBasicBlock(BB1
);
380 MF
->insert(MF
->end(), MBB1
);
381 MBB2
= MF
->CreateMachineBasicBlock(BB2
);
382 MF
->insert(MF
->end(), MBB2
);
383 MBB3
= MF
->CreateMachineBasicBlock(BB3
);
384 MF
->insert(MF
->end(), MBB3
);
385 MBB4
= MF
->CreateMachineBasicBlock(BB4
);
386 MF
->insert(MF
->end(), MBB4
);
387 MBB0
->addSuccessor(MBB1
);
388 MBB0
->addSuccessor(MBB2
);
389 MBB1
->addSuccessor(MBB3
);
390 MBB2
->addSuccessor(MBB3
);
391 MBB3
->addSuccessor(MBB1
);
392 MBB3
->addSuccessor(MBB2
);
393 MBB3
->addSuccessor(MBB4
);
394 MF
->RenumberBlocks();
399 void setupBadlyNestedLoops() {
412 // NB: the loop blocks self-loop, which is a bit too fiddly to draw on
414 llvm::Function
&F
= const_cast<llvm::Function
&>(MF
->getFunction());
415 auto *BB0
= BasicBlock::Create(Ctx
, "entry", &F
);
416 auto *BB1
= BasicBlock::Create(Ctx
, "loop1", &F
);
417 auto *BB2
= BasicBlock::Create(Ctx
, "loop2", &F
);
418 auto *BB3
= BasicBlock::Create(Ctx
, "loop3", &F
);
419 auto *BB4
= BasicBlock::Create(Ctx
, "ret", &F
);
420 IRBuilder
<> IRB0(BB0
), IRB1(BB1
), IRB2(BB2
), IRB3(BB3
), IRB4(BB4
);
425 IRB4
.CreateRetVoid();
426 MBB0
= MF
->CreateMachineBasicBlock(BB0
);
427 MF
->insert(MF
->end(), MBB0
);
428 MBB1
= MF
->CreateMachineBasicBlock(BB1
);
429 MF
->insert(MF
->end(), MBB1
);
430 MBB2
= MF
->CreateMachineBasicBlock(BB2
);
431 MF
->insert(MF
->end(), MBB2
);
432 MBB3
= MF
->CreateMachineBasicBlock(BB3
);
433 MF
->insert(MF
->end(), MBB3
);
434 MBB4
= MF
->CreateMachineBasicBlock(BB4
);
435 MF
->insert(MF
->end(), MBB4
);
436 MBB0
->addSuccessor(MBB1
);
437 MBB1
->addSuccessor(MBB1
);
438 MBB1
->addSuccessor(MBB2
);
439 MBB2
->addSuccessor(MBB1
);
440 MBB2
->addSuccessor(MBB2
);
441 MBB2
->addSuccessor(MBB3
);
442 MBB3
->addSuccessor(MBB2
);
443 MBB3
->addSuccessor(MBB3
);
444 MBB3
->addSuccessor(MBB4
);
445 MF
->RenumberBlocks();
450 MachineFunction
*readMIRBlock(const char *Input
) {
452 StringRef S
= Twine(Twine(R
"MIR(
454 target triple = "x86_64
-unknown
-linux
-gnu
"
455 define void @test() { ret void }
459 tracksRegLiveness: true
461 - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
462 stack-id: default, callee-saved-register: '', callee-saved-restored: true,
463 debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
467 )MIR") + Twine(Input
) + Twine("...\n"))
468 .toNullTerminatedStringRef(MIRStr
);
471 // Clear the "test" function from MMI if it's still present.
472 if (Function
*Fn
= Mod
->getFunction("test"))
473 MMI
->deleteMachineFunctionFor(*Fn
);
475 auto MemBuf
= MemoryBuffer::getMemBuffer(S
, "<input>");
476 auto MIRParse
= createMIRParser(std::move(MemBuf
), Ctx
);
477 Mod
= MIRParse
->parseIRModule();
479 Mod
->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-"
480 "f80:128-n8:16:32:64-S128");
482 bool Result
= MIRParse
->parseMachineFunctions(*Mod
, *MMI
);
483 assert(!Result
&& "Failed to parse unit test machine function?");
486 Function
*Fn
= Mod
->getFunction("test");
487 assert(Fn
&& "Failed to parse a unit test module string?");
488 Fn
->setSubprogram(OurFunc
);
489 return MMI
->getMachineFunction(*Fn
);
493 produceMLocTransferFunction(MachineFunction
&MF
,
494 SmallVectorImpl
<MLocTransferMap
> &MLocTransfer
,
495 unsigned MaxNumBlocks
) {
496 LDV
->produceMLocTransferFunction(MF
, MLocTransfer
, MaxNumBlocks
);
499 std::pair
<FuncValueTable
, FuncValueTable
>
500 allocValueTables(unsigned Blocks
, unsigned Locs
) {
501 return {FuncValueTable(Blocks
, Locs
), FuncValueTable(Blocks
, Locs
)};
505 TEST_F(InstrRefLDVTest
, MTransferDefs
) {
506 MachineFunction
*MF
= readMIRBlock(
507 " $rax = MOV64ri 0\n"
511 // We should start with only SP tracked.
512 EXPECT_TRUE(MTracker
->getNumLocs() == 1);
514 SmallVector
<MLocTransferMap
, 1> TransferMap
;
515 TransferMap
.resize(1);
516 produceMLocTransferFunction(*MF
, TransferMap
, 1);
518 // Code contains only one register write: that should assign to each of the
519 // aliasing registers. Test that all of them get locations, and have a
520 // corresponding def at the first instr in the function.
521 const char *RegNames
[] = {"RAX", "HAX", "EAX", "AX", "AH", "AL"};
522 EXPECT_TRUE(MTracker
->getNumLocs() == 7);
523 for (const char *RegName
: RegNames
) {
524 Register R
= getRegByName(RegName
);
525 ASSERT_TRUE(MTracker
->isRegisterTracked(R
));
526 LocIdx L
= MTracker
->getRegMLoc(R
);
527 ValueIDNum V
= MTracker
->readReg(R
);
528 // Value of this register should be: block zero, instruction 1, and the
529 // location it's defined in is itself.
530 ValueIDNum
ToCmp(0, 1, L
);
534 // Do the same again, but with an aliasing write. This should write to all
535 // the same registers again, except $ah and $hax (the upper 8 bits of $ax
536 // and 32 bits of $rax resp.).
538 " $rax = MOV64ri 0\n"
543 TransferMap
.resize(1);
544 produceMLocTransferFunction(*MF
, TransferMap
, 1);
546 auto TestRegSetSite
= [&](const char *Name
, unsigned InstrNum
) {
547 Register R
= getRegByName(Name
);
548 ASSERT_TRUE(MTracker
->isRegisterTracked(R
));
549 LocIdx L
= MTracker
->getRegMLoc(R
);
550 ValueIDNum V
= MTracker
->readMLoc(L
);
551 ValueIDNum
ToCmp(0, InstrNum
, L
);
555 TestRegSetSite("AL", 2);
556 TestRegSetSite("AH", 1);
557 TestRegSetSite("AX", 2);
558 TestRegSetSite("EAX", 2);
559 TestRegSetSite("HAX", 1);
560 TestRegSetSite("RAX", 2);
563 // * Def rax via the implicit-def,
564 // * Clobber rsi/rdi and all their subregs, via the register mask
565 // * Same for rcx, despite it not being a use in the instr, it's in the mask
566 // * NOT clobber $rsp / $esp $ sp, LiveDebugValues deliberately ignores
568 // * NOT clobber $rbx, because it's non-volatile
569 // * Not track every other register in the machine, only those needed.
571 " $rax = MOV64ri 0\n" // instr 1
572 " $rbx = MOV64ri 0\n" // instr 2
573 " $rcx = MOV64ri 0\n" // instr 3
574 " $rdi = MOV64ri 0\n" // instr 4
575 " $rsi = MOV64ri 0\n" // instr 5
576 " 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
577 " RET64 $rax\n"); // instr 7
580 TransferMap
.resize(1);
581 produceMLocTransferFunction(*MF
, TransferMap
, 1);
583 const char *RegsSetInCall
[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX",
584 "DIL", "DIH", "DI", "EDI", "HDI", "RDI",
585 "SIL", "SIH", "SI", "ESI", "HSI", "RSI",
586 "CL", "CH", "CX", "ECX", "HCX", "RCX"};
587 for (const char *RegSetInCall
: RegsSetInCall
)
588 TestRegSetSite(RegSetInCall
, 6);
590 const char *RegsLeftAlone
[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
591 for (const char *RegLeftAlone
: RegsLeftAlone
)
592 TestRegSetSite(RegLeftAlone
, 2);
594 // Stack pointer should be the live-in to the function, instruction zero.
595 TestRegSetSite("RSP", 0);
596 // These stack regs should not be tracked either. Nor the (fake) subregs.
597 EXPECT_FALSE(MTracker
->isRegisterTracked(getRegByName("ESP")));
598 EXPECT_FALSE(MTracker
->isRegisterTracked(getRegByName("SP")));
599 EXPECT_FALSE(MTracker
->isRegisterTracked(getRegByName("SPL")));
600 EXPECT_FALSE(MTracker
->isRegisterTracked(getRegByName("SPH")));
601 EXPECT_FALSE(MTracker
->isRegisterTracked(getRegByName("HSP")));
603 // Should only be tracking: 6 x {A, B, C, DI, SI} registers = 30,
604 // Plus RSP, SSP = 32.
605 EXPECT_EQ(32u, MTracker
->getNumLocs());
608 // When we DBG_PHI something, we should track all its subregs.
614 TransferMap
.resize(1);
615 produceMLocTransferFunction(*MF
, TransferMap
, 1);
617 // All DI regs and RSP tracked.
618 EXPECT_EQ(7u, MTracker
->getNumLocs());
620 // All the DI registers should have block live-in values, i.e. the argument
622 const char *DIRegs
[] = {"DIL", "DIH", "DI", "EDI", "HDI", "RDI"};
623 for (const char *DIReg
: DIRegs
)
624 TestRegSetSite(DIReg
, 0);
627 TEST_F(InstrRefLDVTest
, MTransferMeta
) {
628 // Meta instructions should not have any effect on register values.
629 SmallVector
<MLocTransferMap
, 1> TransferMap
;
630 MachineFunction
*MF
= readMIRBlock(
631 " $rax = MOV64ri 0\n"
632 " $rax = IMPLICIT_DEF\n"
633 " $rax = KILL killed $rax\n"
637 TransferMap
.resize(1);
638 produceMLocTransferFunction(*MF
, TransferMap
, 1);
640 LocIdx RaxLoc
= MTracker
->getRegMLoc(getRegByName("RAX"));
641 ValueIDNum V
= MTracker
->readMLoc(RaxLoc
);
642 // Def of rax should be from instruction 1, i.e., unmodified.
643 ValueIDNum
Cmp(0, 1, RaxLoc
);
647 TEST_F(InstrRefLDVTest
, MTransferCopies
) {
648 SmallVector
<MLocTransferMap
, 1> TransferMap
;
649 // This memory spill should be recognised, and a spill slot created.
650 MachineFunction
*MF
= readMIRBlock(
651 " $rax = MOV64ri 0\n"
652 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
656 TransferMap
.resize(1);
657 produceMLocTransferFunction(*MF
, TransferMap
, 1);
659 // Check that the spill location contains the value defined in rax by
660 // instruction 1. The MIR header says -16 offset, but it's stored as -8;
661 // it's not completely clear why, but here we only care about correctly
662 // identifying the slot, not that all the surrounding data is correct.
663 SpillLoc L
= {getRegByName("RSP"), StackOffset::getFixed(-8)};
664 SpillLocationNo SpillNo
= *MTracker
->getOrTrackSpillLoc(L
);
665 unsigned SpillLocID
= MTracker
->getLocID(SpillNo
, {64, 0});
666 LocIdx SpillLoc
= MTracker
->getSpillMLoc(SpillLocID
);
667 ValueIDNum V
= MTracker
->readMLoc(SpillLoc
);
668 Register RAX
= getRegByName("RAX");
669 LocIdx RaxLoc
= MTracker
->getRegMLoc(RAX
);
670 ValueIDNum
Cmp(0, 1, RaxLoc
);
673 // A spill and restore should be recognised.
675 " $rax = MOV64ri 0\n"
676 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
677 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
681 TransferMap
.resize(1);
682 produceMLocTransferFunction(*MF
, TransferMap
, 1);
684 // Test that rbx contains rax from instruction 1.
685 RAX
= getRegByName("RAX");
686 RaxLoc
= MTracker
->getRegMLoc(RAX
);
687 Register RBX
= getRegByName("RBX");
688 LocIdx RbxLoc
= MTracker
->getRegMLoc(RBX
);
689 Cmp
= ValueIDNum(0, 1, RaxLoc
);
690 ValueIDNum RbxVal
= MTracker
->readMLoc(RbxLoc
);
691 EXPECT_EQ(RbxVal
, Cmp
);
693 // Testing that all the subregisters are transferred happens in
694 // MTransferSubregSpills.
696 // Copies and x86 movs should be recognised and honoured. In addition, all
697 // of the subregisters should be copied across too.
699 " $rax = MOV64ri 0\n"
700 " $rcx = COPY $rax\n"
701 " $rbx = MOV64rr $rcx\n"
705 TransferMap
.resize(1);
706 produceMLocTransferFunction(*MF
, TransferMap
, 1);
708 const char *ARegs
[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
709 const char *BRegs
[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
710 const char *CRegs
[] = {"CL", "CH", "CX", "ECX", "HCX", "RCX"};
711 auto CheckReg
= [&](unsigned int I
) {
712 LocIdx A
= MTracker
->getRegMLoc(getRegByName(ARegs
[I
]));
713 LocIdx B
= MTracker
->getRegMLoc(getRegByName(BRegs
[I
]));
714 LocIdx C
= MTracker
->getRegMLoc(getRegByName(CRegs
[I
]));
715 ValueIDNum
ARefVal(0, 1, A
);
716 ValueIDNum AVal
= MTracker
->readMLoc(A
);
717 ValueIDNum BVal
= MTracker
->readMLoc(B
);
718 ValueIDNum CVal
= MTracker
->readMLoc(C
);
719 EXPECT_EQ(ARefVal
, AVal
);
720 EXPECT_EQ(ARefVal
, BVal
);
721 EXPECT_EQ(ARefVal
, CVal
);
724 for (unsigned int I
= 0; I
< 6; ++I
)
727 // When we copy to a subregister, the super-register should be def'd too: it's
728 // value will have changed.
730 " $rax = MOV64ri 0\n"
731 " $ecx = COPY $eax\n"
735 TransferMap
.resize(1);
736 produceMLocTransferFunction(*MF
, TransferMap
, 1);
738 // First four regs [al, ah, ax, eax] should be copied to *cx.
739 for (unsigned int I
= 0; I
< 4; ++I
) {
740 LocIdx A
= MTracker
->getRegMLoc(getRegByName(ARegs
[I
]));
741 LocIdx C
= MTracker
->getRegMLoc(getRegByName(CRegs
[I
]));
742 ValueIDNum
ARefVal(0, 1, A
);
743 ValueIDNum AVal
= MTracker
->readMLoc(A
);
744 ValueIDNum CVal
= MTracker
->readMLoc(C
);
745 EXPECT_EQ(ARefVal
, AVal
);
746 EXPECT_EQ(ARefVal
, CVal
);
749 // But rcx should contain a value defined by the COPY.
750 LocIdx RcxLoc
= MTracker
->getRegMLoc(getRegByName("RCX"));
751 ValueIDNum RcxVal
= MTracker
->readMLoc(RcxLoc
);
752 ValueIDNum
RcxDefVal(0, 2, RcxLoc
); // instr 2 -> the copy
753 EXPECT_EQ(RcxVal
, RcxDefVal
);
756 TEST_F(InstrRefLDVTest
, MTransferSubregSpills
) {
757 SmallVector
<MLocTransferMap
, 1> TransferMap
;
758 MachineFunction
*MF
= readMIRBlock(
759 " $rax = MOV64ri 0\n"
760 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
761 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
765 TransferMap
.resize(1);
766 produceMLocTransferFunction(*MF
, TransferMap
, 1);
768 // Check that all the subregs of rax and rbx contain the same values. One
769 // should completely transfer to the other.
770 const char *ARegs
[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
771 const char *BRegs
[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
772 for (unsigned int I
= 0; I
< 6; ++I
) {
773 LocIdx A
= MTracker
->getRegMLoc(getRegByName(ARegs
[I
]));
774 LocIdx B
= MTracker
->getRegMLoc(getRegByName(BRegs
[I
]));
775 EXPECT_EQ(MTracker
->readMLoc(A
), MTracker
->readMLoc(B
));
778 // Explicitly check what's in the different subreg slots, on the stack.
779 // Pair up subreg idx fields with the corresponding subregister in $rax.
780 MLocTracker::StackSlotPos SubRegIdxes
[] = {{8, 0}, {8, 8}, {16, 0}, {32, 0}, {64, 0}};
781 const char *SubRegNames
[] = {"AL", "AH", "AX", "EAX", "RAX"};
782 for (unsigned int I
= 0; I
< 5; ++I
) {
783 // Value number where it's defined,
784 LocIdx RegLoc
= MTracker
->getRegMLoc(getRegByName(SubRegNames
[I
]));
785 ValueIDNum
DefNum(0, 1, RegLoc
);
786 // Read the corresponding subreg field from the stack.
787 SpillLoc L
= {getRegByName("RSP"), StackOffset::getFixed(-8)};
788 SpillLocationNo SpillNo
= *MTracker
->getOrTrackSpillLoc(L
);
789 unsigned SpillID
= MTracker
->getLocID(SpillNo
, SubRegIdxes
[I
]);
790 LocIdx SpillLoc
= MTracker
->getSpillMLoc(SpillID
);
791 ValueIDNum SpillValue
= MTracker
->readMLoc(SpillLoc
);
792 EXPECT_EQ(DefNum
, SpillValue
);
795 // If we have exactly the same code, but we write $eax to the stack slot after
796 // $rax, then we should still have exactly the same output in the lower five
797 // subregisters. Storing $eax to the start of the slot will overwrite with the
798 // same values. $rax, as an aliasing register, should be reset to something
799 // else by that write.
800 // In theory, we could try and recognise that we're writing the _same_ values
801 // to the stack again, and so $rax doesn't need to be reset to something else.
802 // It seems vanishingly unlikely that LLVM would generate such code though,
803 // so the benefits would be small.
805 " $rax = MOV64ri 0\n"
806 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
807 " MOV32mr $rsp, 1, $noreg, 16, $noreg, $eax :: (store 4 into %stack.0)\n"
808 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
812 TransferMap
.resize(1);
813 produceMLocTransferFunction(*MF
, TransferMap
, 1);
815 // Check lower five registers up to and include $eax == $ebx,
816 for (unsigned int I
= 0; I
< 5; ++I
) {
817 LocIdx A
= MTracker
->getRegMLoc(getRegByName(ARegs
[I
]));
818 LocIdx B
= MTracker
->getRegMLoc(getRegByName(BRegs
[I
]));
819 EXPECT_EQ(MTracker
->readMLoc(A
), MTracker
->readMLoc(B
));
822 // $rbx should contain something else; today it's a def at the spill point
823 // of the 4 byte value.
824 SpillLoc L
= {getRegByName("RSP"), StackOffset::getFixed(-8)};
825 SpillLocationNo SpillNo
= *MTracker
->getOrTrackSpillLoc(L
);
826 unsigned SpillID
= MTracker
->getLocID(SpillNo
, {64, 0});
827 LocIdx Spill64Loc
= MTracker
->getSpillMLoc(SpillID
);
828 ValueIDNum
DefAtSpill64(0, 3, Spill64Loc
);
829 LocIdx RbxLoc
= MTracker
->getRegMLoc(getRegByName("RBX"));
830 EXPECT_EQ(MTracker
->readMLoc(RbxLoc
), DefAtSpill64
);
832 // Same again, test that the lower four subreg slots on the stack are the
833 // value defined by $rax in instruction 1.
834 for (unsigned int I
= 0; I
< 4; ++I
) {
835 // Value number where it's defined,
836 LocIdx RegLoc
= MTracker
->getRegMLoc(getRegByName(SubRegNames
[I
]));
837 ValueIDNum
DefNum(0, 1, RegLoc
);
838 // Read the corresponding subreg field from the stack.
839 SpillNo
= *MTracker
->getOrTrackSpillLoc(L
);
840 SpillID
= MTracker
->getLocID(SpillNo
, SubRegIdxes
[I
]);
841 LocIdx SpillLoc
= MTracker
->getSpillMLoc(SpillID
);
842 ValueIDNum SpillValue
= MTracker
->readMLoc(SpillLoc
);
843 EXPECT_EQ(DefNum
, SpillValue
);
846 // Stack slot for $rax should be a different value, today it's EmptyValue.
847 ValueIDNum SpillValue
= MTracker
->readMLoc(Spill64Loc
);
848 EXPECT_EQ(SpillValue
, DefAtSpill64
);
850 // If we write something to the stack, then over-write with some register
851 // from a completely different hierarchy, none of the "old" values should be
853 // NB: slight hack, store 16 in to a 8 byte stack slot.
855 " $rax = MOV64ri 0\n"
856 " MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
857 " $xmm0 = IMPLICIT_DEF\n"
858 " MOVUPDmr $rsp, 1, $noreg, 16, $noreg, killed $xmm0 :: (store (s128) into %stack.0)\n"
859 " $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
863 TransferMap
.resize(1);
864 produceMLocTransferFunction(*MF
, TransferMap
, 1);
866 for (unsigned int I
= 0; I
< 5; ++I
) {
867 // Read subreg fields from the stack.
868 SpillLocationNo SpillNo
= *MTracker
->getOrTrackSpillLoc(L
);
869 unsigned SpillID
= MTracker
->getLocID(SpillNo
, SubRegIdxes
[I
]);
870 LocIdx SpillLoc
= MTracker
->getSpillMLoc(SpillID
);
871 ValueIDNum SpillValue
= MTracker
->readMLoc(SpillLoc
);
873 // Value should be defined by the spill-to-xmm0 instr, get value of a def
874 // at the point of the spill.
875 ValueIDNum
SpillDef(0, 4, SpillLoc
);
876 EXPECT_EQ(SpillValue
, SpillDef
);
879 // Read xmm0's position and ensure it has a value. Should be the live-in
880 // value to the block, as IMPLICIT_DEF isn't a real def.
881 SpillNo
= *MTracker
->getOrTrackSpillLoc(L
);
882 SpillID
= MTracker
->getLocID(SpillNo
, {128, 0});
883 LocIdx Spill128Loc
= MTracker
->getSpillMLoc(SpillID
);
884 SpillValue
= MTracker
->readMLoc(Spill128Loc
);
885 Register XMM0
= getRegByName("XMM0");
886 LocIdx Xmm0Loc
= MTracker
->getRegMLoc(XMM0
);
887 EXPECT_EQ(ValueIDNum(0, 0, Xmm0Loc
), SpillValue
);
889 // What happens if we spill ah to the stack, then load al? It should find
892 " $rax = MOV64ri 0\n"
893 " MOV8mr $rsp, 1, $noreg, 16, $noreg, $ah :: (store 1 into %stack.0)\n"
894 " $al = MOV8rm $rsp, 1, $noreg, 0, $noreg :: (load 1 from %stack.0)\n"
898 TransferMap
.resize(1);
899 produceMLocTransferFunction(*MF
, TransferMap
, 1);
901 Register AL
= getRegByName("AL");
902 Register AH
= getRegByName("AH");
903 LocIdx AlLoc
= MTracker
->getRegMLoc(AL
);
904 LocIdx AhLoc
= MTracker
->getRegMLoc(AH
);
905 ValueIDNum
AHDef(0, 1, AhLoc
);
906 ValueIDNum ALValue
= MTracker
->readMLoc(AlLoc
);
907 EXPECT_EQ(ALValue
, AHDef
);
910 TEST_F(InstrRefLDVTest
, MLocSingleBlock
) {
911 // Test some very simple properties about interpreting the transfer function.
914 // We should start with a single location, the stack pointer.
915 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
918 // Set up live-in and live-out tables for this function: two locations (we
919 // add one later) in a single block.
920 auto [MOutLocs
, MInLocs
] = allocValueTables(1, 2);
922 // Transfer function: nothing.
923 SmallVector
<MLocTransferMap
, 1> TransferFunc
;
924 TransferFunc
.resize(1);
926 // Try and build value maps...
927 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
929 // The result should be that RSP is marked as a live-in-PHI -- this represents
930 // an argument. And as there's no transfer function, the block live-out should
932 EXPECT_EQ(MInLocs
[0][0], ValueIDNum(0, 0, RspLoc
));
933 EXPECT_EQ(MOutLocs
[0][0], ValueIDNum(0, 0, RspLoc
));
935 // Try again, this time initialising the in-locs to be defined by an
936 // instruction. The entry block should always be re-assigned to be the
938 initValueArray(MInLocs
, 1, 2);
939 initValueArray(MOutLocs
, 1, 2);
940 MInLocs
[0][0] = ValueIDNum(0, 1, RspLoc
);
941 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
942 EXPECT_EQ(MInLocs
[0][0], ValueIDNum(0, 0, RspLoc
));
943 EXPECT_EQ(MOutLocs
[0][0], ValueIDNum(0, 0, RspLoc
));
945 // Now insert something into the transfer function to assign to the single
947 TransferFunc
[0].insert({RspLoc
, ValueIDNum(0, 1, RspLoc
)});
948 initValueArray(MInLocs
, 1, 2);
949 initValueArray(MOutLocs
, 1, 2);
950 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
951 EXPECT_EQ(MInLocs
[0][0], ValueIDNum(0, 0, RspLoc
));
952 EXPECT_EQ(MOutLocs
[0][0], ValueIDNum(0, 1, RspLoc
));
953 TransferFunc
[0].clear();
955 // Add a new register to be tracked, and insert it into the transfer function
956 // as a copy. The output of $rax should be the live-in value of $rsp.
957 Register RAX
= getRegByName("RAX");
958 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
959 TransferFunc
[0].insert({RspLoc
, ValueIDNum(0, 1, RspLoc
)});
960 TransferFunc
[0].insert({RaxLoc
, ValueIDNum(0, 0, RspLoc
)});
961 initValueArray(MInLocs
, 1, 2);
962 initValueArray(MOutLocs
, 1, 2);
963 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
964 EXPECT_EQ(MInLocs
[0][0], ValueIDNum(0, 0, RspLoc
));
965 EXPECT_EQ(MInLocs
[0][1], ValueIDNum(0, 0, RaxLoc
));
966 EXPECT_EQ(MOutLocs
[0][0], ValueIDNum(0, 1, RspLoc
));
967 EXPECT_EQ(MOutLocs
[0][1], ValueIDNum(0, 0, RspLoc
)); // Rax contains RspLoc.
968 TransferFunc
[0].clear();
971 TEST_F(InstrRefLDVTest
, MLocDiamondBlocks
) {
972 // Test that information flows from the entry block to two successors.
978 setupDiamondBlocks();
980 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
982 Register RAX
= getRegByName("RAX");
983 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
985 auto [MInLocs
, MOutLocs
] = allocValueTables(4, 2);
987 // Transfer function: start with nothing.
988 SmallVector
<MLocTransferMap
, 1> TransferFunc
;
989 TransferFunc
.resize(4);
992 unsigned EntryBlk
= 0, BrBlk1
= 1, BrBlk2
= 2, RetBlk
= 3;
994 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
995 ValueIDNum
RspDefInBlk0(EntryBlk
, 1, RspLoc
);
996 ValueIDNum
RspDefInBlk1(BrBlk1
, 1, RspLoc
);
997 ValueIDNum
RspDefInBlk2(BrBlk2
, 1, RspLoc
);
998 ValueIDNum
RspPHIInBlk3(RetBlk
, 0, RspLoc
);
999 ValueIDNum
RaxLiveInBlk1(BrBlk1
, 0, RaxLoc
);
1000 ValueIDNum
RaxLiveInBlk2(BrBlk2
, 0, RaxLoc
);
1002 // With no transfer function, the live-in values to the entry block should
1003 // propagate to all live-outs and the live-ins to the two successor blocks.
1004 // IN ADDITION: this checks that the exit block doesn't get a PHI put in it.
1005 initValueArray(MInLocs
, 4, 2);
1006 initValueArray(MOutLocs
, 4, 2);
1007 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1008 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1009 EXPECT_EQ(MInLocs
[1][0], LiveInRsp
);
1010 EXPECT_EQ(MInLocs
[2][0], LiveInRsp
);
1011 EXPECT_EQ(MInLocs
[3][0], LiveInRsp
);
1012 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1013 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1014 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1015 EXPECT_EQ(MOutLocs
[3][0], LiveInRsp
);
1016 // (Skipped writing out locations for $rax).
1018 // Check that a def of $rsp in the entry block will likewise reach all the
1020 TransferFunc
[0].insert({RspLoc
, RspDefInBlk0
});
1021 initValueArray(MInLocs
, 4, 2);
1022 initValueArray(MOutLocs
, 4, 2);
1023 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1024 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1025 EXPECT_EQ(MInLocs
[1][0], RspDefInBlk0
);
1026 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk0
);
1027 EXPECT_EQ(MInLocs
[3][0], RspDefInBlk0
);
1028 EXPECT_EQ(MOutLocs
[0][0], RspDefInBlk0
);
1029 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk0
);
1030 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk0
);
1031 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk0
);
1032 TransferFunc
[0].clear();
1034 // Def in one branch of the diamond means that we need a PHI in the ret block
1035 TransferFunc
[0].insert({RspLoc
, RspDefInBlk0
});
1036 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1037 initValueArray(MInLocs
, 4, 2);
1038 initValueArray(MOutLocs
, 4, 2);
1039 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1040 // This value map: like above, where RspDefInBlk0 is propagated through one
1041 // branch of the diamond, but is def'ed in the live-outs of the other. The
1042 // ret / merging block should have a PHI in its live-ins.
1043 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1044 EXPECT_EQ(MInLocs
[1][0], RspDefInBlk0
);
1045 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk0
);
1046 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk3
);
1047 EXPECT_EQ(MOutLocs
[0][0], RspDefInBlk0
);
1048 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1049 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk0
);
1050 EXPECT_EQ(MOutLocs
[3][0], RspPHIInBlk3
);
1051 TransferFunc
[0].clear();
1052 TransferFunc
[1].clear();
1054 // If we have differeing defs in either side of the diamond, we should
1055 // continue to produce a PHI,
1056 TransferFunc
[0].insert({RspLoc
, RspDefInBlk0
});
1057 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1058 TransferFunc
[2].insert({RspLoc
, RspDefInBlk2
});
1059 initValueArray(MInLocs
, 4, 2);
1060 initValueArray(MOutLocs
, 4, 2);
1061 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1062 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1063 EXPECT_EQ(MInLocs
[1][0], RspDefInBlk0
);
1064 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk0
);
1065 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk3
);
1066 EXPECT_EQ(MOutLocs
[0][0], RspDefInBlk0
);
1067 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1068 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk2
);
1069 EXPECT_EQ(MOutLocs
[3][0], RspPHIInBlk3
);
1070 TransferFunc
[0].clear();
1071 TransferFunc
[1].clear();
1072 TransferFunc
[2].clear();
1074 // If we have defs of the same value on either side of the branch, a PHI will
1075 // initially be created, however value propagation should then eliminate it.
1076 // Encode this by copying the live-in value to $rax, and copying it to $rsp
1077 // from $rax in each branch of the diamond. We don't allow the definition of
1078 // arbitary values in transfer functions.
1079 TransferFunc
[0].insert({RspLoc
, RspDefInBlk0
});
1080 TransferFunc
[0].insert({RaxLoc
, LiveInRsp
});
1081 TransferFunc
[1].insert({RspLoc
, RaxLiveInBlk1
});
1082 TransferFunc
[2].insert({RspLoc
, RaxLiveInBlk2
});
1083 initValueArray(MInLocs
, 4, 2);
1084 initValueArray(MOutLocs
, 4, 2);
1085 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1086 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1087 EXPECT_EQ(MInLocs
[1][0], RspDefInBlk0
);
1088 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk0
);
1089 EXPECT_EQ(MInLocs
[3][0], LiveInRsp
);
1090 EXPECT_EQ(MOutLocs
[0][0], RspDefInBlk0
);
1091 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1092 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1093 EXPECT_EQ(MOutLocs
[3][0], LiveInRsp
);
1094 TransferFunc
[0].clear();
1095 TransferFunc
[1].clear();
1096 TransferFunc
[2].clear();
1099 TEST_F(InstrRefLDVTest
, MLocDiamondSpills
) {
1100 // Test that defs in stack locations that require PHIs, cause PHIs to be
1101 // installed in aliasing locations. i.e., if there's a PHI in the lower
1102 // 8 bits of the stack, there should be PHIs for 16/32/64 bit locations
1103 // on the stack too.
1104 // Technically this isn't needed for accuracy: we should calculate PHIs
1105 // independently for each location. However, because there's an optimisation
1106 // that only places PHIs for the lower "interfering" parts of stack slots,
1107 // test for this behaviour.
1108 setupDiamondBlocks();
1110 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
1113 // Create a stack location and ensure it's tracked.
1114 SpillLoc SL
= {getRegByName("RSP"), StackOffset::getFixed(-8)};
1115 SpillLocationNo SpillNo
= *MTracker
->getOrTrackSpillLoc(SL
);
1116 ASSERT_EQ(MTracker
->getNumLocs(), 13u); // Tracks all possible stack locs.
1117 // Locations are: RSP, stack slots from 2^3 bits wide up to 2^9 for zmm regs,
1118 // then slots for sub_8bit_hi and sub_16bit_hi ({8, 8} and {16, 16}).
1119 // Finally, one for spilt fp80 registers.
1121 // Pick out the locations on the stack that various x86 regs would be written
1122 // to. HAX is the upper 16 bits of EAX.
1123 unsigned ALID
= MTracker
->getLocID(SpillNo
, {8, 0});
1124 unsigned AHID
= MTracker
->getLocID(SpillNo
, {8, 8});
1125 unsigned AXID
= MTracker
->getLocID(SpillNo
, {16, 0});
1126 unsigned EAXID
= MTracker
->getLocID(SpillNo
, {32, 0});
1127 unsigned HAXID
= MTracker
->getLocID(SpillNo
, {16, 16});
1128 unsigned RAXID
= MTracker
->getLocID(SpillNo
, {64, 0});
1129 LocIdx ALStackLoc
= MTracker
->getSpillMLoc(ALID
);
1130 LocIdx AHStackLoc
= MTracker
->getSpillMLoc(AHID
);
1131 LocIdx AXStackLoc
= MTracker
->getSpillMLoc(AXID
);
1132 LocIdx EAXStackLoc
= MTracker
->getSpillMLoc(EAXID
);
1133 LocIdx HAXStackLoc
= MTracker
->getSpillMLoc(HAXID
);
1134 LocIdx RAXStackLoc
= MTracker
->getSpillMLoc(RAXID
);
1135 // There are other locations, for things like xmm0, which we're going to
1138 auto [MInLocs
, MOutLocs
] = allocValueTables(4, 13);
1140 // Transfer function: start with nothing.
1141 SmallVector
<MLocTransferMap
, 1> TransferFunc
;
1142 TransferFunc
.resize(4);
1144 // Name some values.
1145 unsigned EntryBlk
= 0, Blk1
= 1, RetBlk
= 3;
1147 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
1148 ValueIDNum
ALLiveIn(EntryBlk
, 0, ALStackLoc
);
1149 ValueIDNum
AHLiveIn(EntryBlk
, 0, AHStackLoc
);
1150 ValueIDNum
HAXLiveIn(EntryBlk
, 0, HAXStackLoc
);
1151 ValueIDNum
ALPHI(RetBlk
, 0, ALStackLoc
);
1152 ValueIDNum
AXPHI(RetBlk
, 0, AXStackLoc
);
1153 ValueIDNum
EAXPHI(RetBlk
, 0, EAXStackLoc
);
1154 ValueIDNum
HAXPHI(RetBlk
, 0, HAXStackLoc
);
1155 ValueIDNum
RAXPHI(RetBlk
, 0, RAXStackLoc
);
1157 ValueIDNum
ALDefInBlk1(Blk1
, 1, ALStackLoc
);
1158 ValueIDNum
HAXDefInBlk1(Blk1
, 1, HAXStackLoc
);
1160 SmallPtrSet
<MachineBasicBlock
*, 4> AllBlocks
{MBB0
, MBB1
, MBB2
, MBB3
};
1162 // If we put defs into one side of the diamond, for AL and HAX, then we should
1163 // find all aliasing positions have PHIs placed. This isn't technically what
1164 // the transfer function says to do: but we're testing that the optimisation
1165 // to reduce IDF calculation does the right thing.
1166 // AH should not be def'd: it don't alias AL or HAX.
1168 // NB: we don't call buildMLocValueMap, because it will try to eliminate the
1169 // upper-slot PHIs, and succeed because of our slightly cooked transfer
1171 TransferFunc
[1].insert({ALStackLoc
, ALDefInBlk1
});
1172 TransferFunc
[1].insert({HAXStackLoc
, HAXDefInBlk1
});
1173 initValueArray(MInLocs
, 4, 13);
1174 placeMLocPHIs(*MF
, AllBlocks
, MInLocs
, TransferFunc
);
1175 EXPECT_EQ(MInLocs
[3][ALStackLoc
.asU64()], ALPHI
);
1176 EXPECT_EQ(MInLocs
[3][AXStackLoc
.asU64()], AXPHI
);
1177 EXPECT_EQ(MInLocs
[3][EAXStackLoc
.asU64()], EAXPHI
);
1178 EXPECT_EQ(MInLocs
[3][HAXStackLoc
.asU64()], HAXPHI
);
1179 EXPECT_EQ(MInLocs
[3][RAXStackLoc
.asU64()], RAXPHI
);
1180 // AH should be left untouched,
1181 EXPECT_EQ(MInLocs
[3][AHStackLoc
.asU64()], ValueIDNum::EmptyValue
);
1184 TEST_F(InstrRefLDVTest
, MLocSimpleLoop
) {
1194 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
1196 Register RAX
= getRegByName("RAX");
1197 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
1199 auto [MInLocs
, MOutLocs
] = allocValueTables(3, 2);
1201 SmallVector
<MLocTransferMap
, 1> TransferFunc
;
1202 TransferFunc
.resize(3);
1204 // Name some values.
1205 unsigned EntryBlk
= 0, LoopBlk
= 1, RetBlk
= 2;
1207 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
1208 ValueIDNum
RspPHIInBlk1(LoopBlk
, 0, RspLoc
);
1209 ValueIDNum
RspDefInBlk1(LoopBlk
, 1, RspLoc
);
1210 ValueIDNum
LiveInRax(EntryBlk
, 0, RaxLoc
);
1211 ValueIDNum
RaxPHIInBlk1(LoopBlk
, 0, RaxLoc
);
1212 ValueIDNum
RaxPHIInBlk2(RetBlk
, 0, RaxLoc
);
1214 // Begin test with all locations being live-through.
1215 initValueArray(MInLocs
, 3, 2);
1216 initValueArray(MOutLocs
, 3, 2);
1217 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1218 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1219 EXPECT_EQ(MInLocs
[1][0], LiveInRsp
);
1220 EXPECT_EQ(MInLocs
[2][0], LiveInRsp
);
1221 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1222 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1223 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1225 // Add a def of $rsp to the loop block: it should be in the live-outs, but
1226 // should cause a PHI to be placed in the live-ins. Test the transfer function
1227 // by copying that PHI into $rax in the loop, then back to $rsp in the ret
1229 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1230 TransferFunc
[1].insert({RaxLoc
, RspPHIInBlk1
});
1231 TransferFunc
[2].insert({RspLoc
, RaxPHIInBlk2
});
1232 initValueArray(MInLocs
, 3, 2);
1233 initValueArray(MOutLocs
, 3, 2);
1234 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1235 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1236 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1237 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk1
);
1238 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1239 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1240 EXPECT_EQ(MOutLocs
[2][0], RspPHIInBlk1
);
1241 // Check rax as well,
1242 EXPECT_EQ(MInLocs
[0][1], LiveInRax
);
1243 EXPECT_EQ(MInLocs
[1][1], RaxPHIInBlk1
);
1244 EXPECT_EQ(MInLocs
[2][1], RspPHIInBlk1
);
1245 EXPECT_EQ(MOutLocs
[0][1], LiveInRax
);
1246 EXPECT_EQ(MOutLocs
[1][1], RspPHIInBlk1
);
1247 EXPECT_EQ(MOutLocs
[2][1], RspPHIInBlk1
);
1248 TransferFunc
[1].clear();
1249 TransferFunc
[2].clear();
1251 // As with the diamond case, a PHI will be created if there's a (implicit)
1252 // def in the entry block and loop block; but should be value propagated away
1253 // if it copies in the same value. Copy live-in $rsp to $rax, then copy it
1254 // into $rsp in the loop. Encoded as copying the live-in $rax value in block 1
1256 TransferFunc
[0].insert({RaxLoc
, LiveInRsp
});
1257 TransferFunc
[1].insert({RspLoc
, RaxPHIInBlk1
});
1258 initValueArray(MInLocs
, 3, 2);
1259 initValueArray(MOutLocs
, 3, 2);
1260 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1261 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1262 EXPECT_EQ(MInLocs
[1][0], LiveInRsp
);
1263 EXPECT_EQ(MInLocs
[2][0], LiveInRsp
);
1264 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1265 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1266 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1267 // Check $rax's values.
1268 EXPECT_EQ(MInLocs
[0][1], LiveInRax
);
1269 EXPECT_EQ(MInLocs
[1][1], LiveInRsp
);
1270 EXPECT_EQ(MInLocs
[2][1], LiveInRsp
);
1271 EXPECT_EQ(MOutLocs
[0][1], LiveInRsp
);
1272 EXPECT_EQ(MOutLocs
[1][1], LiveInRsp
);
1273 EXPECT_EQ(MOutLocs
[2][1], LiveInRsp
);
1274 TransferFunc
[0].clear();
1275 TransferFunc
[1].clear();
1278 TEST_F(InstrRefLDVTest
, MLocNestedLoop
) {
1292 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
1294 Register RAX
= getRegByName("RAX");
1295 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
1297 auto [MInLocs
, MOutLocs
] = allocValueTables(5, 2);
1299 SmallVector
<MLocTransferMap
, 1> TransferFunc
;
1300 TransferFunc
.resize(5);
1302 unsigned EntryBlk
= 0, Loop1Blk
= 1, Loop2Blk
= 2, JoinBlk
= 3;
1304 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
1305 ValueIDNum
RspPHIInBlk1(Loop1Blk
, 0, RspLoc
);
1306 ValueIDNum
RspDefInBlk1(Loop1Blk
, 1, RspLoc
);
1307 ValueIDNum
RspPHIInBlk2(Loop2Blk
, 0, RspLoc
);
1308 ValueIDNum
RspDefInBlk2(Loop2Blk
, 1, RspLoc
);
1309 ValueIDNum
RspDefInBlk3(JoinBlk
, 1, RspLoc
);
1310 ValueIDNum
LiveInRax(EntryBlk
, 0, RaxLoc
);
1311 ValueIDNum
RaxPHIInBlk1(Loop1Blk
, 0, RaxLoc
);
1312 ValueIDNum
RaxPHIInBlk2(Loop2Blk
, 0, RaxLoc
);
1314 // Like the other tests: first ensure that if there's nothing in the transfer
1315 // function, then everything is live-through (check $rsp).
1316 initValueArray(MInLocs
, 5, 2);
1317 initValueArray(MOutLocs
, 5, 2);
1318 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1319 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1320 EXPECT_EQ(MInLocs
[1][0], LiveInRsp
);
1321 EXPECT_EQ(MInLocs
[2][0], LiveInRsp
);
1322 EXPECT_EQ(MInLocs
[3][0], LiveInRsp
);
1323 EXPECT_EQ(MInLocs
[4][0], LiveInRsp
);
1324 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1325 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1326 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1327 EXPECT_EQ(MOutLocs
[3][0], LiveInRsp
);
1328 EXPECT_EQ(MOutLocs
[4][0], LiveInRsp
);
1330 // A def in the inner loop means we should get PHIs at the heads of both
1331 // loops. Live-outs of the last three blocks will be the def, as it dominates
1333 TransferFunc
[2].insert({RspLoc
, RspDefInBlk2
});
1334 initValueArray(MInLocs
, 5, 2);
1335 initValueArray(MOutLocs
, 5, 2);
1336 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1337 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1338 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1339 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1340 EXPECT_EQ(MInLocs
[3][0], RspDefInBlk2
);
1341 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk2
);
1342 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1343 EXPECT_EQ(MOutLocs
[1][0], RspPHIInBlk1
);
1344 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk2
);
1345 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk2
);
1346 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk2
);
1347 TransferFunc
[2].clear();
1349 // Adding a def to the outer loop header shouldn't affect this much -- the
1350 // live-out of block 1 changes.
1351 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1352 TransferFunc
[2].insert({RspLoc
, RspDefInBlk2
});
1353 initValueArray(MInLocs
, 5, 2);
1354 initValueArray(MOutLocs
, 5, 2);
1355 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1356 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1357 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1358 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1359 EXPECT_EQ(MInLocs
[3][0], RspDefInBlk2
);
1360 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk2
);
1361 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1362 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1363 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk2
);
1364 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk2
);
1365 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk2
);
1366 TransferFunc
[1].clear();
1367 TransferFunc
[2].clear();
1369 // Likewise, putting a def in the outer loop tail shouldn't affect where
1370 // the PHIs go, and should propagate into the ret block.
1372 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1373 TransferFunc
[2].insert({RspLoc
, RspDefInBlk2
});
1374 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1375 initValueArray(MInLocs
, 5, 2);
1376 initValueArray(MOutLocs
, 5, 2);
1377 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1378 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1379 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1380 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1381 EXPECT_EQ(MInLocs
[3][0], RspDefInBlk2
);
1382 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk3
);
1383 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1384 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1385 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk2
);
1386 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk3
);
1387 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk3
);
1388 TransferFunc
[1].clear();
1389 TransferFunc
[2].clear();
1390 TransferFunc
[3].clear();
1392 // However: if we don't def in the inner-loop, then we just have defs in the
1393 // head and tail of the outer loop. The inner loop should be live-through.
1394 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1395 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1396 initValueArray(MInLocs
, 5, 2);
1397 initValueArray(MOutLocs
, 5, 2);
1398 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1399 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1400 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1401 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk1
);
1402 EXPECT_EQ(MInLocs
[3][0], RspDefInBlk1
);
1403 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk3
);
1404 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1405 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1406 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk1
);
1407 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk3
);
1408 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk3
);
1409 TransferFunc
[1].clear();
1410 TransferFunc
[3].clear();
1412 // Check that this still works if we copy RspDefInBlk1 to $rax and then
1413 // copy it back into $rsp in the inner loop.
1414 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1415 TransferFunc
[1].insert({RaxLoc
, RspDefInBlk1
});
1416 TransferFunc
[2].insert({RspLoc
, RaxPHIInBlk2
});
1417 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1418 initValueArray(MInLocs
, 5, 2);
1419 initValueArray(MOutLocs
, 5, 2);
1420 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1421 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1422 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1423 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk1
);
1424 EXPECT_EQ(MInLocs
[3][0], RspDefInBlk1
);
1425 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk3
);
1426 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1427 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1428 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk1
);
1429 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk3
);
1430 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk3
);
1431 // Look at raxes value in the relevant blocks,
1432 EXPECT_EQ(MInLocs
[2][1], RspDefInBlk1
);
1433 EXPECT_EQ(MOutLocs
[1][1], RspDefInBlk1
);
1434 TransferFunc
[1].clear();
1435 TransferFunc
[2].clear();
1436 TransferFunc
[3].clear();
1438 // If we have a single def in the tail of the outer loop, that should produce
1439 // a PHI at the loop head, and be live-through the inner loop.
1440 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1441 initValueArray(MInLocs
, 5, 2);
1442 initValueArray(MOutLocs
, 5, 2);
1443 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1444 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1445 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1446 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk1
);
1447 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk1
);
1448 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk3
);
1449 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1450 EXPECT_EQ(MOutLocs
[1][0], RspPHIInBlk1
);
1451 EXPECT_EQ(MOutLocs
[2][0], RspPHIInBlk1
);
1452 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk3
);
1453 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk3
);
1454 TransferFunc
[3].clear();
1456 // And if we copy from $rsp to $rax in block 2, it should resolve to the PHI
1457 // in block 1, and we should keep that value in rax until the ret block.
1458 // There'll be a PHI in block 1 and 2, because we're putting a def in the
1460 TransferFunc
[2].insert({RaxLoc
, RspPHIInBlk2
});
1461 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1462 initValueArray(MInLocs
, 5, 2);
1463 initValueArray(MOutLocs
, 5, 2);
1464 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1465 // Examining the values of rax,
1466 EXPECT_EQ(MInLocs
[0][1], LiveInRax
);
1467 EXPECT_EQ(MInLocs
[1][1], RaxPHIInBlk1
);
1468 EXPECT_EQ(MInLocs
[2][1], RaxPHIInBlk2
);
1469 EXPECT_EQ(MInLocs
[3][1], RspPHIInBlk1
);
1470 EXPECT_EQ(MInLocs
[4][1], RspPHIInBlk1
);
1471 EXPECT_EQ(MOutLocs
[0][1], LiveInRax
);
1472 EXPECT_EQ(MOutLocs
[1][1], RaxPHIInBlk1
);
1473 EXPECT_EQ(MOutLocs
[2][1], RspPHIInBlk1
);
1474 EXPECT_EQ(MOutLocs
[3][1], RspPHIInBlk1
);
1475 EXPECT_EQ(MOutLocs
[4][1], RspPHIInBlk1
);
1476 TransferFunc
[2].clear();
1477 TransferFunc
[3].clear();
1480 TEST_F(InstrRefLDVTest
, MLocNoDominatingLoop
) {
1491 setupNoDominatingLoop();
1493 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
1495 Register RAX
= getRegByName("RAX");
1496 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
1498 auto [MInLocs
, MOutLocs
] = allocValueTables(5, 2);
1500 SmallVector
<MLocTransferMap
, 1> TransferFunc
;
1501 TransferFunc
.resize(5);
1503 unsigned EntryBlk
= 0, Head1Blk
= 1, Head2Blk
= 2, JoinBlk
= 3;
1505 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
1506 ValueIDNum
RspPHIInBlk1(Head1Blk
, 0, RspLoc
);
1507 ValueIDNum
RspDefInBlk1(Head1Blk
, 1, RspLoc
);
1508 ValueIDNum
RspPHIInBlk2(Head2Blk
, 0, RspLoc
);
1509 ValueIDNum
RspDefInBlk2(Head2Blk
, 1, RspLoc
);
1510 ValueIDNum
RspPHIInBlk3(JoinBlk
, 0, RspLoc
);
1511 ValueIDNum
RspDefInBlk3(JoinBlk
, 1, RspLoc
);
1512 ValueIDNum
RaxPHIInBlk1(Head1Blk
, 0, RaxLoc
);
1513 ValueIDNum
RaxPHIInBlk2(Head2Blk
, 0, RaxLoc
);
1515 // As ever, test that everything is live-through if there are no defs.
1516 initValueArray(MInLocs
, 5, 2);
1517 initValueArray(MOutLocs
, 5, 2);
1518 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1519 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1520 EXPECT_EQ(MInLocs
[1][0], LiveInRsp
);
1521 EXPECT_EQ(MInLocs
[2][0], LiveInRsp
);
1522 EXPECT_EQ(MInLocs
[3][0], LiveInRsp
);
1523 EXPECT_EQ(MInLocs
[4][0], LiveInRsp
);
1524 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1525 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1526 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1527 EXPECT_EQ(MOutLocs
[3][0], LiveInRsp
);
1528 EXPECT_EQ(MOutLocs
[4][0], LiveInRsp
);
1530 // Putting a def in the 'join' block will cause us to have two distinct
1531 // PHIs in each loop head, then on entry to the join block.
1532 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1533 initValueArray(MInLocs
, 5, 2);
1534 initValueArray(MOutLocs
, 5, 2);
1535 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1536 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1537 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1538 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1539 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk3
);
1540 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk3
);
1541 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1542 EXPECT_EQ(MOutLocs
[1][0], RspPHIInBlk1
);
1543 EXPECT_EQ(MOutLocs
[2][0], RspPHIInBlk2
);
1544 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk3
);
1545 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk3
);
1546 TransferFunc
[3].clear();
1548 // We should get the same behaviour if we put the def in either of the
1549 // loop heads -- it should force the other head to be a PHI.
1550 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1551 initValueArray(MInLocs
, 5, 2);
1552 initValueArray(MOutLocs
, 5, 2);
1553 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1554 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1555 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1556 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1557 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk3
);
1558 EXPECT_EQ(MInLocs
[4][0], RspPHIInBlk3
);
1559 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1560 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1561 EXPECT_EQ(MOutLocs
[2][0], RspPHIInBlk2
);
1562 EXPECT_EQ(MOutLocs
[3][0], RspPHIInBlk3
);
1563 EXPECT_EQ(MOutLocs
[4][0], RspPHIInBlk3
);
1564 TransferFunc
[1].clear();
1567 TransferFunc
[2].insert({RspLoc
, RspDefInBlk2
});
1568 initValueArray(MInLocs
, 5, 2);
1569 initValueArray(MOutLocs
, 5, 2);
1570 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1571 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1572 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1573 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1574 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk3
);
1575 EXPECT_EQ(MInLocs
[4][0], RspPHIInBlk3
);
1576 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1577 EXPECT_EQ(MOutLocs
[1][0], RspPHIInBlk1
);
1578 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk2
);
1579 EXPECT_EQ(MOutLocs
[3][0], RspPHIInBlk3
);
1580 EXPECT_EQ(MOutLocs
[4][0], RspPHIInBlk3
);
1581 TransferFunc
[2].clear();
1583 // Test some scenarios where there _shouldn't_ be any PHIs created at heads.
1584 // These are those PHIs are created, but value propagation eliminates them.
1585 // For example, lets copy rsp-livein to $rsp inside each loop head, so that
1586 // there's no need for a PHI in the join block. Put a def of $rsp in block 3
1587 // to force PHIs elsewhere.
1588 TransferFunc
[0].insert({RaxLoc
, LiveInRsp
});
1589 TransferFunc
[1].insert({RspLoc
, RaxPHIInBlk1
});
1590 TransferFunc
[2].insert({RspLoc
, RaxPHIInBlk2
});
1591 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1592 initValueArray(MInLocs
, 5, 2);
1593 initValueArray(MOutLocs
, 5, 2);
1594 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1595 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1596 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1597 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1598 EXPECT_EQ(MInLocs
[3][0], LiveInRsp
);
1599 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk3
);
1600 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1601 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1602 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1603 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk3
);
1604 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk3
);
1605 TransferFunc
[0].clear();
1606 TransferFunc
[1].clear();
1607 TransferFunc
[2].clear();
1608 TransferFunc
[3].clear();
1610 // In fact, if we eliminate the def in block 3, none of those PHIs are
1611 // necessary, as we're just repeatedly copying LiveInRsp into $rsp. They
1612 // should all be value propagated out.
1613 TransferFunc
[0].insert({RaxLoc
, LiveInRsp
});
1614 TransferFunc
[1].insert({RspLoc
, RaxPHIInBlk1
});
1615 TransferFunc
[2].insert({RspLoc
, RaxPHIInBlk2
});
1616 initValueArray(MInLocs
, 5, 2);
1617 initValueArray(MOutLocs
, 5, 2);
1618 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1619 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1620 EXPECT_EQ(MInLocs
[1][0], LiveInRsp
);
1621 EXPECT_EQ(MInLocs
[2][0], LiveInRsp
);
1622 EXPECT_EQ(MInLocs
[3][0], LiveInRsp
);
1623 EXPECT_EQ(MInLocs
[4][0], LiveInRsp
);
1624 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1625 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1626 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1627 EXPECT_EQ(MOutLocs
[3][0], LiveInRsp
);
1628 EXPECT_EQ(MOutLocs
[4][0], LiveInRsp
);
1629 TransferFunc
[0].clear();
1630 TransferFunc
[1].clear();
1631 TransferFunc
[2].clear();
1634 TEST_F(InstrRefLDVTest
, MLocBadlyNestedLoops
) {
1646 setupBadlyNestedLoops();
1648 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
1650 Register RAX
= getRegByName("RAX");
1651 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
1653 auto [MInLocs
, MOutLocs
] = allocValueTables(5, 2);
1655 SmallVector
<MLocTransferMap
, 1> TransferFunc
;
1656 TransferFunc
.resize(5);
1658 unsigned EntryBlk
= 0, Loop1Blk
= 1, Loop2Blk
= 2, Loop3Blk
= 3;
1660 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
1661 ValueIDNum
RspPHIInBlk1(Loop1Blk
, 0, RspLoc
);
1662 ValueIDNum
RspDefInBlk1(Loop1Blk
, 1, RspLoc
);
1663 ValueIDNum
RspPHIInBlk2(Loop2Blk
, 0, RspLoc
);
1664 ValueIDNum
RspPHIInBlk3(Loop3Blk
, 0, RspLoc
);
1665 ValueIDNum
RspDefInBlk3(Loop3Blk
, 1, RspLoc
);
1666 ValueIDNum
LiveInRax(EntryBlk
, 0, RaxLoc
);
1667 ValueIDNum
RaxPHIInBlk3(Loop3Blk
, 0, RaxLoc
);
1669 // As ever, test that everything is live-through if there are no defs.
1670 initValueArray(MInLocs
, 5, 2);
1671 initValueArray(MOutLocs
, 5, 2);
1672 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1673 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1674 EXPECT_EQ(MInLocs
[1][0], LiveInRsp
);
1675 EXPECT_EQ(MInLocs
[2][0], LiveInRsp
);
1676 EXPECT_EQ(MInLocs
[3][0], LiveInRsp
);
1677 EXPECT_EQ(MInLocs
[4][0], LiveInRsp
);
1678 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1679 EXPECT_EQ(MOutLocs
[1][0], LiveInRsp
);
1680 EXPECT_EQ(MOutLocs
[2][0], LiveInRsp
);
1681 EXPECT_EQ(MOutLocs
[3][0], LiveInRsp
);
1682 EXPECT_EQ(MOutLocs
[4][0], LiveInRsp
);
1684 // A def in loop3 should cause PHIs in every loop block: they're all
1685 // reachable from each other.
1686 TransferFunc
[3].insert({RspLoc
, RspDefInBlk3
});
1687 initValueArray(MInLocs
, 5, 2);
1688 initValueArray(MOutLocs
, 5, 2);
1689 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1690 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1691 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1692 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1693 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk3
);
1694 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk3
);
1695 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1696 EXPECT_EQ(MOutLocs
[1][0], RspPHIInBlk1
);
1697 EXPECT_EQ(MOutLocs
[2][0], RspPHIInBlk2
);
1698 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk3
);
1699 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk3
);
1700 TransferFunc
[3].clear();
1702 // A def in loop1 should cause a PHI in loop1, but not the other blocks.
1703 // loop2 and loop3 are dominated by the def in loop1, so they should have
1704 // that value live-through.
1705 TransferFunc
[1].insert({RspLoc
, RspDefInBlk1
});
1706 initValueArray(MInLocs
, 5, 2);
1707 initValueArray(MOutLocs
, 5, 2);
1708 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1709 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1710 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1711 EXPECT_EQ(MInLocs
[2][0], RspDefInBlk1
);
1712 EXPECT_EQ(MInLocs
[3][0], RspDefInBlk1
);
1713 EXPECT_EQ(MInLocs
[4][0], RspDefInBlk1
);
1714 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1715 EXPECT_EQ(MOutLocs
[1][0], RspDefInBlk1
);
1716 EXPECT_EQ(MOutLocs
[2][0], RspDefInBlk1
);
1717 EXPECT_EQ(MOutLocs
[3][0], RspDefInBlk1
);
1718 EXPECT_EQ(MOutLocs
[4][0], RspDefInBlk1
);
1719 TransferFunc
[1].clear();
1721 // As with earlier tricks: copy $rsp to $rax in the entry block, then $rax
1722 // to $rsp in block 3. The only def of $rsp is simply copying the same value
1723 // back into itself, and the value of $rsp is LiveInRsp all the way through.
1724 // PHIs should be created, then value-propagated away... however this
1725 // doesn't work in practice.
1726 // Consider the entry to loop3: we can determine that there's an incoming
1727 // PHI value from loop2, and LiveInRsp from the self-loop. This would still
1728 // justify having a PHI on entry to loop3. The only way to completely
1729 // value-propagate these PHIs away would be to speculatively explore what
1730 // PHIs could be eliminated and what that would lead to; which is
1731 // combinatorially complex.
1733 // a) In this scenario, we always have a tracked location for LiveInRsp
1734 // anyway, so there's no loss in availability,
1735 // b) Only DBG_PHIs of a register would be vunlerable to this scenario, and
1736 // even then only if a true PHI became a DBG_PHI and was then optimised
1737 // through branch folding to no longer be at a CFG join,
1738 // c) The register allocator can spot this kind of redundant COPY easily,
1739 // and eliminate it.
1741 // This unit test left in as a reference for the limitations of this
1742 // approach. PHIs will be left in $rsp on entry to each block.
1743 TransferFunc
[0].insert({RaxLoc
, LiveInRsp
});
1744 TransferFunc
[3].insert({RspLoc
, RaxPHIInBlk3
});
1745 initValueArray(MInLocs
, 5, 2);
1746 initValueArray(MOutLocs
, 5, 2);
1747 buildMLocValueMap(MInLocs
, MOutLocs
, TransferFunc
);
1748 EXPECT_EQ(MInLocs
[0][0], LiveInRsp
);
1749 EXPECT_EQ(MInLocs
[1][0], RspPHIInBlk1
);
1750 EXPECT_EQ(MInLocs
[2][0], RspPHIInBlk2
);
1751 EXPECT_EQ(MInLocs
[3][0], RspPHIInBlk3
);
1752 EXPECT_EQ(MInLocs
[4][0], LiveInRsp
);
1753 EXPECT_EQ(MOutLocs
[0][0], LiveInRsp
);
1754 EXPECT_EQ(MOutLocs
[1][0], RspPHIInBlk1
);
1755 EXPECT_EQ(MOutLocs
[2][0], RspPHIInBlk2
);
1756 EXPECT_EQ(MOutLocs
[3][0], LiveInRsp
);
1757 EXPECT_EQ(MOutLocs
[4][0], LiveInRsp
);
1758 // Check $rax's value. It should have $rsps value from the entry block
1760 EXPECT_EQ(MInLocs
[0][1], LiveInRax
);
1761 EXPECT_EQ(MInLocs
[1][1], LiveInRsp
);
1762 EXPECT_EQ(MInLocs
[2][1], LiveInRsp
);
1763 EXPECT_EQ(MInLocs
[3][1], LiveInRsp
);
1764 EXPECT_EQ(MInLocs
[4][1], LiveInRsp
);
1765 EXPECT_EQ(MOutLocs
[0][1], LiveInRsp
);
1766 EXPECT_EQ(MOutLocs
[1][1], LiveInRsp
);
1767 EXPECT_EQ(MOutLocs
[2][1], LiveInRsp
);
1768 EXPECT_EQ(MOutLocs
[3][1], LiveInRsp
);
1769 EXPECT_EQ(MOutLocs
[4][1], LiveInRsp
);
1772 TEST_F(InstrRefLDVTest
, pickVPHILocDiamond
) {
1778 setupDiamondBlocks();
1780 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
1782 Register RAX
= getRegByName("RAX");
1783 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
1785 auto [MInLocs
, MOutLocs
] = allocValueTables(4, 2);
1787 initValueArray(MOutLocs
, 4, 2);
1789 unsigned EntryBlk
= 0, Br2Blk
= 2, RetBlk
= 3;
1791 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
1792 ValueIDNum
LiveInRax(EntryBlk
, 0, RaxLoc
);
1793 ValueIDNum
RspPHIInBlk2(Br2Blk
, 0, RspLoc
);
1794 ValueIDNum
RspPHIInBlk3(RetBlk
, 0, RspLoc
);
1795 ValueIDNum
RaxPHIInBlk3(RetBlk
, 0, RaxLoc
);
1796 DbgOpID LiveInRspID
= addValueDbgOp(LiveInRsp
);
1797 DbgOpID LiveInRaxID
= addValueDbgOp(LiveInRax
);
1798 DbgOpID RspPHIInBlk2ID
= addValueDbgOp(RspPHIInBlk2
);
1799 DbgOpID RspPHIInBlk3ID
= addValueDbgOp(RspPHIInBlk3
);
1800 DbgOpID RaxPHIInBlk3ID
= addValueDbgOp(RaxPHIInBlk3
);
1801 DbgOpID ConstZeroID
= addConstDbgOp(MachineOperand::CreateImm(0));
1803 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
1804 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
1805 DIExpression
*TwoOpExpr
=
1806 DIExpression::get(Ctx
, {dwarf::DW_OP_LLVM_arg
, 0, dwarf::DW_OP_LLVM_arg
,
1807 1, dwarf::DW_OP_plus
});
1808 DbgValueProperties
TwoOpProps(TwoOpExpr
, false, true);
1809 SmallVector
<DbgValue
, 32> VLiveOuts
;
1810 VLiveOuts
.resize(4, DbgValue(EmptyProps
, DbgValue::Undef
));
1811 InstrRefBasedLDV::LiveIdxT VLiveOutIdx
;
1812 VLiveOutIdx
[MBB0
] = &VLiveOuts
[0];
1813 VLiveOutIdx
[MBB1
] = &VLiveOuts
[1];
1814 VLiveOutIdx
[MBB2
] = &VLiveOuts
[2];
1815 VLiveOutIdx
[MBB3
] = &VLiveOuts
[3];
1817 SmallVector
<const MachineBasicBlock
*, 2> Preds
;
1818 for (const auto *Pred
: MBB3
->predecessors())
1819 Preds
.push_back(Pred
);
1821 // Specify the live-outs around the joining block.
1822 MOutLocs
[1][0] = LiveInRsp
;
1823 MOutLocs
[2][0] = LiveInRax
;
1826 SmallVector
<DbgOpID
> OutValues
;
1828 // Simple case: join two distinct values on entry to the block.
1829 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
1830 VLiveOuts
[2] = DbgValue(LiveInRaxID
, EmptyProps
);
1832 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1833 // Should have picked a PHI in $rsp in block 3.
1834 EXPECT_TRUE(Result
);
1836 EXPECT_EQ(OutValues
[0], RspPHIInBlk3ID
);
1839 // If the incoming values are swapped between blocks, we should not
1840 // successfully join. The CFG merge would select the right values, but in
1841 // the wrong conditions.
1842 std::swap(VLiveOuts
[1], VLiveOuts
[2]);
1844 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1845 EXPECT_FALSE(Result
);
1848 std::swap(VLiveOuts
[1], VLiveOuts
[2]);
1849 // Setting one of these to being a constant should prohibit merging.
1850 VLiveOuts
[1].setDbgOpIDs(ConstZeroID
);
1852 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1853 EXPECT_FALSE(Result
);
1855 // Setting both to being identical constants should result in a valid join
1856 // with a constant value.
1857 VLiveOuts
[2] = VLiveOuts
[1];
1859 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1860 EXPECT_TRUE(Result
);
1862 EXPECT_EQ(OutValues
[0], ConstZeroID
);
1865 // NoVals shouldn't join with anything else.
1866 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
1867 VLiveOuts
[2] = DbgValue(2, EmptyProps
, DbgValue::NoVal
);
1869 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1870 EXPECT_FALSE(Result
);
1872 // We might merge in another VPHI in such a join. Present pickVPHILoc with
1873 // such a scenario: first, where one incoming edge has a VPHI with no known
1874 // value. This represents an edge where there was a PHI value that can't be
1875 // found in the register file -- we can't subsequently find a PHI here.
1876 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
1877 VLiveOuts
[2] = DbgValue(2, EmptyProps
, DbgValue::VPHI
);
1879 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1880 EXPECT_FALSE(Result
);
1882 // However, if we know the value of the incoming VPHI, we can search for its
1883 // location. Use a PHI machine-value for doing this, as VPHIs should always
1884 // have PHI values, or they should have been eliminated.
1885 MOutLocs
[2][0] = RspPHIInBlk2
;
1886 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
1887 VLiveOuts
[2] = DbgValue(2, EmptyProps
, DbgValue::VPHI
);
1888 VLiveOuts
[2].setDbgOpIDs(RspPHIInBlk2ID
); // Set location where PHI happens.
1890 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1891 EXPECT_TRUE(Result
);
1893 EXPECT_EQ(OutValues
[0], RspPHIInBlk3ID
);
1896 // If that value isn't available from that block, don't join.
1897 MOutLocs
[2][0] = LiveInRsp
;
1899 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1900 EXPECT_FALSE(Result
);
1902 // Check that we don't pick values when the properties disagree, for example
1903 // different indirectness or DIExpression.
1904 MOutLocs
[2][0] = LiveInRax
;
1905 DIExpression
*NewExpr
=
1906 DIExpression::prepend(EmptyExpr
, DIExpression::ApplyOffset
, 4);
1907 DbgValueProperties
PropsWithExpr(NewExpr
, false, false);
1908 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
1909 VLiveOuts
[2] = DbgValue(LiveInRspID
, PropsWithExpr
);
1911 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1912 EXPECT_FALSE(Result
);
1914 DbgValueProperties
PropsWithIndirect(EmptyExpr
, true, false);
1915 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
1916 VLiveOuts
[2] = DbgValue(LiveInRspID
, PropsWithIndirect
);
1918 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1919 EXPECT_FALSE(Result
);
1921 // When we have operands with values [A, B] and [B, A], we do not necessarily
1922 // pick identical join locations for each operand if the locations of those
1923 // values differ between incoming basic blocks.
1924 MOutLocs
[1][0] = LiveInRsp
;
1925 MOutLocs
[2][0] = LiveInRax
;
1926 MOutLocs
[1][1] = LiveInRax
;
1927 MOutLocs
[2][1] = LiveInRsp
;
1928 DbgOpID Locs0
[] = {LiveInRspID
, LiveInRaxID
};
1929 DbgOpID Locs1
[] = {LiveInRaxID
, LiveInRspID
};
1930 VLiveOuts
[1] = DbgValue(Locs0
, TwoOpProps
);
1931 VLiveOuts
[2] = DbgValue(Locs1
, TwoOpProps
);
1933 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1934 // Should have picked PHIs in block 3.
1935 EXPECT_TRUE(Result
);
1937 EXPECT_EQ(OutValues
[0], RspPHIInBlk3ID
);
1938 EXPECT_EQ(OutValues
[1], RaxPHIInBlk3ID
);
1941 // When joining identical constants for an operand, we should simply keep that
1942 // constant while joining the remaining operands as normal.
1943 DbgOpID Locs2
[] = {LiveInRspID
, ConstZeroID
};
1944 DbgOpID Locs3
[] = {LiveInRaxID
, ConstZeroID
};
1945 VLiveOuts
[1] = DbgValue(Locs2
, TwoOpProps
);
1946 VLiveOuts
[2] = DbgValue(Locs3
, TwoOpProps
);
1948 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1949 EXPECT_TRUE(Result
);
1951 EXPECT_EQ(OutValues
[0], RspPHIInBlk3ID
);
1952 EXPECT_EQ(OutValues
[1], ConstZeroID
);
1955 // If the debug values have different constants for the same operand, they
1956 // cannot be joined.
1957 DbgOpID ConstOneID
= addConstDbgOp(MachineOperand::CreateImm(1));
1958 DbgOpID Locs4
[] = {LiveInRaxID
, ConstOneID
};
1959 VLiveOuts
[1] = DbgValue(Locs3
, TwoOpProps
);
1960 VLiveOuts
[2] = DbgValue(Locs4
, TwoOpProps
);
1962 Result
= pickVPHILoc(OutValues
, *MBB3
, VLiveOutIdx
, MOutLocs
, Preds
);
1963 EXPECT_FALSE(Result
);
1966 TEST_F(InstrRefLDVTest
, pickVPHILocLoops
) {
1976 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
1978 Register RAX
= getRegByName("RAX");
1979 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
1981 auto [MInLocs
, MOutLocs
] = allocValueTables(3, 2);
1983 initValueArray(MOutLocs
, 3, 2);
1985 unsigned EntryBlk
= 0, LoopBlk
= 1;
1987 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
1988 ValueIDNum
LiveInRax(EntryBlk
, 0, RaxLoc
);
1989 ValueIDNum
RspPHIInBlk1(LoopBlk
, 0, RspLoc
);
1990 ValueIDNum
RaxPHIInBlk1(LoopBlk
, 0, RaxLoc
);
1991 DbgOpID LiveInRspID
= addValueDbgOp(LiveInRsp
);
1992 DbgOpID LiveInRaxID
= addValueDbgOp(LiveInRax
);
1993 DbgOpID RspPHIInBlk1ID
= addValueDbgOp(RspPHIInBlk1
);
1994 DbgOpID RaxPHIInBlk1ID
= addValueDbgOp(RaxPHIInBlk1
);
1996 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
1997 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
1998 DIExpression
*TwoOpExpr
=
1999 DIExpression::get(Ctx
, {dwarf::DW_OP_LLVM_arg
, 0, dwarf::DW_OP_LLVM_arg
,
2000 1, dwarf::DW_OP_plus
});
2001 DbgValueProperties
TwoOpProps(TwoOpExpr
, false, true);
2002 SmallVector
<DbgValue
, 32> VLiveOuts
;
2003 VLiveOuts
.resize(3, DbgValue(EmptyProps
, DbgValue::Undef
));
2004 InstrRefBasedLDV::LiveIdxT VLiveOutIdx
;
2005 VLiveOutIdx
[MBB0
] = &VLiveOuts
[0];
2006 VLiveOutIdx
[MBB1
] = &VLiveOuts
[1];
2007 VLiveOutIdx
[MBB2
] = &VLiveOuts
[2];
2009 SmallVector
<const MachineBasicBlock
*, 2> Preds
;
2010 for (const auto *Pred
: MBB1
->predecessors())
2011 Preds
.push_back(Pred
);
2013 // Specify the live-outs around the joining block.
2014 MOutLocs
[0][0] = LiveInRsp
;
2015 MOutLocs
[1][0] = LiveInRax
;
2018 SmallVector
<DbgOpID
> OutValues
;
2020 // See that we can merge as normal on a backedge.
2021 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2022 VLiveOuts
[1] = DbgValue(LiveInRaxID
, EmptyProps
);
2024 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2025 // Should have picked a PHI in $rsp in block 1.
2026 EXPECT_TRUE(Result
);
2028 EXPECT_EQ(OutValues
[0], RspPHIInBlk1ID
);
2031 // And that, if the desired values aren't available, we don't merge.
2032 MOutLocs
[1][0] = LiveInRsp
;
2034 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2035 EXPECT_FALSE(Result
);
2037 // Test the backedge behaviour: PHIs that feed back into themselves can
2038 // carry this variables value. Feed in LiveInRsp in both $rsp and $rax
2039 // from the entry block, but only put an appropriate backedge PHI in $rax.
2040 // Only the $rax location can form the correct PHI.
2041 MOutLocs
[0][0] = LiveInRsp
;
2042 MOutLocs
[0][1] = LiveInRsp
;
2043 MOutLocs
[1][0] = RaxPHIInBlk1
;
2044 MOutLocs
[1][1] = RaxPHIInBlk1
;
2045 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2046 // Crucially, a VPHI originating in this block:
2047 VLiveOuts
[1] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2049 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2050 EXPECT_TRUE(Result
);
2052 EXPECT_EQ(OutValues
[0], RaxPHIInBlk1ID
);
2055 // Test that we can also find a location when joining a backedge PHI with
2056 // a variadic debug value.
2057 MOutLocs
[1][0] = RspPHIInBlk1
;
2058 MOutLocs
[0][1] = LiveInRax
;
2059 DbgOpID Locs0
[] = {LiveInRspID
, LiveInRaxID
};
2060 VLiveOuts
[0] = DbgValue(Locs0
, TwoOpProps
);
2061 // Crucially, a VPHI originating in this block:
2062 VLiveOuts
[1] = DbgValue(1, TwoOpProps
, DbgValue::VPHI
);
2064 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2065 EXPECT_TRUE(Result
);
2067 EXPECT_EQ(OutValues
[0], RspPHIInBlk1ID
);
2068 EXPECT_EQ(OutValues
[1], RaxPHIInBlk1ID
);
2071 // Merging should not be permitted if there's a usable PHI on the backedge,
2072 // but it's in the wrong place. (Overwrite $rax).
2073 MOutLocs
[1][1] = LiveInRax
;
2074 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2076 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2077 EXPECT_FALSE(Result
);
2079 // Additionally, if the VPHI coming back on the loop backedge isn't from
2080 // this block (block 1), we can't merge it.
2081 MOutLocs
[1][1] = RaxPHIInBlk1
;
2082 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2083 VLiveOuts
[1] = DbgValue(0, EmptyProps
, DbgValue::VPHI
);
2085 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2086 EXPECT_FALSE(Result
);
2089 TEST_F(InstrRefLDVTest
, pickVPHILocBadlyNestedLoops
) {
2090 // Run some tests similar to pickVPHILocLoops, with more than one backedge,
2091 // and check that we merge correctly over many candidate locations.
2092 setupBadlyNestedLoops();
2104 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
2106 Register RAX
= getRegByName("RAX");
2107 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
2108 Register RBX
= getRegByName("RBX");
2109 LocIdx RbxLoc
= MTracker
->lookupOrTrackRegister(RBX
);
2111 auto [MInLocs
, MOutLocs
] = allocValueTables(5, 3);
2113 initValueArray(MOutLocs
, 5, 3);
2115 unsigned EntryBlk
= 0, Loop1Blk
= 1;
2117 ValueIDNum
LiveInRsp(EntryBlk
, 0, RspLoc
);
2118 ValueIDNum
LiveInRax(EntryBlk
, 0, RaxLoc
);
2119 ValueIDNum
LiveInRbx(EntryBlk
, 0, RbxLoc
);
2120 ValueIDNum
RspPHIInBlk1(Loop1Blk
, 0, RspLoc
);
2121 ValueIDNum
RaxPHIInBlk1(Loop1Blk
, 0, RaxLoc
);
2122 ValueIDNum
RbxPHIInBlk1(Loop1Blk
, 0, RbxLoc
);
2123 DbgOpID LiveInRspID
= addValueDbgOp(LiveInRsp
);
2124 DbgOpID LiveInRaxID
= addValueDbgOp(LiveInRax
);
2125 DbgOpID LiveInRbxID
= addValueDbgOp(LiveInRbx
);
2126 DbgOpID RspPHIInBlk1ID
= addValueDbgOp(RspPHIInBlk1
);
2127 addValueDbgOp(RaxPHIInBlk1
);
2128 DbgOpID RbxPHIInBlk1ID
= addValueDbgOp(RbxPHIInBlk1
);
2130 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
2131 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
2132 SmallVector
<DbgValue
, 32> VLiveOuts
;
2133 VLiveOuts
.resize(5, DbgValue(EmptyProps
, DbgValue::Undef
));
2134 InstrRefBasedLDV::LiveIdxT VLiveOutIdx
;
2135 VLiveOutIdx
[MBB0
] = &VLiveOuts
[0];
2136 VLiveOutIdx
[MBB1
] = &VLiveOuts
[1];
2137 VLiveOutIdx
[MBB2
] = &VLiveOuts
[2];
2138 VLiveOutIdx
[MBB3
] = &VLiveOuts
[3];
2139 VLiveOutIdx
[MBB4
] = &VLiveOuts
[4];
2141 // We're going to focus on block 1.
2142 SmallVector
<const MachineBasicBlock
*, 2> Preds
;
2143 for (const auto *Pred
: MBB1
->predecessors())
2144 Preds
.push_back(Pred
);
2146 // Specify the live-outs around the joining block. Incoming edges from the
2147 // entry block, self, and loop2.
2148 MOutLocs
[0][0] = LiveInRsp
;
2149 MOutLocs
[1][0] = LiveInRax
;
2150 MOutLocs
[2][0] = LiveInRbx
;
2153 SmallVector
<DbgOpID
> OutValues
;
2155 // See that we can merge as normal on a backedge.
2156 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2157 VLiveOuts
[1] = DbgValue(LiveInRaxID
, EmptyProps
);
2158 VLiveOuts
[2] = DbgValue(LiveInRbxID
, EmptyProps
);
2160 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2161 // Should have picked a PHI in $rsp in block 1.
2162 EXPECT_TRUE(Result
);
2164 EXPECT_EQ(OutValues
[0], RspPHIInBlk1ID
);
2167 // Check too that permuting the live-out locations prevents merging
2168 MOutLocs
[0][0] = LiveInRax
;
2169 MOutLocs
[1][0] = LiveInRbx
;
2170 MOutLocs
[2][0] = LiveInRsp
;
2172 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2173 EXPECT_FALSE(Result
);
2175 MOutLocs
[0][0] = LiveInRsp
;
2176 MOutLocs
[1][0] = LiveInRax
;
2177 MOutLocs
[2][0] = LiveInRbx
;
2179 // Feeding a PHI back on one backedge shouldn't merge (block 1 self backedge
2180 // wants LiveInRax).
2181 MOutLocs
[1][0] = RspPHIInBlk1
;
2183 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2184 EXPECT_FALSE(Result
);
2186 // If the variables value on that edge is a VPHI feeding into itself, that's
2188 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2189 VLiveOuts
[1] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2190 VLiveOuts
[2] = DbgValue(LiveInRbxID
, EmptyProps
);
2192 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2193 EXPECT_TRUE(Result
);
2195 EXPECT_EQ(OutValues
[0], RspPHIInBlk1ID
);
2198 // Likewise: the other backedge being a VPHI from block 1 should be accepted.
2199 MOutLocs
[2][0] = RspPHIInBlk1
;
2200 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2201 VLiveOuts
[1] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2202 VLiveOuts
[2] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2204 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2205 EXPECT_TRUE(Result
);
2207 EXPECT_EQ(OutValues
[0], RspPHIInBlk1ID
);
2210 // Here's where it becomes tricky: we should not merge if there are two
2211 // _distinct_ backedge PHIs. We can't have a PHI that happens in both rsp
2212 // and rax for example. We can only pick one location as the live-in.
2213 MOutLocs
[2][0] = RaxPHIInBlk1
;
2215 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2216 EXPECT_FALSE(Result
);
2218 // The above test sources correct machine-PHI-value from two places. Now
2219 // try with one machine-PHI-value, but placed in two different locations
2220 // on the backedge. Again, we can't merge a location here, there's no
2221 // location that works on all paths.
2222 MOutLocs
[0][0] = LiveInRsp
;
2223 MOutLocs
[1][0] = RspPHIInBlk1
;
2224 MOutLocs
[2][0] = LiveInRsp
;
2225 MOutLocs
[2][1] = RspPHIInBlk1
;
2227 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2228 EXPECT_FALSE(Result
);
2230 // Scatter various PHI values across the available locations. Only rbx (loc 2)
2231 // has the right value in both backedges -- that's the loc that should be
2233 MOutLocs
[0][2] = LiveInRsp
;
2234 MOutLocs
[1][0] = RspPHIInBlk1
;
2235 MOutLocs
[1][1] = RaxPHIInBlk1
;
2236 MOutLocs
[1][2] = RbxPHIInBlk1
;
2237 MOutLocs
[2][0] = LiveInRsp
;
2238 MOutLocs
[2][1] = RspPHIInBlk1
;
2239 MOutLocs
[2][2] = RbxPHIInBlk1
;
2241 Result
= pickVPHILoc(OutValues
, *MBB1
, VLiveOutIdx
, MOutLocs
, Preds
);
2242 EXPECT_TRUE(Result
);
2244 EXPECT_EQ(OutValues
[0], RbxPHIInBlk1ID
);
2248 TEST_F(InstrRefLDVTest
, vlocJoinDiamond
) {
2254 setupDiamondBlocks();
2256 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
2258 Register RAX
= getRegByName("RAX");
2259 MTracker
->lookupOrTrackRegister(RAX
);
2261 DbgOpID LiveInRspID
= DbgOpID(false, 0);
2262 DbgOpID LiveInRaxID
= DbgOpID(false, 1);
2264 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
2265 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
2266 SmallVector
<DbgValue
, 32> VLiveOuts
;
2267 VLiveOuts
.resize(4, DbgValue(EmptyProps
, DbgValue::Undef
));
2268 InstrRefBasedLDV::LiveIdxT VLiveOutIdx
;
2269 VLiveOutIdx
[MBB0
] = &VLiveOuts
[0];
2270 VLiveOutIdx
[MBB1
] = &VLiveOuts
[1];
2271 VLiveOutIdx
[MBB2
] = &VLiveOuts
[2];
2272 VLiveOutIdx
[MBB3
] = &VLiveOuts
[3];
2274 SmallPtrSet
<const MachineBasicBlock
*, 8> AllBlocks
;
2275 AllBlocks
.insert(MBB0
);
2276 AllBlocks
.insert(MBB1
);
2277 AllBlocks
.insert(MBB2
);
2278 AllBlocks
.insert(MBB3
);
2280 SmallVector
<const MachineBasicBlock
*, 2> Preds
;
2281 for (const auto *Pred
: MBB3
->predecessors())
2282 Preds
.push_back(Pred
);
2284 SmallSet
<DebugVariable
, 4> AllVars
;
2285 AllVars
.insert(Var
);
2287 // vlocJoin is here to propagate incoming values, and eliminate PHIs. Start
2288 // off by propagating a value into the merging block, number 3.
2289 DbgValue JoinedLoc
= DbgValue(3, EmptyProps
, DbgValue::NoVal
);
2290 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2291 VLiveOuts
[2] = DbgValue(LiveInRspID
, EmptyProps
);
2292 bool Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2293 EXPECT_TRUE(Result
); // Output locs should have changed.
2294 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2295 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRspID
);
2297 // And if we did it a second time, leaving the live-ins as it was, then
2298 // we should report no change.
2299 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2300 EXPECT_FALSE(Result
);
2302 // If the live-in variable values are different, but there's no PHI placed
2303 // in this block, then just pick a location. It should be the first (in RPO)
2304 // predecessor to avoid being a backedge.
2305 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2306 VLiveOuts
[2] = DbgValue(LiveInRaxID
, EmptyProps
);
2307 JoinedLoc
= DbgValue(3, EmptyProps
, DbgValue::NoVal
);
2308 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2309 EXPECT_TRUE(Result
);
2310 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2311 // RPO is blocks 0 2 1 3, so LiveInRax is picked as the first predecessor
2313 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRaxID
);
2315 // No tests for whether vlocJoin will pass-through a variable with differing
2316 // expressions / properties. Those can only come about due to assignments; and
2317 // for any assignment at all, a PHI should have been placed at the dominance
2318 // frontier. We rely on the IDF calculator being accurate (which is OK,
2319 // because so does the rest of LLVM).
2321 // Try placing a PHI. With differing input values (LiveInRsp, LiveInRax),
2322 // this PHI should not be eliminated.
2323 JoinedLoc
= DbgValue(3, EmptyProps
, DbgValue::VPHI
);
2324 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2325 // Expect no change.
2326 EXPECT_FALSE(Result
);
2327 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2328 // This should not have been assigned a fixed value.
2329 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), DbgOpID::UndefID
);
2330 EXPECT_EQ(JoinedLoc
.BlockNo
, 3);
2332 // Try a simple PHI elimination. Put a PHI in block 3, but LiveInRsp on both
2333 // incoming edges. Re-load in and out-locs with unrelated values; they're
2335 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2336 VLiveOuts
[2] = DbgValue(LiveInRspID
, EmptyProps
);
2337 JoinedLoc
= DbgValue(3, EmptyProps
, DbgValue::VPHI
);
2338 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2339 EXPECT_TRUE(Result
);
2340 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2341 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRspID
);
2343 // Try the same PHI elimination but with one incoming value being a VPHI
2344 // referring to the same value.
2345 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2346 VLiveOuts
[2] = DbgValue(2, EmptyProps
, DbgValue::VPHI
);
2347 VLiveOuts
[2].setDbgOpIDs(LiveInRspID
);
2348 JoinedLoc
= DbgValue(3, EmptyProps
, DbgValue::VPHI
);
2349 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2350 EXPECT_TRUE(Result
);
2351 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2352 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRspID
);
2354 // If the "current" live-in is a VPHI, but not a VPHI generated in the current
2355 // block, then it's the remains of an earlier value propagation. We should
2356 // value propagate through this merge. Even if the current incoming values
2357 // disagree, because we've previously determined any VPHI here is redundant.
2358 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2359 VLiveOuts
[2] = DbgValue(LiveInRaxID
, EmptyProps
);
2360 JoinedLoc
= DbgValue(2, EmptyProps
, DbgValue::VPHI
);
2361 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2362 EXPECT_TRUE(Result
);
2363 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2364 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRaxID
); // from block 2
2366 // The above test, but test that we will install one value-propagated VPHI
2368 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2369 VLiveOuts
[2] = DbgValue(0, EmptyProps
, DbgValue::VPHI
);
2370 JoinedLoc
= DbgValue(2, EmptyProps
, DbgValue::VPHI
);
2371 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2372 EXPECT_TRUE(Result
);
2373 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2374 EXPECT_EQ(JoinedLoc
.BlockNo
, 0);
2376 // We shouldn't eliminate PHIs when properties disagree.
2377 DbgValueProperties
PropsWithIndirect(EmptyExpr
, true, false);
2378 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2379 VLiveOuts
[2] = DbgValue(LiveInRspID
, PropsWithIndirect
);
2380 JoinedLoc
= DbgValue(3, EmptyProps
, DbgValue::VPHI
);
2381 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2382 EXPECT_FALSE(Result
);
2383 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2384 EXPECT_EQ(JoinedLoc
.BlockNo
, 3);
2386 // Even if properties disagree, we should still value-propagate if there's no
2387 // PHI to be eliminated. The disagreeing values should work themselves out,
2388 // seeing how we've determined no PHI is necessary.
2389 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2390 VLiveOuts
[2] = DbgValue(LiveInRspID
, PropsWithIndirect
);
2391 JoinedLoc
= DbgValue(2, EmptyProps
, DbgValue::VPHI
);
2392 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2393 EXPECT_TRUE(Result
);
2394 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2395 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRspID
);
2396 // Also check properties come from block 2, the first RPO predecessor to block
2398 EXPECT_EQ(JoinedLoc
.Properties
, PropsWithIndirect
);
2400 // Again, disagreeing properties, this time the expr, should cause a PHI to
2401 // not be eliminated.
2402 DIExpression
*NewExpr
=
2403 DIExpression::prepend(EmptyExpr
, DIExpression::ApplyOffset
, 4);
2404 DbgValueProperties
PropsWithExpr(NewExpr
, false, false);
2405 VLiveOuts
[1] = DbgValue(LiveInRspID
, EmptyProps
);
2406 VLiveOuts
[2] = DbgValue(LiveInRspID
, PropsWithExpr
);
2407 JoinedLoc
= DbgValue(3, EmptyProps
, DbgValue::VPHI
);
2408 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2409 EXPECT_FALSE(Result
);
2411 // Try placing a PHI with variadic debug values. With differing input values
2412 // (LiveInRsp, LiveInRax), this PHI should not be eliminated.
2413 DIExpression
*TwoOpExpr
=
2414 DIExpression::get(Ctx
, {dwarf::DW_OP_LLVM_arg
, 0, dwarf::DW_OP_LLVM_arg
,
2415 1, dwarf::DW_OP_plus
});
2416 DbgValueProperties
TwoOpProps(TwoOpExpr
, false, true);
2417 DbgOpID Locs0
[] = {LiveInRspID
, LiveInRaxID
};
2418 DbgOpID Locs1
[] = {LiveInRaxID
, LiveInRspID
};
2419 JoinedLoc
= DbgValue(3, TwoOpProps
, DbgValue::VPHI
);
2420 VLiveOuts
[1] = DbgValue(Locs0
, TwoOpProps
);
2421 VLiveOuts
[2] = DbgValue(Locs1
, TwoOpProps
);
2422 Result
= vlocJoin(*MBB3
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2423 // Expect no change.
2424 EXPECT_FALSE(Result
);
2425 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2426 // This should not have been assigned a fixed value.
2427 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), DbgOpID::UndefID
);
2428 EXPECT_EQ(JoinedLoc
.BlockNo
, 3);
2431 TEST_F(InstrRefLDVTest
, vlocJoinLoops
) {
2440 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
2442 Register RAX
= getRegByName("RAX");
2443 MTracker
->lookupOrTrackRegister(RAX
);
2445 DbgOpID LiveInRspID
= DbgOpID(false, 0);
2446 DbgOpID LiveInRaxID
= DbgOpID(false, 1);
2448 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
2449 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
2450 SmallVector
<DbgValue
, 32> VLiveOuts
;
2451 VLiveOuts
.resize(3, DbgValue(EmptyProps
, DbgValue::Undef
));
2452 InstrRefBasedLDV::LiveIdxT VLiveOutIdx
;
2453 VLiveOutIdx
[MBB0
] = &VLiveOuts
[0];
2454 VLiveOutIdx
[MBB1
] = &VLiveOuts
[1];
2455 VLiveOutIdx
[MBB2
] = &VLiveOuts
[2];
2457 SmallPtrSet
<const MachineBasicBlock
*, 8> AllBlocks
;
2458 AllBlocks
.insert(MBB0
);
2459 AllBlocks
.insert(MBB1
);
2460 AllBlocks
.insert(MBB2
);
2462 SmallVector
<const MachineBasicBlock
*, 2> Preds
;
2463 for (const auto *Pred
: MBB1
->predecessors())
2464 Preds
.push_back(Pred
);
2466 SmallSet
<DebugVariable
, 4> AllVars
;
2467 AllVars
.insert(Var
);
2469 // Test some back-edge-specific behaviours of vloc join. Mostly: the fact that
2470 // VPHIs that arrive on backedges can be eliminated, despite having different
2471 // values to the predecessor.
2473 // First: when there's no VPHI placed already, propagate the live-in value of
2474 // the first RPO predecessor.
2475 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2476 VLiveOuts
[1] = DbgValue(LiveInRaxID
, EmptyProps
);
2477 DbgValue JoinedLoc
= DbgValue(LiveInRaxID
, EmptyProps
);
2478 bool Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2479 EXPECT_TRUE(Result
);
2480 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2481 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRspID
);
2483 // If there is a VPHI: don't elimiante it if there are disagreeing values.
2484 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2485 VLiveOuts
[1] = DbgValue(LiveInRaxID
, EmptyProps
);
2486 JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2487 Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2488 EXPECT_FALSE(Result
);
2489 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2490 EXPECT_EQ(JoinedLoc
.BlockNo
, 1);
2492 // If we feed this VPHI back into itself though, we can eliminate it.
2493 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2494 VLiveOuts
[1] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2495 JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2496 Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2497 EXPECT_TRUE(Result
);
2498 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2499 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRspID
);
2501 // Don't eliminate backedge VPHIs if the predecessors have different
2503 DIExpression
*NewExpr
=
2504 DIExpression::prepend(EmptyExpr
, DIExpression::ApplyOffset
, 4);
2505 DbgValueProperties
PropsWithExpr(NewExpr
, false, false);
2506 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2507 VLiveOuts
[1] = DbgValue(1, PropsWithExpr
, DbgValue::VPHI
);
2508 JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2509 Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2510 EXPECT_FALSE(Result
);
2511 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2512 EXPECT_EQ(JoinedLoc
.BlockNo
, 1);
2514 // Backedges with VPHIs, but from the wrong block, shouldn't be eliminated.
2515 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2516 VLiveOuts
[1] = DbgValue(0, EmptyProps
, DbgValue::VPHI
);
2517 JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2518 Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2519 EXPECT_FALSE(Result
);
2520 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2521 EXPECT_EQ(JoinedLoc
.BlockNo
, 1);
2524 TEST_F(InstrRefLDVTest
, vlocJoinBadlyNestedLoops
) {
2525 // Test PHI elimination in the presence of multiple backedges.
2526 setupBadlyNestedLoops();
2538 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
2540 Register RAX
= getRegByName("RAX");
2541 MTracker
->lookupOrTrackRegister(RAX
);
2542 Register RBX
= getRegByName("RBX");
2543 MTracker
->lookupOrTrackRegister(RBX
);
2545 DbgOpID LiveInRspID
= DbgOpID(false, 0);
2546 DbgOpID LiveInRaxID
= DbgOpID(false, 1);
2547 DbgOpID LiveInRbxID
= DbgOpID(false, 2);
2549 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
2550 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
2551 SmallVector
<DbgValue
, 32> VLiveOuts
;
2552 VLiveOuts
.resize(5, DbgValue(EmptyProps
, DbgValue::Undef
));
2553 InstrRefBasedLDV::LiveIdxT VLiveOutIdx
;
2554 VLiveOutIdx
[MBB0
] = &VLiveOuts
[0];
2555 VLiveOutIdx
[MBB1
] = &VLiveOuts
[1];
2556 VLiveOutIdx
[MBB2
] = &VLiveOuts
[2];
2557 VLiveOutIdx
[MBB3
] = &VLiveOuts
[3];
2558 VLiveOutIdx
[MBB4
] = &VLiveOuts
[4];
2560 SmallPtrSet
<const MachineBasicBlock
*, 8> AllBlocks
;
2561 AllBlocks
.insert(MBB0
);
2562 AllBlocks
.insert(MBB1
);
2563 AllBlocks
.insert(MBB2
);
2564 AllBlocks
.insert(MBB3
);
2565 AllBlocks
.insert(MBB4
);
2567 // We're going to focus on block 1.
2568 SmallVector
<const MachineBasicBlock
*, 3> Preds
;
2569 for (const auto *Pred
: MBB1
->predecessors())
2570 Preds
.push_back(Pred
);
2572 SmallSet
<DebugVariable
, 4> AllVars
;
2573 AllVars
.insert(Var
);
2575 // Test a normal VPHI isn't eliminated.
2576 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2577 VLiveOuts
[1] = DbgValue(LiveInRaxID
, EmptyProps
);
2578 VLiveOuts
[2] = DbgValue(LiveInRbxID
, EmptyProps
);
2579 DbgValue JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2580 bool Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2581 EXPECT_FALSE(Result
);
2582 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2583 EXPECT_EQ(JoinedLoc
.BlockNo
, 1);
2585 // Common VPHIs on backedges should merge.
2586 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2587 VLiveOuts
[1] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2588 VLiveOuts
[2] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2589 JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2590 Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2591 EXPECT_TRUE(Result
);
2592 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::Def
);
2593 EXPECT_EQ(JoinedLoc
.getDbgOpID(0), LiveInRspID
);
2595 // They shouldn't merge if one of their properties is different.
2596 DbgValueProperties
PropsWithIndirect(EmptyExpr
, true, false);
2597 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2598 VLiveOuts
[1] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2599 VLiveOuts
[2] = DbgValue(1, PropsWithIndirect
, DbgValue::VPHI
);
2600 JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2601 Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2602 EXPECT_FALSE(Result
);
2603 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2604 EXPECT_EQ(JoinedLoc
.BlockNo
, 1);
2606 // VPHIs from different blocks should not merge.
2607 VLiveOuts
[0] = DbgValue(LiveInRspID
, EmptyProps
);
2608 VLiveOuts
[1] = DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2609 VLiveOuts
[2] = DbgValue(2, EmptyProps
, DbgValue::VPHI
);
2610 JoinedLoc
= DbgValue(1, EmptyProps
, DbgValue::VPHI
);
2611 Result
= vlocJoin(*MBB1
, VLiveOutIdx
, AllBlocks
, JoinedLoc
);
2612 EXPECT_FALSE(Result
);
2613 EXPECT_EQ(JoinedLoc
.Kind
, DbgValue::VPHI
);
2614 EXPECT_EQ(JoinedLoc
.BlockNo
, 1);
2617 // Above are tests for picking VPHI locations, and eliminating VPHIs. No
2618 // unit-tests are written for evaluating the transfer function as that's
2619 // pretty straight forwards, or applying VPHI-location-picking to live-ins.
2620 // Instead, pre-set some machine locations and apply buildVLocValueMap to the
2621 // existing CFG patterns.
2622 TEST_F(InstrRefLDVTest
, VLocSingleBlock
) {
2625 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
2628 auto [MInLocs
, MOutLocs
] = allocValueTables(1, 2);
2630 ValueIDNum LiveInRsp
= ValueIDNum(0, 0, RspLoc
);
2631 DbgOpID LiveInRspID
= addValueDbgOp(LiveInRsp
);
2632 MInLocs
[0][0] = MOutLocs
[0][0] = LiveInRsp
;
2634 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
2635 DebugVariableID VarID
= LDV
->getDVMap().insertDVID(Var
, OutermostLoc
);
2636 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
2638 SmallSet
<DebugVariableID
, 4> AllVars
;
2639 AllVars
.insert(VarID
);
2641 // Mild hack: rather than constructing machine instructions in each block
2642 // and creating lexical scopes across them, instead just tell
2643 // buildVLocValueMap that there's an assignment in every block. That makes
2644 // every block in scope.
2645 SmallPtrSet
<MachineBasicBlock
*, 4> AssignBlocks
;
2646 AssignBlocks
.insert(MBB0
);
2648 SmallVector
<VLocTracker
, 1> VLocs
;
2649 VLocs
.resize(1, VLocTracker(LDV
->getDVMap(), Overlaps
, EmptyExpr
));
2651 InstrRefBasedLDV::LiveInsT Output
;
2653 // Test that, with no assignments at all, no mappings are created for the
2654 // variable in this function.
2655 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2656 MOutLocs
, MInLocs
, VLocs
);
2657 EXPECT_EQ(Output
.size(), 0ul);
2659 // If we put an assignment in the transfer function, that should... well,
2660 // do nothing, because we don't store the live-outs.
2661 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2662 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2663 MOutLocs
, MInLocs
, VLocs
);
2664 EXPECT_EQ(Output
.size(), 0ul);
2666 // There is pretty much nothing else of interest to test with a single block.
2667 // It's not relevant to the SSA-construction parts of variable values.
2670 TEST_F(InstrRefLDVTest
, VLocDiamondBlocks
) {
2671 setupDiamondBlocks();
2678 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
2680 Register RAX
= getRegByName("RAX");
2681 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
2683 unsigned EntryBlk
= 0, RetBlk
= 3;
2685 ValueIDNum LiveInRsp
= ValueIDNum(EntryBlk
, 0, RspLoc
);
2686 ValueIDNum LiveInRax
= ValueIDNum(EntryBlk
, 0, RaxLoc
);
2687 ValueIDNum RspPHIInBlk3
= ValueIDNum(RetBlk
, 0, RspLoc
);
2688 DbgOpID LiveInRspID
= addValueDbgOp(LiveInRsp
);
2689 DbgOpID LiveInRaxID
= addValueDbgOp(LiveInRax
);
2690 DbgOpID RspPHIInBlk3ID
= addValueDbgOp(RspPHIInBlk3
);
2692 auto [MInLocs
, MOutLocs
] = allocValueTables(4, 2);
2694 initValueArray(MInLocs
, 4, 2);
2695 initValueArray(MOutLocs
, 4, 2);
2697 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
2698 DebugVariableID VarID
= LDV
->getDVMap().insertDVID(Var
, OutermostLoc
);
2699 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
2701 SmallSet
<DebugVariableID
, 4> AllVars
;
2702 AllVars
.insert(VarID
);
2704 // Mild hack: rather than constructing machine instructions in each block
2705 // and creating lexical scopes across them, instead just tell
2706 // buildVLocValueMap that there's an assignment in every block. That makes
2707 // every block in scope.
2708 SmallPtrSet
<MachineBasicBlock
*, 4> AssignBlocks
;
2709 AssignBlocks
.insert(MBB0
);
2710 AssignBlocks
.insert(MBB1
);
2711 AssignBlocks
.insert(MBB2
);
2712 AssignBlocks
.insert(MBB3
);
2714 SmallVector
<VLocTracker
, 1> VLocs
;
2715 VLocs
.resize(4, VLocTracker(LDV
->getDVMap(), Overlaps
, EmptyExpr
));
2717 InstrRefBasedLDV::LiveInsT Output
;
2719 // Start off with LiveInRsp in every location.
2720 for (unsigned int I
= 0; I
< 4; ++I
) {
2721 MInLocs
[I
][0] = MInLocs
[I
][1] = LiveInRsp
;
2722 MOutLocs
[I
][0] = MOutLocs
[I
][1] = LiveInRsp
;
2725 auto ClearOutputs
= [&]() {
2726 for (auto &Elem
: Output
)
2731 // No assignments -> no values.
2732 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2733 MOutLocs
, MInLocs
, VLocs
);
2734 EXPECT_EQ(Output
[0].size(), 0ul);
2735 EXPECT_EQ(Output
[1].size(), 0ul);
2736 EXPECT_EQ(Output
[2].size(), 0ul);
2737 EXPECT_EQ(Output
[3].size(), 0ul);
2739 // An assignment in the end block should also not affect other blocks; or
2740 // produce any live-ins.
2741 VLocs
[3].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2742 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2743 MOutLocs
, MInLocs
, VLocs
);
2744 EXPECT_EQ(Output
[0].size(), 0ul);
2745 EXPECT_EQ(Output
[1].size(), 0ul);
2746 EXPECT_EQ(Output
[2].size(), 0ul);
2747 EXPECT_EQ(Output
[3].size(), 0ul);
2750 // Assignments in either of the side-of-diamond blocks should also not be
2751 // propagated anywhere.
2752 VLocs
[3].Vars
.clear();
2753 VLocs
[2].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2754 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2755 MOutLocs
, MInLocs
, VLocs
);
2756 EXPECT_EQ(Output
[0].size(), 0ul);
2757 EXPECT_EQ(Output
[1].size(), 0ul);
2758 EXPECT_EQ(Output
[2].size(), 0ul);
2759 EXPECT_EQ(Output
[3].size(), 0ul);
2760 VLocs
[2].Vars
.clear();
2763 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2764 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2765 MOutLocs
, MInLocs
, VLocs
);
2766 EXPECT_EQ(Output
[0].size(), 0ul);
2767 EXPECT_EQ(Output
[1].size(), 0ul);
2768 EXPECT_EQ(Output
[2].size(), 0ul);
2769 EXPECT_EQ(Output
[3].size(), 0ul);
2770 VLocs
[1].Vars
.clear();
2773 // However: putting an assignment in the first block should propagate variable
2774 // values through to all other blocks, as it dominates.
2775 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2776 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2777 MOutLocs
, MInLocs
, VLocs
);
2778 EXPECT_EQ(Output
[0].size(), 0ul);
2779 ASSERT_EQ(Output
[1].size(), 1ul);
2780 ASSERT_EQ(Output
[2].size(), 1ul);
2781 ASSERT_EQ(Output
[3].size(), 1ul);
2782 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
2783 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
2784 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
2785 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
2786 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
2787 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRspID
);
2789 VLocs
[0].Vars
.clear();
2791 // Additionally, even if that value isn't available in the register file, it
2792 // should still be propagated, as buildVLocValueMap shouldn't care about
2793 // what's in the registers (except for PHIs).
2794 // values through to all other blocks, as it dominates.
2795 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
2796 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2797 MOutLocs
, MInLocs
, VLocs
);
2798 EXPECT_EQ(Output
[0].size(), 0ul);
2799 ASSERT_EQ(Output
[1].size(), 1ul);
2800 ASSERT_EQ(Output
[2].size(), 1ul);
2801 ASSERT_EQ(Output
[3].size(), 1ul);
2802 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
2803 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRaxID
);
2804 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
2805 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRaxID
);
2806 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
2807 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRaxID
);
2809 VLocs
[0].Vars
.clear();
2811 // We should get a live-in to the merging block, if there are two assigns of
2812 // the same value in either side of the diamond.
2813 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2814 VLocs
[2].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2815 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2816 MOutLocs
, MInLocs
, VLocs
);
2817 EXPECT_EQ(Output
[0].size(), 0ul);
2818 EXPECT_EQ(Output
[1].size(), 0ul);
2819 EXPECT_EQ(Output
[2].size(), 0ul);
2820 ASSERT_EQ(Output
[3].size(), 1ul);
2821 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
2822 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRspID
);
2824 VLocs
[1].Vars
.clear();
2825 VLocs
[2].Vars
.clear();
2827 // If we assign a value in the entry block, then 'undef' on a branch, we
2828 // shouldn't have a live-in in the merge block.
2829 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2830 VLocs
[1].Vars
.insert({VarID
, DbgValue(EmptyProps
, DbgValue::Undef
)});
2831 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2832 MOutLocs
, MInLocs
, VLocs
);
2833 EXPECT_EQ(Output
[0].size(), 0ul);
2834 ASSERT_EQ(Output
[1].size(), 1ul);
2835 ASSERT_EQ(Output
[2].size(), 1ul);
2836 EXPECT_EQ(Output
[3].size(), 0ul);
2837 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
2838 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
2839 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
2840 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
2842 VLocs
[0].Vars
.clear();
2843 VLocs
[1].Vars
.clear();
2845 // Having different values joining into the merge block should mean we have
2846 // no live-in in that block. Block ones LiveInRax value doesn't appear as a
2847 // live-in anywhere, it's block internal.
2848 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2849 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
2850 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2851 MOutLocs
, MInLocs
, VLocs
);
2852 EXPECT_EQ(Output
[0].size(), 0ul);
2853 ASSERT_EQ(Output
[1].size(), 1ul);
2854 ASSERT_EQ(Output
[2].size(), 1ul);
2855 EXPECT_EQ(Output
[3].size(), 0ul);
2856 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
2857 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
2858 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
2859 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
2861 VLocs
[0].Vars
.clear();
2862 VLocs
[1].Vars
.clear();
2864 // But on the other hand, if there's a location in the register file where
2865 // those two values can be joined, do so.
2866 MOutLocs
[1][0] = LiveInRax
;
2867 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2868 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
2869 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2870 MOutLocs
, MInLocs
, VLocs
);
2871 EXPECT_EQ(Output
[0].size(), 0ul);
2872 ASSERT_EQ(Output
[1].size(), 1ul);
2873 ASSERT_EQ(Output
[2].size(), 1ul);
2874 ASSERT_EQ(Output
[3].size(), 1ul);
2875 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
2876 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
2877 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
2878 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
2879 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
2880 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), RspPHIInBlk3ID
);
2882 VLocs
[0].Vars
.clear();
2883 VLocs
[1].Vars
.clear();
2886 TEST_F(InstrRefLDVTest
, VLocSimpleLoop
) {
2896 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
2898 Register RAX
= getRegByName("RAX");
2899 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
2901 unsigned EntryBlk
= 0, LoopBlk
= 1;
2903 ValueIDNum LiveInRsp
= ValueIDNum(EntryBlk
, 0, RspLoc
);
2904 ValueIDNum LiveInRax
= ValueIDNum(EntryBlk
, 0, RaxLoc
);
2905 ValueIDNum RspPHIInBlk1
= ValueIDNum(LoopBlk
, 0, RspLoc
);
2906 ValueIDNum RspDefInBlk1
= ValueIDNum(LoopBlk
, 1, RspLoc
);
2907 ValueIDNum RaxPHIInBlk1
= ValueIDNum(LoopBlk
, 0, RaxLoc
);
2908 DbgOpID LiveInRspID
= addValueDbgOp(LiveInRsp
);
2909 DbgOpID LiveInRaxID
= addValueDbgOp(LiveInRax
);
2910 DbgOpID RspPHIInBlk1ID
= addValueDbgOp(RspPHIInBlk1
);
2911 DbgOpID RspDefInBlk1ID
= addValueDbgOp(RspDefInBlk1
);
2912 DbgOpID RaxPHIInBlk1ID
= addValueDbgOp(RaxPHIInBlk1
);
2914 auto [MInLocs
, MOutLocs
] = allocValueTables(3, 2);
2916 initValueArray(MInLocs
, 3, 2);
2917 initValueArray(MOutLocs
, 3, 2);
2919 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
2920 DebugVariableID VarID
= LDV
->getDVMap().insertDVID(Var
, OutermostLoc
);
2921 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
2922 DIExpression
*TwoOpExpr
=
2923 DIExpression::get(Ctx
, {dwarf::DW_OP_LLVM_arg
, 0, dwarf::DW_OP_LLVM_arg
,
2924 1, dwarf::DW_OP_plus
});
2925 DbgValueProperties
VariadicProps(TwoOpExpr
, false, true);
2927 SmallSet
<DebugVariableID
, 4> AllVars
;
2928 AllVars
.insert(VarID
);
2930 SmallPtrSet
<MachineBasicBlock
*, 4> AssignBlocks
;
2931 AssignBlocks
.insert(MBB0
);
2932 AssignBlocks
.insert(MBB1
);
2933 AssignBlocks
.insert(MBB2
);
2935 SmallVector
<VLocTracker
, 3> VLocs
;
2936 VLocs
.resize(3, VLocTracker(LDV
->getDVMap(), Overlaps
, EmptyExpr
));
2938 InstrRefBasedLDV::LiveInsT Output
;
2940 // Start off with LiveInRsp in every location.
2941 for (unsigned int I
= 0; I
< 3; ++I
) {
2942 MInLocs
[I
][0] = MInLocs
[I
][1] = LiveInRsp
;
2943 MOutLocs
[I
][0] = MOutLocs
[I
][1] = LiveInRsp
;
2946 auto ClearOutputs
= [&]() {
2947 for (auto &Elem
: Output
)
2952 // Easy starter: a dominating assign should propagate to all blocks.
2953 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2954 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2955 MOutLocs
, MInLocs
, VLocs
);
2956 EXPECT_EQ(Output
[0].size(), 0ul);
2957 ASSERT_EQ(Output
[1].size(), 1ul);
2958 ASSERT_EQ(Output
[2].size(), 1ul);
2959 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
2960 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
2961 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
2962 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
2964 VLocs
[0].Vars
.clear();
2965 VLocs
[1].Vars
.clear();
2967 // A variadic assignment should behave the same.
2968 DbgOpID Locs0
[] = {LiveInRspID
, LiveInRaxID
};
2969 VLocs
[0].Vars
.insert({VarID
, DbgValue(Locs0
, VariadicProps
)});
2970 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
, MOutLocs
,
2972 EXPECT_EQ(Output
[0].size(), 0ul);
2973 ASSERT_EQ(Output
[1].size(), 1ul);
2974 ASSERT_EQ(Output
[2].size(), 1ul);
2975 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
2976 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
2977 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(1), LiveInRaxID
);
2978 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
2979 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
2981 VLocs
[0].Vars
.clear();
2982 VLocs
[1].Vars
.clear();
2984 // Put an undef assignment in the loop. Should get no live-in value.
2985 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2986 VLocs
[1].Vars
.insert({VarID
, DbgValue(EmptyProps
, DbgValue::Undef
)});
2987 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
2988 MOutLocs
, MInLocs
, VLocs
);
2989 EXPECT_EQ(Output
[0].size(), 0ul);
2990 EXPECT_EQ(Output
[1].size(), 0ul);
2991 EXPECT_EQ(Output
[2].size(), 0ul);
2993 VLocs
[0].Vars
.clear();
2994 VLocs
[1].Vars
.clear();
2996 // Assignment of the same value should naturally join.
2997 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2998 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
2999 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3000 MOutLocs
, MInLocs
, VLocs
);
3001 EXPECT_EQ(Output
[0].size(), 0ul);
3002 ASSERT_EQ(Output
[1].size(), 1ul);
3003 ASSERT_EQ(Output
[2].size(), 1ul);
3004 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3005 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
3006 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3007 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
3009 VLocs
[0].Vars
.clear();
3010 VLocs
[1].Vars
.clear();
3012 // Assignment of different values shouldn't join with no machine PHI vals.
3013 // Will be live-in to exit block as it's dominated.
3014 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3015 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
3016 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3017 MOutLocs
, MInLocs
, VLocs
);
3018 EXPECT_EQ(Output
[0].size(), 0ul);
3019 EXPECT_EQ(Output
[1].size(), 0ul);
3020 ASSERT_EQ(Output
[2].size(), 1ul);
3021 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3022 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRaxID
);
3024 VLocs
[0].Vars
.clear();
3025 VLocs
[1].Vars
.clear();
3027 // Install a completely unrelated PHI value, that we should not join on. Try
3028 // with unrelated assign in loop block again.
3029 MInLocs
[1][0] = RspPHIInBlk1
;
3030 MOutLocs
[1][0] = RspDefInBlk1
;
3031 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3032 VLocs
[1].Vars
.insert({VarID
, 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
);
3041 VLocs
[0].Vars
.clear();
3042 VLocs
[1].Vars
.clear();
3044 // Now, if we assign RspDefInBlk1 in the loop block, we should be able to
3045 // find the appropriate PHI.
3046 MInLocs
[1][0] = RspPHIInBlk1
;
3047 MOutLocs
[1][0] = RspDefInBlk1
;
3048 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3049 VLocs
[1].Vars
.insert({VarID
, DbgValue(RspDefInBlk1ID
, EmptyProps
)});
3050 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3051 MOutLocs
, MInLocs
, VLocs
);
3052 EXPECT_EQ(Output
[0].size(), 0ul);
3053 ASSERT_EQ(Output
[1].size(), 1ul);
3054 ASSERT_EQ(Output
[2].size(), 1ul);
3055 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3056 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), RspPHIInBlk1ID
);
3057 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3058 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), RspDefInBlk1ID
);
3060 VLocs
[0].Vars
.clear();
3061 VLocs
[1].Vars
.clear();
3063 // If the PHI happens in a different location, the live-in should happen
3065 MInLocs
[1][0] = LiveInRsp
;
3066 MOutLocs
[1][0] = LiveInRsp
;
3067 MInLocs
[1][1] = RaxPHIInBlk1
;
3068 MOutLocs
[1][1] = RspDefInBlk1
;
3069 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3070 VLocs
[1].Vars
.insert({VarID
, DbgValue(RspDefInBlk1ID
, EmptyProps
)});
3071 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3072 MOutLocs
, MInLocs
, VLocs
);
3073 EXPECT_EQ(Output
[0].size(), 0ul);
3074 ASSERT_EQ(Output
[1].size(), 1ul);
3075 ASSERT_EQ(Output
[2].size(), 1ul);
3076 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3077 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), RaxPHIInBlk1ID
);
3078 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3079 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), RspDefInBlk1ID
);
3081 VLocs
[0].Vars
.clear();
3082 VLocs
[1].Vars
.clear();
3084 // The PHI happening in both places should be handled too. Exactly where
3085 // isn't important, but if the location picked changes, this test will let
3087 MInLocs
[1][0] = RaxPHIInBlk1
;
3088 MOutLocs
[1][0] = RspDefInBlk1
;
3089 MInLocs
[1][1] = RaxPHIInBlk1
;
3090 MOutLocs
[1][1] = RspDefInBlk1
;
3091 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3092 VLocs
[1].Vars
.insert({VarID
, DbgValue(RspDefInBlk1ID
, EmptyProps
)});
3093 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3094 MOutLocs
, MInLocs
, VLocs
);
3095 EXPECT_EQ(Output
[0].size(), 0ul);
3096 ASSERT_EQ(Output
[1].size(), 1ul);
3097 ASSERT_EQ(Output
[2].size(), 1ul);
3098 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3099 // Today, the first register is picked.
3100 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), RspPHIInBlk1ID
);
3101 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3102 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), RspDefInBlk1ID
);
3104 VLocs
[0].Vars
.clear();
3105 VLocs
[1].Vars
.clear();
3107 // If the loop block looked a bit like this:
3111 // Then with instr-ref it becomes:
3115 // And we would be feeding a machine PHI-value back around the loop. However:
3116 // this does not mean we can eliminate the variable value PHI and use the
3117 // variable value from the entry block: they are distinct values that must be
3118 // joined at some location by the control flow.
3119 // [This test input would never occur naturally, the machine-PHI would be
3121 MInLocs
[1][0] = RspPHIInBlk1
;
3122 MOutLocs
[1][0] = RspPHIInBlk1
;
3123 MInLocs
[1][1] = LiveInRax
;
3124 MOutLocs
[1][1] = LiveInRax
;
3125 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3126 VLocs
[1].Vars
.insert({VarID
, DbgValue(RspPHIInBlk1ID
, EmptyProps
)});
3127 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3128 MOutLocs
, MInLocs
, VLocs
);
3129 EXPECT_EQ(Output
[0].size(), 0ul);
3130 ASSERT_EQ(Output
[1].size(), 1ul);
3131 ASSERT_EQ(Output
[2].size(), 1ul);
3132 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3133 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), RspPHIInBlk1ID
);
3134 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3135 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), RspPHIInBlk1ID
);
3137 VLocs
[0].Vars
.clear();
3138 VLocs
[1].Vars
.clear();
3140 // Test that we can eliminate PHIs. A PHI will be placed at the loop head
3141 // because there's a def in it.
3142 MInLocs
[1][0] = LiveInRsp
;
3143 MOutLocs
[1][0] = LiveInRsp
;
3144 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3145 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3146 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3147 MOutLocs
, MInLocs
, VLocs
);
3148 EXPECT_EQ(Output
[0].size(), 0ul);
3149 ASSERT_EQ(Output
[1].size(), 1ul);
3150 ASSERT_EQ(Output
[2].size(), 1ul);
3151 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3152 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
3153 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3154 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
3156 VLocs
[0].Vars
.clear();
3157 VLocs
[1].Vars
.clear();
3160 // test phi elimination with the nested situation
3161 TEST_F(InstrRefLDVTest
, VLocNestedLoop
) {
3175 ASSERT_TRUE(MTracker
->getNumLocs() == 1);
3177 Register RAX
= getRegByName("RAX");
3178 LocIdx RaxLoc
= MTracker
->lookupOrTrackRegister(RAX
);
3180 unsigned EntryBlk
= 0, Loop1Blk
= 1, Loop2Blk
= 2;
3182 ValueIDNum LiveInRsp
= ValueIDNum(EntryBlk
, 0, RspLoc
);
3183 ValueIDNum LiveInRax
= ValueIDNum(EntryBlk
, 0, RaxLoc
);
3184 ValueIDNum RspPHIInBlk1
= ValueIDNum(Loop1Blk
, 0, RspLoc
);
3185 ValueIDNum RspPHIInBlk2
= ValueIDNum(Loop2Blk
, 0, RspLoc
);
3186 ValueIDNum RspDefInBlk2
= ValueIDNum(Loop2Blk
, 1, RspLoc
);
3187 DbgOpID LiveInRspID
= addValueDbgOp(LiveInRsp
);
3188 DbgOpID LiveInRaxID
= addValueDbgOp(LiveInRax
);
3189 DbgOpID RspPHIInBlk1ID
= addValueDbgOp(RspPHIInBlk1
);
3190 DbgOpID RspPHIInBlk2ID
= addValueDbgOp(RspPHIInBlk2
);
3191 DbgOpID RspDefInBlk2ID
= addValueDbgOp(RspDefInBlk2
);
3193 auto [MInLocs
, MOutLocs
] = allocValueTables(5, 2);
3195 initValueArray(MInLocs
, 5, 2);
3196 initValueArray(MOutLocs
, 5, 2);
3198 DebugVariable
Var(FuncVariable
, std::nullopt
, nullptr);
3199 DebugVariableID VarID
= LDV
->getDVMap().insertDVID(Var
, OutermostLoc
);
3200 DbgValueProperties
EmptyProps(EmptyExpr
, false, false);
3202 SmallSet
<DebugVariableID
, 4> AllVars
;
3203 AllVars
.insert(VarID
);
3205 SmallPtrSet
<MachineBasicBlock
*, 5> AssignBlocks
;
3206 AssignBlocks
.insert(MBB0
);
3207 AssignBlocks
.insert(MBB1
);
3208 AssignBlocks
.insert(MBB2
);
3209 AssignBlocks
.insert(MBB3
);
3210 AssignBlocks
.insert(MBB4
);
3212 SmallVector
<VLocTracker
, 5> VLocs
;
3213 VLocs
.resize(5, VLocTracker(LDV
->getDVMap(), Overlaps
, EmptyExpr
));
3215 InstrRefBasedLDV::LiveInsT Output
;
3217 // Start off with LiveInRsp in every location.
3218 for (unsigned int I
= 0; I
< 5; ++I
) {
3219 MInLocs
[I
][0] = MInLocs
[I
][1] = LiveInRsp
;
3220 MOutLocs
[I
][0] = MOutLocs
[I
][1] = LiveInRsp
;
3223 auto ClearOutputs
= [&]() {
3224 for (auto &Elem
: Output
)
3229 // A dominating assign should propagate to all blocks.
3230 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3231 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3232 MOutLocs
, MInLocs
, VLocs
);
3233 EXPECT_EQ(Output
[0].size(), 0ul);
3234 ASSERT_EQ(Output
[1].size(), 1ul);
3235 ASSERT_EQ(Output
[2].size(), 1ul);
3236 ASSERT_EQ(Output
[3].size(), 1ul);
3237 ASSERT_EQ(Output
[4].size(), 1ul);
3238 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3239 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
3240 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3241 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
3242 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
3243 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRspID
);
3244 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3245 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), LiveInRspID
);
3247 VLocs
[0].Vars
.clear();
3249 // Test that an assign in the inner loop causes unresolved PHIs at the heads
3250 // of both loops, and no output location. Dominated blocks do get values.
3251 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3252 VLocs
[2].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
3253 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3254 MOutLocs
, MInLocs
, VLocs
);
3255 EXPECT_EQ(Output
[0].size(), 0ul);
3256 EXPECT_EQ(Output
[1].size(), 0ul);
3257 EXPECT_EQ(Output
[2].size(), 0ul);
3258 ASSERT_EQ(Output
[3].size(), 1ul);
3259 ASSERT_EQ(Output
[4].size(), 1ul);
3260 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
3261 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRaxID
);
3262 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3263 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), LiveInRaxID
);
3265 VLocs
[0].Vars
.clear();
3266 VLocs
[2].Vars
.clear();
3268 // Same test, but with no assignment in block 0. We should still get values
3269 // in dominated blocks.
3270 VLocs
[2].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
3271 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3272 MOutLocs
, MInLocs
, VLocs
);
3273 EXPECT_EQ(Output
[0].size(), 0ul);
3274 EXPECT_EQ(Output
[1].size(), 0ul);
3275 EXPECT_EQ(Output
[2].size(), 0ul);
3276 ASSERT_EQ(Output
[3].size(), 1ul);
3277 ASSERT_EQ(Output
[4].size(), 1ul);
3278 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
3279 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRaxID
);
3280 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3281 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), LiveInRaxID
);
3283 VLocs
[2].Vars
.clear();
3285 // Similarly, assignments in the outer loop gives location to dominated
3286 // blocks, but no PHI locations are found at the outer loop head.
3287 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3288 VLocs
[3].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
3289 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3290 MOutLocs
, MInLocs
, VLocs
);
3291 EXPECT_EQ(Output
[0].size(), 0ul);
3292 EXPECT_EQ(Output
[1].size(), 0ul);
3293 EXPECT_EQ(Output
[2].size(), 0ul);
3294 EXPECT_EQ(Output
[3].size(), 0ul);
3295 ASSERT_EQ(Output
[4].size(), 1ul);
3296 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3297 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), LiveInRaxID
);
3299 VLocs
[0].Vars
.clear();
3300 VLocs
[3].Vars
.clear();
3302 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3303 VLocs
[1].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
3304 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3305 MOutLocs
, MInLocs
, VLocs
);
3306 EXPECT_EQ(Output
[0].size(), 0ul);
3307 EXPECT_EQ(Output
[1].size(), 0ul);
3308 ASSERT_EQ(Output
[2].size(), 1ul);
3309 ASSERT_EQ(Output
[3].size(), 1ul);
3310 ASSERT_EQ(Output
[4].size(), 1ul);
3311 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3312 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRaxID
);
3313 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
3314 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRaxID
);
3315 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3316 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), LiveInRaxID
);
3318 VLocs
[0].Vars
.clear();
3319 VLocs
[1].Vars
.clear();
3321 // With an assignment of the same value in the inner loop, we should work out
3322 // that all PHIs can be eliminated and the same value is live-through the
3324 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3325 VLocs
[2].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3326 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3327 MOutLocs
, MInLocs
, VLocs
);
3328 EXPECT_EQ(Output
[0].size(), 0ul);
3329 EXPECT_EQ(Output
[1].size(), 1ul);
3330 EXPECT_EQ(Output
[2].size(), 1ul);
3331 ASSERT_EQ(Output
[3].size(), 1ul);
3332 ASSERT_EQ(Output
[4].size(), 1ul);
3333 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3334 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), LiveInRspID
);
3335 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3336 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), LiveInRspID
);
3337 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
3338 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRspID
);
3339 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3340 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), LiveInRspID
);
3342 VLocs
[0].Vars
.clear();
3343 VLocs
[2].Vars
.clear();
3345 // If we have an assignment in the inner loop, and a PHI for it at the inner
3346 // loop head, we could find a live-in location for the inner loop. But because
3347 // the outer loop has no PHI, we can't find a variable value for outer loop
3348 // head, so can't have a live-in value for the inner loop head.
3349 MInLocs
[2][0] = RspPHIInBlk2
;
3350 MOutLocs
[2][0] = LiveInRax
;
3351 // NB: all other machine locations are LiveInRsp, disallowing a PHI in block
3352 // one. Even though RspPHIInBlk2 isn't available later in the function, we
3353 // should still produce a live-in value. The fact it's unavailable is a
3354 // different concern.
3355 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3356 VLocs
[2].Vars
.insert({VarID
, DbgValue(LiveInRaxID
, EmptyProps
)});
3357 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3358 MOutLocs
, MInLocs
, VLocs
);
3359 EXPECT_EQ(Output
[0].size(), 0ul);
3360 EXPECT_EQ(Output
[1].size(), 0ul);
3361 EXPECT_EQ(Output
[2].size(), 0ul);
3362 ASSERT_EQ(Output
[3].size(), 1ul);
3363 ASSERT_EQ(Output
[4].size(), 1ul);
3364 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
3365 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), LiveInRaxID
);
3366 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3367 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), LiveInRaxID
);
3369 VLocs
[0].Vars
.clear();
3370 VLocs
[2].Vars
.clear();
3372 // Have an assignment in inner loop that can have a PHI resolved; and add a
3373 // machine value PHI to the outer loop head, so that we can find a location
3374 // all the way through the function.
3375 MInLocs
[1][0] = RspPHIInBlk1
;
3376 MOutLocs
[1][0] = RspPHIInBlk1
;
3377 MInLocs
[2][0] = RspPHIInBlk2
;
3378 MOutLocs
[2][0] = RspDefInBlk2
;
3379 MInLocs
[3][0] = RspDefInBlk2
;
3380 MOutLocs
[3][0] = RspDefInBlk2
;
3381 VLocs
[0].Vars
.insert({VarID
, DbgValue(LiveInRspID
, EmptyProps
)});
3382 VLocs
[2].Vars
.insert({VarID
, DbgValue(RspDefInBlk2ID
, EmptyProps
)});
3383 buildVLocValueMap(OutermostLoc
, AllVars
, AssignBlocks
, Output
,
3384 MOutLocs
, MInLocs
, VLocs
);
3385 EXPECT_EQ(Output
[0].size(), 0ul);
3386 ASSERT_EQ(Output
[1].size(), 1ul);
3387 ASSERT_EQ(Output
[2].size(), 1ul);
3388 ASSERT_EQ(Output
[3].size(), 1ul);
3389 ASSERT_EQ(Output
[4].size(), 1ul);
3390 EXPECT_EQ(Output
[1][0].second
.Kind
, DbgValue::Def
);
3391 EXPECT_EQ(Output
[1][0].second
.getDbgOpID(0), RspPHIInBlk1ID
);
3392 EXPECT_EQ(Output
[2][0].second
.Kind
, DbgValue::Def
);
3393 EXPECT_EQ(Output
[2][0].second
.getDbgOpID(0), RspPHIInBlk2ID
);
3394 EXPECT_EQ(Output
[3][0].second
.Kind
, DbgValue::Def
);
3395 EXPECT_EQ(Output
[3][0].second
.getDbgOpID(0), RspDefInBlk2ID
);
3396 EXPECT_EQ(Output
[4][0].second
.Kind
, DbgValue::Def
);
3397 EXPECT_EQ(Output
[4][0].second
.getDbgOpID(0), RspDefInBlk2ID
);
3399 VLocs
[0].Vars
.clear();
3400 VLocs
[2].Vars
.clear();