xref: /llvm-project/llvm/unittests/CodeGen/InstrRefLDVTest.cpp (revision bb3f5e1fed7c6ba733b7f273e93f5d3930976185)
1838b4a53SJeremy Morse //===------------- llvm/unittest/CodeGen/InstrRefLDVTest.cpp --------------===//
2838b4a53SJeremy Morse //
3838b4a53SJeremy Morse // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4838b4a53SJeremy Morse // See https://llvm.org/LICENSE.txt for license information.
5838b4a53SJeremy Morse // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6838b4a53SJeremy Morse //
7838b4a53SJeremy Morse //===----------------------------------------------------------------------===//
8838b4a53SJeremy Morse 
9*bb3f5e1fSMatin Raayai #include "llvm/CodeGen/CodeGenTargetMachineImpl.h"
10d9eebe3cSJeremy Morse #include "llvm/CodeGen/MIRParser/MIRParser.h"
11989f1c72Sserge-sans-paille #include "llvm/CodeGen/MachineDominators.h"
12838b4a53SJeremy Morse #include "llvm/CodeGen/MachineModuleInfo.h"
13989f1c72Sserge-sans-paille #include "llvm/CodeGen/TargetFrameLowering.h"
14989f1c72Sserge-sans-paille #include "llvm/CodeGen/TargetInstrInfo.h"
15838b4a53SJeremy Morse #include "llvm/CodeGen/TargetLowering.h"
16989f1c72Sserge-sans-paille #include "llvm/CodeGen/TargetRegisterInfo.h"
17838b4a53SJeremy Morse #include "llvm/CodeGen/TargetSubtargetInfo.h"
18838b4a53SJeremy Morse #include "llvm/IR/DIBuilder.h"
19838b4a53SJeremy Morse #include "llvm/IR/DebugInfoMetadata.h"
20838b4a53SJeremy Morse #include "llvm/IR/IRBuilder.h"
2174deadf1SNikita Popov #include "llvm/IR/Module.h"
22838b4a53SJeremy Morse #include "llvm/MC/TargetRegistry.h"
23d9eebe3cSJeremy Morse #include "llvm/Support/MemoryBuffer.h"
24838b4a53SJeremy Morse #include "llvm/Support/TargetSelect.h"
25838b4a53SJeremy Morse #include "llvm/Target/TargetOptions.h"
26838b4a53SJeremy Morse 
27838b4a53SJeremy Morse #include "../lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h"
28838b4a53SJeremy Morse 
29838b4a53SJeremy Morse #include "gtest/gtest.h"
30838b4a53SJeremy Morse 
31838b4a53SJeremy Morse using namespace llvm;
32838b4a53SJeremy Morse using namespace LiveDebugValues;
33838b4a53SJeremy Morse 
34838b4a53SJeremy Morse // Include helper functions to ease the manipulation of MachineFunctions
35838b4a53SJeremy Morse #include "MFCommon.inc"
36838b4a53SJeremy Morse 
37838b4a53SJeremy Morse class InstrRefLDVTest : public testing::Test {
38838b4a53SJeremy Morse public:
39a3936a6cSJeremy Morse   friend class InstrRefBasedLDV;
40a3936a6cSJeremy Morse   using MLocTransferMap = InstrRefBasedLDV::MLocTransferMap;
41a3936a6cSJeremy Morse 
42838b4a53SJeremy Morse   LLVMContext Ctx;
43d9eebe3cSJeremy Morse   std::unique_ptr<Module> Mod;
44a3936a6cSJeremy Morse   std::unique_ptr<TargetMachine> Machine;
45838b4a53SJeremy Morse   std::unique_ptr<MachineFunction> MF;
46a3936a6cSJeremy Morse   std::unique_ptr<MachineDominatorTree> DomTree;
47d9eebe3cSJeremy Morse   std::unique_ptr<MachineModuleInfo> MMI;
48838b4a53SJeremy Morse   DICompileUnit *OurCU;
49838b4a53SJeremy Morse   DIFile *OurFile;
50838b4a53SJeremy Morse   DISubprogram *OurFunc;
51838b4a53SJeremy Morse   DILexicalBlock *OurBlock, *AnotherBlock;
52838b4a53SJeremy Morse   DISubprogram *ToInlineFunc;
53838b4a53SJeremy Morse   DILexicalBlock *ToInlineBlock;
54b5426cedSJeremy Morse   DILocalVariable *FuncVariable;
55b5426cedSJeremy Morse   DIBasicType *LongInt;
56b5426cedSJeremy Morse   DIExpression *EmptyExpr;
570eee8445SJeremy Morse   LiveDebugValues::OverlapMap Overlaps;
58676efd0fSJeremy Morse   LiveDebugValues::DebugVariableMap DVMap;
59838b4a53SJeremy Morse 
60838b4a53SJeremy Morse   DebugLoc OutermostLoc, InBlockLoc, NotNestedBlockLoc, InlinedLoc;
61838b4a53SJeremy Morse 
62b5426cedSJeremy Morse   MachineBasicBlock *MBB0, *MBB1, *MBB2, *MBB3, *MBB4;
63a3936a6cSJeremy Morse 
64a3936a6cSJeremy Morse   std::unique_ptr<InstrRefBasedLDV> LDV;
65a3936a6cSJeremy Morse   std::unique_ptr<MLocTracker> MTracker;
66b5426cedSJeremy Morse   std::unique_ptr<VLocTracker> VTracker;
67838b4a53SJeremy Morse 
68d9eebe3cSJeremy Morse   SmallString<256> MIRStr;
69d9eebe3cSJeremy Morse 
70d9eebe3cSJeremy Morse   InstrRefLDVTest() : Ctx(), Mod(std::make_unique<Module>("beehives", Ctx)) {}
71a3936a6cSJeremy Morse 
72a3936a6cSJeremy Morse   void SetUp() {
73838b4a53SJeremy Morse     // Boilerplate that creates a MachineFunction and associated blocks.
74a3936a6cSJeremy Morse 
75a21abc78SHarald van Dijk     Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-"
76a21abc78SHarald van Dijk                        "f80:128-n8:16:32:64-S128");
77a3936a6cSJeremy Morse     Triple TargetTriple("x86_64--");
78a3936a6cSJeremy Morse     std::string Error;
79a3936a6cSJeremy Morse     const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
80a3936a6cSJeremy Morse     if (!T)
81a3936a6cSJeremy Morse       GTEST_SKIP();
82a3936a6cSJeremy Morse 
83a3936a6cSJeremy Morse     TargetOptions Options;
84b6a01caaSKazu Hirata     Machine = std::unique_ptr<TargetMachine>(T->createTargetMachine(
85b6a01caaSKazu Hirata         Triple::normalize("x86_64--"), "", "", Options, std::nullopt,
860a1aa6cdSArthur Eubanks         std::nullopt, CodeGenOptLevel::Aggressive));
87a3936a6cSJeremy Morse 
88a3936a6cSJeremy Morse     auto Type = FunctionType::get(Type::getVoidTy(Ctx), false);
89d9eebe3cSJeremy Morse     auto F =
90d9eebe3cSJeremy Morse         Function::Create(Type, GlobalValue::ExternalLinkage, "Test", &*Mod);
91a3936a6cSJeremy Morse 
92a3936a6cSJeremy Morse     unsigned FunctionNum = 42;
93*bb3f5e1fSMatin Raayai     MMI = std::make_unique<MachineModuleInfo>(Machine.get());
94a3936a6cSJeremy Morse     const TargetSubtargetInfo &STI = *Machine->getSubtargetImpl(*F);
95a3936a6cSJeremy Morse 
96*bb3f5e1fSMatin Raayai     MF = std::make_unique<MachineFunction>(*F, *Machine, STI, MMI->getContext(),
97*bb3f5e1fSMatin Raayai                                            FunctionNum);
98a3936a6cSJeremy Morse 
99a3936a6cSJeremy Morse     // Create metadata: CU, subprogram, some blocks and an inline function
100a3936a6cSJeremy Morse     // scope.
101d9eebe3cSJeremy Morse     DIBuilder DIB(*Mod);
102a3936a6cSJeremy Morse     OurFile = DIB.createFile("xyzzy.c", "/cave");
103a3936a6cSJeremy Morse     OurCU =
104a3936a6cSJeremy Morse         DIB.createCompileUnit(dwarf::DW_LANG_C99, OurFile, "nou", false, "", 0);
105eb6e7e8fSJay Foad     auto OurSubT = DIB.createSubroutineType(DIB.getOrCreateTypeArray({}));
106a3936a6cSJeremy Morse     OurFunc =
107a3936a6cSJeremy Morse         DIB.createFunction(OurCU, "bees", "", OurFile, 1, OurSubT, 1,
108a3936a6cSJeremy Morse                            DINode::FlagZero, DISubprogram::SPFlagDefinition);
109a3936a6cSJeremy Morse     F->setSubprogram(OurFunc);
110a3936a6cSJeremy Morse     OurBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 3);
111a3936a6cSJeremy Morse     AnotherBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 6);
112a3936a6cSJeremy Morse     ToInlineFunc =
113a3936a6cSJeremy Morse         DIB.createFunction(OurFile, "shoes", "", OurFile, 10, OurSubT, 10,
114a3936a6cSJeremy Morse                            DINode::FlagZero, DISubprogram::SPFlagDefinition);
115a3936a6cSJeremy Morse 
116a3936a6cSJeremy Morse     // Make some nested scopes.
117a3936a6cSJeremy Morse     OutermostLoc = DILocation::get(Ctx, 3, 1, OurFunc);
118a3936a6cSJeremy Morse     InBlockLoc = DILocation::get(Ctx, 4, 1, OurBlock);
119a3936a6cSJeremy Morse     InlinedLoc = DILocation::get(Ctx, 10, 1, ToInlineFunc, InBlockLoc.get());
120a3936a6cSJeremy Morse 
121a3936a6cSJeremy Morse     // Make a scope that isn't nested within the others.
122a3936a6cSJeremy Morse     NotNestedBlockLoc = DILocation::get(Ctx, 4, 1, AnotherBlock);
123a3936a6cSJeremy Morse 
124b5426cedSJeremy Morse     LongInt = DIB.createBasicType("long", 64, llvm::dwarf::DW_ATE_unsigned);
125b5426cedSJeremy Morse     FuncVariable = DIB.createAutoVariable(OurFunc, "lala", OurFile, 1, LongInt);
126b5426cedSJeremy Morse     EmptyExpr = DIExpression::get(Ctx, {});
127b5426cedSJeremy Morse 
128a3936a6cSJeremy Morse     DIB.finalize();
129a3936a6cSJeremy Morse   }
130a3936a6cSJeremy Morse 
131a3936a6cSJeremy Morse   Register getRegByName(const char *WantedName) {
132a3936a6cSJeremy Morse     auto *TRI = MF->getRegInfo().getTargetRegisterInfo();
133a3936a6cSJeremy Morse     // Slow, but works.
134a3936a6cSJeremy Morse     for (unsigned int I = 1; I < TRI->getNumRegs(); ++I) {
135a3936a6cSJeremy Morse       const char *Name = TRI->getName(I);
136a3936a6cSJeremy Morse       if (strcmp(WantedName, Name) == 0)
137a3936a6cSJeremy Morse         return I;
138a3936a6cSJeremy Morse     }
139a3936a6cSJeremy Morse 
140a3936a6cSJeremy Morse     // If this ever fails, something is very wrong with this unit test.
141a3936a6cSJeremy Morse     llvm_unreachable("Can't find register by name");
142a3936a6cSJeremy Morse   }
143a3936a6cSJeremy Morse 
144d9eebe3cSJeremy Morse   InstrRefBasedLDV *setupLDVObj(MachineFunction *MF) {
145a3936a6cSJeremy Morse     // Create a new LDV object, and plug some relevant object ptrs into it.
146a3936a6cSJeremy Morse     LDV = std::make_unique<InstrRefBasedLDV>();
147a3936a6cSJeremy Morse     const TargetSubtargetInfo &STI = MF->getSubtarget();
148a3936a6cSJeremy Morse     LDV->TII = STI.getInstrInfo();
149a3936a6cSJeremy Morse     LDV->TRI = STI.getRegisterInfo();
150a3936a6cSJeremy Morse     LDV->TFI = STI.getFrameLowering();
151a3936a6cSJeremy Morse     LDV->MFI = &MF->getFrameInfo();
152c99fdd45SJeremy Morse     LDV->MRI = &MF->getRegInfo();
153a3936a6cSJeremy Morse 
154a3936a6cSJeremy Morse     DomTree = std::make_unique<MachineDominatorTree>(*MF);
155a3936a6cSJeremy Morse     LDV->DomTree = &*DomTree;
156a3936a6cSJeremy Morse 
157a3936a6cSJeremy Morse     // Future work: unit tests for mtracker / vtracker / ttracker.
158a3936a6cSJeremy Morse 
159a3936a6cSJeremy Morse     // Setup things like the artifical block map, and BlockNo <=> RPO Order
160a3936a6cSJeremy Morse     // mappings.
161a3936a6cSJeremy Morse     LDV->initialSetup(*MF);
162b5426cedSJeremy Morse     LDV->LS.initialize(*MF);
163d9eebe3cSJeremy Morse     addMTracker(MF);
164a3936a6cSJeremy Morse     return &*LDV;
165a3936a6cSJeremy Morse   }
166a3936a6cSJeremy Morse 
167d9eebe3cSJeremy Morse   void addMTracker(MachineFunction *MF) {
168a3936a6cSJeremy Morse     ASSERT_TRUE(LDV);
169a3936a6cSJeremy Morse     // Add a machine-location-tracking object to LDV. Don't initialize any
170a3936a6cSJeremy Morse     // register locations within it though.
171a3936a6cSJeremy Morse     const TargetSubtargetInfo &STI = MF->getSubtarget();
172a3936a6cSJeremy Morse     MTracker = std::make_unique<MLocTracker>(
173a3936a6cSJeremy Morse           *MF, *LDV->TII, *LDV->TRI, *STI.getTargetLowering());
174a3936a6cSJeremy Morse     LDV->MTracker = &*MTracker;
175a3936a6cSJeremy Morse   }
176a3936a6cSJeremy Morse 
177b5426cedSJeremy Morse   void addVTracker() {
178b5426cedSJeremy Morse     ASSERT_TRUE(LDV);
179676efd0fSJeremy Morse     VTracker = std::make_unique<VLocTracker>(DVMap, Overlaps, EmptyExpr);
180b5426cedSJeremy Morse     LDV->VTracker = &*VTracker;
181b5426cedSJeremy Morse   }
182b5426cedSJeremy Morse 
183b5ba5d2aSStephen Tozer   DbgOpID addValueDbgOp(ValueIDNum V) {
184b5ba5d2aSStephen Tozer     return LDV->DbgOpStore.insert(DbgOp(V));
185b5ba5d2aSStephen Tozer   }
186b5ba5d2aSStephen Tozer   DbgOpID addConstDbgOp(MachineOperand MO) {
187b5ba5d2aSStephen Tozer     return LDV->DbgOpStore.insert(DbgOp(MO));
188b5ba5d2aSStephen Tozer   }
189b5ba5d2aSStephen Tozer 
190a3936a6cSJeremy Morse   // Some routines for bouncing into LDV,
191ab49dce0SJeremy Morse   void buildMLocValueMap(FuncValueTable &MInLocs, FuncValueTable &MOutLocs,
192a3936a6cSJeremy Morse                          SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
193a3936a6cSJeremy Morse     LDV->buildMLocValueMap(*MF, MInLocs, MOutLocs, MLocTransfer);
194a3936a6cSJeremy Morse   }
195a3936a6cSJeremy Morse 
19697ddf49eSJeremy Morse   void placeMLocPHIs(MachineFunction &MF,
19797ddf49eSJeremy Morse                      SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks,
198ab49dce0SJeremy Morse                      FuncValueTable &MInLocs,
19997ddf49eSJeremy Morse                      SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
20097ddf49eSJeremy Morse     LDV->placeMLocPHIs(MF, AllBlocks, MInLocs, MLocTransfer);
20197ddf49eSJeremy Morse   }
20297ddf49eSJeremy Morse 
20353fd5af6SStephen Tozer   bool
20453fd5af6SStephen Tozer   pickVPHILoc(SmallVectorImpl<DbgOpID> &OutValues, const MachineBasicBlock &MBB,
20553fd5af6SStephen Tozer               const InstrRefBasedLDV::LiveIdxT &LiveOuts,
20653fd5af6SStephen Tozer               FuncValueTable &MOutLocs,
207b5426cedSJeremy Morse               const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
20853fd5af6SStephen Tozer     return LDV->pickVPHILoc(OutValues, MBB, LiveOuts, MOutLocs, BlockOrders);
209b5426cedSJeremy Morse   }
210b5426cedSJeremy Morse 
211b5426cedSJeremy Morse   bool vlocJoin(MachineBasicBlock &MBB, InstrRefBasedLDV::LiveIdxT &VLOCOutLocs,
212b5426cedSJeremy Morse                 SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore,
21389950adeSJeremy Morse                 DbgValue &InLoc) {
2148dda516bSJeremy Morse     return LDV->vlocJoin(MBB, VLOCOutLocs, BlocksToExplore, InLoc);
215b5426cedSJeremy Morse   }
216b5426cedSJeremy Morse 
217b5426cedSJeremy Morse   void buildVLocValueMap(const DILocation *DILoc,
218676efd0fSJeremy Morse                     const SmallSet<DebugVariableID, 4> &VarsWeCareAbout,
219b5426cedSJeremy Morse                     SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks,
220ab49dce0SJeremy Morse                     InstrRefBasedLDV::LiveInsT &Output, FuncValueTable &MOutLocs,
221ab49dce0SJeremy Morse                     FuncValueTable &MInLocs,
222b5426cedSJeremy Morse                     SmallVectorImpl<VLocTracker> &AllTheVLocs) {
223b5426cedSJeremy Morse     LDV->buildVLocValueMap(DILoc, VarsWeCareAbout, AssignBlocks, Output,
224b5426cedSJeremy Morse                            MOutLocs, MInLocs, AllTheVLocs);
225b5426cedSJeremy Morse   }
226b5426cedSJeremy Morse 
227ab49dce0SJeremy Morse   void initValueArray(FuncValueTable &Nums, unsigned Blks, unsigned Locs) {
228a3936a6cSJeremy Morse     for (unsigned int I = 0; I < Blks; ++I)
229a3936a6cSJeremy Morse       for (unsigned int J = 0; J < Locs; ++J)
230a3936a6cSJeremy Morse         Nums[I][J] = ValueIDNum::EmptyValue;
231a3936a6cSJeremy Morse   }
232b5426cedSJeremy Morse 
233b5426cedSJeremy Morse   void setupSingleBlock() {
234b5426cedSJeremy Morse     // Add an entry block with nothing but 'ret void' in it.
235b5426cedSJeremy Morse     Function &F = const_cast<llvm::Function &>(MF->getFunction());
236b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
237b5426cedSJeremy Morse     IRBuilder<> IRB(BB0);
238b5426cedSJeremy Morse     IRB.CreateRetVoid();
239b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
240b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
241b5426cedSJeremy Morse     MF->RenumberBlocks();
242b5426cedSJeremy Morse 
243d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
244b5426cedSJeremy Morse   }
245b5426cedSJeremy Morse 
246b5426cedSJeremy Morse   void setupDiamondBlocks() {
247b5426cedSJeremy Morse     //        entry
248b5426cedSJeremy Morse     //        /  \
249b5426cedSJeremy Morse     //      br1  br2
250b5426cedSJeremy Morse     //        \  /
251b5426cedSJeremy Morse     //         ret
252b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
253b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "a", &F);
254b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "b", &F);
255b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "c", &F);
256b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "d", &F);
257b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3);
258b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
259b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
260b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
261b5426cedSJeremy Morse     IRB3.CreateRetVoid();
262b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
263b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
264b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
265b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
266b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
267b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
268b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
269b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
270b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
271b5426cedSJeremy Morse     MBB0->addSuccessor(MBB2);
272b5426cedSJeremy Morse     MBB1->addSuccessor(MBB3);
273b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
274b5426cedSJeremy Morse     MF->RenumberBlocks();
275b5426cedSJeremy Morse 
276d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
277b5426cedSJeremy Morse   }
278b5426cedSJeremy Morse 
279b5426cedSJeremy Morse   void setupSimpleLoop() {
280b5426cedSJeremy Morse     //    entry
281b5426cedSJeremy Morse     //     |
282b5426cedSJeremy Morse     //     |/-----\
283b5426cedSJeremy Morse     //    loopblk |
284b5426cedSJeremy Morse     //     |\-----/
285b5426cedSJeremy Morse     //     |
286b5426cedSJeremy Morse     //     ret
287b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
288b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
289b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "loop", &F);
290b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "ret", &F);
291b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2);
292b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
293b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
294b5426cedSJeremy Morse     IRB2.CreateRetVoid();
295b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
296b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
297b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
298b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
299b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
300b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
301b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
302b5426cedSJeremy Morse     MBB1->addSuccessor(MBB2);
303b5426cedSJeremy Morse     MBB1->addSuccessor(MBB1);
304b5426cedSJeremy Morse     MF->RenumberBlocks();
305b5426cedSJeremy Morse 
306d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
307b5426cedSJeremy Morse   }
308b5426cedSJeremy Morse 
309b5426cedSJeremy Morse   void setupNestedLoops() {
310b5426cedSJeremy Morse     //    entry
311b5426cedSJeremy Morse     //     |
312b5426cedSJeremy Morse     //    loop1
313b5426cedSJeremy Morse     //     ^\
314b5426cedSJeremy Morse     //     | \    /-\
315b5426cedSJeremy Morse     //     |  loop2  |
316b5426cedSJeremy Morse     //     |  /   \-/
317b5426cedSJeremy Morse     //     ^ /
318b5426cedSJeremy Morse     //     join
319b5426cedSJeremy Morse     //     |
320b5426cedSJeremy Morse     //     ret
321b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
322b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
323b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "loop1", &F);
324b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "loop2", &F);
325b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "join", &F);
326b5426cedSJeremy Morse     auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
327b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
328b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
329b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
330b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
331b5426cedSJeremy Morse     IRB3.CreateBr(BB4);
332b5426cedSJeremy Morse     IRB4.CreateRetVoid();
333b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
334b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
335b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
336b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
337b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
338b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
339b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
340b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
341b5426cedSJeremy Morse     MBB4 = MF->CreateMachineBasicBlock(BB4);
342b5426cedSJeremy Morse     MF->insert(MF->end(), MBB4);
343b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
344b5426cedSJeremy Morse     MBB1->addSuccessor(MBB2);
345b5426cedSJeremy Morse     MBB2->addSuccessor(MBB2);
346b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
347b5426cedSJeremy Morse     MBB3->addSuccessor(MBB1);
348b5426cedSJeremy Morse     MBB3->addSuccessor(MBB4);
349b5426cedSJeremy Morse     MF->RenumberBlocks();
350b5426cedSJeremy Morse 
351d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
352b5426cedSJeremy Morse   }
353b5426cedSJeremy Morse 
354b5426cedSJeremy Morse   void setupNoDominatingLoop() {
355b5426cedSJeremy Morse     //           entry
356b5426cedSJeremy Morse     //            / \
357b5426cedSJeremy Morse     //           /   \
358b5426cedSJeremy Morse     //          /     \
359b5426cedSJeremy Morse     //        head1   head2
360b5426cedSJeremy Morse     //        ^  \   /   ^
361b5426cedSJeremy Morse     //        ^   \ /    ^
362b5426cedSJeremy Morse     //        \-joinblk -/
363b5426cedSJeremy Morse     //             |
364b5426cedSJeremy Morse     //            ret
365b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
366b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
367b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "head1", &F);
368b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "head2", &F);
369b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "joinblk", &F);
370b5426cedSJeremy Morse     auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
371b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
372b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
373b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
374b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
375b5426cedSJeremy Morse     IRB3.CreateBr(BB4);
376b5426cedSJeremy Morse     IRB4.CreateRetVoid();
377b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
378b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
379b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
380b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
381b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
382b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
383b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
384b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
385b5426cedSJeremy Morse     MBB4 = MF->CreateMachineBasicBlock(BB4);
386b5426cedSJeremy Morse     MF->insert(MF->end(), MBB4);
387b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
388b5426cedSJeremy Morse     MBB0->addSuccessor(MBB2);
389b5426cedSJeremy Morse     MBB1->addSuccessor(MBB3);
390b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
391b5426cedSJeremy Morse     MBB3->addSuccessor(MBB1);
392b5426cedSJeremy Morse     MBB3->addSuccessor(MBB2);
393b5426cedSJeremy Morse     MBB3->addSuccessor(MBB4);
394b5426cedSJeremy Morse     MF->RenumberBlocks();
395b5426cedSJeremy Morse 
396d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
397b5426cedSJeremy Morse   }
398b5426cedSJeremy Morse 
399b5426cedSJeremy Morse   void setupBadlyNestedLoops() {
400b5426cedSJeremy Morse     //           entry
401b5426cedSJeremy Morse     //             |
402b5426cedSJeremy Morse     //           loop1 -o
403b5426cedSJeremy Morse     //             | ^
404b5426cedSJeremy Morse     //             | ^
405b5426cedSJeremy Morse     //           loop2 -o
406b5426cedSJeremy Morse     //             | ^
407b5426cedSJeremy Morse     //             | ^
408b5426cedSJeremy Morse     //           loop3 -o
409b5426cedSJeremy Morse     //             |
410b5426cedSJeremy Morse     //            ret
411b5426cedSJeremy Morse     //
412b5426cedSJeremy Morse     // NB: the loop blocks self-loop, which is a bit too fiddly to draw on
413b5426cedSJeremy Morse     // accurately.
414b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
415b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
416b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "loop1", &F);
417b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "loop2", &F);
418b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "loop3", &F);
419b5426cedSJeremy Morse     auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
420b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
421b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
422b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
423b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
424b5426cedSJeremy Morse     IRB3.CreateBr(BB4);
425b5426cedSJeremy Morse     IRB4.CreateRetVoid();
426b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
427b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
428b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
429b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
430b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
431b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
432b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
433b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
434b5426cedSJeremy Morse     MBB4 = MF->CreateMachineBasicBlock(BB4);
435b5426cedSJeremy Morse     MF->insert(MF->end(), MBB4);
436b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
437b5426cedSJeremy Morse     MBB1->addSuccessor(MBB1);
438b5426cedSJeremy Morse     MBB1->addSuccessor(MBB2);
439b5426cedSJeremy Morse     MBB2->addSuccessor(MBB1);
440b5426cedSJeremy Morse     MBB2->addSuccessor(MBB2);
441b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
442b5426cedSJeremy Morse     MBB3->addSuccessor(MBB2);
443b5426cedSJeremy Morse     MBB3->addSuccessor(MBB3);
444b5426cedSJeremy Morse     MBB3->addSuccessor(MBB4);
445b5426cedSJeremy Morse     MF->RenumberBlocks();
446b5426cedSJeremy Morse 
447d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
448d9eebe3cSJeremy Morse   }
449d9eebe3cSJeremy Morse 
450d9eebe3cSJeremy Morse   MachineFunction *readMIRBlock(const char *Input) {
451d9eebe3cSJeremy Morse     MIRStr.clear();
452d9eebe3cSJeremy Morse     StringRef S = Twine(Twine(R"MIR(
453d9eebe3cSJeremy Morse --- |
454d9eebe3cSJeremy Morse   target triple = "x86_64-unknown-linux-gnu"
455d9eebe3cSJeremy Morse   define void @test() { ret void }
456d9eebe3cSJeremy Morse ...
457d9eebe3cSJeremy Morse ---
458d9eebe3cSJeremy Morse name: test
459d9eebe3cSJeremy Morse tracksRegLiveness: true
460d9eebe3cSJeremy Morse stack:
461d9eebe3cSJeremy Morse   - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
462d9eebe3cSJeremy Morse       stack-id: default, callee-saved-register: '', callee-saved-restored: true,
463d9eebe3cSJeremy Morse       debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
464d9eebe3cSJeremy Morse body:  |
465d9eebe3cSJeremy Morse    bb.0:
466d9eebe3cSJeremy Morse     liveins: $rdi, $rsi
467d9eebe3cSJeremy Morse )MIR") + Twine(Input) + Twine("...\n"))
468d9eebe3cSJeremy Morse                       .toNullTerminatedStringRef(MIRStr);
469d9eebe3cSJeremy Morse     ;
470d9eebe3cSJeremy Morse 
471d9eebe3cSJeremy Morse     // Clear the "test" function from MMI if it's still present.
472d9eebe3cSJeremy Morse     if (Function *Fn = Mod->getFunction("test"))
473d9eebe3cSJeremy Morse       MMI->deleteMachineFunctionFor(*Fn);
474d9eebe3cSJeremy Morse 
475d9eebe3cSJeremy Morse     auto MemBuf = MemoryBuffer::getMemBuffer(S, "<input>");
476d9eebe3cSJeremy Morse     auto MIRParse = createMIRParser(std::move(MemBuf), Ctx);
477d9eebe3cSJeremy Morse     Mod = MIRParse->parseIRModule();
478d9eebe3cSJeremy Morse     assert(Mod);
479a21abc78SHarald van Dijk     Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-"
480a21abc78SHarald van Dijk                        "f80:128-n8:16:32:64-S128");
481d9eebe3cSJeremy Morse 
482d9eebe3cSJeremy Morse     bool Result = MIRParse->parseMachineFunctions(*Mod, *MMI);
483d9eebe3cSJeremy Morse     assert(!Result && "Failed to parse unit test machine function?");
484d9eebe3cSJeremy Morse     (void)Result;
485d9eebe3cSJeremy Morse 
486d9eebe3cSJeremy Morse     Function *Fn = Mod->getFunction("test");
487d9eebe3cSJeremy Morse     assert(Fn && "Failed to parse a unit test module string?");
488d9eebe3cSJeremy Morse     Fn->setSubprogram(OurFunc);
489d9eebe3cSJeremy Morse     return MMI->getMachineFunction(*Fn);
490d9eebe3cSJeremy Morse   }
491d9eebe3cSJeremy Morse 
492d9eebe3cSJeremy Morse   void
493d9eebe3cSJeremy Morse   produceMLocTransferFunction(MachineFunction &MF,
494d9eebe3cSJeremy Morse                               SmallVectorImpl<MLocTransferMap> &MLocTransfer,
495d9eebe3cSJeremy Morse                               unsigned MaxNumBlocks) {
496d9eebe3cSJeremy Morse     LDV->produceMLocTransferFunction(MF, MLocTransfer, MaxNumBlocks);
497b5426cedSJeremy Morse   }
498ab49dce0SJeremy Morse 
499ab49dce0SJeremy Morse   std::pair<FuncValueTable, FuncValueTable>
500ab49dce0SJeremy Morse   allocValueTables(unsigned Blocks, unsigned Locs) {
501acacec3bSFelipe de Azevedo Piovezan     return {FuncValueTable(Blocks, Locs), FuncValueTable(Blocks, Locs)};
502ab49dce0SJeremy Morse   }
503a3936a6cSJeremy Morse };
504a3936a6cSJeremy Morse 
505d9eebe3cSJeremy Morse TEST_F(InstrRefLDVTest, MTransferDefs) {
506d9eebe3cSJeremy Morse   MachineFunction *MF = readMIRBlock(
507d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
508d391e4feSSimon Pilgrim    "    RET64 $rax\n");
509d9eebe3cSJeremy Morse   setupLDVObj(MF);
510d9eebe3cSJeremy Morse 
511d9eebe3cSJeremy Morse   // We should start with only SP tracked.
512d9eebe3cSJeremy Morse   EXPECT_TRUE(MTracker->getNumLocs() == 1);
513d9eebe3cSJeremy Morse 
514d9eebe3cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
515d9eebe3cSJeremy Morse   TransferMap.resize(1);
516d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
517d9eebe3cSJeremy Morse 
518d9eebe3cSJeremy Morse   // Code contains only one register write: that should assign to each of the
519d9eebe3cSJeremy Morse   // aliasing registers. Test that all of them get locations, and have a
520d9eebe3cSJeremy Morse   // corresponding def at the first instr in the function.
521d9eebe3cSJeremy Morse   const char *RegNames[] = {"RAX", "HAX", "EAX", "AX", "AH", "AL"};
522d9eebe3cSJeremy Morse   EXPECT_TRUE(MTracker->getNumLocs() == 7);
523d9eebe3cSJeremy Morse   for (const char *RegName : RegNames) {
524d9eebe3cSJeremy Morse     Register R = getRegByName(RegName);
525d9eebe3cSJeremy Morse     ASSERT_TRUE(MTracker->isRegisterTracked(R));
526d9eebe3cSJeremy Morse     LocIdx L = MTracker->getRegMLoc(R);
527d9eebe3cSJeremy Morse     ValueIDNum V = MTracker->readReg(R);
528d9eebe3cSJeremy Morse     // Value of this register should be: block zero, instruction 1, and the
529d9eebe3cSJeremy Morse     // location it's defined in is itself.
530d9eebe3cSJeremy Morse     ValueIDNum ToCmp(0, 1, L);
531d9eebe3cSJeremy Morse     EXPECT_EQ(V, ToCmp);
532d9eebe3cSJeremy Morse   }
533d9eebe3cSJeremy Morse 
534d9eebe3cSJeremy Morse   // Do the same again, but with an aliasing write. This should write to all
535d9eebe3cSJeremy Morse   // the same registers again, except $ah and $hax (the upper 8 bits of $ax
536d9eebe3cSJeremy Morse   // and 32 bits of $rax resp.).
537d9eebe3cSJeremy Morse   MF = readMIRBlock(
538d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
539d9eebe3cSJeremy Morse    "    $al = MOV8ri 0\n"
540d391e4feSSimon Pilgrim    "    RET64 $rax\n");
541d9eebe3cSJeremy Morse   setupLDVObj(MF);
542d9eebe3cSJeremy Morse   TransferMap.clear();
543d9eebe3cSJeremy Morse   TransferMap.resize(1);
544d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
545d9eebe3cSJeremy Morse 
546d9eebe3cSJeremy Morse   auto TestRegSetSite = [&](const char *Name, unsigned InstrNum) {
547d9eebe3cSJeremy Morse     Register R = getRegByName(Name);
548d9eebe3cSJeremy Morse     ASSERT_TRUE(MTracker->isRegisterTracked(R));
549d9eebe3cSJeremy Morse     LocIdx L = MTracker->getRegMLoc(R);
550d9eebe3cSJeremy Morse     ValueIDNum V = MTracker->readMLoc(L);
551d9eebe3cSJeremy Morse     ValueIDNum ToCmp(0, InstrNum, L);
552d9eebe3cSJeremy Morse     EXPECT_EQ(V, ToCmp);
553d9eebe3cSJeremy Morse   };
554d9eebe3cSJeremy Morse 
555d9eebe3cSJeremy Morse   TestRegSetSite("AL", 2);
556d9eebe3cSJeremy Morse   TestRegSetSite("AH", 1);
557d9eebe3cSJeremy Morse   TestRegSetSite("AX", 2);
558d9eebe3cSJeremy Morse   TestRegSetSite("EAX", 2);
559d9eebe3cSJeremy Morse   TestRegSetSite("HAX", 1);
560d9eebe3cSJeremy Morse   TestRegSetSite("RAX", 2);
561d9eebe3cSJeremy Morse 
562d9eebe3cSJeremy Morse   // This call should:
563d9eebe3cSJeremy Morse   //  * Def rax via the implicit-def,
564d9eebe3cSJeremy Morse   //  * Clobber rsi/rdi and all their subregs, via the register mask
565d9eebe3cSJeremy Morse   //  * Same for rcx, despite it not being a use in the instr, it's in the mask
566d9eebe3cSJeremy Morse   //  * NOT clobber $rsp / $esp $ sp, LiveDebugValues deliberately ignores
567d9eebe3cSJeremy Morse   //    these.
568d9eebe3cSJeremy Morse   //  * NOT clobber $rbx, because it's non-volatile
569d9eebe3cSJeremy Morse   //  * Not track every other register in the machine, only those needed.
570d9eebe3cSJeremy Morse  MF = readMIRBlock(
571d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n" // instr 1
572d9eebe3cSJeremy Morse    "    $rbx = MOV64ri 0\n" // instr 2
573d9eebe3cSJeremy Morse    "    $rcx = MOV64ri 0\n" // instr 3
574d9eebe3cSJeremy Morse    "    $rdi = MOV64ri 0\n" // instr 4
575d9eebe3cSJeremy Morse    "    $rsi = MOV64ri 0\n" // instr 5
576d9eebe3cSJeremy Morse    "    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
577d391e4feSSimon Pilgrim    "    RET64 $rax\n"); // instr 7
578d9eebe3cSJeremy Morse   setupLDVObj(MF);
579d9eebe3cSJeremy Morse   TransferMap.clear();
580d9eebe3cSJeremy Morse   TransferMap.resize(1);
581d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
582d9eebe3cSJeremy Morse 
583d9eebe3cSJeremy Morse   const char *RegsSetInCall[] = {"AL",  "AH",  "AX", "EAX", "HAX", "RAX",
584d9eebe3cSJeremy Morse                                  "DIL", "DIH", "DI", "EDI", "HDI", "RDI",
585d9eebe3cSJeremy Morse                                  "SIL", "SIH", "SI", "ESI", "HSI", "RSI",
586d9eebe3cSJeremy Morse                                  "CL",  "CH",  "CX", "ECX", "HCX", "RCX"};
587d9eebe3cSJeremy Morse   for (const char *RegSetInCall : RegsSetInCall)
588d9eebe3cSJeremy Morse     TestRegSetSite(RegSetInCall, 6);
589d9eebe3cSJeremy Morse 
590d9eebe3cSJeremy Morse   const char *RegsLeftAlone[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
591d9eebe3cSJeremy Morse   for (const char *RegLeftAlone : RegsLeftAlone)
592d9eebe3cSJeremy Morse     TestRegSetSite(RegLeftAlone, 2);
593d9eebe3cSJeremy Morse 
594d9eebe3cSJeremy Morse   // Stack pointer should be the live-in to the function, instruction zero.
595d9eebe3cSJeremy Morse   TestRegSetSite("RSP", 0);
596d9eebe3cSJeremy Morse   // These stack regs should not be tracked either. Nor the (fake) subregs.
597d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("ESP")));
598d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SP")));
599d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPL")));
600d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPH")));
601d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("HSP")));
602d9eebe3cSJeremy Morse 
603d9eebe3cSJeremy Morse   // Should only be tracking: 6 x {A, B, C, DI, SI} registers = 30,
604d9eebe3cSJeremy Morse   // Plus RSP, SSP = 32.
605d9eebe3cSJeremy Morse   EXPECT_EQ(32u, MTracker->getNumLocs());
606d9eebe3cSJeremy Morse 
607d9eebe3cSJeremy Morse 
608d9eebe3cSJeremy Morse   // When we DBG_PHI something, we should track all its subregs.
609d9eebe3cSJeremy Morse   MF = readMIRBlock(
610d9eebe3cSJeremy Morse    "    DBG_PHI $rdi, 0\n"
611d391e4feSSimon Pilgrim    "    RET64\n");
612d9eebe3cSJeremy Morse   setupLDVObj(MF);
613d9eebe3cSJeremy Morse   TransferMap.clear();
614d9eebe3cSJeremy Morse   TransferMap.resize(1);
615d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
616d9eebe3cSJeremy Morse 
617d9eebe3cSJeremy Morse   // All DI regs and RSP tracked.
618d9eebe3cSJeremy Morse   EXPECT_EQ(7u, MTracker->getNumLocs());
619d9eebe3cSJeremy Morse 
620d9eebe3cSJeremy Morse   // All the DI registers should have block live-in values, i.e. the argument
621d9eebe3cSJeremy Morse   // to the function.
622d9eebe3cSJeremy Morse   const char *DIRegs[] = {"DIL", "DIH", "DI", "EDI", "HDI", "RDI"};
623d9eebe3cSJeremy Morse   for (const char *DIReg : DIRegs)
624d9eebe3cSJeremy Morse     TestRegSetSite(DIReg, 0);
625d9eebe3cSJeremy Morse }
626d9eebe3cSJeremy Morse 
627d9eebe3cSJeremy Morse TEST_F(InstrRefLDVTest, MTransferMeta) {
628d9eebe3cSJeremy Morse   // Meta instructions should not have any effect on register values.
629d9eebe3cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
630d9eebe3cSJeremy Morse   MachineFunction *MF = readMIRBlock(
631d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
632d9eebe3cSJeremy Morse    "    $rax = IMPLICIT_DEF\n"
633d9eebe3cSJeremy Morse    "    $rax = KILL killed $rax\n"
634d391e4feSSimon Pilgrim    "    RET64 $rax\n");
635d9eebe3cSJeremy Morse   setupLDVObj(MF);
636d9eebe3cSJeremy Morse   TransferMap.clear();
637d9eebe3cSJeremy Morse   TransferMap.resize(1);
638d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
639d9eebe3cSJeremy Morse 
640d9eebe3cSJeremy Morse   LocIdx RaxLoc = MTracker->getRegMLoc(getRegByName("RAX"));
641d9eebe3cSJeremy Morse   ValueIDNum V = MTracker->readMLoc(RaxLoc);
642d9eebe3cSJeremy Morse   // Def of rax should be from instruction 1, i.e., unmodified.
643d9eebe3cSJeremy Morse   ValueIDNum Cmp(0, 1, RaxLoc);
644d9eebe3cSJeremy Morse   EXPECT_EQ(Cmp, V);
645d9eebe3cSJeremy Morse }
646d9eebe3cSJeremy Morse 
647d9eebe3cSJeremy Morse TEST_F(InstrRefLDVTest, MTransferCopies) {
648d9eebe3cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
649d9eebe3cSJeremy Morse   // This memory spill should be recognised, and a spill slot created.
650d9eebe3cSJeremy Morse   MachineFunction *MF = readMIRBlock(
651d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
652d9eebe3cSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
653d391e4feSSimon Pilgrim    "    RET64 $rax\n");
654d9eebe3cSJeremy Morse   setupLDVObj(MF);
655d9eebe3cSJeremy Morse   TransferMap.clear();
656d9eebe3cSJeremy Morse   TransferMap.resize(1);
657d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
658d9eebe3cSJeremy Morse 
659d9eebe3cSJeremy Morse   // Check that the spill location contains the value defined in rax by
660d9eebe3cSJeremy Morse   // instruction 1. The MIR header says -16 offset, but it's stored as -8;
661d9eebe3cSJeremy Morse   // it's not completely clear why, but here we only care about correctly
662d9eebe3cSJeremy Morse   // identifying the slot, not that all the surrounding data is correct.
663d9eebe3cSJeremy Morse   SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
66414aaaa12SJeremy Morse   SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
665e7084ceaSJeremy Morse   unsigned SpillLocID = MTracker->getLocID(SpillNo, {64, 0});
666e7084ceaSJeremy Morse   LocIdx SpillLoc = MTracker->getSpillMLoc(SpillLocID);
667e7084ceaSJeremy Morse   ValueIDNum V = MTracker->readMLoc(SpillLoc);
668d9eebe3cSJeremy Morse   Register RAX = getRegByName("RAX");
669d9eebe3cSJeremy Morse   LocIdx RaxLoc = MTracker->getRegMLoc(RAX);
670d9eebe3cSJeremy Morse   ValueIDNum Cmp(0, 1, RaxLoc);
671e7084ceaSJeremy Morse   EXPECT_EQ(V, Cmp);
672d9eebe3cSJeremy Morse 
673d9eebe3cSJeremy Morse   // A spill and restore should be recognised.
674d9eebe3cSJeremy Morse   MF = readMIRBlock(
675d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
676d9eebe3cSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
677d9eebe3cSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
678d391e4feSSimon Pilgrim    "    RET64\n");
679d9eebe3cSJeremy Morse   setupLDVObj(MF);
680d9eebe3cSJeremy Morse   TransferMap.clear();
681d9eebe3cSJeremy Morse   TransferMap.resize(1);
682d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
683d9eebe3cSJeremy Morse 
684d9eebe3cSJeremy Morse   // Test that rbx contains rax from instruction 1.
685d9eebe3cSJeremy Morse   RAX = getRegByName("RAX");
686d9eebe3cSJeremy Morse   RaxLoc = MTracker->getRegMLoc(RAX);
687d9eebe3cSJeremy Morse   Register RBX = getRegByName("RBX");
688d9eebe3cSJeremy Morse   LocIdx RbxLoc = MTracker->getRegMLoc(RBX);
689d9eebe3cSJeremy Morse   Cmp = ValueIDNum(0, 1, RaxLoc);
690d9eebe3cSJeremy Morse   ValueIDNum RbxVal = MTracker->readMLoc(RbxLoc);
691d9eebe3cSJeremy Morse   EXPECT_EQ(RbxVal, Cmp);
692d9eebe3cSJeremy Morse 
693e7084ceaSJeremy Morse   // Testing that all the subregisters are transferred happens in
694e7084ceaSJeremy Morse   // MTransferSubregSpills.
695d9eebe3cSJeremy Morse 
696d9eebe3cSJeremy Morse   // Copies and x86 movs should be recognised and honoured. In addition, all
697d9eebe3cSJeremy Morse   // of the subregisters should be copied across too.
698d9eebe3cSJeremy Morse   MF = readMIRBlock(
699d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
700d9eebe3cSJeremy Morse    "    $rcx = COPY $rax\n"
701d9eebe3cSJeremy Morse    "    $rbx = MOV64rr $rcx\n"
702d391e4feSSimon Pilgrim    "    RET64\n");
703d9eebe3cSJeremy Morse   setupLDVObj(MF);
704d9eebe3cSJeremy Morse   TransferMap.clear();
705d9eebe3cSJeremy Morse   TransferMap.resize(1);
706d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
707d9eebe3cSJeremy Morse 
708d9eebe3cSJeremy Morse   const char *ARegs[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
709d9eebe3cSJeremy Morse   const char *BRegs[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
710d9eebe3cSJeremy Morse   const char *CRegs[] = {"CL", "CH", "CX", "ECX", "HCX", "RCX"};
711d9eebe3cSJeremy Morse   auto CheckReg = [&](unsigned int I) {
712d9eebe3cSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
713d9eebe3cSJeremy Morse     LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
714d9eebe3cSJeremy Morse     LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
715d9eebe3cSJeremy Morse     ValueIDNum ARefVal(0, 1, A);
716d9eebe3cSJeremy Morse     ValueIDNum AVal = MTracker->readMLoc(A);
717d9eebe3cSJeremy Morse     ValueIDNum BVal = MTracker->readMLoc(B);
718d9eebe3cSJeremy Morse     ValueIDNum CVal = MTracker->readMLoc(C);
719d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, AVal);
720d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, BVal);
721d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, CVal);
722d9eebe3cSJeremy Morse   };
723d9eebe3cSJeremy Morse 
724d9eebe3cSJeremy Morse   for (unsigned int I = 0; I < 6; ++I)
725d9eebe3cSJeremy Morse     CheckReg(I);
726d9eebe3cSJeremy Morse 
727d9eebe3cSJeremy Morse   // When we copy to a subregister, the super-register should be def'd too: it's
728d9eebe3cSJeremy Morse   // value will have changed.
729d9eebe3cSJeremy Morse   MF = readMIRBlock(
730d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
731d9eebe3cSJeremy Morse    "    $ecx = COPY $eax\n"
732d391e4feSSimon Pilgrim    "    RET64\n");
733d9eebe3cSJeremy Morse   setupLDVObj(MF);
734d9eebe3cSJeremy Morse   TransferMap.clear();
735d9eebe3cSJeremy Morse   TransferMap.resize(1);
736d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
737d9eebe3cSJeremy Morse 
738d9eebe3cSJeremy Morse   // First four regs [al, ah, ax, eax] should be copied to *cx.
739d9eebe3cSJeremy Morse   for (unsigned int I = 0; I < 4; ++I) {
740d9eebe3cSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
741d9eebe3cSJeremy Morse     LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
742d9eebe3cSJeremy Morse     ValueIDNum ARefVal(0, 1, A);
743d9eebe3cSJeremy Morse     ValueIDNum AVal = MTracker->readMLoc(A);
744d9eebe3cSJeremy Morse     ValueIDNum CVal = MTracker->readMLoc(C);
745d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, AVal);
746d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, CVal);
747d9eebe3cSJeremy Morse   }
748d9eebe3cSJeremy Morse 
749d9eebe3cSJeremy Morse   // But rcx should contain a value defined by the COPY.
750d9eebe3cSJeremy Morse   LocIdx RcxLoc = MTracker->getRegMLoc(getRegByName("RCX"));
751d9eebe3cSJeremy Morse   ValueIDNum RcxVal = MTracker->readMLoc(RcxLoc);
752d9eebe3cSJeremy Morse   ValueIDNum RcxDefVal(0, 2, RcxLoc); // instr 2 -> the copy
753d9eebe3cSJeremy Morse   EXPECT_EQ(RcxVal, RcxDefVal);
754d9eebe3cSJeremy Morse }
755d9eebe3cSJeremy Morse 
756e7084ceaSJeremy Morse TEST_F(InstrRefLDVTest, MTransferSubregSpills) {
757e7084ceaSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
758e7084ceaSJeremy Morse   MachineFunction *MF = readMIRBlock(
759e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
760e7084ceaSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
761e7084ceaSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
762d391e4feSSimon Pilgrim    "    RET64\n");
763e7084ceaSJeremy Morse   setupLDVObj(MF);
764e7084ceaSJeremy Morse   TransferMap.clear();
765e7084ceaSJeremy Morse   TransferMap.resize(1);
766e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
767e7084ceaSJeremy Morse 
768e7084ceaSJeremy Morse   // Check that all the subregs of rax and rbx contain the same values. One
769e7084ceaSJeremy Morse   // should completely transfer to the other.
770e7084ceaSJeremy Morse   const char *ARegs[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
771e7084ceaSJeremy Morse   const char *BRegs[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
772e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 6; ++I) {
773e7084ceaSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
774e7084ceaSJeremy Morse     LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
775e7084ceaSJeremy Morse     EXPECT_EQ(MTracker->readMLoc(A), MTracker->readMLoc(B));
776e7084ceaSJeremy Morse   }
777e7084ceaSJeremy Morse 
778e7084ceaSJeremy Morse   // Explicitly check what's in the different subreg slots, on the stack.
779e7084ceaSJeremy Morse   // Pair up subreg idx fields with the corresponding subregister in $rax.
780e7084ceaSJeremy Morse   MLocTracker::StackSlotPos SubRegIdxes[] = {{8, 0}, {8, 8}, {16, 0}, {32, 0}, {64, 0}};
781e7084ceaSJeremy Morse   const char *SubRegNames[] = {"AL", "AH", "AX", "EAX", "RAX"};
782e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
783e7084ceaSJeremy Morse     // Value number where it's defined,
784e7084ceaSJeremy Morse     LocIdx RegLoc = MTracker->getRegMLoc(getRegByName(SubRegNames[I]));
785e7084ceaSJeremy Morse     ValueIDNum DefNum(0, 1, RegLoc);
786e7084ceaSJeremy Morse     // Read the corresponding subreg field from the stack.
787e7084ceaSJeremy Morse     SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
78814aaaa12SJeremy Morse     SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
789e7084ceaSJeremy Morse     unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
790e7084ceaSJeremy Morse     LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
791e7084ceaSJeremy Morse     ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
792e7084ceaSJeremy Morse     EXPECT_EQ(DefNum, SpillValue);
793e7084ceaSJeremy Morse   }
794e7084ceaSJeremy Morse 
795e7084ceaSJeremy Morse   // If we have exactly the same code, but we write $eax to the stack slot after
796e7084ceaSJeremy Morse   // $rax, then we should still have exactly the same output in the lower five
797e7084ceaSJeremy Morse   // subregisters. Storing $eax to the start of the slot will overwrite with the
798e7084ceaSJeremy Morse   // same values. $rax, as an aliasing register, should be reset to something
799e7084ceaSJeremy Morse   // else by that write.
800e7084ceaSJeremy Morse   // In theory, we could try and recognise that we're writing the _same_ values
801e7084ceaSJeremy Morse   // to the stack again, and so $rax doesn't need to be reset to something else.
802e7084ceaSJeremy Morse   // It seems vanishingly unlikely that LLVM would generate such code though,
803e7084ceaSJeremy Morse   // so the benefits would be small.
804e7084ceaSJeremy Morse   MF = readMIRBlock(
805e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
806e7084ceaSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
807e7084ceaSJeremy Morse    "    MOV32mr $rsp, 1, $noreg, 16, $noreg, $eax :: (store 4 into %stack.0)\n"
808e7084ceaSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
809d391e4feSSimon Pilgrim    "    RET64\n");
810e7084ceaSJeremy Morse   setupLDVObj(MF);
811e7084ceaSJeremy Morse   TransferMap.clear();
812e7084ceaSJeremy Morse   TransferMap.resize(1);
813e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
814e7084ceaSJeremy Morse 
815e7084ceaSJeremy Morse   // Check lower five registers up to and include $eax == $ebx,
816e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
817e7084ceaSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
818e7084ceaSJeremy Morse     LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
819e7084ceaSJeremy Morse     EXPECT_EQ(MTracker->readMLoc(A), MTracker->readMLoc(B));
820e7084ceaSJeremy Morse   }
821e7084ceaSJeremy Morse 
822e7084ceaSJeremy Morse   // $rbx should contain something else; today it's a def at the spill point
823e7084ceaSJeremy Morse   // of the 4 byte value.
824e7084ceaSJeremy Morse   SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
82514aaaa12SJeremy Morse   SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
826e7084ceaSJeremy Morse   unsigned SpillID = MTracker->getLocID(SpillNo, {64, 0});
827e7084ceaSJeremy Morse   LocIdx Spill64Loc = MTracker->getSpillMLoc(SpillID);
828e7084ceaSJeremy Morse   ValueIDNum DefAtSpill64(0, 3, Spill64Loc);
829e7084ceaSJeremy Morse   LocIdx RbxLoc = MTracker->getRegMLoc(getRegByName("RBX"));
830e7084ceaSJeremy Morse   EXPECT_EQ(MTracker->readMLoc(RbxLoc), DefAtSpill64);
831e7084ceaSJeremy Morse 
832e7084ceaSJeremy Morse   // Same again, test that the lower four subreg slots on the stack are the
833e7084ceaSJeremy Morse   // value defined by $rax in instruction 1.
834e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 4; ++I) {
835e7084ceaSJeremy Morse     // Value number where it's defined,
836e7084ceaSJeremy Morse     LocIdx RegLoc = MTracker->getRegMLoc(getRegByName(SubRegNames[I]));
837e7084ceaSJeremy Morse     ValueIDNum DefNum(0, 1, RegLoc);
838e7084ceaSJeremy Morse     // Read the corresponding subreg field from the stack.
83914aaaa12SJeremy Morse     SpillNo = *MTracker->getOrTrackSpillLoc(L);
840e7084ceaSJeremy Morse     SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
841e7084ceaSJeremy Morse     LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
842e7084ceaSJeremy Morse     ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
843e7084ceaSJeremy Morse     EXPECT_EQ(DefNum, SpillValue);
844e7084ceaSJeremy Morse   }
845e7084ceaSJeremy Morse 
846e7084ceaSJeremy Morse   // Stack slot for $rax should be a different value, today it's EmptyValue.
847e7084ceaSJeremy Morse   ValueIDNum SpillValue = MTracker->readMLoc(Spill64Loc);
848e7084ceaSJeremy Morse   EXPECT_EQ(SpillValue, DefAtSpill64);
849e7084ceaSJeremy Morse 
850e7084ceaSJeremy Morse   // If we write something to the stack, then over-write with some register
851e7084ceaSJeremy Morse   // from a completely different hierarchy, none of the "old" values should be
852e7084ceaSJeremy Morse   // readable.
853e7084ceaSJeremy Morse   // NB: slight hack, store 16 in to a 8 byte stack slot.
854e7084ceaSJeremy Morse   MF = readMIRBlock(
855e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
856e7084ceaSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
857e7084ceaSJeremy Morse    "    $xmm0 = IMPLICIT_DEF\n"
858e7084ceaSJeremy Morse    "    MOVUPDmr $rsp, 1, $noreg, 16, $noreg, killed $xmm0 :: (store (s128) into %stack.0)\n"
859e7084ceaSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
860d391e4feSSimon Pilgrim    "    RET64\n");
861e7084ceaSJeremy Morse   setupLDVObj(MF);
862e7084ceaSJeremy Morse   TransferMap.clear();
863e7084ceaSJeremy Morse   TransferMap.resize(1);
864e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
865e7084ceaSJeremy Morse 
866e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
867e7084ceaSJeremy Morse     // Read subreg fields from the stack.
86814aaaa12SJeremy Morse     SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
869e7084ceaSJeremy Morse     unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
870e7084ceaSJeremy Morse     LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
871e7084ceaSJeremy Morse     ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
872e7084ceaSJeremy Morse 
873e7084ceaSJeremy Morse     // Value should be defined by the spill-to-xmm0 instr, get value of a def
874e7084ceaSJeremy Morse     // at the point of the spill.
875e7084ceaSJeremy Morse     ValueIDNum SpillDef(0, 4, SpillLoc);
876e7084ceaSJeremy Morse     EXPECT_EQ(SpillValue, SpillDef);
877e7084ceaSJeremy Morse   }
878e7084ceaSJeremy Morse 
879e7084ceaSJeremy Morse   // Read xmm0's position and ensure it has a value. Should be the live-in
880e7084ceaSJeremy Morse   // value to the block, as IMPLICIT_DEF isn't a real def.
88114aaaa12SJeremy Morse   SpillNo = *MTracker->getOrTrackSpillLoc(L);
882e7084ceaSJeremy Morse   SpillID = MTracker->getLocID(SpillNo, {128, 0});
883e7084ceaSJeremy Morse   LocIdx Spill128Loc = MTracker->getSpillMLoc(SpillID);
884e7084ceaSJeremy Morse   SpillValue = MTracker->readMLoc(Spill128Loc);
885e7084ceaSJeremy Morse   Register XMM0 = getRegByName("XMM0");
886e7084ceaSJeremy Morse   LocIdx Xmm0Loc = MTracker->getRegMLoc(XMM0);
887e7084ceaSJeremy Morse   EXPECT_EQ(ValueIDNum(0, 0, Xmm0Loc), SpillValue);
888e7084ceaSJeremy Morse 
889e7084ceaSJeremy Morse   // What happens if we spill ah to the stack, then load al? It should find
890e7084ceaSJeremy Morse   // the same value.
891e7084ceaSJeremy Morse   MF = readMIRBlock(
892e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
893e7084ceaSJeremy Morse    "    MOV8mr $rsp, 1, $noreg, 16, $noreg, $ah :: (store 1 into %stack.0)\n"
894e7084ceaSJeremy Morse    "    $al = MOV8rm $rsp, 1, $noreg, 0, $noreg :: (load 1 from %stack.0)\n"
895d391e4feSSimon Pilgrim    "    RET64\n");
896e7084ceaSJeremy Morse   setupLDVObj(MF);
897e7084ceaSJeremy Morse   TransferMap.clear();
898e7084ceaSJeremy Morse   TransferMap.resize(1);
899e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
900e7084ceaSJeremy Morse 
901e7084ceaSJeremy Morse   Register AL = getRegByName("AL");
902e7084ceaSJeremy Morse   Register AH = getRegByName("AH");
903e7084ceaSJeremy Morse   LocIdx AlLoc = MTracker->getRegMLoc(AL);
904e7084ceaSJeremy Morse   LocIdx AhLoc = MTracker->getRegMLoc(AH);
905e7084ceaSJeremy Morse   ValueIDNum AHDef(0, 1, AhLoc);
906e7084ceaSJeremy Morse   ValueIDNum ALValue = MTracker->readMLoc(AlLoc);
907e7084ceaSJeremy Morse   EXPECT_EQ(ALValue, AHDef);
908e7084ceaSJeremy Morse }
909e7084ceaSJeremy Morse 
910a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocSingleBlock) {
911a3936a6cSJeremy Morse   // Test some very simple properties about interpreting the transfer function.
912b5426cedSJeremy Morse   setupSingleBlock();
913a3936a6cSJeremy Morse 
914a3936a6cSJeremy Morse   // We should start with a single location, the stack pointer.
915a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
916a3936a6cSJeremy Morse   LocIdx RspLoc(0);
917a3936a6cSJeremy Morse 
918a3936a6cSJeremy Morse   // Set up live-in and live-out tables for this function: two locations (we
919a3936a6cSJeremy Morse   // add one later) in a single block.
920acacec3bSFelipe de Azevedo Piovezan   auto [MOutLocs, MInLocs] = allocValueTables(1, 2);
921a3936a6cSJeremy Morse 
922a3936a6cSJeremy Morse   // Transfer function: nothing.
9234136897bSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
9244136897bSJeremy Morse   TransferFunc.resize(1);
925a3936a6cSJeremy Morse 
926a3936a6cSJeremy Morse   // Try and build value maps...
927ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
928a3936a6cSJeremy Morse 
929a3936a6cSJeremy Morse   // The result should be that RSP is marked as a live-in-PHI -- this represents
930a3936a6cSJeremy Morse   // an argument. And as there's no transfer function, the block live-out should
931a3936a6cSJeremy Morse   // be the same.
932ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
933ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
934a3936a6cSJeremy Morse 
935a3936a6cSJeremy Morse   // Try again, this time initialising the in-locs to be defined by an
936a3936a6cSJeremy Morse   // instruction. The entry block should always be re-assigned to be the
937a3936a6cSJeremy Morse   // arguments.
938ab49dce0SJeremy Morse   initValueArray(MInLocs, 1, 2);
939ab49dce0SJeremy Morse   initValueArray(MOutLocs, 1, 2);
940ab49dce0SJeremy Morse   MInLocs[0][0] = ValueIDNum(0, 1, RspLoc);
941ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
942ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
943ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
944a3936a6cSJeremy Morse 
945a3936a6cSJeremy Morse   // Now insert something into the transfer function to assign to the single
946a3936a6cSJeremy Morse   // machine location.
947a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
948ab49dce0SJeremy Morse   initValueArray(MInLocs, 1, 2);
949ab49dce0SJeremy Morse   initValueArray(MOutLocs, 1, 2);
950ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
951ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
952ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
953a3936a6cSJeremy Morse   TransferFunc[0].clear();
954a3936a6cSJeremy Morse 
955a3936a6cSJeremy Morse   // Add a new register to be tracked, and insert it into the transfer function
956a3936a6cSJeremy Morse   // as a copy. The output of $rax should be the live-in value of $rsp.
957a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
958a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
959a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
960a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, ValueIDNum(0, 0, RspLoc)});
961ab49dce0SJeremy Morse   initValueArray(MInLocs, 1, 2);
962ab49dce0SJeremy Morse   initValueArray(MOutLocs, 1, 2);
963ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
964ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
965ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], ValueIDNum(0, 0, RaxLoc));
966ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
967ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], ValueIDNum(0, 0, RspLoc)); // Rax contains RspLoc.
968a3936a6cSJeremy Morse   TransferFunc[0].clear();
969a3936a6cSJeremy Morse }
970a3936a6cSJeremy Morse 
971a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocDiamondBlocks) {
972a3936a6cSJeremy Morse   // Test that information flows from the entry block to two successors.
973a3936a6cSJeremy Morse   //        entry
974a3936a6cSJeremy Morse   //        /  \
975a3936a6cSJeremy Morse   //      br1  br2
976a3936a6cSJeremy Morse   //        \  /
977a3936a6cSJeremy Morse   //         ret
978b5426cedSJeremy Morse   setupDiamondBlocks();
979838b4a53SJeremy Morse 
980a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
981a3936a6cSJeremy Morse   LocIdx RspLoc(0);
982a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
983a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
984838b4a53SJeremy Morse 
985acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(4, 2);
986838b4a53SJeremy Morse 
987a3936a6cSJeremy Morse   // Transfer function: start with nothing.
988a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
989a3936a6cSJeremy Morse   TransferFunc.resize(4);
990a3936a6cSJeremy Morse 
991a3936a6cSJeremy Morse   // Name some values.
992b5426cedSJeremy Morse   unsigned EntryBlk = 0, BrBlk1 = 1, BrBlk2 = 2, RetBlk = 3;
993b5426cedSJeremy Morse 
994b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
995b5426cedSJeremy Morse   ValueIDNum RspDefInBlk0(EntryBlk, 1, RspLoc);
996b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(BrBlk1, 1, RspLoc);
997b5426cedSJeremy Morse   ValueIDNum RspDefInBlk2(BrBlk2, 1, RspLoc);
998b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3(RetBlk, 0, RspLoc);
999b5426cedSJeremy Morse   ValueIDNum RaxLiveInBlk1(BrBlk1, 0, RaxLoc);
1000b5426cedSJeremy Morse   ValueIDNum RaxLiveInBlk2(BrBlk2, 0, RaxLoc);
1001a3936a6cSJeremy Morse 
1002a3936a6cSJeremy Morse   // With no transfer function, the live-in values to the entry block should
1003a3936a6cSJeremy Morse   // propagate to all live-outs and the live-ins to the two successor blocks.
1004a3936a6cSJeremy Morse   // IN ADDITION: this checks that the exit block doesn't get a PHI put in it.
1005ab49dce0SJeremy Morse   initValueArray(MInLocs, 4, 2);
1006ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
1007ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1008ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1009ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1010ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1011ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1012ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1013ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1014ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1015ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1016a3936a6cSJeremy Morse   // (Skipped writing out locations for $rax).
1017a3936a6cSJeremy Morse 
1018a3936a6cSJeremy Morse   // Check that a def of $rsp in the entry block will likewise reach all the
1019a3936a6cSJeremy Morse   // successors.
1020a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1021ab49dce0SJeremy Morse   initValueArray(MInLocs, 4, 2);
1022ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
1023ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1024ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1025ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1026ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1027ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk0);
1028ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1029ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk0);
1030ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk0);
1031ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk0);
1032a3936a6cSJeremy Morse   TransferFunc[0].clear();
1033a3936a6cSJeremy Morse 
1034a3936a6cSJeremy Morse   // Def in one branch of the diamond means that we need a PHI in the ret block
1035a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1036a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1037ab49dce0SJeremy Morse   initValueArray(MInLocs, 4, 2);
1038ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
1039ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1040a3936a6cSJeremy Morse   // This value map: like above, where RspDefInBlk0 is propagated through one
1041a3936a6cSJeremy Morse   // branch of the diamond, but is def'ed in the live-outs of the other. The
1042a3936a6cSJeremy Morse   // ret / merging block should have a PHI in its live-ins.
1043ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1044ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1045ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1046ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1047ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1048ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1049ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk0);
1050ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1051a3936a6cSJeremy Morse   TransferFunc[0].clear();
1052a3936a6cSJeremy Morse   TransferFunc[1].clear();
1053a3936a6cSJeremy Morse 
1054a3936a6cSJeremy Morse   // If we have differeing defs in either side of the diamond, we should
1055a3936a6cSJeremy Morse   // continue to produce a PHI,
1056a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1057a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1058a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1059ab49dce0SJeremy Morse   initValueArray(MInLocs, 4, 2);
1060ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
1061ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1062ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1063ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1064ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1065ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1066ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1067ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1068ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1069ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1070a3936a6cSJeremy Morse   TransferFunc[0].clear();
1071a3936a6cSJeremy Morse   TransferFunc[1].clear();
1072a3936a6cSJeremy Morse   TransferFunc[2].clear();
1073a3936a6cSJeremy Morse 
1074a3936a6cSJeremy Morse   // If we have defs of the same value on either side of the branch, a PHI will
1075a3936a6cSJeremy Morse   // initially be created, however value propagation should then eliminate it.
1076a3936a6cSJeremy Morse   // Encode this by copying the live-in value to $rax, and copying it to $rsp
1077a3936a6cSJeremy Morse   // from $rax in each branch of the diamond. We don't allow the definition of
1078a3936a6cSJeremy Morse   // arbitary values in transfer functions.
1079a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, RspDefInBlk0});
1080a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1081a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RaxLiveInBlk1});
1082a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxLiveInBlk2});
1083ab49dce0SJeremy Morse   initValueArray(MInLocs, 4, 2);
1084ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
1085ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1086ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1087ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspDefInBlk0);
1088ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk0);
1089ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1090ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], RspDefInBlk0);
1091ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1092ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1093ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1094a3936a6cSJeremy Morse   TransferFunc[0].clear();
1095a3936a6cSJeremy Morse   TransferFunc[1].clear();
1096a3936a6cSJeremy Morse   TransferFunc[2].clear();
1097838b4a53SJeremy Morse }
1098a3936a6cSJeremy Morse 
109997ddf49eSJeremy Morse TEST_F(InstrRefLDVTest, MLocDiamondSpills) {
110097ddf49eSJeremy Morse   // Test that defs in stack locations that require PHIs, cause PHIs to be
110197ddf49eSJeremy Morse   // installed in aliasing locations. i.e., if there's a PHI in the lower
110297ddf49eSJeremy Morse   // 8 bits of the stack, there should be PHIs for 16/32/64 bit locations
110397ddf49eSJeremy Morse   // on the stack too.
110497ddf49eSJeremy Morse   // Technically this isn't needed for accuracy: we should calculate PHIs
110597ddf49eSJeremy Morse   // independently for each location. However, because there's an optimisation
110697ddf49eSJeremy Morse   // that only places PHIs for the lower "interfering" parts of stack slots,
110797ddf49eSJeremy Morse   // test for this behaviour.
110897ddf49eSJeremy Morse   setupDiamondBlocks();
110997ddf49eSJeremy Morse 
111097ddf49eSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
111197ddf49eSJeremy Morse   LocIdx RspLoc(0);
111297ddf49eSJeremy Morse 
111397ddf49eSJeremy Morse   // Create a stack location and ensure it's tracked.
111497ddf49eSJeremy Morse   SpillLoc SL = {getRegByName("RSP"), StackOffset::getFixed(-8)};
111514aaaa12SJeremy Morse   SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(SL);
1116c72a751dSPhoebe Wang   ASSERT_EQ(MTracker->getNumLocs(), 13u); // Tracks all possible stack locs.
111797ddf49eSJeremy Morse   // Locations are: RSP, stack slots from 2^3 bits wide up to 2^9 for zmm regs,
111897ddf49eSJeremy Morse   // then slots for sub_8bit_hi and sub_16bit_hi ({8, 8} and {16, 16}).
111965d5becaSJeremy Morse   // Finally, one for spilt fp80 registers.
112097ddf49eSJeremy Morse 
112197ddf49eSJeremy Morse   // Pick out the locations on the stack that various x86 regs would be written
112297ddf49eSJeremy Morse   // to. HAX is the upper 16 bits of EAX.
112397ddf49eSJeremy Morse   unsigned ALID = MTracker->getLocID(SpillNo, {8, 0});
112497ddf49eSJeremy Morse   unsigned AHID = MTracker->getLocID(SpillNo, {8, 8});
112597ddf49eSJeremy Morse   unsigned AXID = MTracker->getLocID(SpillNo, {16, 0});
112697ddf49eSJeremy Morse   unsigned EAXID = MTracker->getLocID(SpillNo, {32, 0});
112797ddf49eSJeremy Morse   unsigned HAXID = MTracker->getLocID(SpillNo, {16, 16});
112897ddf49eSJeremy Morse   unsigned RAXID = MTracker->getLocID(SpillNo, {64, 0});
112997ddf49eSJeremy Morse   LocIdx ALStackLoc = MTracker->getSpillMLoc(ALID);
113097ddf49eSJeremy Morse   LocIdx AHStackLoc = MTracker->getSpillMLoc(AHID);
113197ddf49eSJeremy Morse   LocIdx AXStackLoc = MTracker->getSpillMLoc(AXID);
113297ddf49eSJeremy Morse   LocIdx EAXStackLoc = MTracker->getSpillMLoc(EAXID);
113397ddf49eSJeremy Morse   LocIdx HAXStackLoc = MTracker->getSpillMLoc(HAXID);
113497ddf49eSJeremy Morse   LocIdx RAXStackLoc = MTracker->getSpillMLoc(RAXID);
113597ddf49eSJeremy Morse   // There are other locations, for things like xmm0, which we're going to
113697ddf49eSJeremy Morse   // ignore here.
113797ddf49eSJeremy Morse 
1138c72a751dSPhoebe Wang   auto [MInLocs, MOutLocs] = allocValueTables(4, 13);
113997ddf49eSJeremy Morse 
114097ddf49eSJeremy Morse   // Transfer function: start with nothing.
114197ddf49eSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
114297ddf49eSJeremy Morse   TransferFunc.resize(4);
114397ddf49eSJeremy Morse 
114497ddf49eSJeremy Morse   // Name some values.
114597ddf49eSJeremy Morse   unsigned EntryBlk = 0, Blk1 = 1, RetBlk = 3;
114697ddf49eSJeremy Morse 
114797ddf49eSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
114897ddf49eSJeremy Morse   ValueIDNum ALLiveIn(EntryBlk, 0, ALStackLoc);
114997ddf49eSJeremy Morse   ValueIDNum AHLiveIn(EntryBlk, 0, AHStackLoc);
115097ddf49eSJeremy Morse   ValueIDNum HAXLiveIn(EntryBlk, 0, HAXStackLoc);
115197ddf49eSJeremy Morse   ValueIDNum ALPHI(RetBlk, 0, ALStackLoc);
115297ddf49eSJeremy Morse   ValueIDNum AXPHI(RetBlk, 0, AXStackLoc);
115397ddf49eSJeremy Morse   ValueIDNum EAXPHI(RetBlk, 0, EAXStackLoc);
115497ddf49eSJeremy Morse   ValueIDNum HAXPHI(RetBlk, 0, HAXStackLoc);
115597ddf49eSJeremy Morse   ValueIDNum RAXPHI(RetBlk, 0, RAXStackLoc);
115697ddf49eSJeremy Morse 
115797ddf49eSJeremy Morse   ValueIDNum ALDefInBlk1(Blk1, 1, ALStackLoc);
115897ddf49eSJeremy Morse   ValueIDNum HAXDefInBlk1(Blk1, 1, HAXStackLoc);
115997ddf49eSJeremy Morse 
116097ddf49eSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AllBlocks{MBB0, MBB1, MBB2, MBB3};
116197ddf49eSJeremy Morse 
116297ddf49eSJeremy Morse   // If we put defs into one side of the diamond, for AL and HAX, then we should
116397ddf49eSJeremy Morse   // find all aliasing positions have PHIs placed. This isn't technically what
116497ddf49eSJeremy Morse   // the transfer function says to do: but we're testing that the optimisation
116597ddf49eSJeremy Morse   // to reduce IDF calculation does the right thing.
116697ddf49eSJeremy Morse   // AH should not be def'd: it don't alias AL or HAX.
116797ddf49eSJeremy Morse   //
116897ddf49eSJeremy Morse   // NB: we don't call buildMLocValueMap, because it will try to eliminate the
116997ddf49eSJeremy Morse   // upper-slot PHIs, and succeed because of our slightly cooked transfer
117097ddf49eSJeremy Morse   // function.
117197ddf49eSJeremy Morse   TransferFunc[1].insert({ALStackLoc, ALDefInBlk1});
117297ddf49eSJeremy Morse   TransferFunc[1].insert({HAXStackLoc, HAXDefInBlk1});
1173c72a751dSPhoebe Wang   initValueArray(MInLocs, 4, 13);
1174ab49dce0SJeremy Morse   placeMLocPHIs(*MF, AllBlocks, MInLocs, TransferFunc);
1175ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][ALStackLoc.asU64()], ALPHI);
1176ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][AXStackLoc.asU64()], AXPHI);
1177ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][EAXStackLoc.asU64()], EAXPHI);
1178ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][HAXStackLoc.asU64()], HAXPHI);
1179ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][RAXStackLoc.asU64()], RAXPHI);
118097ddf49eSJeremy Morse   // AH should be left untouched,
1181ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][AHStackLoc.asU64()], ValueIDNum::EmptyValue);
118297ddf49eSJeremy Morse }
118397ddf49eSJeremy Morse 
1184a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
1185a3936a6cSJeremy Morse   //    entry
1186a3936a6cSJeremy Morse   //     |
1187a3936a6cSJeremy Morse   //     |/-----\
1188a3936a6cSJeremy Morse   //    loopblk |
1189a3936a6cSJeremy Morse   //     |\-----/
1190a3936a6cSJeremy Morse   //     |
1191a3936a6cSJeremy Morse   //     ret
1192b5426cedSJeremy Morse   setupSimpleLoop();
1193a3936a6cSJeremy Morse 
1194a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1195a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1196a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1197a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1198a3936a6cSJeremy Morse 
1199acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(3, 2);
1200a3936a6cSJeremy Morse 
1201a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1202a3936a6cSJeremy Morse   TransferFunc.resize(3);
1203a3936a6cSJeremy Morse 
1204a3936a6cSJeremy Morse   // Name some values.
1205b5426cedSJeremy Morse   unsigned EntryBlk = 0, LoopBlk = 1, RetBlk = 2;
1206b5426cedSJeremy Morse 
1207b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1208b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
1209b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(LoopBlk, 1, RspLoc);
1210b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1211b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
1212b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk2(RetBlk, 0, RaxLoc);
1213a3936a6cSJeremy Morse 
1214a3936a6cSJeremy Morse   // Begin test with all locations being live-through.
1215ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
1216ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1217ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1218ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1219ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1220ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1221ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1222ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1223ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1224a3936a6cSJeremy Morse 
1225a3936a6cSJeremy Morse   // Add a def of $rsp to the loop block: it should be in the live-outs, but
1226a3936a6cSJeremy Morse   // should cause a PHI to be placed in the live-ins. Test the transfer function
1227a3936a6cSJeremy Morse   // by copying that PHI into $rax in the loop, then back to $rsp in the ret
1228a3936a6cSJeremy Morse   // block.
1229a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1230a3936a6cSJeremy Morse   TransferFunc[1].insert({RaxLoc, RspPHIInBlk1});
1231a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1232ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
1233ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1234ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1235ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1236ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1237ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1238ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1239ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1240ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
1241a3936a6cSJeremy Morse   // Check rax as well,
1242ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1243ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
1244ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], RspPHIInBlk1);
1245ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRax);
1246ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], RspPHIInBlk1);
1247ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
1248a3936a6cSJeremy Morse   TransferFunc[1].clear();
1249a3936a6cSJeremy Morse   TransferFunc[2].clear();
1250a3936a6cSJeremy Morse 
1251a3936a6cSJeremy Morse   // As with the diamond case, a PHI will be created if there's a (implicit)
1252a3936a6cSJeremy Morse   // def in the entry block and loop block; but should be value propagated away
1253a3936a6cSJeremy Morse   // if it copies in the same value. Copy live-in $rsp to $rax, then copy it
1254a3936a6cSJeremy Morse   // into $rsp in the loop. Encoded as copying the live-in $rax value in block 1
1255a3936a6cSJeremy Morse   // to $rsp.
1256a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1257a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1258ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
1259ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1260ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1261ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1262ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1263ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1264ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1265ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1266ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1267a3936a6cSJeremy Morse   // Check $rax's values.
1268ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1269ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], LiveInRsp);
1270ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], LiveInRsp);
1271ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
1272ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
1273ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
1274a3936a6cSJeremy Morse   TransferFunc[0].clear();
1275a3936a6cSJeremy Morse   TransferFunc[1].clear();
1276a3936a6cSJeremy Morse }
1277a3936a6cSJeremy Morse 
1278a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocNestedLoop) {
1279a3936a6cSJeremy Morse   //    entry
1280a3936a6cSJeremy Morse   //     |
1281a3936a6cSJeremy Morse   //    loop1
1282a3936a6cSJeremy Morse   //     ^\
1283a3936a6cSJeremy Morse   //     | \    /-\
1284a3936a6cSJeremy Morse   //     |  loop2  |
1285a3936a6cSJeremy Morse   //     |  /   \-/
1286a3936a6cSJeremy Morse   //     ^ /
1287a3936a6cSJeremy Morse   //     join
1288a3936a6cSJeremy Morse   //     |
1289a3936a6cSJeremy Morse   //     ret
1290b5426cedSJeremy Morse   setupNestedLoops();
1291a3936a6cSJeremy Morse 
1292a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1293a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1294a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1295a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1296a3936a6cSJeremy Morse 
1297acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(5, 2);
1298a3936a6cSJeremy Morse 
1299a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1300a3936a6cSJeremy Morse   TransferFunc.resize(5);
1301a3936a6cSJeremy Morse 
1302b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2, JoinBlk = 3;
1303b5426cedSJeremy Morse 
1304b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1305b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
1306b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(Loop1Blk, 1, RspLoc);
1307b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Loop2Blk, 0, RspLoc);
1308b5426cedSJeremy Morse   ValueIDNum RspDefInBlk2(Loop2Blk, 1, RspLoc);
1309b5426cedSJeremy Morse   ValueIDNum RspDefInBlk3(JoinBlk, 1, RspLoc);
1310b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1311b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(Loop1Blk, 0, RaxLoc);
1312b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk2(Loop2Blk, 0, RaxLoc);
1313a3936a6cSJeremy Morse 
1314a3936a6cSJeremy Morse   // Like the other tests: first ensure that if there's nothing in the transfer
1315a3936a6cSJeremy Morse   // function, then everything is live-through (check $rsp).
1316ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1317ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1318ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1319ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1320ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1321ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1322ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1323ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1324ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1325ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1326ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1327ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1328ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1329a3936a6cSJeremy Morse 
1330a3936a6cSJeremy Morse   // A def in the inner loop means we should get PHIs at the heads of both
1331a3936a6cSJeremy Morse   // loops. Live-outs of the last three blocks will be the def, as it dominates
1332a3936a6cSJeremy Morse   // those.
1333a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1334ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1335ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1336ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1337ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1338ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1339ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1340ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1341ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
1342ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1343ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1344ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1345ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
1346ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
1347a3936a6cSJeremy Morse   TransferFunc[2].clear();
1348a3936a6cSJeremy Morse 
1349a3936a6cSJeremy Morse   // Adding a def to the outer loop header shouldn't affect this much -- the
1350a3936a6cSJeremy Morse   // live-out of block 1 changes.
1351a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1352a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1353ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1354ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1355ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1356ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1357ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1358ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1359ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1360ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
1361ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1362ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1363ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1364ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
1365ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
1366a3936a6cSJeremy Morse   TransferFunc[1].clear();
1367a3936a6cSJeremy Morse   TransferFunc[2].clear();
1368a3936a6cSJeremy Morse 
1369a3936a6cSJeremy Morse   // Likewise, putting a def in the outer loop tail shouldn't affect where
1370a3936a6cSJeremy Morse   // the PHIs go, and should propagate into the ret block.
1371a3936a6cSJeremy Morse 
1372a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1373a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1374a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1375ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1376ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1377ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1378ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1379ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1380ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1381ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1382ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1383ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1384ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1385ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1386ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1387ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1388a3936a6cSJeremy Morse   TransferFunc[1].clear();
1389a3936a6cSJeremy Morse   TransferFunc[2].clear();
1390a3936a6cSJeremy Morse   TransferFunc[3].clear();
1391a3936a6cSJeremy Morse 
1392a3936a6cSJeremy Morse   // However: if we don't def in the inner-loop, then we just have defs in the
1393a3936a6cSJeremy Morse   // head and tail of the outer loop. The inner loop should be live-through.
1394a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1395a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1396ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1397ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1398ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1399ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1400ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1401ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1402ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1403ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1404ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1405ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1406ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1407ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1408ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1409a3936a6cSJeremy Morse   TransferFunc[1].clear();
1410a3936a6cSJeremy Morse   TransferFunc[3].clear();
1411a3936a6cSJeremy Morse 
1412a3936a6cSJeremy Morse   // Check that this still works if we copy RspDefInBlk1 to $rax and then
1413a3936a6cSJeremy Morse   // copy it back into $rsp in the inner loop.
1414a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1415a3936a6cSJeremy Morse   TransferFunc[1].insert({RaxLoc, RspDefInBlk1});
1416a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1417a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1418ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1419ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1420ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1421ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1422ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1423ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1424ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1425ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1426ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1427ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1428ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1429ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1430ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1431a3936a6cSJeremy Morse   // Look at raxes value in the relevant blocks,
1432ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], RspDefInBlk1);
1433ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], RspDefInBlk1);
1434a3936a6cSJeremy Morse   TransferFunc[1].clear();
1435a3936a6cSJeremy Morse   TransferFunc[2].clear();
1436a3936a6cSJeremy Morse   TransferFunc[3].clear();
1437a3936a6cSJeremy Morse 
1438a3936a6cSJeremy Morse   // If we have a single def in the tail of the outer loop, that should produce
1439a3936a6cSJeremy Morse   // a PHI at the loop head, and be live-through the inner loop.
1440a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1441ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1442ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1443ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1444ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1445ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1446ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk1);
1447ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk1);
1448ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1449ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1450ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1451ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
1452ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1453ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1454a3936a6cSJeremy Morse   TransferFunc[3].clear();
1455a3936a6cSJeremy Morse 
1456a3936a6cSJeremy Morse   // And if we copy from $rsp to $rax in block 2, it should resolve to the PHI
1457a3936a6cSJeremy Morse   // in block 1, and we should keep that value in rax until the ret block.
1458a3936a6cSJeremy Morse   // There'll be a PHI in block 1 and 2, because we're putting a def in the
1459a3936a6cSJeremy Morse   // inner loop.
1460a3936a6cSJeremy Morse   TransferFunc[2].insert({RaxLoc, RspPHIInBlk2});
1461a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1462ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1463ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1464ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1465a3936a6cSJeremy Morse   // Examining the values of rax,
1466ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1467ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
1468ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], RaxPHIInBlk2);
1469ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][1], RspPHIInBlk1);
1470ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][1], RspPHIInBlk1);
1471ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRax);
1472ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], RaxPHIInBlk1);
1473ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
1474ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][1], RspPHIInBlk1);
1475ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][1], RspPHIInBlk1);
1476a3936a6cSJeremy Morse   TransferFunc[2].clear();
1477a3936a6cSJeremy Morse   TransferFunc[3].clear();
1478a3936a6cSJeremy Morse }
1479a3936a6cSJeremy Morse 
1480a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocNoDominatingLoop) {
1481a3936a6cSJeremy Morse   //           entry
1482a3936a6cSJeremy Morse   //            / \
1483a3936a6cSJeremy Morse   //           /   \
1484a3936a6cSJeremy Morse   //          /     \
1485a3936a6cSJeremy Morse   //        head1   head2
1486a3936a6cSJeremy Morse   //        ^  \   /   ^
1487a3936a6cSJeremy Morse   //        ^   \ /    ^
1488a3936a6cSJeremy Morse   //        \-joinblk -/
1489a3936a6cSJeremy Morse   //             |
1490a3936a6cSJeremy Morse   //            ret
1491b5426cedSJeremy Morse   setupNoDominatingLoop();
1492a3936a6cSJeremy Morse 
1493a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1494a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1495a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1496a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1497a3936a6cSJeremy Morse 
1498acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(5, 2);
1499a3936a6cSJeremy Morse 
1500a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1501a3936a6cSJeremy Morse   TransferFunc.resize(5);
1502a3936a6cSJeremy Morse 
1503b5426cedSJeremy Morse   unsigned EntryBlk = 0, Head1Blk = 1, Head2Blk = 2, JoinBlk = 3;
1504b5426cedSJeremy Morse 
1505b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1506b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Head1Blk, 0, RspLoc);
1507b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(Head1Blk, 1, RspLoc);
1508b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Head2Blk, 0, RspLoc);
1509b5426cedSJeremy Morse   ValueIDNum RspDefInBlk2(Head2Blk, 1, RspLoc);
1510b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3(JoinBlk, 0, RspLoc);
1511b5426cedSJeremy Morse   ValueIDNum RspDefInBlk3(JoinBlk, 1, RspLoc);
1512b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(Head1Blk, 0, RaxLoc);
1513b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk2(Head2Blk, 0, RaxLoc);
1514a3936a6cSJeremy Morse 
1515a3936a6cSJeremy Morse   // As ever, test that everything is live-through if there are no defs.
1516ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1517ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1518ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1519ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1520ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1521ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1522ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1523ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1524ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1525ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1526ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1527ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1528ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1529a3936a6cSJeremy Morse 
1530a3936a6cSJeremy Morse   // Putting a def in the 'join' block will cause us to have two distinct
1531a3936a6cSJeremy Morse   // PHIs in each loop head, then on entry to the join block.
1532a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1533ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1534ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1535ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1536ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1537ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1538ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1539ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1540ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1541ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1542ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1543ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1544ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1545ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1546a3936a6cSJeremy Morse   TransferFunc[3].clear();
1547a3936a6cSJeremy Morse 
1548a3936a6cSJeremy Morse   // We should get the same behaviour if we put the def in either of the
1549a3936a6cSJeremy Morse   // loop heads -- it should force the other head to be a PHI.
1550a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1551ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1552ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1553ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1554ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1555ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1556ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1557ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1558ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
1559ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1560ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1561ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1562ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1563ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
1564a3936a6cSJeremy Morse   TransferFunc[1].clear();
1565a3936a6cSJeremy Morse 
1566a3936a6cSJeremy Morse   // Check symmetry,
1567a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1568ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1569ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1570ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1571ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1572ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1573ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1574ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1575ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
1576ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1577ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1578ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1579ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1580ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
1581a3936a6cSJeremy Morse   TransferFunc[2].clear();
1582a3936a6cSJeremy Morse 
1583a3936a6cSJeremy Morse   // Test some scenarios where there _shouldn't_ be any PHIs created at heads.
1584a3936a6cSJeremy Morse   // These are those PHIs are created, but value propagation eliminates them.
1585a3936a6cSJeremy Morse   // For example, lets copy rsp-livein to $rsp inside each loop head, so that
1586a3936a6cSJeremy Morse   // there's no need for a PHI in the join block. Put a def of $rsp in block 3
1587a3936a6cSJeremy Morse   // to force PHIs elsewhere.
1588a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1589a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1590a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1591a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1592ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1593ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1594ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1595ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1596ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1597ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1598ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1599ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1600ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1601ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1602ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1603ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1604ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1605a3936a6cSJeremy Morse   TransferFunc[0].clear();
1606a3936a6cSJeremy Morse   TransferFunc[1].clear();
1607a3936a6cSJeremy Morse   TransferFunc[2].clear();
1608a3936a6cSJeremy Morse   TransferFunc[3].clear();
1609a3936a6cSJeremy Morse 
1610a3936a6cSJeremy Morse   // In fact, if we eliminate the def in block 3, none of those PHIs are
1611a3936a6cSJeremy Morse   // necessary, as we're just repeatedly copying LiveInRsp into $rsp. They
1612a3936a6cSJeremy Morse   // should all be value propagated out.
1613a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1614a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1615a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1616ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1617ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1618ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1619ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1620ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1621ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1622ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1623ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1624ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1625ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1626ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1627ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1628ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1629a3936a6cSJeremy Morse   TransferFunc[0].clear();
1630a3936a6cSJeremy Morse   TransferFunc[1].clear();
1631a3936a6cSJeremy Morse   TransferFunc[2].clear();
1632a3936a6cSJeremy Morse }
1633a3936a6cSJeremy Morse 
1634a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocBadlyNestedLoops) {
1635a3936a6cSJeremy Morse   //           entry
1636a3936a6cSJeremy Morse   //             |
1637a3936a6cSJeremy Morse   //           loop1 -o
1638a3936a6cSJeremy Morse   //             | ^
1639a3936a6cSJeremy Morse   //             | ^
1640a3936a6cSJeremy Morse   //           loop2 -o
1641a3936a6cSJeremy Morse   //             | ^
1642a3936a6cSJeremy Morse   //             | ^
1643a3936a6cSJeremy Morse   //           loop3 -o
1644a3936a6cSJeremy Morse   //             |
1645a3936a6cSJeremy Morse   //            ret
1646b5426cedSJeremy Morse   setupBadlyNestedLoops();
1647a3936a6cSJeremy Morse 
1648a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1649a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1650a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1651a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1652a3936a6cSJeremy Morse 
1653acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(5, 2);
1654a3936a6cSJeremy Morse 
1655a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1656a3936a6cSJeremy Morse   TransferFunc.resize(5);
1657a3936a6cSJeremy Morse 
1658b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2, Loop3Blk = 3;
1659b5426cedSJeremy Morse 
1660b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1661b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
1662b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(Loop1Blk, 1, RspLoc);
1663b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Loop2Blk, 0, RspLoc);
1664b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3(Loop3Blk, 0, RspLoc);
1665b5426cedSJeremy Morse   ValueIDNum RspDefInBlk3(Loop3Blk, 1, RspLoc);
1666b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1667b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk3(Loop3Blk, 0, RaxLoc);
1668a3936a6cSJeremy Morse 
1669a3936a6cSJeremy Morse   // As ever, test that everything is live-through if there are no defs.
1670ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1671ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1672ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1673ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1674ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1675ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1676ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1677ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1678ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1679ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1680ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1681ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1682ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1683a3936a6cSJeremy Morse 
1684a3936a6cSJeremy Morse   // A def in loop3 should cause PHIs in every loop block: they're all
1685a3936a6cSJeremy Morse   // reachable from each other.
1686a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1687ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1688ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1689ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1690ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1691ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1692ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1693ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1694ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1695ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1696ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1697ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1698ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1699ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1700a3936a6cSJeremy Morse   TransferFunc[3].clear();
1701a3936a6cSJeremy Morse 
1702a3936a6cSJeremy Morse   // A def in loop1 should cause a PHI in loop1, but not the other blocks.
1703a3936a6cSJeremy Morse   // loop2 and loop3 are dominated by the def in loop1, so they should have
1704a3936a6cSJeremy Morse   // that value live-through.
1705a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1706ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1707ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1708ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1709ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1710ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1711ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1712ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1713ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk1);
1714ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1715ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1716ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1717ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk1);
1718ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk1);
1719a3936a6cSJeremy Morse   TransferFunc[1].clear();
1720a3936a6cSJeremy Morse 
1721a3936a6cSJeremy Morse   // As with earlier tricks: copy $rsp to $rax in the entry block, then $rax
1722a3936a6cSJeremy Morse   // to $rsp in block 3. The only def of $rsp is simply copying the same value
1723a3936a6cSJeremy Morse   // back into itself, and the value of $rsp is LiveInRsp all the way through.
1724a3936a6cSJeremy Morse   // PHIs should be created, then value-propagated away...  however this
1725a3936a6cSJeremy Morse   // doesn't work in practice.
1726a3936a6cSJeremy Morse   // Consider the entry to loop3: we can determine that there's an incoming
1727a3936a6cSJeremy Morse   // PHI value from loop2, and LiveInRsp from the self-loop. This would still
1728a3936a6cSJeremy Morse   // justify having a PHI on entry to loop3. The only way to completely
1729a3936a6cSJeremy Morse   // value-propagate these PHIs away would be to speculatively explore what
1730a3936a6cSJeremy Morse   // PHIs could be eliminated and what that would lead to; which is
1731a3936a6cSJeremy Morse   // combinatorially complex.
1732a3936a6cSJeremy Morse   // Happily:
1733a3936a6cSJeremy Morse   //  a) In this scenario, we always have a tracked location for LiveInRsp
1734a3936a6cSJeremy Morse   //     anyway, so there's no loss in availability,
1735a3936a6cSJeremy Morse   //  b) Only DBG_PHIs of a register would be vunlerable to this scenario, and
1736a3936a6cSJeremy Morse   //     even then only if a true PHI became a DBG_PHI and was then optimised
1737a3936a6cSJeremy Morse   //     through branch folding to no longer be at a CFG join,
1738a3936a6cSJeremy Morse   //  c) The register allocator can spot this kind of redundant COPY easily,
1739a3936a6cSJeremy Morse   //     and eliminate it.
1740a3936a6cSJeremy Morse   //
1741a3936a6cSJeremy Morse   // This unit test left in as a reference for the limitations of this
1742a3936a6cSJeremy Morse   // approach. PHIs will be left in $rsp on entry to each block.
1743a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1744a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RaxPHIInBlk3});
1745ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1746ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1747ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1748ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1749ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1750ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1751ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1752ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1753ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1754ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1755ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1756ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1757ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1758a3936a6cSJeremy Morse   // Check $rax's value. It should have $rsps value from the entry block
1759a3936a6cSJeremy Morse   // onwards.
1760ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1761ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], LiveInRsp);
1762ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], LiveInRsp);
1763ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][1], LiveInRsp);
1764ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][1], LiveInRsp);
1765ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
1766ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
1767ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
1768ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][1], LiveInRsp);
1769ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][1], LiveInRsp);
1770a3936a6cSJeremy Morse }
1771b5426cedSJeremy Morse 
1772b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
1773b5426cedSJeremy Morse   //        entry
1774b5426cedSJeremy Morse   //        /  \
1775b5426cedSJeremy Morse   //      br1  br2
1776b5426cedSJeremy Morse   //        \  /
1777b5426cedSJeremy Morse   //         ret
1778b5426cedSJeremy Morse   setupDiamondBlocks();
1779b5426cedSJeremy Morse 
1780b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1781b5426cedSJeremy Morse   LocIdx RspLoc(0);
1782b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
1783b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1784b5426cedSJeremy Morse 
1785acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(4, 2);
1786b5426cedSJeremy Morse 
1787ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
1788b5426cedSJeremy Morse 
1789b5426cedSJeremy Morse   unsigned EntryBlk = 0, Br2Blk = 2, RetBlk = 3;
1790b5426cedSJeremy Morse 
1791b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1792b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1793b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Br2Blk, 0, RspLoc);
1794b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3(RetBlk, 0, RspLoc);
179553fd5af6SStephen Tozer   ValueIDNum RaxPHIInBlk3(RetBlk, 0, RaxLoc);
1796b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
1797b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
1798b5ba5d2aSStephen Tozer   DbgOpID RspPHIInBlk2ID = addValueDbgOp(RspPHIInBlk2);
179953fd5af6SStephen Tozer   DbgOpID RspPHIInBlk3ID = addValueDbgOp(RspPHIInBlk3);
180053fd5af6SStephen Tozer   DbgOpID RaxPHIInBlk3ID = addValueDbgOp(RaxPHIInBlk3);
180153fd5af6SStephen Tozer   DbgOpID ConstZeroID = addConstDbgOp(MachineOperand::CreateImm(0));
1802b5426cedSJeremy Morse 
1803b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
180411ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
180553fd5af6SStephen Tozer   DIExpression *TwoOpExpr =
180653fd5af6SStephen Tozer       DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
180753fd5af6SStephen Tozer                               1, dwarf::DW_OP_plus});
180853fd5af6SStephen Tozer   DbgValueProperties TwoOpProps(TwoOpExpr, false, true);
180989950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
181089950adeSJeremy Morse   VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef));
1811b5426cedSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
1812b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
1813b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
1814b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
1815b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
1816b5426cedSJeremy Morse 
1817b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
1818b5426cedSJeremy Morse   for (const auto *Pred : MBB3->predecessors())
1819b5426cedSJeremy Morse     Preds.push_back(Pred);
1820b5426cedSJeremy Morse 
1821b5426cedSJeremy Morse   // Specify the live-outs around the joining block.
1822ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
1823ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRax;
1824b5426cedSJeremy Morse 
182553fd5af6SStephen Tozer   bool Result;
182653fd5af6SStephen Tozer   SmallVector<DbgOpID> OutValues;
1827b5426cedSJeremy Morse 
1828b5426cedSJeremy Morse   // Simple case: join two distinct values on entry to the block.
1829b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1830b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
183153fd5af6SStephen Tozer   OutValues.clear();
183253fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1833b5426cedSJeremy Morse   // Should have picked a PHI in $rsp in block 3.
1834b5426cedSJeremy Morse   EXPECT_TRUE(Result);
18359da51402SLuke Benes   if (Result) {
183653fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
18379da51402SLuke Benes   }
1838b5426cedSJeremy Morse 
1839b5426cedSJeremy Morse   // If the incoming values are swapped between blocks, we should not
1840b5426cedSJeremy Morse   // successfully join. The CFG merge would select the right values, but in
1841b5426cedSJeremy Morse   // the wrong conditions.
1842b5426cedSJeremy Morse   std::swap(VLiveOuts[1], VLiveOuts[2]);
184353fd5af6SStephen Tozer   OutValues.clear();
184453fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1845b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1846b5426cedSJeremy Morse 
1847b5426cedSJeremy Morse   // Swap back,
1848b5426cedSJeremy Morse   std::swap(VLiveOuts[1], VLiveOuts[2]);
1849b5426cedSJeremy Morse   // Setting one of these to being a constant should prohibit merging.
185053fd5af6SStephen Tozer   VLiveOuts[1].setDbgOpIDs(ConstZeroID);
185153fd5af6SStephen Tozer   OutValues.clear();
185253fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1853b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1854b5426cedSJeremy Morse 
185553fd5af6SStephen Tozer   // Setting both to being identical constants should result in a valid join
185653fd5af6SStephen Tozer   // with a constant value.
185789950adeSJeremy Morse   VLiveOuts[2] = VLiveOuts[1];
185853fd5af6SStephen Tozer   OutValues.clear();
185953fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
186053fd5af6SStephen Tozer   EXPECT_TRUE(Result);
186153fd5af6SStephen Tozer   if (Result) {
186253fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], ConstZeroID);
186353fd5af6SStephen Tozer   }
1864b5426cedSJeremy Morse 
1865b5426cedSJeremy Morse   // NoVals shouldn't join with anything else.
1866b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
186789950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::NoVal);
186853fd5af6SStephen Tozer   OutValues.clear();
186953fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1870b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1871b5426cedSJeremy Morse 
1872b5426cedSJeremy Morse   // We might merge in another VPHI in such a join. Present pickVPHILoc with
1873b5426cedSJeremy Morse   // such a scenario: first, where one incoming edge has a VPHI with no known
1874b5426cedSJeremy Morse   // value. This represents an edge where there was a PHI value that can't be
1875b5426cedSJeremy Morse   // found in the register file -- we can't subsequently find a PHI here.
1876b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
187789950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
187853fd5af6SStephen Tozer   OutValues.clear();
187953fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1880b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1881b5426cedSJeremy Morse 
1882b5426cedSJeremy Morse   // However, if we know the value of the incoming VPHI, we can search for its
1883b5426cedSJeremy Morse   // location. Use a PHI machine-value for doing this, as VPHIs should always
1884b5426cedSJeremy Morse   // have PHI values, or they should have been eliminated.
1885ab49dce0SJeremy Morse   MOutLocs[2][0] = RspPHIInBlk2;
1886b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
188789950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
1888b5ba5d2aSStephen Tozer   VLiveOuts[2].setDbgOpIDs(RspPHIInBlk2ID); // Set location where PHI happens.
188953fd5af6SStephen Tozer   OutValues.clear();
189053fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1891b5426cedSJeremy Morse   EXPECT_TRUE(Result);
18929da51402SLuke Benes   if (Result) {
189353fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
18949da51402SLuke Benes   }
1895b5426cedSJeremy Morse 
1896b5426cedSJeremy Morse   // If that value isn't available from that block, don't join.
1897ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
189853fd5af6SStephen Tozer   OutValues.clear();
189953fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1900b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1901b5426cedSJeremy Morse 
1902b5426cedSJeremy Morse   // Check that we don't pick values when the properties disagree, for example
1903b5426cedSJeremy Morse   // different indirectness or DIExpression.
190453fd5af6SStephen Tozer   MOutLocs[2][0] = LiveInRax;
190589950adeSJeremy Morse   DIExpression *NewExpr =
190689950adeSJeremy Morse       DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
190711ce014aSStephen Tozer   DbgValueProperties PropsWithExpr(NewExpr, false, false);
1908b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1909b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithExpr);
191053fd5af6SStephen Tozer   OutValues.clear();
191153fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1912b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1913b5426cedSJeremy Morse 
191411ce014aSStephen Tozer   DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
1915b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
1916b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
191753fd5af6SStephen Tozer   OutValues.clear();
191853fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
191953fd5af6SStephen Tozer   EXPECT_FALSE(Result);
192053fd5af6SStephen Tozer 
192153fd5af6SStephen Tozer   // When we have operands with values [A, B] and [B, A], we do not necessarily
192253fd5af6SStephen Tozer   // pick identical join locations for each operand if the locations of those
192353fd5af6SStephen Tozer   // values differ between incoming basic blocks.
192453fd5af6SStephen Tozer   MOutLocs[1][0] = LiveInRsp;
192553fd5af6SStephen Tozer   MOutLocs[2][0] = LiveInRax;
192653fd5af6SStephen Tozer   MOutLocs[1][1] = LiveInRax;
192753fd5af6SStephen Tozer   MOutLocs[2][1] = LiveInRsp;
192853fd5af6SStephen Tozer   DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
192953fd5af6SStephen Tozer   DbgOpID Locs1[] = {LiveInRaxID, LiveInRspID};
193053fd5af6SStephen Tozer   VLiveOuts[1] = DbgValue(Locs0, TwoOpProps);
193153fd5af6SStephen Tozer   VLiveOuts[2] = DbgValue(Locs1, TwoOpProps);
193253fd5af6SStephen Tozer   OutValues.clear();
193353fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
193453fd5af6SStephen Tozer   // Should have picked PHIs in block 3.
193553fd5af6SStephen Tozer   EXPECT_TRUE(Result);
193653fd5af6SStephen Tozer   if (Result) {
193753fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
193853fd5af6SStephen Tozer     EXPECT_EQ(OutValues[1], RaxPHIInBlk3ID);
193953fd5af6SStephen Tozer   }
194053fd5af6SStephen Tozer 
194153fd5af6SStephen Tozer   // When joining identical constants for an operand, we should simply keep that
194253fd5af6SStephen Tozer   // constant while joining the remaining operands as normal.
194353fd5af6SStephen Tozer   DbgOpID Locs2[] = {LiveInRspID, ConstZeroID};
194453fd5af6SStephen Tozer   DbgOpID Locs3[] = {LiveInRaxID, ConstZeroID};
194553fd5af6SStephen Tozer   VLiveOuts[1] = DbgValue(Locs2, TwoOpProps);
194653fd5af6SStephen Tozer   VLiveOuts[2] = DbgValue(Locs3, TwoOpProps);
194753fd5af6SStephen Tozer   OutValues.clear();
194853fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
194953fd5af6SStephen Tozer   EXPECT_TRUE(Result);
195053fd5af6SStephen Tozer   if (Result) {
195153fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk3ID);
195253fd5af6SStephen Tozer     EXPECT_EQ(OutValues[1], ConstZeroID);
195353fd5af6SStephen Tozer   }
195453fd5af6SStephen Tozer 
195553fd5af6SStephen Tozer   // If the debug values have different constants for the same operand, they
195653fd5af6SStephen Tozer   // cannot be joined.
195753fd5af6SStephen Tozer   DbgOpID ConstOneID = addConstDbgOp(MachineOperand::CreateImm(1));
195853fd5af6SStephen Tozer   DbgOpID Locs4[] = {LiveInRaxID, ConstOneID};
19595fa6e8c3SStephen Tozer   VLiveOuts[1] = DbgValue(Locs3, TwoOpProps);
19605fa6e8c3SStephen Tozer   VLiveOuts[2] = DbgValue(Locs4, TwoOpProps);
196153fd5af6SStephen Tozer   OutValues.clear();
196253fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB3, VLiveOutIdx, MOutLocs, Preds);
1963b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1964b5426cedSJeremy Morse }
1965b5426cedSJeremy Morse 
1966b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
1967b5426cedSJeremy Morse   setupSimpleLoop();
1968b5426cedSJeremy Morse   //    entry
1969b5426cedSJeremy Morse   //     |
1970b5426cedSJeremy Morse   //     |/-----\
1971b5426cedSJeremy Morse   //    loopblk |
1972b5426cedSJeremy Morse   //     |\-----/
1973b5426cedSJeremy Morse   //     |
1974b5426cedSJeremy Morse   //     ret
1975b5426cedSJeremy Morse 
1976b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1977b5426cedSJeremy Morse   LocIdx RspLoc(0);
1978b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
1979b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1980b5426cedSJeremy Morse 
1981acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(3, 2);
1982b5426cedSJeremy Morse 
1983ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1984b5426cedSJeremy Morse 
1985b5426cedSJeremy Morse   unsigned EntryBlk = 0, LoopBlk = 1;
1986b5426cedSJeremy Morse 
1987b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1988b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1989b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
1990b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
1991b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
1992b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
199353fd5af6SStephen Tozer   DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
199453fd5af6SStephen Tozer   DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
1995b5426cedSJeremy Morse 
1996b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
199711ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
199853fd5af6SStephen Tozer   DIExpression *TwoOpExpr =
199953fd5af6SStephen Tozer       DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
200053fd5af6SStephen Tozer                               1, dwarf::DW_OP_plus});
200153fd5af6SStephen Tozer   DbgValueProperties TwoOpProps(TwoOpExpr, false, true);
200289950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
200389950adeSJeremy Morse   VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef));
2004b5426cedSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2005b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2006b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2007b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2008b5426cedSJeremy Morse 
2009b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
2010b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
2011b5426cedSJeremy Morse     Preds.push_back(Pred);
2012b5426cedSJeremy Morse 
2013b5426cedSJeremy Morse   // Specify the live-outs around the joining block.
2014ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2015ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
2016b5426cedSJeremy Morse 
201753fd5af6SStephen Tozer   bool Result;
201853fd5af6SStephen Tozer   SmallVector<DbgOpID> OutValues;
2019b5426cedSJeremy Morse 
2020b5426cedSJeremy Morse   // See that we can merge as normal on a backedge.
2021b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2022b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
202353fd5af6SStephen Tozer   OutValues.clear();
202453fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2025b5426cedSJeremy Morse   // Should have picked a PHI in $rsp in block 1.
2026b5426cedSJeremy Morse   EXPECT_TRUE(Result);
20279da51402SLuke Benes   if (Result) {
202853fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
20299da51402SLuke Benes   }
2030b5426cedSJeremy Morse 
2031b5426cedSJeremy Morse   // And that, if the desired values aren't available, we don't merge.
2032ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
203353fd5af6SStephen Tozer   OutValues.clear();
203453fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2035b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2036b5426cedSJeremy Morse 
2037b5426cedSJeremy Morse   // Test the backedge behaviour: PHIs that feed back into themselves can
2038b5426cedSJeremy Morse   // carry this variables value. Feed in LiveInRsp in both $rsp and $rax
2039b5426cedSJeremy Morse   // from the entry block, but only put an appropriate backedge PHI in $rax.
2040b5426cedSJeremy Morse   // Only the $rax location can form the correct PHI.
2041ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2042ab49dce0SJeremy Morse   MOutLocs[0][1] = LiveInRsp;
2043ab49dce0SJeremy Morse   MOutLocs[1][0] = RaxPHIInBlk1;
2044ab49dce0SJeremy Morse   MOutLocs[1][1] = RaxPHIInBlk1;
2045b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2046b5426cedSJeremy Morse   // Crucially, a VPHI originating in this block:
204789950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
204853fd5af6SStephen Tozer   OutValues.clear();
204953fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2050b5426cedSJeremy Morse   EXPECT_TRUE(Result);
20519da51402SLuke Benes   if (Result) {
205253fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RaxPHIInBlk1ID);
205353fd5af6SStephen Tozer   }
205453fd5af6SStephen Tozer 
205553fd5af6SStephen Tozer   // Test that we can also find a location when joining a backedge PHI with
205653fd5af6SStephen Tozer   // a variadic debug value.
205753fd5af6SStephen Tozer   MOutLocs[1][0] = RspPHIInBlk1;
205853fd5af6SStephen Tozer   MOutLocs[0][1] = LiveInRax;
205953fd5af6SStephen Tozer   DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
206053fd5af6SStephen Tozer   VLiveOuts[0] = DbgValue(Locs0, TwoOpProps);
206153fd5af6SStephen Tozer   // Crucially, a VPHI originating in this block:
206253fd5af6SStephen Tozer   VLiveOuts[1] = DbgValue(1, TwoOpProps, DbgValue::VPHI);
206353fd5af6SStephen Tozer   OutValues.clear();
206453fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
206553fd5af6SStephen Tozer   EXPECT_TRUE(Result);
206653fd5af6SStephen Tozer   if (Result) {
206753fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
206853fd5af6SStephen Tozer     EXPECT_EQ(OutValues[1], RaxPHIInBlk1ID);
20699da51402SLuke Benes   }
2070b5426cedSJeremy Morse 
2071b5426cedSJeremy Morse   // Merging should not be permitted if there's a usable PHI on the backedge,
2072b5426cedSJeremy Morse   // but it's in the wrong place. (Overwrite $rax).
2073ab49dce0SJeremy Morse   MOutLocs[1][1] = LiveInRax;
207453fd5af6SStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
207553fd5af6SStephen Tozer   OutValues.clear();
207653fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2077b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2078b5426cedSJeremy Morse 
2079b5426cedSJeremy Morse   // Additionally, if the VPHI coming back on the loop backedge isn't from
2080b5426cedSJeremy Morse   // this block (block 1), we can't merge it.
2081ab49dce0SJeremy Morse   MOutLocs[1][1] = RaxPHIInBlk1;
2082b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
208389950adeSJeremy Morse   VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
208453fd5af6SStephen Tozer   OutValues.clear();
208553fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2086b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2087b5426cedSJeremy Morse }
2088b5426cedSJeremy Morse 
2089b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
2090b5426cedSJeremy Morse   // Run some tests similar to pickVPHILocLoops, with more than one backedge,
2091b5426cedSJeremy Morse   // and check that we merge correctly over many candidate locations.
2092b5426cedSJeremy Morse   setupBadlyNestedLoops();
2093b5426cedSJeremy Morse   //           entry
2094b5426cedSJeremy Morse   //             |
2095b5426cedSJeremy Morse   //           loop1 -o
2096b5426cedSJeremy Morse   //             | ^
2097b5426cedSJeremy Morse   //             | ^
2098b5426cedSJeremy Morse   //           loop2 -o
2099b5426cedSJeremy Morse   //             | ^
2100b5426cedSJeremy Morse   //             | ^
2101b5426cedSJeremy Morse   //           loop3 -o
2102b5426cedSJeremy Morse   //             |
2103b5426cedSJeremy Morse   //            ret
2104b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2105b5426cedSJeremy Morse   LocIdx RspLoc(0);
2106b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2107b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2108b5426cedSJeremy Morse   Register RBX = getRegByName("RBX");
2109b5426cedSJeremy Morse   LocIdx RbxLoc = MTracker->lookupOrTrackRegister(RBX);
2110b5426cedSJeremy Morse 
2111acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(5, 3);
2112b5426cedSJeremy Morse 
2113ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 3);
2114b5426cedSJeremy Morse 
2115b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1;
2116b5426cedSJeremy Morse 
2117b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
2118b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
2119b5426cedSJeremy Morse   ValueIDNum LiveInRbx(EntryBlk, 0, RbxLoc);
2120b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
2121b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(Loop1Blk, 0, RaxLoc);
2122b5426cedSJeremy Morse   ValueIDNum RbxPHIInBlk1(Loop1Blk, 0, RbxLoc);
2123b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2124b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
2125b5ba5d2aSStephen Tozer   DbgOpID LiveInRbxID = addValueDbgOp(LiveInRbx);
212653fd5af6SStephen Tozer   DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
212771771f85SKazu Hirata   addValueDbgOp(RaxPHIInBlk1);
212853fd5af6SStephen Tozer   DbgOpID RbxPHIInBlk1ID = addValueDbgOp(RbxPHIInBlk1);
2129b5426cedSJeremy Morse 
2130b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
213111ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
213289950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
213389950adeSJeremy Morse   VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef));
2134b5426cedSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2135b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2136b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2137b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2138b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
2139b5426cedSJeremy Morse   VLiveOutIdx[MBB4] = &VLiveOuts[4];
2140b5426cedSJeremy Morse 
2141b5426cedSJeremy Morse   // We're going to focus on block 1.
2142b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
2143b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
2144b5426cedSJeremy Morse     Preds.push_back(Pred);
2145b5426cedSJeremy Morse 
2146b5426cedSJeremy Morse   // Specify the live-outs around the joining block. Incoming edges from the
2147b5426cedSJeremy Morse   // entry block, self, and loop2.
2148ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2149ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
2150ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRbx;
2151b5426cedSJeremy Morse 
215253fd5af6SStephen Tozer   bool Result;
215353fd5af6SStephen Tozer   SmallVector<DbgOpID> OutValues;
2154b5426cedSJeremy Morse 
2155b5426cedSJeremy Morse   // See that we can merge as normal on a backedge.
2156b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2157b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2158b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
215953fd5af6SStephen Tozer   OutValues.clear();
216053fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2161b5426cedSJeremy Morse   // Should have picked a PHI in $rsp in block 1.
2162b5426cedSJeremy Morse   EXPECT_TRUE(Result);
21639da51402SLuke Benes   if (Result) {
216453fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
21659da51402SLuke Benes   }
2166b5426cedSJeremy Morse 
2167b5426cedSJeremy Morse   // Check too that permuting the live-out locations prevents merging
2168ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRax;
2169ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRbx;
2170ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
217153fd5af6SStephen Tozer   OutValues.clear();
217253fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2173b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2174b5426cedSJeremy Morse 
2175ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2176ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
2177ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRbx;
2178b5426cedSJeremy Morse 
2179b5426cedSJeremy Morse   // Feeding a PHI back on one backedge shouldn't merge (block 1 self backedge
2180b5426cedSJeremy Morse   // wants LiveInRax).
2181ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
218253fd5af6SStephen Tozer   OutValues.clear();
218353fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2184b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2185b5426cedSJeremy Morse 
2186b5426cedSJeremy Morse   // If the variables value on that edge is a VPHI feeding into itself, that's
2187b5426cedSJeremy Morse   // fine.
2188b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
218989950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2190b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
219153fd5af6SStephen Tozer   OutValues.clear();
219253fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2193b5426cedSJeremy Morse   EXPECT_TRUE(Result);
21949da51402SLuke Benes   if (Result) {
219553fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
21969da51402SLuke Benes   }
2197b5426cedSJeremy Morse 
2198b5426cedSJeremy Morse   // Likewise: the other backedge being a VPHI from block 1 should be accepted.
2199ab49dce0SJeremy Morse   MOutLocs[2][0] = RspPHIInBlk1;
2200b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
220189950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
220289950adeSJeremy Morse   VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
220353fd5af6SStephen Tozer   OutValues.clear();
220453fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2205b5426cedSJeremy Morse   EXPECT_TRUE(Result);
22069da51402SLuke Benes   if (Result) {
220753fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RspPHIInBlk1ID);
22089da51402SLuke Benes   }
2209b5426cedSJeremy Morse 
2210b5426cedSJeremy Morse   // Here's where it becomes tricky: we should not merge if there are two
2211b5426cedSJeremy Morse   // _distinct_ backedge PHIs. We can't have a PHI that happens in both rsp
2212b5426cedSJeremy Morse   // and rax for example. We can only pick one location as the live-in.
2213ab49dce0SJeremy Morse   MOutLocs[2][0] = RaxPHIInBlk1;
221453fd5af6SStephen Tozer   OutValues.clear();
221553fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2216b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2217b5426cedSJeremy Morse 
2218b5426cedSJeremy Morse   // The above test sources correct machine-PHI-value from two places. Now
2219b5426cedSJeremy Morse   // try with one machine-PHI-value, but placed in two different locations
2220b5426cedSJeremy Morse   // on the backedge. Again, we can't merge a location here, there's no
2221b5426cedSJeremy Morse   // location that works on all paths.
2222ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2223ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
2224ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
2225ab49dce0SJeremy Morse   MOutLocs[2][1] = RspPHIInBlk1;
222653fd5af6SStephen Tozer   OutValues.clear();
222753fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2228b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2229b5426cedSJeremy Morse 
2230b5426cedSJeremy Morse   // Scatter various PHI values across the available locations. Only rbx (loc 2)
2231b5426cedSJeremy Morse   // has the right value in both backedges -- that's the loc that should be
2232b5426cedSJeremy Morse   // picked.
2233ab49dce0SJeremy Morse   MOutLocs[0][2] = LiveInRsp;
2234ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
2235ab49dce0SJeremy Morse   MOutLocs[1][1] = RaxPHIInBlk1;
2236ab49dce0SJeremy Morse   MOutLocs[1][2] = RbxPHIInBlk1;
2237ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
2238ab49dce0SJeremy Morse   MOutLocs[2][1] = RspPHIInBlk1;
2239ab49dce0SJeremy Morse   MOutLocs[2][2] = RbxPHIInBlk1;
224053fd5af6SStephen Tozer   OutValues.clear();
224153fd5af6SStephen Tozer   Result = pickVPHILoc(OutValues, *MBB1, VLiveOutIdx, MOutLocs, Preds);
2242b5426cedSJeremy Morse   EXPECT_TRUE(Result);
22439da51402SLuke Benes   if (Result) {
224453fd5af6SStephen Tozer     EXPECT_EQ(OutValues[0], RbxPHIInBlk1ID);
2245b5426cedSJeremy Morse   }
22469da51402SLuke Benes }
2247b5426cedSJeremy Morse 
2248b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, vlocJoinDiamond) {
2249b5426cedSJeremy Morse   //        entry
2250b5426cedSJeremy Morse   //        /  \
2251b5426cedSJeremy Morse   //      br1  br2
2252b5426cedSJeremy Morse   //        \  /
2253b5426cedSJeremy Morse   //         ret
2254b5426cedSJeremy Morse   setupDiamondBlocks();
2255b5426cedSJeremy Morse 
2256b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2257b5426cedSJeremy Morse   LocIdx RspLoc(0);
2258b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
225971771f85SKazu Hirata   MTracker->lookupOrTrackRegister(RAX);
2260b5426cedSJeremy Morse 
2261b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = DbgOpID(false, 0);
2262b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = DbgOpID(false, 1);
2263b5426cedSJeremy Morse 
2264b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
226511ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
226689950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
226789950adeSJeremy Morse   VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef));
226889950adeSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2269b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2270b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2271b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2272b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
2273b5426cedSJeremy Morse 
2274b5426cedSJeremy Morse   SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2275b5426cedSJeremy Morse   AllBlocks.insert(MBB0);
2276b5426cedSJeremy Morse   AllBlocks.insert(MBB1);
2277b5426cedSJeremy Morse   AllBlocks.insert(MBB2);
2278b5426cedSJeremy Morse   AllBlocks.insert(MBB3);
2279b5426cedSJeremy Morse 
2280b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
2281b5426cedSJeremy Morse   for (const auto *Pred : MBB3->predecessors())
2282b5426cedSJeremy Morse     Preds.push_back(Pred);
2283b5426cedSJeremy Morse 
2284b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2285b5426cedSJeremy Morse   AllVars.insert(Var);
2286b5426cedSJeremy Morse 
2287b5426cedSJeremy Morse   // vlocJoin is here to propagate incoming values, and eliminate PHIs. Start
2288b5426cedSJeremy Morse   // off by propagating a value into the merging block, number 3.
228989950adeSJeremy Morse   DbgValue JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
2290b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2291b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRspID, EmptyProps);
22928dda516bSJeremy Morse   bool Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2293b5426cedSJeremy Morse   EXPECT_TRUE(Result); // Output locs should have changed.
229489950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2295b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2296b5426cedSJeremy Morse 
2297b5426cedSJeremy Morse   // And if we did it a second time, leaving the live-ins as it was, then
2298b5426cedSJeremy Morse   // we should report no change.
22998dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2300b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2301b5426cedSJeremy Morse 
2302b5426cedSJeremy Morse   // If the live-in variable values are different, but there's no PHI placed
2303b5426cedSJeremy Morse   // in this block, then just pick a location. It should be the first (in RPO)
2304b5426cedSJeremy Morse   // predecessor to avoid being a backedge.
2305b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2306b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
230789950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
23088dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2309b5426cedSJeremy Morse   EXPECT_TRUE(Result);
231089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2311b5426cedSJeremy Morse   // RPO is blocks 0 2 1 3, so LiveInRax is picked as the first predecessor
2312b5426cedSJeremy Morse   // of this join.
2313b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRaxID);
2314b5426cedSJeremy Morse 
2315b5426cedSJeremy Morse   // No tests for whether vlocJoin will pass-through a variable with differing
2316b5426cedSJeremy Morse   // expressions / properties. Those can only come about due to assignments; and
2317b5426cedSJeremy Morse   // for any assignment at all, a PHI should have been placed at the dominance
2318b5426cedSJeremy Morse   // frontier. We rely on the IDF calculator being accurate (which is OK,
2319b5426cedSJeremy Morse   // because so does the rest of LLVM).
2320b5426cedSJeremy Morse 
2321b5426cedSJeremy Morse   // Try placing a PHI. With differing input values (LiveInRsp, LiveInRax),
2322b5426cedSJeremy Morse   // this PHI should not be eliminated.
232389950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
23248dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2325b5426cedSJeremy Morse   // Expect no change.
2326b5426cedSJeremy Morse   EXPECT_FALSE(Result);
232789950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2328b5426cedSJeremy Morse   // This should not have been assigned a fixed value.
2329b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), DbgOpID::UndefID);
233089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 3);
2331b5426cedSJeremy Morse 
2332b5426cedSJeremy Morse   // Try a simple PHI elimination. Put a PHI in block 3, but LiveInRsp on both
2333b5426cedSJeremy Morse   // incoming edges. Re-load in and out-locs with unrelated values; they're
2334b5426cedSJeremy Morse   // irrelevant.
2335b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2336b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRspID, EmptyProps);
233789950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
23388dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2339b5426cedSJeremy Morse   EXPECT_TRUE(Result);
234089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2341b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2342b5426cedSJeremy Morse 
234353125e7dSStephen Tozer   // Try the same PHI elimination but with one incoming value being a VPHI
234453125e7dSStephen Tozer   // referring to the same value.
2345b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
234653125e7dSStephen Tozer   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
2347b5ba5d2aSStephen Tozer   VLiveOuts[2].setDbgOpIDs(LiveInRspID);
234853125e7dSStephen Tozer   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
234953125e7dSStephen Tozer   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
235053125e7dSStephen Tozer   EXPECT_TRUE(Result);
235153125e7dSStephen Tozer   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2352b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
235353125e7dSStephen Tozer 
2354b5426cedSJeremy Morse   // If the "current" live-in is a VPHI, but not a VPHI generated in the current
2355b5426cedSJeremy Morse   // block, then it's the remains of an earlier value propagation. We should
2356b5426cedSJeremy Morse   // value propagate through this merge. Even if the current incoming values
2357b5426cedSJeremy Morse   // disagree, because we've previously determined any VPHI here is redundant.
2358b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2359b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRaxID, EmptyProps);
236089950adeSJeremy Morse   JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
23618dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2362b5426cedSJeremy Morse   EXPECT_TRUE(Result);
236389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2364b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRaxID); // from block 2
2365b5426cedSJeremy Morse 
2366b5426cedSJeremy Morse   // The above test, but test that we will install one value-propagated VPHI
2367b5426cedSJeremy Morse   // over another.
2368b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
236989950adeSJeremy Morse   VLiveOuts[2] = DbgValue(0, EmptyProps, DbgValue::VPHI);
237089950adeSJeremy Morse   JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
23718dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2372b5426cedSJeremy Morse   EXPECT_TRUE(Result);
237389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
237489950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 0);
2375b5426cedSJeremy Morse 
2376b5426cedSJeremy Morse   // We shouldn't eliminate PHIs when properties disagree.
237711ce014aSStephen Tozer   DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
2378b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2379b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
238089950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
23818dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2382b5426cedSJeremy Morse   EXPECT_FALSE(Result);
238389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
238489950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 3);
2385b5426cedSJeremy Morse 
2386b5426cedSJeremy Morse   // Even if properties disagree, we should still value-propagate if there's no
2387b5426cedSJeremy Morse   // PHI to be eliminated. The disagreeing values should work themselves out,
2388b5426cedSJeremy Morse   // seeing how we've determined no PHI is necessary.
2389b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2390b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithIndirect);
239189950adeSJeremy Morse   JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
23928dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2393b5426cedSJeremy Morse   EXPECT_TRUE(Result);
239489950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2395b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2396b5426cedSJeremy Morse   // Also check properties come from block 2, the first RPO predecessor to block
2397b5426cedSJeremy Morse   // three.
239889950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Properties, PropsWithIndirect);
2399b5426cedSJeremy Morse 
2400b5426cedSJeremy Morse   // Again, disagreeing properties, this time the expr, should cause a PHI to
2401b5426cedSJeremy Morse   // not be eliminated.
240289950adeSJeremy Morse   DIExpression *NewExpr =
240389950adeSJeremy Morse       DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
240411ce014aSStephen Tozer   DbgValueProperties PropsWithExpr(NewExpr, false, false);
2405b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRspID, EmptyProps);
2406b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRspID, PropsWithExpr);
240789950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
24088dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2409b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2410b5ba5d2aSStephen Tozer 
2411b5ba5d2aSStephen Tozer   // Try placing a PHI with variadic debug values. With differing input values
2412b5ba5d2aSStephen Tozer   // (LiveInRsp, LiveInRax), this PHI should not be eliminated.
2413b5ba5d2aSStephen Tozer   DIExpression *TwoOpExpr =
2414b5ba5d2aSStephen Tozer       DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
2415b5ba5d2aSStephen Tozer                               1, dwarf::DW_OP_plus});
2416b5ba5d2aSStephen Tozer   DbgValueProperties TwoOpProps(TwoOpExpr, false, true);
2417b5ba5d2aSStephen Tozer   DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
2418b5ba5d2aSStephen Tozer   DbgOpID Locs1[] = {LiveInRaxID, LiveInRspID};
2419b5ba5d2aSStephen Tozer   JoinedLoc = DbgValue(3, TwoOpProps, DbgValue::VPHI);
2420b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(Locs0, TwoOpProps);
2421b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(Locs1, TwoOpProps);
2422b5ba5d2aSStephen Tozer   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2423b5ba5d2aSStephen Tozer   // Expect no change.
2424b5ba5d2aSStephen Tozer   EXPECT_FALSE(Result);
2425b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2426b5ba5d2aSStephen Tozer   // This should not have been assigned a fixed value.
2427b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), DbgOpID::UndefID);
2428b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.BlockNo, 3);
2429b5426cedSJeremy Morse }
2430b5426cedSJeremy Morse 
2431b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, vlocJoinLoops) {
2432b5426cedSJeremy Morse   setupSimpleLoop();
2433b5426cedSJeremy Morse   //    entry
2434b5426cedSJeremy Morse   //     |
2435b5426cedSJeremy Morse   //     |/-----\
2436b5426cedSJeremy Morse   //    loopblk |
2437b5426cedSJeremy Morse   //     |\-----/
2438b5426cedSJeremy Morse   //     |
2439b5426cedSJeremy Morse   //     ret
2440b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2441b5426cedSJeremy Morse   LocIdx RspLoc(0);
2442b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
244371771f85SKazu Hirata   MTracker->lookupOrTrackRegister(RAX);
2444b5426cedSJeremy Morse 
2445b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = DbgOpID(false, 0);
2446b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = DbgOpID(false, 1);
2447b5426cedSJeremy Morse 
2448b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
244911ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
245089950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
245189950adeSJeremy Morse   VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef));
2452849b1794SJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2453b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2454b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2455b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2456b5426cedSJeremy Morse 
2457b5426cedSJeremy Morse   SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2458b5426cedSJeremy Morse   AllBlocks.insert(MBB0);
2459b5426cedSJeremy Morse   AllBlocks.insert(MBB1);
2460b5426cedSJeremy Morse   AllBlocks.insert(MBB2);
2461b5426cedSJeremy Morse 
2462b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
2463b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
2464b5426cedSJeremy Morse     Preds.push_back(Pred);
2465b5426cedSJeremy Morse 
2466b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2467b5426cedSJeremy Morse   AllVars.insert(Var);
2468b5426cedSJeremy Morse 
2469b5426cedSJeremy Morse   // Test some back-edge-specific behaviours of vloc join. Mostly: the fact that
2470b5426cedSJeremy Morse   // VPHIs that arrive on backedges can be eliminated, despite having different
2471b5426cedSJeremy Morse   // values to the predecessor.
2472b5426cedSJeremy Morse 
2473b5426cedSJeremy Morse   // First: when there's no VPHI placed already, propagate the live-in value of
2474b5426cedSJeremy Morse   // the first RPO predecessor.
2475b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2476b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2477b5ba5d2aSStephen Tozer   DbgValue JoinedLoc = DbgValue(LiveInRaxID, EmptyProps);
24788dda516bSJeremy Morse   bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2479b5426cedSJeremy Morse   EXPECT_TRUE(Result);
248089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2481b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2482b5426cedSJeremy Morse 
2483b5426cedSJeremy Morse   // If there is a VPHI: don't elimiante it if there are disagreeing values.
2484b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2485b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
248689950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
24878dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2488b5426cedSJeremy Morse   EXPECT_FALSE(Result);
248989950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
249089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2491b5426cedSJeremy Morse 
2492b5426cedSJeremy Morse   // If we feed this VPHI back into itself though, we can eliminate it.
2493b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
249489950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
249589950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
24968dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2497b5426cedSJeremy Morse   EXPECT_TRUE(Result);
249889950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2499b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2500b5426cedSJeremy Morse 
2501b5426cedSJeremy Morse   // Don't eliminate backedge VPHIs if the predecessors have different
2502b5426cedSJeremy Morse   // properties.
250389950adeSJeremy Morse   DIExpression *NewExpr =
250489950adeSJeremy Morse       DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
250511ce014aSStephen Tozer   DbgValueProperties PropsWithExpr(NewExpr, false, false);
2506b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
250789950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, PropsWithExpr, DbgValue::VPHI);
250889950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
25098dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2510b5426cedSJeremy Morse   EXPECT_FALSE(Result);
251189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
251289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2513b5426cedSJeremy Morse 
2514b5426cedSJeremy Morse   // Backedges with VPHIs, but from the wrong block, shouldn't be eliminated.
2515b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
251689950adeSJeremy Morse   VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
251789950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
25188dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2519b5426cedSJeremy Morse   EXPECT_FALSE(Result);
252089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
252189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2522b5426cedSJeremy Morse }
2523b5426cedSJeremy Morse 
2524b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, vlocJoinBadlyNestedLoops) {
2525b5426cedSJeremy Morse   // Test PHI elimination in the presence of multiple backedges.
2526b5426cedSJeremy Morse   setupBadlyNestedLoops();
2527b5426cedSJeremy Morse   //           entry
2528b5426cedSJeremy Morse   //             |
2529b5426cedSJeremy Morse   //           loop1 -o
2530b5426cedSJeremy Morse   //             | ^
2531b5426cedSJeremy Morse   //             | ^
2532b5426cedSJeremy Morse   //           loop2 -o
2533b5426cedSJeremy Morse   //             | ^
2534b5426cedSJeremy Morse   //             | ^
2535b5426cedSJeremy Morse   //           loop3 -o
2536b5426cedSJeremy Morse   //             |
2537b5426cedSJeremy Morse   //            ret
2538b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2539b5426cedSJeremy Morse   LocIdx RspLoc(0);
2540b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
254171771f85SKazu Hirata   MTracker->lookupOrTrackRegister(RAX);
2542b5426cedSJeremy Morse   Register RBX = getRegByName("RBX");
254371771f85SKazu Hirata   MTracker->lookupOrTrackRegister(RBX);
2544b5426cedSJeremy Morse 
2545b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = DbgOpID(false, 0);
2546b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = DbgOpID(false, 1);
2547b5ba5d2aSStephen Tozer   DbgOpID LiveInRbxID = DbgOpID(false, 2);
2548b5426cedSJeremy Morse 
2549b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
255011ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
255189950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
255289950adeSJeremy Morse   VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef));
2553849b1794SJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2554b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2555b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2556b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2557b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
2558b5426cedSJeremy Morse   VLiveOutIdx[MBB4] = &VLiveOuts[4];
2559b5426cedSJeremy Morse 
2560b5426cedSJeremy Morse   SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2561b5426cedSJeremy Morse   AllBlocks.insert(MBB0);
2562b5426cedSJeremy Morse   AllBlocks.insert(MBB1);
2563b5426cedSJeremy Morse   AllBlocks.insert(MBB2);
2564b5426cedSJeremy Morse   AllBlocks.insert(MBB3);
2565b5426cedSJeremy Morse   AllBlocks.insert(MBB4);
2566b5426cedSJeremy Morse 
2567b5426cedSJeremy Morse   // We're going to focus on block 1.
2568b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 3> Preds;
2569b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
2570b5426cedSJeremy Morse     Preds.push_back(Pred);
2571b5426cedSJeremy Morse 
2572b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2573b5426cedSJeremy Morse   AllVars.insert(Var);
2574b5426cedSJeremy Morse 
2575b5426cedSJeremy Morse   // Test a normal VPHI isn't eliminated.
2576b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
2577b5ba5d2aSStephen Tozer   VLiveOuts[1] = DbgValue(LiveInRaxID, EmptyProps);
2578b5ba5d2aSStephen Tozer   VLiveOuts[2] = DbgValue(LiveInRbxID, EmptyProps);
257989950adeSJeremy Morse   DbgValue JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
25808dda516bSJeremy Morse   bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2581b5426cedSJeremy Morse   EXPECT_FALSE(Result);
258289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
258389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2584b5426cedSJeremy Morse 
2585b5426cedSJeremy Morse   // Common VPHIs on backedges should merge.
2586b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
258789950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
258889950adeSJeremy Morse   VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
258989950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
25908dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2591b5426cedSJeremy Morse   EXPECT_TRUE(Result);
259289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2593b5ba5d2aSStephen Tozer   EXPECT_EQ(JoinedLoc.getDbgOpID(0), LiveInRspID);
2594b5426cedSJeremy Morse 
2595b5426cedSJeremy Morse   // They shouldn't merge if one of their properties is different.
259611ce014aSStephen Tozer   DbgValueProperties PropsWithIndirect(EmptyExpr, true, false);
2597b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
259889950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
259989950adeSJeremy Morse   VLiveOuts[2] = DbgValue(1, PropsWithIndirect, DbgValue::VPHI);
260089950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
26018dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2602b5426cedSJeremy Morse   EXPECT_FALSE(Result);
260389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
260489950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2605b5426cedSJeremy Morse 
2606b5426cedSJeremy Morse   // VPHIs from different blocks should not merge.
2607b5ba5d2aSStephen Tozer   VLiveOuts[0] = DbgValue(LiveInRspID, EmptyProps);
260889950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
260989950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
261089950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
26118dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2612b5426cedSJeremy Morse   EXPECT_FALSE(Result);
261389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
261489950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2615b5426cedSJeremy Morse }
2616b5426cedSJeremy Morse 
2617b5426cedSJeremy Morse // Above are tests for picking VPHI locations, and eliminating VPHIs. No
2618b5426cedSJeremy Morse // unit-tests are written for evaluating the transfer function as that's
2619b5426cedSJeremy Morse // pretty straight forwards, or applying VPHI-location-picking to live-ins.
2620b5426cedSJeremy Morse // Instead, pre-set some machine locations and apply buildVLocValueMap to the
2621b5426cedSJeremy Morse // existing CFG patterns.
2622b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocSingleBlock) {
2623b5426cedSJeremy Morse   setupSingleBlock();
2624b5426cedSJeremy Morse 
2625b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2626b5426cedSJeremy Morse   LocIdx RspLoc(0);
2627b5426cedSJeremy Morse 
2628acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(1, 2);
2629b5426cedSJeremy Morse 
2630b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(0, 0, RspLoc);
2631b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2632ab49dce0SJeremy Morse   MInLocs[0][0] = MOutLocs[0][0] = LiveInRsp;
2633b5426cedSJeremy Morse 
2634b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2635676efd0fSJeremy Morse   DebugVariableID VarID = LDV->getDVMap().insertDVID(Var, OutermostLoc);
263611ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
2637b5426cedSJeremy Morse 
2638676efd0fSJeremy Morse   SmallSet<DebugVariableID, 4> AllVars;
2639676efd0fSJeremy Morse   AllVars.insert(VarID);
2640b5426cedSJeremy Morse 
2641b5426cedSJeremy Morse   // Mild hack: rather than constructing machine instructions in each block
2642b5426cedSJeremy Morse   // and creating lexical scopes across them, instead just tell
2643b5426cedSJeremy Morse   // buildVLocValueMap that there's an assignment in every block. That makes
2644b5426cedSJeremy Morse   // every block in scope.
2645b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2646b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
2647b5426cedSJeremy Morse 
2648b5426cedSJeremy Morse   SmallVector<VLocTracker, 1> VLocs;
2649676efd0fSJeremy Morse   VLocs.resize(1, VLocTracker(LDV->getDVMap(), Overlaps, EmptyExpr));
2650b5426cedSJeremy Morse 
2651b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
2652b5426cedSJeremy Morse 
2653b5426cedSJeremy Morse   // Test that, with no assignments at all, no mappings are created for the
2654b5426cedSJeremy Morse   // variable in this function.
2655b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2656ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2657b5426cedSJeremy Morse   EXPECT_EQ(Output.size(), 0ul);
2658b5426cedSJeremy Morse 
2659b5426cedSJeremy Morse   // If we put an assignment in the transfer function, that should... well,
2660b5426cedSJeremy Morse   // do nothing, because we don't store the live-outs.
2661676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2662b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2663ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2664b5426cedSJeremy Morse   EXPECT_EQ(Output.size(), 0ul);
2665b5426cedSJeremy Morse 
2666b5426cedSJeremy Morse   // There is pretty much nothing else of interest to test with a single block.
2667b5426cedSJeremy Morse   // It's not relevant to the SSA-construction parts of variable values.
2668b5426cedSJeremy Morse }
2669b5426cedSJeremy Morse 
2670b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
2671b5426cedSJeremy Morse   setupDiamondBlocks();
2672b5426cedSJeremy Morse   //        entry
2673b5426cedSJeremy Morse   //        /  \
2674b5426cedSJeremy Morse   //      br1  br2
2675b5426cedSJeremy Morse   //        \  /
2676b5426cedSJeremy Morse   //         ret
2677b5426cedSJeremy Morse 
2678b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2679b5426cedSJeremy Morse   LocIdx RspLoc(0);
2680b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2681b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2682b5426cedSJeremy Morse 
2683b5426cedSJeremy Morse   unsigned EntryBlk = 0, RetBlk = 3;
2684b5426cedSJeremy Morse 
2685b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
2686b5426cedSJeremy Morse   ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
2687b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3 = ValueIDNum(RetBlk, 0, RspLoc);
2688b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2689b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
2690b5ba5d2aSStephen Tozer   DbgOpID RspPHIInBlk3ID = addValueDbgOp(RspPHIInBlk3);
2691b5426cedSJeremy Morse 
2692acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(4, 2);
2693b5426cedSJeremy Morse 
2694ab49dce0SJeremy Morse   initValueArray(MInLocs, 4, 2);
2695ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
2696b5426cedSJeremy Morse 
2697b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2698676efd0fSJeremy Morse   DebugVariableID VarID = LDV->getDVMap().insertDVID(Var, OutermostLoc);
269911ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
2700b5426cedSJeremy Morse 
2701676efd0fSJeremy Morse   SmallSet<DebugVariableID, 4> AllVars;
2702676efd0fSJeremy Morse   AllVars.insert(VarID);
2703b5426cedSJeremy Morse 
2704b5426cedSJeremy Morse   // Mild hack: rather than constructing machine instructions in each block
2705b5426cedSJeremy Morse   // and creating lexical scopes across them, instead just tell
2706b5426cedSJeremy Morse   // buildVLocValueMap that there's an assignment in every block. That makes
2707b5426cedSJeremy Morse   // every block in scope.
2708b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2709b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
2710b5426cedSJeremy Morse   AssignBlocks.insert(MBB1);
2711b5426cedSJeremy Morse   AssignBlocks.insert(MBB2);
2712b5426cedSJeremy Morse   AssignBlocks.insert(MBB3);
2713b5426cedSJeremy Morse 
2714b5426cedSJeremy Morse   SmallVector<VLocTracker, 1> VLocs;
2715676efd0fSJeremy Morse   VLocs.resize(4, VLocTracker(LDV->getDVMap(), Overlaps, EmptyExpr));
2716b5426cedSJeremy Morse 
2717b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
2718b5426cedSJeremy Morse 
2719b5426cedSJeremy Morse   // Start off with LiveInRsp in every location.
2720b5426cedSJeremy Morse   for (unsigned int I = 0; I < 4; ++I) {
2721ab49dce0SJeremy Morse     MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
2722ab49dce0SJeremy Morse     MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
2723b5426cedSJeremy Morse   }
2724b5426cedSJeremy Morse 
2725b5426cedSJeremy Morse   auto ClearOutputs = [&]() {
2726b5426cedSJeremy Morse     for (auto &Elem : Output)
2727b5426cedSJeremy Morse       Elem.clear();
2728b5426cedSJeremy Morse   };
2729b5426cedSJeremy Morse   Output.resize(4);
2730b5426cedSJeremy Morse 
2731b5426cedSJeremy Morse   // No assignments -> no values.
2732b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2733ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2734b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2735b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2736b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2737b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2738b5426cedSJeremy Morse 
2739b5426cedSJeremy Morse   // An assignment in the end block should also not affect other blocks; or
2740b5426cedSJeremy Morse   // produce any live-ins.
2741676efd0fSJeremy Morse   VLocs[3].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2742b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2743ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2744b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2745b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2746b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2747b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2748b5426cedSJeremy Morse   ClearOutputs();
2749b5426cedSJeremy Morse 
2750b5426cedSJeremy Morse   // Assignments in either of the side-of-diamond blocks should also not be
2751b5426cedSJeremy Morse   // propagated anywhere.
2752b5426cedSJeremy Morse   VLocs[3].Vars.clear();
2753676efd0fSJeremy Morse   VLocs[2].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2754b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2755ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2756b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2757b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2758b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2759b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2760b5426cedSJeremy Morse   VLocs[2].Vars.clear();
2761b5426cedSJeremy Morse   ClearOutputs();
2762b5426cedSJeremy Morse 
2763676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2764b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2765ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2766b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2767b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2768b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2769b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2770b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2771b5426cedSJeremy Morse   ClearOutputs();
2772b5426cedSJeremy Morse 
2773b5426cedSJeremy Morse   // However: putting an assignment in the first block should propagate variable
2774b5426cedSJeremy Morse   // values through to all other blocks, as it dominates.
2775676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2776b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2777ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2778b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2779b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2780b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2781b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2782b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2783b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2784b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2785b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2786b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2787b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
2788b5426cedSJeremy Morse   ClearOutputs();
2789b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2790b5426cedSJeremy Morse 
2791b5426cedSJeremy Morse   // Additionally, even if that value isn't available in the register file, it
2792b5426cedSJeremy Morse   // should still be propagated, as buildVLocValueMap shouldn't care about
2793b5426cedSJeremy Morse   // what's in the registers (except for PHIs).
2794b5426cedSJeremy Morse   // values through to all other blocks, as it dominates.
2795676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
2796b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2797ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2798b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2799b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2800b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2801b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2802b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2803b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRaxID);
2804b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2805b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
2806b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2807b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
2808b5426cedSJeremy Morse   ClearOutputs();
2809b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2810b5426cedSJeremy Morse 
2811b5426cedSJeremy Morse   // We should get a live-in to the merging block, if there are two assigns of
2812b5426cedSJeremy Morse   // the same value in either side of the diamond.
2813676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2814676efd0fSJeremy Morse   VLocs[2].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2815b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2816ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2817b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2818b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2819b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2820b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2821b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2822b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
2823b5426cedSJeremy Morse   ClearOutputs();
2824b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2825b5426cedSJeremy Morse   VLocs[2].Vars.clear();
2826b5426cedSJeremy Morse 
2827b5426cedSJeremy Morse   // If we assign a value in the entry block, then 'undef' on a branch, we
2828b5426cedSJeremy Morse   // shouldn't have a live-in in the merge block.
2829676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2830676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(EmptyProps, DbgValue::Undef)});
2831b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2832ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2833b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2834b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2835b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2836b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2837b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2838b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2839b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2840b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2841b5426cedSJeremy Morse   ClearOutputs();
2842b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2843b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2844b5426cedSJeremy Morse 
2845b5426cedSJeremy Morse   // Having different values joining into the merge block should mean we have
2846b5426cedSJeremy Morse   // no live-in in that block. Block ones LiveInRax value doesn't appear as a
2847b5426cedSJeremy Morse   // live-in anywhere, it's block internal.
2848676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2849676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
2850b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2851ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2852b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2853b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2854b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2855b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2856b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2857b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2858b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2859b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2860b5426cedSJeremy Morse   ClearOutputs();
2861b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2862b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2863b5426cedSJeremy Morse 
2864b5426cedSJeremy Morse   // But on the other hand, if there's a location in the register file where
2865b5426cedSJeremy Morse   // those two values can be joined, do so.
2866ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
2867676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2868676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
2869b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2870ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2871b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2872b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2873b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2874b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2875b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2876b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2877b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2878b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2879b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2880b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), RspPHIInBlk3ID);
2881b5426cedSJeremy Morse   ClearOutputs();
2882b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2883b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2884b5426cedSJeremy Morse }
2885b5426cedSJeremy Morse 
2886b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
2887b5426cedSJeremy Morse   setupSimpleLoop();
2888b5426cedSJeremy Morse   //    entry
2889b5426cedSJeremy Morse   //     |
2890b5426cedSJeremy Morse   //     |/-----\
2891b5426cedSJeremy Morse   //    loopblk |
2892b5426cedSJeremy Morse   //     |\-----/
2893b5426cedSJeremy Morse   //     |
2894b5426cedSJeremy Morse   //     ret
2895b5426cedSJeremy Morse 
2896b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2897b5426cedSJeremy Morse   LocIdx RspLoc(0);
2898b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2899b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2900b5426cedSJeremy Morse 
2901b5426cedSJeremy Morse   unsigned EntryBlk = 0, LoopBlk = 1;
2902b5426cedSJeremy Morse 
2903b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
2904b5426cedSJeremy Morse   ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
2905b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1 = ValueIDNum(LoopBlk, 0, RspLoc);
2906b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1 = ValueIDNum(LoopBlk, 1, RspLoc);
2907b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1 = ValueIDNum(LoopBlk, 0, RaxLoc);
2908b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
2909b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
2910b5ba5d2aSStephen Tozer   DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
2911b5ba5d2aSStephen Tozer   DbgOpID RspDefInBlk1ID = addValueDbgOp(RspDefInBlk1);
2912b5ba5d2aSStephen Tozer   DbgOpID RaxPHIInBlk1ID = addValueDbgOp(RaxPHIInBlk1);
2913b5426cedSJeremy Morse 
2914acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(3, 2);
2915b5426cedSJeremy Morse 
2916ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
2917ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
2918b5426cedSJeremy Morse 
2919b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
2920676efd0fSJeremy Morse   DebugVariableID VarID = LDV->getDVMap().insertDVID(Var, OutermostLoc);
292111ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
292253fd5af6SStephen Tozer   DIExpression *TwoOpExpr =
292353fd5af6SStephen Tozer       DIExpression::get(Ctx, {dwarf::DW_OP_LLVM_arg, 0, dwarf::DW_OP_LLVM_arg,
292453fd5af6SStephen Tozer                               1, dwarf::DW_OP_plus});
292553fd5af6SStephen Tozer   DbgValueProperties VariadicProps(TwoOpExpr, false, true);
2926b5426cedSJeremy Morse 
2927676efd0fSJeremy Morse   SmallSet<DebugVariableID, 4> AllVars;
2928676efd0fSJeremy Morse   AllVars.insert(VarID);
2929b5426cedSJeremy Morse 
2930b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2931b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
2932b5426cedSJeremy Morse   AssignBlocks.insert(MBB1);
2933b5426cedSJeremy Morse   AssignBlocks.insert(MBB2);
2934b5426cedSJeremy Morse 
2935b5426cedSJeremy Morse   SmallVector<VLocTracker, 3> VLocs;
2936676efd0fSJeremy Morse   VLocs.resize(3, VLocTracker(LDV->getDVMap(), Overlaps, EmptyExpr));
2937b5426cedSJeremy Morse 
2938b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
2939b5426cedSJeremy Morse 
2940b5426cedSJeremy Morse   // Start off with LiveInRsp in every location.
2941b5426cedSJeremy Morse   for (unsigned int I = 0; I < 3; ++I) {
2942ab49dce0SJeremy Morse     MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
2943ab49dce0SJeremy Morse     MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
2944b5426cedSJeremy Morse   }
2945b5426cedSJeremy Morse 
2946b5426cedSJeremy Morse   auto ClearOutputs = [&]() {
2947b5426cedSJeremy Morse     for (auto &Elem : Output)
2948b5426cedSJeremy Morse       Elem.clear();
2949b5426cedSJeremy Morse   };
2950b5426cedSJeremy Morse   Output.resize(3);
2951b5426cedSJeremy Morse 
2952b5426cedSJeremy Morse   // Easy starter: a dominating assign should propagate to all blocks.
2953676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2954b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2955ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2956b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2957b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2958b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2959b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2960b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
2961b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2962b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
2963b5426cedSJeremy Morse   ClearOutputs();
2964b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2965b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2966b5426cedSJeremy Morse 
296753fd5af6SStephen Tozer   // A variadic assignment should behave the same.
296853fd5af6SStephen Tozer   DbgOpID Locs0[] = {LiveInRspID, LiveInRaxID};
2969676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(Locs0, VariadicProps)});
297053fd5af6SStephen Tozer   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output, MOutLocs,
297153fd5af6SStephen Tozer                     MInLocs, VLocs);
297253fd5af6SStephen Tozer   EXPECT_EQ(Output[0].size(), 0ul);
297353fd5af6SStephen Tozer   ASSERT_EQ(Output[1].size(), 1ul);
297453fd5af6SStephen Tozer   ASSERT_EQ(Output[2].size(), 1ul);
297553fd5af6SStephen Tozer   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
297653fd5af6SStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
297753fd5af6SStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(1), LiveInRaxID);
297853fd5af6SStephen Tozer   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
297953fd5af6SStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
298053fd5af6SStephen Tozer   ClearOutputs();
298153fd5af6SStephen Tozer   VLocs[0].Vars.clear();
298253fd5af6SStephen Tozer   VLocs[1].Vars.clear();
298353fd5af6SStephen Tozer 
2984b5426cedSJeremy Morse   // Put an undef assignment in the loop. Should get no live-in value.
2985676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2986676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(EmptyProps, DbgValue::Undef)});
2987b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2988ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2989b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2990b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2991b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2992b5426cedSJeremy Morse   ClearOutputs();
2993b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2994b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2995b5426cedSJeremy Morse 
2996b5426cedSJeremy Morse   // Assignment of the same value should naturally join.
2997676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2998676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
2999b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3000ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3001b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3002b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3003b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3004b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3005b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3006b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3007b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3008b5426cedSJeremy Morse   ClearOutputs();
3009b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3010b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3011b5426cedSJeremy Morse 
3012b5426cedSJeremy Morse   // Assignment of different values shouldn't join with no machine PHI vals.
3013b5426cedSJeremy Morse   // Will be live-in to exit block as it's dominated.
3014676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3015676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
3016b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3017ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3018b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3019b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3020b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3021b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3022b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
3023b5426cedSJeremy Morse   ClearOutputs();
3024b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3025b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3026b5426cedSJeremy Morse 
3027b5426cedSJeremy Morse   // Install a completely unrelated PHI value, that we should not join on. Try
3028b5426cedSJeremy Morse   // with unrelated assign in loop block again.
3029ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
3030ab49dce0SJeremy Morse   MOutLocs[1][0] = RspDefInBlk1;
3031676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3032676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
3033b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3034ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3035b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3036b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3037b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3038b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3039b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
3040b5426cedSJeremy Morse   ClearOutputs();
3041b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3042b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3043b5426cedSJeremy Morse 
3044b5426cedSJeremy Morse   // Now, if we assign RspDefInBlk1 in the loop block, we should be able to
3045b5426cedSJeremy Morse   // find the appropriate PHI.
3046ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
3047ab49dce0SJeremy Morse   MOutLocs[1][0] = RspDefInBlk1;
3048676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3049676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(RspDefInBlk1ID, EmptyProps)});
3050b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3051ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3052b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3053b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3054b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3055b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3056b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3057b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3058b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
3059b5426cedSJeremy Morse   ClearOutputs();
3060b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3061b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3062b5426cedSJeremy Morse 
3063b5426cedSJeremy Morse   // If the PHI happens in a different location, the live-in should happen
3064b5426cedSJeremy Morse   // there.
3065ab49dce0SJeremy Morse   MInLocs[1][0] = LiveInRsp;
3066ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
3067ab49dce0SJeremy Morse   MInLocs[1][1] = RaxPHIInBlk1;
3068ab49dce0SJeremy Morse   MOutLocs[1][1] = RspDefInBlk1;
3069676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3070676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(RspDefInBlk1ID, EmptyProps)});
3071b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3072ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3073b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3074b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3075b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3076b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3077b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RaxPHIInBlk1ID);
3078b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3079b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
3080b5426cedSJeremy Morse   ClearOutputs();
3081b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3082b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3083b5426cedSJeremy Morse 
3084b5426cedSJeremy Morse   // The PHI happening in both places should be handled too. Exactly where
3085b5426cedSJeremy Morse   // isn't important, but if the location picked changes, this test will let
3086b5426cedSJeremy Morse   // you know.
3087ab49dce0SJeremy Morse   MInLocs[1][0] = RaxPHIInBlk1;
3088ab49dce0SJeremy Morse   MOutLocs[1][0] = RspDefInBlk1;
3089ab49dce0SJeremy Morse   MInLocs[1][1] = RaxPHIInBlk1;
3090ab49dce0SJeremy Morse   MOutLocs[1][1] = RspDefInBlk1;
3091676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3092676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(RspDefInBlk1ID, EmptyProps)});
3093b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3094ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3095b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3096b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3097b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3098b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3099b5426cedSJeremy Morse   // Today, the first register is picked.
3100b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3101b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3102b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspDefInBlk1ID);
3103b5426cedSJeremy Morse   ClearOutputs();
3104b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3105b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3106b5426cedSJeremy Morse 
3107b5426cedSJeremy Morse   // If the loop block looked a bit like this:
3108b5426cedSJeremy Morse   //    %0 = PHI %1, %2
3109b5426cedSJeremy Morse   //    [...]
3110b5426cedSJeremy Morse   //    DBG_VALUE %0
3111b5426cedSJeremy Morse   // Then with instr-ref it becomes:
3112b5426cedSJeremy Morse   //    DBG_PHI %0
3113b5426cedSJeremy Morse   //    [...]
3114b5426cedSJeremy Morse   //    DBG_INSTR_REF
3115b5426cedSJeremy Morse   // And we would be feeding a machine PHI-value back around the loop. However:
3116b5426cedSJeremy Morse   // this does not mean we can eliminate the variable value PHI and use the
3117b5426cedSJeremy Morse   // variable value from the entry block: they are distinct values that must be
3118b5426cedSJeremy Morse   // joined at some location by the control flow.
3119b5426cedSJeremy Morse   // [This test input would never occur naturally, the machine-PHI would be
3120b5426cedSJeremy Morse   //  eliminated]
3121ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
3122ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
3123ab49dce0SJeremy Morse   MInLocs[1][1] = LiveInRax;
3124ab49dce0SJeremy Morse   MOutLocs[1][1] = LiveInRax;
3125676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3126676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(RspPHIInBlk1ID, EmptyProps)});
3127b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3128ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3129b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3130b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3131b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3132b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3133b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3134b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3135b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3136b5426cedSJeremy Morse   ClearOutputs();
3137b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3138b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3139b5426cedSJeremy Morse 
3140b5426cedSJeremy Morse   // Test that we can eliminate PHIs. A PHI will be placed at the loop head
3141111fcb0dSFangrui Song   // because there's a def in it.
3142ab49dce0SJeremy Morse   MInLocs[1][0] = LiveInRsp;
3143ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
3144676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3145676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3146b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3147ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3148b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3149b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3150b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3151b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3152b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3153b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3154b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3155b5426cedSJeremy Morse   ClearOutputs();
3156b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3157b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3158b5426cedSJeremy Morse }
3159b5426cedSJeremy Morse 
3160b5426cedSJeremy Morse // test phi elimination with the nested situation
3161b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocNestedLoop) {
3162b5426cedSJeremy Morse   //    entry
3163b5426cedSJeremy Morse   //     |
3164b5426cedSJeremy Morse   //    loop1
3165b5426cedSJeremy Morse   //     ^\
3166b5426cedSJeremy Morse   //     | \    /-\
3167b5426cedSJeremy Morse   //     |  loop2  |
3168b5426cedSJeremy Morse   //     |  /   \-/
3169b5426cedSJeremy Morse   //     ^ /
3170b5426cedSJeremy Morse   //     join
3171b5426cedSJeremy Morse   //     |
3172b5426cedSJeremy Morse   //     ret
3173b5426cedSJeremy Morse   setupNestedLoops();
3174b5426cedSJeremy Morse 
3175b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
3176b5426cedSJeremy Morse   LocIdx RspLoc(0);
3177b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
3178b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
3179b5426cedSJeremy Morse 
3180b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2;
3181b5426cedSJeremy Morse 
3182b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
3183b5426cedSJeremy Morse   ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
3184b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1 = ValueIDNum(Loop1Blk, 0, RspLoc);
3185b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2 = ValueIDNum(Loop2Blk, 0, RspLoc);
3186b5426cedSJeremy Morse   ValueIDNum RspDefInBlk2 = ValueIDNum(Loop2Blk, 1, RspLoc);
3187b5ba5d2aSStephen Tozer   DbgOpID LiveInRspID = addValueDbgOp(LiveInRsp);
3188b5ba5d2aSStephen Tozer   DbgOpID LiveInRaxID = addValueDbgOp(LiveInRax);
3189b5ba5d2aSStephen Tozer   DbgOpID RspPHIInBlk1ID = addValueDbgOp(RspPHIInBlk1);
3190b5ba5d2aSStephen Tozer   DbgOpID RspPHIInBlk2ID = addValueDbgOp(RspPHIInBlk2);
3191b5ba5d2aSStephen Tozer   DbgOpID RspDefInBlk2ID = addValueDbgOp(RspDefInBlk2);
3192b5426cedSJeremy Morse 
3193acacec3bSFelipe de Azevedo Piovezan   auto [MInLocs, MOutLocs] = allocValueTables(5, 2);
3194b5426cedSJeremy Morse 
3195ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
3196ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
3197b5426cedSJeremy Morse 
3198b6a01caaSKazu Hirata   DebugVariable Var(FuncVariable, std::nullopt, nullptr);
3199676efd0fSJeremy Morse   DebugVariableID VarID = LDV->getDVMap().insertDVID(Var, OutermostLoc);
320011ce014aSStephen Tozer   DbgValueProperties EmptyProps(EmptyExpr, false, false);
3201b5426cedSJeremy Morse 
3202676efd0fSJeremy Morse   SmallSet<DebugVariableID, 4> AllVars;
3203676efd0fSJeremy Morse   AllVars.insert(VarID);
3204b5426cedSJeremy Morse 
3205b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 5> AssignBlocks;
3206b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
3207b5426cedSJeremy Morse   AssignBlocks.insert(MBB1);
3208b5426cedSJeremy Morse   AssignBlocks.insert(MBB2);
3209b5426cedSJeremy Morse   AssignBlocks.insert(MBB3);
3210b5426cedSJeremy Morse   AssignBlocks.insert(MBB4);
3211b5426cedSJeremy Morse 
3212b5426cedSJeremy Morse   SmallVector<VLocTracker, 5> VLocs;
3213676efd0fSJeremy Morse   VLocs.resize(5, VLocTracker(LDV->getDVMap(), Overlaps, EmptyExpr));
3214b5426cedSJeremy Morse 
3215b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
3216b5426cedSJeremy Morse 
3217b5426cedSJeremy Morse   // Start off with LiveInRsp in every location.
3218b5426cedSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
3219ab49dce0SJeremy Morse     MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
3220ab49dce0SJeremy Morse     MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
3221b5426cedSJeremy Morse   }
3222b5426cedSJeremy Morse 
3223b5426cedSJeremy Morse   auto ClearOutputs = [&]() {
3224b5426cedSJeremy Morse     for (auto &Elem : Output)
3225b5426cedSJeremy Morse       Elem.clear();
3226b5426cedSJeremy Morse   };
3227b5426cedSJeremy Morse   Output.resize(5);
3228b5426cedSJeremy Morse 
3229b5426cedSJeremy Morse   // A dominating assign should propagate to all blocks.
3230676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3231b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3232ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3233b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3234b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3235b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3236b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3237b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3238b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3239b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3240b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3241b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3242b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3243b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
3244b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3245b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRspID);
3246b5426cedSJeremy Morse   ClearOutputs();
3247b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3248b5426cedSJeremy Morse 
3249b5426cedSJeremy Morse   // Test that an assign in the inner loop causes unresolved PHIs at the heads
3250b5426cedSJeremy Morse   // of both loops, and no output location. Dominated blocks do get values.
3251676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3252676efd0fSJeremy Morse   VLocs[2].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
3253b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3254ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3255b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3256b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3257b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3258b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3259b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3260b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3261b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3262b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3263b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3264b5426cedSJeremy Morse   ClearOutputs();
3265b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3266b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3267b5426cedSJeremy Morse 
3268b5426cedSJeremy Morse   // Same test, but with no assignment in block 0. We should still get values
3269b5426cedSJeremy Morse   // in dominated blocks.
3270676efd0fSJeremy Morse   VLocs[2].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
3271b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3272ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3273b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3274b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3275b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3276b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3277b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3278b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3279b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3280b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3281b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3282b5426cedSJeremy Morse   ClearOutputs();
3283b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3284b5426cedSJeremy Morse 
3285b5426cedSJeremy Morse   // Similarly, assignments in the outer loop gives location to dominated
3286b5426cedSJeremy Morse   // blocks, but no PHI locations are found at the outer loop head.
3287676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3288676efd0fSJeremy Morse   VLocs[3].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
3289b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3290ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3291b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3292b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3293b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3294b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
3295b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3296b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3297b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3298b5426cedSJeremy Morse   ClearOutputs();
3299b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3300b5426cedSJeremy Morse   VLocs[3].Vars.clear();
3301b5426cedSJeremy Morse 
3302676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3303676efd0fSJeremy Morse   VLocs[1].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
3304b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3305ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3306b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3307b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3308b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3309b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3310b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3311b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3312b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRaxID);
3313b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3314b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3315b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3316b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3317b5426cedSJeremy Morse   ClearOutputs();
3318b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3319b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3320b5426cedSJeremy Morse 
3321b5426cedSJeremy Morse   // With an assignment of the same value in the inner loop, we should work out
3322b5426cedSJeremy Morse   // that all PHIs can be eliminated and the same value is live-through the
3323b5426cedSJeremy Morse   // whole function.
3324676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3325676efd0fSJeremy Morse   VLocs[2].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3326b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3327ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3328b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3329b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 1ul);
3330b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 1ul);
3331b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3332b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3333b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3334b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), LiveInRspID);
3335b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3336b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), LiveInRspID);
3337b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3338b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRspID);
3339b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3340b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRspID);
3341b5426cedSJeremy Morse   ClearOutputs();
3342b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3343b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3344b5426cedSJeremy Morse 
3345b5426cedSJeremy Morse   // If we have an assignment in the inner loop, and a PHI for it at the inner
3346b5426cedSJeremy Morse   // loop head, we could find a live-in location for the inner loop. But because
3347b5426cedSJeremy Morse   // the outer loop has no PHI, we can't find a variable value for outer loop
3348b5426cedSJeremy Morse   // head, so can't have a live-in value for the inner loop head.
3349ab49dce0SJeremy Morse   MInLocs[2][0] = RspPHIInBlk2;
3350ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRax;
3351b5426cedSJeremy Morse   // NB: all other machine locations are LiveInRsp, disallowing a PHI in block
3352b5426cedSJeremy Morse   // one. Even though RspPHIInBlk2 isn't available later in the function, we
3353b5426cedSJeremy Morse   // should still produce a live-in value. The fact it's unavailable is a
3354b5426cedSJeremy Morse   // different concern.
3355676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3356676efd0fSJeremy Morse   VLocs[2].Vars.insert({VarID, DbgValue(LiveInRaxID, EmptyProps)});
3357b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3358ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3359b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3360b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3361b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3362b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3363b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3364b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3365b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), LiveInRaxID);
3366b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3367b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), LiveInRaxID);
3368b5426cedSJeremy Morse   ClearOutputs();
3369b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3370b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3371b5426cedSJeremy Morse 
3372b5426cedSJeremy Morse   // Have an assignment in inner loop that can have a PHI resolved; and add a
3373b5426cedSJeremy Morse   // machine value PHI to the outer loop head, so that we can find a location
3374b5426cedSJeremy Morse   // all the way through the function.
3375ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
3376ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
3377ab49dce0SJeremy Morse   MInLocs[2][0] = RspPHIInBlk2;
3378ab49dce0SJeremy Morse   MOutLocs[2][0] = RspDefInBlk2;
3379ab49dce0SJeremy Morse   MInLocs[3][0] = RspDefInBlk2;
3380ab49dce0SJeremy Morse   MOutLocs[3][0] = RspDefInBlk2;
3381676efd0fSJeremy Morse   VLocs[0].Vars.insert({VarID, DbgValue(LiveInRspID, EmptyProps)});
3382676efd0fSJeremy Morse   VLocs[2].Vars.insert({VarID, DbgValue(RspDefInBlk2ID, EmptyProps)});
3383b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3384ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3385b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3386b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3387b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3388b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3389b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3390b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3391b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[1][0].second.getDbgOpID(0), RspPHIInBlk1ID);
3392b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3393b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[2][0].second.getDbgOpID(0), RspPHIInBlk2ID);
3394b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3395b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[3][0].second.getDbgOpID(0), RspDefInBlk2ID);
3396b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3397b5ba5d2aSStephen Tozer   EXPECT_EQ(Output[4][0].second.getDbgOpID(0), RspDefInBlk2ID);
3398b5426cedSJeremy Morse   ClearOutputs();
3399b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3400b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3401b5426cedSJeremy Morse }
3402