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