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 
9d9eebe3cSJeremy Morse #include "llvm/CodeGen/MIRParser/MIRParser.h"
10989f1c72Sserge-sans-paille #include "llvm/CodeGen/MachineDominators.h"
11838b4a53SJeremy Morse #include "llvm/CodeGen/MachineModuleInfo.h"
12989f1c72Sserge-sans-paille #include "llvm/CodeGen/TargetFrameLowering.h"
13989f1c72Sserge-sans-paille #include "llvm/CodeGen/TargetInstrInfo.h"
14838b4a53SJeremy Morse #include "llvm/CodeGen/TargetLowering.h"
15989f1c72Sserge-sans-paille #include "llvm/CodeGen/TargetRegisterInfo.h"
16838b4a53SJeremy Morse #include "llvm/CodeGen/TargetSubtargetInfo.h"
17838b4a53SJeremy Morse #include "llvm/IR/DIBuilder.h"
18838b4a53SJeremy Morse #include "llvm/IR/DebugInfoMetadata.h"
19838b4a53SJeremy Morse #include "llvm/IR/IRBuilder.h"
20838b4a53SJeremy Morse #include "llvm/MC/TargetRegistry.h"
21d9eebe3cSJeremy Morse #include "llvm/Support/MemoryBuffer.h"
22838b4a53SJeremy Morse #include "llvm/Support/TargetSelect.h"
23838b4a53SJeremy Morse #include "llvm/Target/TargetMachine.h"
24838b4a53SJeremy Morse #include "llvm/Target/TargetOptions.h"
25838b4a53SJeremy Morse 
26838b4a53SJeremy Morse #include "../lib/CodeGen/LiveDebugValues/InstrRefBasedImpl.h"
27838b4a53SJeremy Morse 
28838b4a53SJeremy Morse #include "gtest/gtest.h"
29838b4a53SJeremy Morse 
30838b4a53SJeremy Morse using namespace llvm;
31838b4a53SJeremy Morse using namespace LiveDebugValues;
32838b4a53SJeremy Morse 
33838b4a53SJeremy Morse // Include helper functions to ease the manipulation of MachineFunctions
34838b4a53SJeremy Morse #include "MFCommon.inc"
35838b4a53SJeremy Morse 
36838b4a53SJeremy Morse class InstrRefLDVTest : public testing::Test {
37838b4a53SJeremy Morse public:
38a3936a6cSJeremy Morse   friend class InstrRefBasedLDV;
39a3936a6cSJeremy Morse   using MLocTransferMap = InstrRefBasedLDV::MLocTransferMap;
40a3936a6cSJeremy Morse 
41838b4a53SJeremy Morse   LLVMContext Ctx;
42d9eebe3cSJeremy Morse   std::unique_ptr<Module> Mod;
43a3936a6cSJeremy Morse   std::unique_ptr<TargetMachine> Machine;
44838b4a53SJeremy Morse   std::unique_ptr<MachineFunction> MF;
45a3936a6cSJeremy Morse   std::unique_ptr<MachineDominatorTree> DomTree;
46d9eebe3cSJeremy Morse   std::unique_ptr<MachineModuleInfo> MMI;
47838b4a53SJeremy Morse   DICompileUnit *OurCU;
48838b4a53SJeremy Morse   DIFile *OurFile;
49838b4a53SJeremy Morse   DISubprogram *OurFunc;
50838b4a53SJeremy Morse   DILexicalBlock *OurBlock, *AnotherBlock;
51838b4a53SJeremy Morse   DISubprogram *ToInlineFunc;
52838b4a53SJeremy Morse   DILexicalBlock *ToInlineBlock;
53b5426cedSJeremy Morse   DILocalVariable *FuncVariable;
54b5426cedSJeremy Morse   DIBasicType *LongInt;
55b5426cedSJeremy Morse   DIExpression *EmptyExpr;
560eee8445SJeremy Morse   LiveDebugValues::OverlapMap Overlaps;
57838b4a53SJeremy Morse 
58838b4a53SJeremy Morse   DebugLoc OutermostLoc, InBlockLoc, NotNestedBlockLoc, InlinedLoc;
59838b4a53SJeremy Morse 
60b5426cedSJeremy Morse   MachineBasicBlock *MBB0, *MBB1, *MBB2, *MBB3, *MBB4;
61a3936a6cSJeremy Morse 
62a3936a6cSJeremy Morse   std::unique_ptr<InstrRefBasedLDV> LDV;
63a3936a6cSJeremy Morse   std::unique_ptr<MLocTracker> MTracker;
64b5426cedSJeremy Morse   std::unique_ptr<VLocTracker> VTracker;
65838b4a53SJeremy Morse 
66d9eebe3cSJeremy Morse   SmallString<256> MIRStr;
67d9eebe3cSJeremy Morse 
InstrRefLDVTest()68d9eebe3cSJeremy Morse   InstrRefLDVTest() : Ctx(), Mod(std::make_unique<Module>("beehives", Ctx)) {}
69a3936a6cSJeremy Morse 
SetUp()70a3936a6cSJeremy Morse   void SetUp() {
71838b4a53SJeremy Morse     // Boilerplate that creates a MachineFunction and associated blocks.
72a3936a6cSJeremy Morse 
73d9eebe3cSJeremy Morse     Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-"
74d9eebe3cSJeremy Morse                        "n8:16:32:64-S128");
75a3936a6cSJeremy Morse     Triple TargetTriple("x86_64--");
76a3936a6cSJeremy Morse     std::string Error;
77a3936a6cSJeremy Morse     const Target *T = TargetRegistry::lookupTarget("", TargetTriple, Error);
78a3936a6cSJeremy Morse     if (!T)
79a3936a6cSJeremy Morse       GTEST_SKIP();
80a3936a6cSJeremy Morse 
81a3936a6cSJeremy Morse     TargetOptions Options;
82d9eebe3cSJeremy Morse     Machine = std::unique_ptr<TargetMachine>(
83d9eebe3cSJeremy Morse         T->createTargetMachine(Triple::normalize("x86_64--"), "", "", Options,
84d9eebe3cSJeremy Morse                                None, None, CodeGenOpt::Aggressive));
85a3936a6cSJeremy Morse 
86a3936a6cSJeremy Morse     auto Type = FunctionType::get(Type::getVoidTy(Ctx), false);
87d9eebe3cSJeremy Morse     auto F =
88d9eebe3cSJeremy Morse         Function::Create(Type, GlobalValue::ExternalLinkage, "Test", &*Mod);
89a3936a6cSJeremy Morse 
90a3936a6cSJeremy Morse     unsigned FunctionNum = 42;
91d9eebe3cSJeremy Morse     MMI = std::make_unique<MachineModuleInfo>((LLVMTargetMachine *)&*Machine);
92a3936a6cSJeremy Morse     const TargetSubtargetInfo &STI = *Machine->getSubtargetImpl(*F);
93a3936a6cSJeremy Morse 
94d9eebe3cSJeremy Morse     MF = std::make_unique<MachineFunction>(*F, (LLVMTargetMachine &)*Machine,
95d9eebe3cSJeremy Morse                                            STI, FunctionNum, *MMI);
96a3936a6cSJeremy Morse 
97a3936a6cSJeremy Morse     // Create metadata: CU, subprogram, some blocks and an inline function
98a3936a6cSJeremy Morse     // scope.
99d9eebe3cSJeremy Morse     DIBuilder DIB(*Mod);
100a3936a6cSJeremy Morse     OurFile = DIB.createFile("xyzzy.c", "/cave");
101a3936a6cSJeremy Morse     OurCU =
102a3936a6cSJeremy Morse         DIB.createCompileUnit(dwarf::DW_LANG_C99, OurFile, "nou", false, "", 0);
103a3936a6cSJeremy Morse     auto OurSubT = DIB.createSubroutineType(DIB.getOrCreateTypeArray(None));
104a3936a6cSJeremy Morse     OurFunc =
105a3936a6cSJeremy Morse         DIB.createFunction(OurCU, "bees", "", OurFile, 1, OurSubT, 1,
106a3936a6cSJeremy Morse                            DINode::FlagZero, DISubprogram::SPFlagDefinition);
107a3936a6cSJeremy Morse     F->setSubprogram(OurFunc);
108a3936a6cSJeremy Morse     OurBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 3);
109a3936a6cSJeremy Morse     AnotherBlock = DIB.createLexicalBlock(OurFunc, OurFile, 2, 6);
110a3936a6cSJeremy Morse     ToInlineFunc =
111a3936a6cSJeremy Morse         DIB.createFunction(OurFile, "shoes", "", OurFile, 10, OurSubT, 10,
112a3936a6cSJeremy Morse                            DINode::FlagZero, DISubprogram::SPFlagDefinition);
113a3936a6cSJeremy Morse 
114a3936a6cSJeremy Morse     // Make some nested scopes.
115a3936a6cSJeremy Morse     OutermostLoc = DILocation::get(Ctx, 3, 1, OurFunc);
116a3936a6cSJeremy Morse     InBlockLoc = DILocation::get(Ctx, 4, 1, OurBlock);
117a3936a6cSJeremy Morse     InlinedLoc = DILocation::get(Ctx, 10, 1, ToInlineFunc, InBlockLoc.get());
118a3936a6cSJeremy Morse 
119a3936a6cSJeremy Morse     // Make a scope that isn't nested within the others.
120a3936a6cSJeremy Morse     NotNestedBlockLoc = DILocation::get(Ctx, 4, 1, AnotherBlock);
121a3936a6cSJeremy Morse 
122b5426cedSJeremy Morse     LongInt = DIB.createBasicType("long", 64, llvm::dwarf::DW_ATE_unsigned);
123b5426cedSJeremy Morse     FuncVariable = DIB.createAutoVariable(OurFunc, "lala", OurFile, 1, LongInt);
124b5426cedSJeremy Morse     EmptyExpr = DIExpression::get(Ctx, {});
125b5426cedSJeremy Morse 
126a3936a6cSJeremy Morse     DIB.finalize();
127a3936a6cSJeremy Morse   }
128a3936a6cSJeremy Morse 
getRegByName(const char * WantedName)129a3936a6cSJeremy Morse   Register getRegByName(const char *WantedName) {
130a3936a6cSJeremy Morse     auto *TRI = MF->getRegInfo().getTargetRegisterInfo();
131a3936a6cSJeremy Morse     // Slow, but works.
132a3936a6cSJeremy Morse     for (unsigned int I = 1; I < TRI->getNumRegs(); ++I) {
133a3936a6cSJeremy Morse       const char *Name = TRI->getName(I);
134a3936a6cSJeremy Morse       if (strcmp(WantedName, Name) == 0)
135a3936a6cSJeremy Morse         return I;
136a3936a6cSJeremy Morse     }
137a3936a6cSJeremy Morse 
138a3936a6cSJeremy Morse     // If this ever fails, something is very wrong with this unit test.
139a3936a6cSJeremy Morse     llvm_unreachable("Can't find register by name");
140a3936a6cSJeremy Morse   }
141a3936a6cSJeremy Morse 
setupLDVObj(MachineFunction * MF)142d9eebe3cSJeremy Morse   InstrRefBasedLDV *setupLDVObj(MachineFunction *MF) {
143a3936a6cSJeremy Morse     // Create a new LDV object, and plug some relevant object ptrs into it.
144a3936a6cSJeremy Morse     LDV = std::make_unique<InstrRefBasedLDV>();
145a3936a6cSJeremy Morse     const TargetSubtargetInfo &STI = MF->getSubtarget();
146a3936a6cSJeremy Morse     LDV->TII = STI.getInstrInfo();
147a3936a6cSJeremy Morse     LDV->TRI = STI.getRegisterInfo();
148a3936a6cSJeremy Morse     LDV->TFI = STI.getFrameLowering();
149a3936a6cSJeremy Morse     LDV->MFI = &MF->getFrameInfo();
150c99fdd45SJeremy Morse     LDV->MRI = &MF->getRegInfo();
151a3936a6cSJeremy Morse 
152a3936a6cSJeremy Morse     DomTree = std::make_unique<MachineDominatorTree>(*MF);
153a3936a6cSJeremy Morse     LDV->DomTree = &*DomTree;
154a3936a6cSJeremy Morse 
155a3936a6cSJeremy Morse     // Future work: unit tests for mtracker / vtracker / ttracker.
156a3936a6cSJeremy Morse 
157a3936a6cSJeremy Morse     // Setup things like the artifical block map, and BlockNo <=> RPO Order
158a3936a6cSJeremy Morse     // mappings.
159a3936a6cSJeremy Morse     LDV->initialSetup(*MF);
160b5426cedSJeremy Morse     LDV->LS.initialize(*MF);
161d9eebe3cSJeremy Morse     addMTracker(MF);
162a3936a6cSJeremy Morse     return &*LDV;
163a3936a6cSJeremy Morse   }
164a3936a6cSJeremy Morse 
addMTracker(MachineFunction * MF)165d9eebe3cSJeremy Morse   void addMTracker(MachineFunction *MF) {
166a3936a6cSJeremy Morse     ASSERT_TRUE(LDV);
167a3936a6cSJeremy Morse     // Add a machine-location-tracking object to LDV. Don't initialize any
168a3936a6cSJeremy Morse     // register locations within it though.
169a3936a6cSJeremy Morse     const TargetSubtargetInfo &STI = MF->getSubtarget();
170a3936a6cSJeremy Morse     MTracker = std::make_unique<MLocTracker>(
171a3936a6cSJeremy Morse           *MF, *LDV->TII, *LDV->TRI, *STI.getTargetLowering());
172a3936a6cSJeremy Morse     LDV->MTracker = &*MTracker;
173a3936a6cSJeremy Morse   }
174a3936a6cSJeremy Morse 
addVTracker()175b5426cedSJeremy Morse   void addVTracker() {
176b5426cedSJeremy Morse     ASSERT_TRUE(LDV);
1770eee8445SJeremy Morse     VTracker = std::make_unique<VLocTracker>(Overlaps, EmptyExpr);
178b5426cedSJeremy Morse     LDV->VTracker = &*VTracker;
179b5426cedSJeremy Morse   }
180b5426cedSJeremy Morse 
181a3936a6cSJeremy Morse   // Some routines for bouncing into LDV,
buildMLocValueMap(FuncValueTable & MInLocs,FuncValueTable & MOutLocs,SmallVectorImpl<MLocTransferMap> & MLocTransfer)182ab49dce0SJeremy Morse   void buildMLocValueMap(FuncValueTable &MInLocs, FuncValueTable &MOutLocs,
183a3936a6cSJeremy Morse                          SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
184a3936a6cSJeremy Morse     LDV->buildMLocValueMap(*MF, MInLocs, MOutLocs, MLocTransfer);
185a3936a6cSJeremy Morse   }
186a3936a6cSJeremy Morse 
placeMLocPHIs(MachineFunction & MF,SmallPtrSetImpl<MachineBasicBlock * > & AllBlocks,FuncValueTable & MInLocs,SmallVectorImpl<MLocTransferMap> & MLocTransfer)18797ddf49eSJeremy Morse   void placeMLocPHIs(MachineFunction &MF,
18897ddf49eSJeremy Morse                      SmallPtrSetImpl<MachineBasicBlock *> &AllBlocks,
189ab49dce0SJeremy Morse                      FuncValueTable &MInLocs,
19097ddf49eSJeremy Morse                      SmallVectorImpl<MLocTransferMap> &MLocTransfer) {
19197ddf49eSJeremy Morse     LDV->placeMLocPHIs(MF, AllBlocks, MInLocs, MLocTransfer);
19297ddf49eSJeremy Morse   }
19397ddf49eSJeremy Morse 
194b5426cedSJeremy Morse   Optional<ValueIDNum>
pickVPHILoc(const MachineBasicBlock & MBB,const DebugVariable & Var,const InstrRefBasedLDV::LiveIdxT & LiveOuts,FuncValueTable & MOutLocs,const SmallVectorImpl<const MachineBasicBlock * > & BlockOrders)195b5426cedSJeremy Morse   pickVPHILoc(const MachineBasicBlock &MBB, const DebugVariable &Var,
196ab49dce0SJeremy Morse               const InstrRefBasedLDV::LiveIdxT &LiveOuts, FuncValueTable &MOutLocs,
197b5426cedSJeremy Morse               const SmallVectorImpl<const MachineBasicBlock *> &BlockOrders) {
198b5426cedSJeremy Morse     return LDV->pickVPHILoc(MBB, Var, LiveOuts, MOutLocs, BlockOrders);
199b5426cedSJeremy Morse   }
200b5426cedSJeremy Morse 
vlocJoin(MachineBasicBlock & MBB,InstrRefBasedLDV::LiveIdxT & VLOCOutLocs,SmallPtrSet<const MachineBasicBlock *,8> & BlocksToExplore,DbgValue & InLoc)201b5426cedSJeremy Morse   bool vlocJoin(MachineBasicBlock &MBB, InstrRefBasedLDV::LiveIdxT &VLOCOutLocs,
202b5426cedSJeremy Morse                 SmallPtrSet<const MachineBasicBlock *, 8> &BlocksToExplore,
20389950adeSJeremy Morse                 DbgValue &InLoc) {
2048dda516bSJeremy Morse     return LDV->vlocJoin(MBB, VLOCOutLocs, BlocksToExplore, InLoc);
205b5426cedSJeremy Morse   }
206b5426cedSJeremy Morse 
buildVLocValueMap(const DILocation * DILoc,const SmallSet<DebugVariable,4> & VarsWeCareAbout,SmallPtrSetImpl<MachineBasicBlock * > & AssignBlocks,InstrRefBasedLDV::LiveInsT & Output,FuncValueTable & MOutLocs,FuncValueTable & MInLocs,SmallVectorImpl<VLocTracker> & AllTheVLocs)207b5426cedSJeremy Morse   void buildVLocValueMap(const DILocation *DILoc,
208b5426cedSJeremy Morse                     const SmallSet<DebugVariable, 4> &VarsWeCareAbout,
209b5426cedSJeremy Morse                     SmallPtrSetImpl<MachineBasicBlock *> &AssignBlocks,
210ab49dce0SJeremy Morse                     InstrRefBasedLDV::LiveInsT &Output, FuncValueTable &MOutLocs,
211ab49dce0SJeremy Morse                     FuncValueTable &MInLocs,
212b5426cedSJeremy Morse                     SmallVectorImpl<VLocTracker> &AllTheVLocs) {
213b5426cedSJeremy Morse     LDV->buildVLocValueMap(DILoc, VarsWeCareAbout, AssignBlocks, Output,
214b5426cedSJeremy Morse                            MOutLocs, MInLocs, AllTheVLocs);
215b5426cedSJeremy Morse   }
216b5426cedSJeremy Morse 
initValueArray(FuncValueTable & Nums,unsigned Blks,unsigned Locs)217ab49dce0SJeremy Morse   void initValueArray(FuncValueTable &Nums, unsigned Blks, unsigned Locs) {
218a3936a6cSJeremy Morse     for (unsigned int I = 0; I < Blks; ++I)
219a3936a6cSJeremy Morse       for (unsigned int J = 0; J < Locs; ++J)
220a3936a6cSJeremy Morse         Nums[I][J] = ValueIDNum::EmptyValue;
221a3936a6cSJeremy Morse   }
222b5426cedSJeremy Morse 
setupSingleBlock()223b5426cedSJeremy Morse   void setupSingleBlock() {
224b5426cedSJeremy Morse     // Add an entry block with nothing but 'ret void' in it.
225b5426cedSJeremy Morse     Function &F = const_cast<llvm::Function &>(MF->getFunction());
226b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
227b5426cedSJeremy Morse     IRBuilder<> IRB(BB0);
228b5426cedSJeremy Morse     IRB.CreateRetVoid();
229b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
230b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
231b5426cedSJeremy Morse     MF->RenumberBlocks();
232b5426cedSJeremy Morse 
233d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
234b5426cedSJeremy Morse   }
235b5426cedSJeremy Morse 
setupDiamondBlocks()236b5426cedSJeremy Morse   void setupDiamondBlocks() {
237b5426cedSJeremy Morse     //        entry
238b5426cedSJeremy Morse     //        /  \
239b5426cedSJeremy Morse     //      br1  br2
240b5426cedSJeremy Morse     //        \  /
241b5426cedSJeremy Morse     //         ret
242b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
243b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "a", &F);
244b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "b", &F);
245b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "c", &F);
246b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "d", &F);
247b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3);
248b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
249b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
250b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
251b5426cedSJeremy Morse     IRB3.CreateRetVoid();
252b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
253b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
254b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
255b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
256b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
257b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
258b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
259b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
260b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
261b5426cedSJeremy Morse     MBB0->addSuccessor(MBB2);
262b5426cedSJeremy Morse     MBB1->addSuccessor(MBB3);
263b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
264b5426cedSJeremy Morse     MF->RenumberBlocks();
265b5426cedSJeremy Morse 
266d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
267b5426cedSJeremy Morse   }
268b5426cedSJeremy Morse 
setupSimpleLoop()269b5426cedSJeremy Morse   void setupSimpleLoop() {
270b5426cedSJeremy Morse     //    entry
271b5426cedSJeremy Morse     //     |
272b5426cedSJeremy Morse     //     |/-----\
273b5426cedSJeremy Morse     //    loopblk |
274b5426cedSJeremy Morse     //     |\-----/
275b5426cedSJeremy Morse     //     |
276b5426cedSJeremy Morse     //     ret
277b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
278b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
279b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "loop", &F);
280b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "ret", &F);
281b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2);
282b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
283b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
284b5426cedSJeremy Morse     IRB2.CreateRetVoid();
285b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
286b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
287b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
288b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
289b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
290b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
291b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
292b5426cedSJeremy Morse     MBB1->addSuccessor(MBB2);
293b5426cedSJeremy Morse     MBB1->addSuccessor(MBB1);
294b5426cedSJeremy Morse     MF->RenumberBlocks();
295b5426cedSJeremy Morse 
296d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
297b5426cedSJeremy Morse   }
298b5426cedSJeremy Morse 
setupNestedLoops()299b5426cedSJeremy Morse   void setupNestedLoops() {
300b5426cedSJeremy Morse     //    entry
301b5426cedSJeremy Morse     //     |
302b5426cedSJeremy Morse     //    loop1
303b5426cedSJeremy Morse     //     ^\
304b5426cedSJeremy Morse     //     | \    /-\
305b5426cedSJeremy Morse     //     |  loop2  |
306b5426cedSJeremy Morse     //     |  /   \-/
307b5426cedSJeremy Morse     //     ^ /
308b5426cedSJeremy Morse     //     join
309b5426cedSJeremy Morse     //     |
310b5426cedSJeremy Morse     //     ret
311b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
312b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
313b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "loop1", &F);
314b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "loop2", &F);
315b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "join", &F);
316b5426cedSJeremy Morse     auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
317b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
318b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
319b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
320b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
321b5426cedSJeremy Morse     IRB3.CreateBr(BB4);
322b5426cedSJeremy Morse     IRB4.CreateRetVoid();
323b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
324b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
325b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
326b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
327b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
328b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
329b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
330b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
331b5426cedSJeremy Morse     MBB4 = MF->CreateMachineBasicBlock(BB4);
332b5426cedSJeremy Morse     MF->insert(MF->end(), MBB4);
333b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
334b5426cedSJeremy Morse     MBB1->addSuccessor(MBB2);
335b5426cedSJeremy Morse     MBB2->addSuccessor(MBB2);
336b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
337b5426cedSJeremy Morse     MBB3->addSuccessor(MBB1);
338b5426cedSJeremy Morse     MBB3->addSuccessor(MBB4);
339b5426cedSJeremy Morse     MF->RenumberBlocks();
340b5426cedSJeremy Morse 
341d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
342b5426cedSJeremy Morse   }
343b5426cedSJeremy Morse 
setupNoDominatingLoop()344b5426cedSJeremy Morse   void setupNoDominatingLoop() {
345b5426cedSJeremy Morse     //           entry
346b5426cedSJeremy Morse     //            / \
347b5426cedSJeremy Morse     //           /   \
348b5426cedSJeremy Morse     //          /     \
349b5426cedSJeremy Morse     //        head1   head2
350b5426cedSJeremy Morse     //        ^  \   /   ^
351b5426cedSJeremy Morse     //        ^   \ /    ^
352b5426cedSJeremy Morse     //        \-joinblk -/
353b5426cedSJeremy Morse     //             |
354b5426cedSJeremy Morse     //            ret
355b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
356b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
357b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "head1", &F);
358b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "head2", &F);
359b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "joinblk", &F);
360b5426cedSJeremy Morse     auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
361b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
362b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
363b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
364b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
365b5426cedSJeremy Morse     IRB3.CreateBr(BB4);
366b5426cedSJeremy Morse     IRB4.CreateRetVoid();
367b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
368b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
369b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
370b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
371b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
372b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
373b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
374b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
375b5426cedSJeremy Morse     MBB4 = MF->CreateMachineBasicBlock(BB4);
376b5426cedSJeremy Morse     MF->insert(MF->end(), MBB4);
377b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
378b5426cedSJeremy Morse     MBB0->addSuccessor(MBB2);
379b5426cedSJeremy Morse     MBB1->addSuccessor(MBB3);
380b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
381b5426cedSJeremy Morse     MBB3->addSuccessor(MBB1);
382b5426cedSJeremy Morse     MBB3->addSuccessor(MBB2);
383b5426cedSJeremy Morse     MBB3->addSuccessor(MBB4);
384b5426cedSJeremy Morse     MF->RenumberBlocks();
385b5426cedSJeremy Morse 
386d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
387b5426cedSJeremy Morse   }
388b5426cedSJeremy Morse 
setupBadlyNestedLoops()389b5426cedSJeremy Morse   void setupBadlyNestedLoops() {
390b5426cedSJeremy Morse     //           entry
391b5426cedSJeremy Morse     //             |
392b5426cedSJeremy Morse     //           loop1 -o
393b5426cedSJeremy Morse     //             | ^
394b5426cedSJeremy Morse     //             | ^
395b5426cedSJeremy Morse     //           loop2 -o
396b5426cedSJeremy Morse     //             | ^
397b5426cedSJeremy Morse     //             | ^
398b5426cedSJeremy Morse     //           loop3 -o
399b5426cedSJeremy Morse     //             |
400b5426cedSJeremy Morse     //            ret
401b5426cedSJeremy Morse     //
402b5426cedSJeremy Morse     // NB: the loop blocks self-loop, which is a bit too fiddly to draw on
403b5426cedSJeremy Morse     // accurately.
404b5426cedSJeremy Morse     llvm::Function &F = const_cast<llvm::Function &>(MF->getFunction());
405b5426cedSJeremy Morse     auto *BB0 = BasicBlock::Create(Ctx, "entry", &F);
406b5426cedSJeremy Morse     auto *BB1 = BasicBlock::Create(Ctx, "loop1", &F);
407b5426cedSJeremy Morse     auto *BB2 = BasicBlock::Create(Ctx, "loop2", &F);
408b5426cedSJeremy Morse     auto *BB3 = BasicBlock::Create(Ctx, "loop3", &F);
409b5426cedSJeremy Morse     auto *BB4 = BasicBlock::Create(Ctx, "ret", &F);
410b5426cedSJeremy Morse     IRBuilder<> IRB0(BB0), IRB1(BB1), IRB2(BB2), IRB3(BB3), IRB4(BB4);
411b5426cedSJeremy Morse     IRB0.CreateBr(BB1);
412b5426cedSJeremy Morse     IRB1.CreateBr(BB2);
413b5426cedSJeremy Morse     IRB2.CreateBr(BB3);
414b5426cedSJeremy Morse     IRB3.CreateBr(BB4);
415b5426cedSJeremy Morse     IRB4.CreateRetVoid();
416b5426cedSJeremy Morse     MBB0 = MF->CreateMachineBasicBlock(BB0);
417b5426cedSJeremy Morse     MF->insert(MF->end(), MBB0);
418b5426cedSJeremy Morse     MBB1 = MF->CreateMachineBasicBlock(BB1);
419b5426cedSJeremy Morse     MF->insert(MF->end(), MBB1);
420b5426cedSJeremy Morse     MBB2 = MF->CreateMachineBasicBlock(BB2);
421b5426cedSJeremy Morse     MF->insert(MF->end(), MBB2);
422b5426cedSJeremy Morse     MBB3 = MF->CreateMachineBasicBlock(BB3);
423b5426cedSJeremy Morse     MF->insert(MF->end(), MBB3);
424b5426cedSJeremy Morse     MBB4 = MF->CreateMachineBasicBlock(BB4);
425b5426cedSJeremy Morse     MF->insert(MF->end(), MBB4);
426b5426cedSJeremy Morse     MBB0->addSuccessor(MBB1);
427b5426cedSJeremy Morse     MBB1->addSuccessor(MBB1);
428b5426cedSJeremy Morse     MBB1->addSuccessor(MBB2);
429b5426cedSJeremy Morse     MBB2->addSuccessor(MBB1);
430b5426cedSJeremy Morse     MBB2->addSuccessor(MBB2);
431b5426cedSJeremy Morse     MBB2->addSuccessor(MBB3);
432b5426cedSJeremy Morse     MBB3->addSuccessor(MBB2);
433b5426cedSJeremy Morse     MBB3->addSuccessor(MBB3);
434b5426cedSJeremy Morse     MBB3->addSuccessor(MBB4);
435b5426cedSJeremy Morse     MF->RenumberBlocks();
436b5426cedSJeremy Morse 
437d9eebe3cSJeremy Morse     setupLDVObj(&*MF);
438d9eebe3cSJeremy Morse   }
439d9eebe3cSJeremy Morse 
readMIRBlock(const char * Input)440d9eebe3cSJeremy Morse   MachineFunction *readMIRBlock(const char *Input) {
441d9eebe3cSJeremy Morse     MIRStr.clear();
442d9eebe3cSJeremy Morse     StringRef S = Twine(Twine(R"MIR(
443d9eebe3cSJeremy Morse --- |
444d9eebe3cSJeremy Morse   target triple = "x86_64-unknown-linux-gnu"
445d9eebe3cSJeremy Morse   define void @test() { ret void }
446d9eebe3cSJeremy Morse ...
447d9eebe3cSJeremy Morse ---
448d9eebe3cSJeremy Morse name: test
449d9eebe3cSJeremy Morse tracksRegLiveness: true
450d9eebe3cSJeremy Morse stack:
451d9eebe3cSJeremy Morse   - { id: 0, name: '', type: spill-slot, offset: -16, size: 8, alignment: 8,
452d9eebe3cSJeremy Morse       stack-id: default, callee-saved-register: '', callee-saved-restored: true,
453d9eebe3cSJeremy Morse       debug-info-variable: '', debug-info-expression: '', debug-info-location: '' }
454d9eebe3cSJeremy Morse body:  |
455d9eebe3cSJeremy Morse    bb.0:
456d9eebe3cSJeremy Morse     liveins: $rdi, $rsi
457d9eebe3cSJeremy Morse )MIR") + Twine(Input) + Twine("...\n"))
458d9eebe3cSJeremy Morse                       .toNullTerminatedStringRef(MIRStr);
459d9eebe3cSJeremy Morse     ;
460d9eebe3cSJeremy Morse 
461d9eebe3cSJeremy Morse     // Clear the "test" function from MMI if it's still present.
462d9eebe3cSJeremy Morse     if (Function *Fn = Mod->getFunction("test"))
463d9eebe3cSJeremy Morse       MMI->deleteMachineFunctionFor(*Fn);
464d9eebe3cSJeremy Morse 
465d9eebe3cSJeremy Morse     auto MemBuf = MemoryBuffer::getMemBuffer(S, "<input>");
466d9eebe3cSJeremy Morse     auto MIRParse = createMIRParser(std::move(MemBuf), Ctx);
467d9eebe3cSJeremy Morse     Mod = MIRParse->parseIRModule();
468d9eebe3cSJeremy Morse     assert(Mod);
469d9eebe3cSJeremy Morse     Mod->setDataLayout("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-"
470d9eebe3cSJeremy Morse                        "n8:16:32:64-S128");
471d9eebe3cSJeremy Morse 
472d9eebe3cSJeremy Morse     bool Result = MIRParse->parseMachineFunctions(*Mod, *MMI);
473d9eebe3cSJeremy Morse     assert(!Result && "Failed to parse unit test machine function?");
474d9eebe3cSJeremy Morse     (void)Result;
475d9eebe3cSJeremy Morse 
476d9eebe3cSJeremy Morse     Function *Fn = Mod->getFunction("test");
477d9eebe3cSJeremy Morse     assert(Fn && "Failed to parse a unit test module string?");
478d9eebe3cSJeremy Morse     Fn->setSubprogram(OurFunc);
479d9eebe3cSJeremy Morse     return MMI->getMachineFunction(*Fn);
480d9eebe3cSJeremy Morse   }
481d9eebe3cSJeremy Morse 
482d9eebe3cSJeremy Morse   void
produceMLocTransferFunction(MachineFunction & MF,SmallVectorImpl<MLocTransferMap> & MLocTransfer,unsigned MaxNumBlocks)483d9eebe3cSJeremy Morse   produceMLocTransferFunction(MachineFunction &MF,
484d9eebe3cSJeremy Morse                               SmallVectorImpl<MLocTransferMap> &MLocTransfer,
485d9eebe3cSJeremy Morse                               unsigned MaxNumBlocks) {
486d9eebe3cSJeremy Morse     LDV->produceMLocTransferFunction(MF, MLocTransfer, MaxNumBlocks);
487b5426cedSJeremy Morse   }
488ab49dce0SJeremy Morse 
489ab49dce0SJeremy Morse   std::pair<FuncValueTable, FuncValueTable>
allocValueTables(unsigned Blocks,unsigned Locs)490ab49dce0SJeremy Morse   allocValueTables(unsigned Blocks, unsigned Locs) {
491ab49dce0SJeremy Morse     FuncValueTable MOutLocs = std::make_unique<ValueTable[]>(Blocks);
492ab49dce0SJeremy Morse     FuncValueTable MInLocs = std::make_unique<ValueTable[]>(Blocks);
493ab49dce0SJeremy Morse 
494ab49dce0SJeremy Morse     for (unsigned int I = 0; I < Blocks; ++I) {
495ab49dce0SJeremy Morse       MOutLocs[I] = std::make_unique<ValueIDNum[]>(Locs);
496ab49dce0SJeremy Morse       MInLocs[I] = std::make_unique<ValueIDNum[]>(Locs);
497ab49dce0SJeremy Morse     }
498ab49dce0SJeremy Morse 
499ab49dce0SJeremy Morse     return std::make_pair(std::move(MOutLocs), std::move(MInLocs));
500ab49dce0SJeremy Morse   }
501a3936a6cSJeremy Morse };
502a3936a6cSJeremy Morse 
TEST_F(InstrRefLDVTest,MTransferDefs)503d9eebe3cSJeremy Morse TEST_F(InstrRefLDVTest, MTransferDefs) {
504d9eebe3cSJeremy Morse   MachineFunction *MF = readMIRBlock(
505d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
506d391e4feSSimon Pilgrim    "    RET64 $rax\n");
507d9eebe3cSJeremy Morse   setupLDVObj(MF);
508d9eebe3cSJeremy Morse 
509d9eebe3cSJeremy Morse   // We should start with only SP tracked.
510d9eebe3cSJeremy Morse   EXPECT_TRUE(MTracker->getNumLocs() == 1);
511d9eebe3cSJeremy Morse 
512d9eebe3cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
513d9eebe3cSJeremy Morse   TransferMap.resize(1);
514d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
515d9eebe3cSJeremy Morse 
516d9eebe3cSJeremy Morse   // Code contains only one register write: that should assign to each of the
517d9eebe3cSJeremy Morse   // aliasing registers. Test that all of them get locations, and have a
518d9eebe3cSJeremy Morse   // corresponding def at the first instr in the function.
519d9eebe3cSJeremy Morse   const char *RegNames[] = {"RAX", "HAX", "EAX", "AX", "AH", "AL"};
520d9eebe3cSJeremy Morse   EXPECT_TRUE(MTracker->getNumLocs() == 7);
521d9eebe3cSJeremy Morse   for (const char *RegName : RegNames) {
522d9eebe3cSJeremy Morse     Register R = getRegByName(RegName);
523d9eebe3cSJeremy Morse     ASSERT_TRUE(MTracker->isRegisterTracked(R));
524d9eebe3cSJeremy Morse     LocIdx L = MTracker->getRegMLoc(R);
525d9eebe3cSJeremy Morse     ValueIDNum V = MTracker->readReg(R);
526d9eebe3cSJeremy Morse     // Value of this register should be: block zero, instruction 1, and the
527d9eebe3cSJeremy Morse     // location it's defined in is itself.
528d9eebe3cSJeremy Morse     ValueIDNum ToCmp(0, 1, L);
529d9eebe3cSJeremy Morse     EXPECT_EQ(V, ToCmp);
530d9eebe3cSJeremy Morse   }
531d9eebe3cSJeremy Morse 
532d9eebe3cSJeremy Morse   // Do the same again, but with an aliasing write. This should write to all
533d9eebe3cSJeremy Morse   // the same registers again, except $ah and $hax (the upper 8 bits of $ax
534d9eebe3cSJeremy Morse   // and 32 bits of $rax resp.).
535d9eebe3cSJeremy Morse   MF = readMIRBlock(
536d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
537d9eebe3cSJeremy Morse    "    $al = MOV8ri 0\n"
538d391e4feSSimon Pilgrim    "    RET64 $rax\n");
539d9eebe3cSJeremy Morse   setupLDVObj(MF);
540d9eebe3cSJeremy Morse   TransferMap.clear();
541d9eebe3cSJeremy Morse   TransferMap.resize(1);
542d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
543d9eebe3cSJeremy Morse 
544d9eebe3cSJeremy Morse   auto TestRegSetSite = [&](const char *Name, unsigned InstrNum) {
545d9eebe3cSJeremy Morse     Register R = getRegByName(Name);
546d9eebe3cSJeremy Morse     ASSERT_TRUE(MTracker->isRegisterTracked(R));
547d9eebe3cSJeremy Morse     LocIdx L = MTracker->getRegMLoc(R);
548d9eebe3cSJeremy Morse     ValueIDNum V = MTracker->readMLoc(L);
549d9eebe3cSJeremy Morse     ValueIDNum ToCmp(0, InstrNum, L);
550d9eebe3cSJeremy Morse     EXPECT_EQ(V, ToCmp);
551d9eebe3cSJeremy Morse   };
552d9eebe3cSJeremy Morse 
553d9eebe3cSJeremy Morse   TestRegSetSite("AL", 2);
554d9eebe3cSJeremy Morse   TestRegSetSite("AH", 1);
555d9eebe3cSJeremy Morse   TestRegSetSite("AX", 2);
556d9eebe3cSJeremy Morse   TestRegSetSite("EAX", 2);
557d9eebe3cSJeremy Morse   TestRegSetSite("HAX", 1);
558d9eebe3cSJeremy Morse   TestRegSetSite("RAX", 2);
559d9eebe3cSJeremy Morse 
560d9eebe3cSJeremy Morse   // This call should:
561d9eebe3cSJeremy Morse   //  * Def rax via the implicit-def,
562d9eebe3cSJeremy Morse   //  * Clobber rsi/rdi and all their subregs, via the register mask
563d9eebe3cSJeremy Morse   //  * Same for rcx, despite it not being a use in the instr, it's in the mask
564d9eebe3cSJeremy Morse   //  * NOT clobber $rsp / $esp $ sp, LiveDebugValues deliberately ignores
565d9eebe3cSJeremy Morse   //    these.
566d9eebe3cSJeremy Morse   //  * NOT clobber $rbx, because it's non-volatile
567d9eebe3cSJeremy Morse   //  * Not track every other register in the machine, only those needed.
568d9eebe3cSJeremy Morse  MF = readMIRBlock(
569d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n" // instr 1
570d9eebe3cSJeremy Morse    "    $rbx = MOV64ri 0\n" // instr 2
571d9eebe3cSJeremy Morse    "    $rcx = MOV64ri 0\n" // instr 3
572d9eebe3cSJeremy Morse    "    $rdi = MOV64ri 0\n" // instr 4
573d9eebe3cSJeremy Morse    "    $rsi = MOV64ri 0\n" // instr 5
574d9eebe3cSJeremy 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
575d391e4feSSimon Pilgrim    "    RET64 $rax\n"); // instr 7
576d9eebe3cSJeremy Morse   setupLDVObj(MF);
577d9eebe3cSJeremy Morse   TransferMap.clear();
578d9eebe3cSJeremy Morse   TransferMap.resize(1);
579d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
580d9eebe3cSJeremy Morse 
581d9eebe3cSJeremy Morse   const char *RegsSetInCall[] = {"AL",  "AH",  "AX", "EAX", "HAX", "RAX",
582d9eebe3cSJeremy Morse                                  "DIL", "DIH", "DI", "EDI", "HDI", "RDI",
583d9eebe3cSJeremy Morse                                  "SIL", "SIH", "SI", "ESI", "HSI", "RSI",
584d9eebe3cSJeremy Morse                                  "CL",  "CH",  "CX", "ECX", "HCX", "RCX"};
585d9eebe3cSJeremy Morse   for (const char *RegSetInCall : RegsSetInCall)
586d9eebe3cSJeremy Morse     TestRegSetSite(RegSetInCall, 6);
587d9eebe3cSJeremy Morse 
588d9eebe3cSJeremy Morse   const char *RegsLeftAlone[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
589d9eebe3cSJeremy Morse   for (const char *RegLeftAlone : RegsLeftAlone)
590d9eebe3cSJeremy Morse     TestRegSetSite(RegLeftAlone, 2);
591d9eebe3cSJeremy Morse 
592d9eebe3cSJeremy Morse   // Stack pointer should be the live-in to the function, instruction zero.
593d9eebe3cSJeremy Morse   TestRegSetSite("RSP", 0);
594d9eebe3cSJeremy Morse   // These stack regs should not be tracked either. Nor the (fake) subregs.
595d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("ESP")));
596d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SP")));
597d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPL")));
598d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("SPH")));
599d9eebe3cSJeremy Morse   EXPECT_FALSE(MTracker->isRegisterTracked(getRegByName("HSP")));
600d9eebe3cSJeremy Morse 
601d9eebe3cSJeremy Morse   // Should only be tracking: 6 x {A, B, C, DI, SI} registers = 30,
602d9eebe3cSJeremy Morse   // Plus RSP, SSP = 32.
603d9eebe3cSJeremy Morse   EXPECT_EQ(32u, MTracker->getNumLocs());
604d9eebe3cSJeremy Morse 
605d9eebe3cSJeremy Morse 
606d9eebe3cSJeremy Morse   // When we DBG_PHI something, we should track all its subregs.
607d9eebe3cSJeremy Morse   MF = readMIRBlock(
608d9eebe3cSJeremy Morse    "    DBG_PHI $rdi, 0\n"
609d391e4feSSimon Pilgrim    "    RET64\n");
610d9eebe3cSJeremy Morse   setupLDVObj(MF);
611d9eebe3cSJeremy Morse   TransferMap.clear();
612d9eebe3cSJeremy Morse   TransferMap.resize(1);
613d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
614d9eebe3cSJeremy Morse 
615d9eebe3cSJeremy Morse   // All DI regs and RSP tracked.
616d9eebe3cSJeremy Morse   EXPECT_EQ(7u, MTracker->getNumLocs());
617d9eebe3cSJeremy Morse 
618d9eebe3cSJeremy Morse   // All the DI registers should have block live-in values, i.e. the argument
619d9eebe3cSJeremy Morse   // to the function.
620d9eebe3cSJeremy Morse   const char *DIRegs[] = {"DIL", "DIH", "DI", "EDI", "HDI", "RDI"};
621d9eebe3cSJeremy Morse   for (const char *DIReg : DIRegs)
622d9eebe3cSJeremy Morse     TestRegSetSite(DIReg, 0);
623d9eebe3cSJeremy Morse }
624d9eebe3cSJeremy Morse 
TEST_F(InstrRefLDVTest,MTransferMeta)625d9eebe3cSJeremy Morse TEST_F(InstrRefLDVTest, MTransferMeta) {
626d9eebe3cSJeremy Morse   // Meta instructions should not have any effect on register values.
627d9eebe3cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
628d9eebe3cSJeremy Morse   MachineFunction *MF = readMIRBlock(
629d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
630d9eebe3cSJeremy Morse    "    $rax = IMPLICIT_DEF\n"
631d9eebe3cSJeremy Morse    "    $rax = KILL killed $rax\n"
632d391e4feSSimon Pilgrim    "    RET64 $rax\n");
633d9eebe3cSJeremy Morse   setupLDVObj(MF);
634d9eebe3cSJeremy Morse   TransferMap.clear();
635d9eebe3cSJeremy Morse   TransferMap.resize(1);
636d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
637d9eebe3cSJeremy Morse 
638d9eebe3cSJeremy Morse   LocIdx RaxLoc = MTracker->getRegMLoc(getRegByName("RAX"));
639d9eebe3cSJeremy Morse   ValueIDNum V = MTracker->readMLoc(RaxLoc);
640d9eebe3cSJeremy Morse   // Def of rax should be from instruction 1, i.e., unmodified.
641d9eebe3cSJeremy Morse   ValueIDNum Cmp(0, 1, RaxLoc);
642d9eebe3cSJeremy Morse   EXPECT_EQ(Cmp, V);
643d9eebe3cSJeremy Morse }
644d9eebe3cSJeremy Morse 
TEST_F(InstrRefLDVTest,MTransferCopies)645d9eebe3cSJeremy Morse TEST_F(InstrRefLDVTest, MTransferCopies) {
646d9eebe3cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
647d9eebe3cSJeremy Morse   // This memory spill should be recognised, and a spill slot created.
648d9eebe3cSJeremy Morse   MachineFunction *MF = readMIRBlock(
649d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
650d9eebe3cSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
651d391e4feSSimon Pilgrim    "    RET64 $rax\n");
652d9eebe3cSJeremy Morse   setupLDVObj(MF);
653d9eebe3cSJeremy Morse   TransferMap.clear();
654d9eebe3cSJeremy Morse   TransferMap.resize(1);
655d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
656d9eebe3cSJeremy Morse 
657d9eebe3cSJeremy Morse   // Check that the spill location contains the value defined in rax by
658d9eebe3cSJeremy Morse   // instruction 1. The MIR header says -16 offset, but it's stored as -8;
659d9eebe3cSJeremy Morse   // it's not completely clear why, but here we only care about correctly
660d9eebe3cSJeremy Morse   // identifying the slot, not that all the surrounding data is correct.
661d9eebe3cSJeremy Morse   SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
66214aaaa12SJeremy Morse   SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
663e7084ceaSJeremy Morse   unsigned SpillLocID = MTracker->getLocID(SpillNo, {64, 0});
664e7084ceaSJeremy Morse   LocIdx SpillLoc = MTracker->getSpillMLoc(SpillLocID);
665e7084ceaSJeremy Morse   ValueIDNum V = MTracker->readMLoc(SpillLoc);
666d9eebe3cSJeremy Morse   Register RAX = getRegByName("RAX");
667d9eebe3cSJeremy Morse   LocIdx RaxLoc = MTracker->getRegMLoc(RAX);
668d9eebe3cSJeremy Morse   ValueIDNum Cmp(0, 1, RaxLoc);
669e7084ceaSJeremy Morse   EXPECT_EQ(V, Cmp);
670d9eebe3cSJeremy Morse 
671d9eebe3cSJeremy Morse   // A spill and restore should be recognised.
672d9eebe3cSJeremy Morse   MF = readMIRBlock(
673d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
674d9eebe3cSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
675d9eebe3cSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
676d391e4feSSimon Pilgrim    "    RET64\n");
677d9eebe3cSJeremy Morse   setupLDVObj(MF);
678d9eebe3cSJeremy Morse   TransferMap.clear();
679d9eebe3cSJeremy Morse   TransferMap.resize(1);
680d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
681d9eebe3cSJeremy Morse 
682d9eebe3cSJeremy Morse   // Test that rbx contains rax from instruction 1.
683d9eebe3cSJeremy Morse   RAX = getRegByName("RAX");
684d9eebe3cSJeremy Morse   RaxLoc = MTracker->getRegMLoc(RAX);
685d9eebe3cSJeremy Morse   Register RBX = getRegByName("RBX");
686d9eebe3cSJeremy Morse   LocIdx RbxLoc = MTracker->getRegMLoc(RBX);
687d9eebe3cSJeremy Morse   Cmp = ValueIDNum(0, 1, RaxLoc);
688d9eebe3cSJeremy Morse   ValueIDNum RbxVal = MTracker->readMLoc(RbxLoc);
689d9eebe3cSJeremy Morse   EXPECT_EQ(RbxVal, Cmp);
690d9eebe3cSJeremy Morse 
691e7084ceaSJeremy Morse   // Testing that all the subregisters are transferred happens in
692e7084ceaSJeremy Morse   // MTransferSubregSpills.
693d9eebe3cSJeremy Morse 
694d9eebe3cSJeremy Morse   // Copies and x86 movs should be recognised and honoured. In addition, all
695d9eebe3cSJeremy Morse   // of the subregisters should be copied across too.
696d9eebe3cSJeremy Morse   MF = readMIRBlock(
697d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
698d9eebe3cSJeremy Morse    "    $rcx = COPY $rax\n"
699d9eebe3cSJeremy Morse    "    $rbx = MOV64rr $rcx\n"
700d391e4feSSimon Pilgrim    "    RET64\n");
701d9eebe3cSJeremy Morse   setupLDVObj(MF);
702d9eebe3cSJeremy Morse   TransferMap.clear();
703d9eebe3cSJeremy Morse   TransferMap.resize(1);
704d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
705d9eebe3cSJeremy Morse 
706d9eebe3cSJeremy Morse   const char *ARegs[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
707d9eebe3cSJeremy Morse   const char *BRegs[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
708d9eebe3cSJeremy Morse   const char *CRegs[] = {"CL", "CH", "CX", "ECX", "HCX", "RCX"};
709d9eebe3cSJeremy Morse   auto CheckReg = [&](unsigned int I) {
710d9eebe3cSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
711d9eebe3cSJeremy Morse     LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
712d9eebe3cSJeremy Morse     LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
713d9eebe3cSJeremy Morse     ValueIDNum ARefVal(0, 1, A);
714d9eebe3cSJeremy Morse     ValueIDNum AVal = MTracker->readMLoc(A);
715d9eebe3cSJeremy Morse     ValueIDNum BVal = MTracker->readMLoc(B);
716d9eebe3cSJeremy Morse     ValueIDNum CVal = MTracker->readMLoc(C);
717d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, AVal);
718d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, BVal);
719d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, CVal);
720d9eebe3cSJeremy Morse   };
721d9eebe3cSJeremy Morse 
722d9eebe3cSJeremy Morse   for (unsigned int I = 0; I < 6; ++I)
723d9eebe3cSJeremy Morse     CheckReg(I);
724d9eebe3cSJeremy Morse 
725d9eebe3cSJeremy Morse   // When we copy to a subregister, the super-register should be def'd too: it's
726d9eebe3cSJeremy Morse   // value will have changed.
727d9eebe3cSJeremy Morse   MF = readMIRBlock(
728d9eebe3cSJeremy Morse    "    $rax = MOV64ri 0\n"
729d9eebe3cSJeremy Morse    "    $ecx = COPY $eax\n"
730d391e4feSSimon Pilgrim    "    RET64\n");
731d9eebe3cSJeremy Morse   setupLDVObj(MF);
732d9eebe3cSJeremy Morse   TransferMap.clear();
733d9eebe3cSJeremy Morse   TransferMap.resize(1);
734d9eebe3cSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
735d9eebe3cSJeremy Morse 
736d9eebe3cSJeremy Morse   // First four regs [al, ah, ax, eax] should be copied to *cx.
737d9eebe3cSJeremy Morse   for (unsigned int I = 0; I < 4; ++I) {
738d9eebe3cSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
739d9eebe3cSJeremy Morse     LocIdx C = MTracker->getRegMLoc(getRegByName(CRegs[I]));
740d9eebe3cSJeremy Morse     ValueIDNum ARefVal(0, 1, A);
741d9eebe3cSJeremy Morse     ValueIDNum AVal = MTracker->readMLoc(A);
742d9eebe3cSJeremy Morse     ValueIDNum CVal = MTracker->readMLoc(C);
743d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, AVal);
744d9eebe3cSJeremy Morse     EXPECT_EQ(ARefVal, CVal);
745d9eebe3cSJeremy Morse   }
746d9eebe3cSJeremy Morse 
747d9eebe3cSJeremy Morse   // But rcx should contain a value defined by the COPY.
748d9eebe3cSJeremy Morse   LocIdx RcxLoc = MTracker->getRegMLoc(getRegByName("RCX"));
749d9eebe3cSJeremy Morse   ValueIDNum RcxVal = MTracker->readMLoc(RcxLoc);
750d9eebe3cSJeremy Morse   ValueIDNum RcxDefVal(0, 2, RcxLoc); // instr 2 -> the copy
751d9eebe3cSJeremy Morse   EXPECT_EQ(RcxVal, RcxDefVal);
752d9eebe3cSJeremy Morse }
753d9eebe3cSJeremy Morse 
TEST_F(InstrRefLDVTest,MTransferSubregSpills)754e7084ceaSJeremy Morse TEST_F(InstrRefLDVTest, MTransferSubregSpills) {
755e7084ceaSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferMap;
756e7084ceaSJeremy Morse   MachineFunction *MF = readMIRBlock(
757e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
758e7084ceaSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
759e7084ceaSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
760d391e4feSSimon Pilgrim    "    RET64\n");
761e7084ceaSJeremy Morse   setupLDVObj(MF);
762e7084ceaSJeremy Morse   TransferMap.clear();
763e7084ceaSJeremy Morse   TransferMap.resize(1);
764e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
765e7084ceaSJeremy Morse 
766e7084ceaSJeremy Morse   // Check that all the subregs of rax and rbx contain the same values. One
767e7084ceaSJeremy Morse   // should completely transfer to the other.
768e7084ceaSJeremy Morse   const char *ARegs[] = {"AL", "AH", "AX", "EAX", "HAX", "RAX"};
769e7084ceaSJeremy Morse   const char *BRegs[] = {"BL", "BH", "BX", "EBX", "HBX", "RBX"};
770e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 6; ++I) {
771e7084ceaSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
772e7084ceaSJeremy Morse     LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
773e7084ceaSJeremy Morse     EXPECT_EQ(MTracker->readMLoc(A), MTracker->readMLoc(B));
774e7084ceaSJeremy Morse   }
775e7084ceaSJeremy Morse 
776e7084ceaSJeremy Morse   // Explicitly check what's in the different subreg slots, on the stack.
777e7084ceaSJeremy Morse   // Pair up subreg idx fields with the corresponding subregister in $rax.
778e7084ceaSJeremy Morse   MLocTracker::StackSlotPos SubRegIdxes[] = {{8, 0}, {8, 8}, {16, 0}, {32, 0}, {64, 0}};
779e7084ceaSJeremy Morse   const char *SubRegNames[] = {"AL", "AH", "AX", "EAX", "RAX"};
780e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
781e7084ceaSJeremy Morse     // Value number where it's defined,
782e7084ceaSJeremy Morse     LocIdx RegLoc = MTracker->getRegMLoc(getRegByName(SubRegNames[I]));
783e7084ceaSJeremy Morse     ValueIDNum DefNum(0, 1, RegLoc);
784e7084ceaSJeremy Morse     // Read the corresponding subreg field from the stack.
785e7084ceaSJeremy Morse     SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
78614aaaa12SJeremy Morse     SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
787e7084ceaSJeremy Morse     unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
788e7084ceaSJeremy Morse     LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
789e7084ceaSJeremy Morse     ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
790e7084ceaSJeremy Morse     EXPECT_EQ(DefNum, SpillValue);
791e7084ceaSJeremy Morse   }
792e7084ceaSJeremy Morse 
793e7084ceaSJeremy Morse   // If we have exactly the same code, but we write $eax to the stack slot after
794e7084ceaSJeremy Morse   // $rax, then we should still have exactly the same output in the lower five
795e7084ceaSJeremy Morse   // subregisters. Storing $eax to the start of the slot will overwrite with the
796e7084ceaSJeremy Morse   // same values. $rax, as an aliasing register, should be reset to something
797e7084ceaSJeremy Morse   // else by that write.
798e7084ceaSJeremy Morse   // In theory, we could try and recognise that we're writing the _same_ values
799e7084ceaSJeremy Morse   // to the stack again, and so $rax doesn't need to be reset to something else.
800e7084ceaSJeremy Morse   // It seems vanishingly unlikely that LLVM would generate such code though,
801e7084ceaSJeremy Morse   // so the benefits would be small.
802e7084ceaSJeremy Morse   MF = readMIRBlock(
803e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
804e7084ceaSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
805e7084ceaSJeremy Morse    "    MOV32mr $rsp, 1, $noreg, 16, $noreg, $eax :: (store 4 into %stack.0)\n"
806e7084ceaSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
807d391e4feSSimon Pilgrim    "    RET64\n");
808e7084ceaSJeremy Morse   setupLDVObj(MF);
809e7084ceaSJeremy Morse   TransferMap.clear();
810e7084ceaSJeremy Morse   TransferMap.resize(1);
811e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
812e7084ceaSJeremy Morse 
813e7084ceaSJeremy Morse   // Check lower five registers up to and include $eax == $ebx,
814e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
815e7084ceaSJeremy Morse     LocIdx A = MTracker->getRegMLoc(getRegByName(ARegs[I]));
816e7084ceaSJeremy Morse     LocIdx B = MTracker->getRegMLoc(getRegByName(BRegs[I]));
817e7084ceaSJeremy Morse     EXPECT_EQ(MTracker->readMLoc(A), MTracker->readMLoc(B));
818e7084ceaSJeremy Morse   }
819e7084ceaSJeremy Morse 
820e7084ceaSJeremy Morse   // $rbx should contain something else; today it's a def at the spill point
821e7084ceaSJeremy Morse   // of the 4 byte value.
822e7084ceaSJeremy Morse   SpillLoc L = {getRegByName("RSP"), StackOffset::getFixed(-8)};
82314aaaa12SJeremy Morse   SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
824e7084ceaSJeremy Morse   unsigned SpillID = MTracker->getLocID(SpillNo, {64, 0});
825e7084ceaSJeremy Morse   LocIdx Spill64Loc = MTracker->getSpillMLoc(SpillID);
826e7084ceaSJeremy Morse   ValueIDNum DefAtSpill64(0, 3, Spill64Loc);
827e7084ceaSJeremy Morse   LocIdx RbxLoc = MTracker->getRegMLoc(getRegByName("RBX"));
828e7084ceaSJeremy Morse   EXPECT_EQ(MTracker->readMLoc(RbxLoc), DefAtSpill64);
829e7084ceaSJeremy Morse 
830e7084ceaSJeremy Morse   // Same again, test that the lower four subreg slots on the stack are the
831e7084ceaSJeremy Morse   // value defined by $rax in instruction 1.
832e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 4; ++I) {
833e7084ceaSJeremy Morse     // Value number where it's defined,
834e7084ceaSJeremy Morse     LocIdx RegLoc = MTracker->getRegMLoc(getRegByName(SubRegNames[I]));
835e7084ceaSJeremy Morse     ValueIDNum DefNum(0, 1, RegLoc);
836e7084ceaSJeremy Morse     // Read the corresponding subreg field from the stack.
83714aaaa12SJeremy Morse     SpillNo = *MTracker->getOrTrackSpillLoc(L);
838e7084ceaSJeremy Morse     SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
839e7084ceaSJeremy Morse     LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
840e7084ceaSJeremy Morse     ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
841e7084ceaSJeremy Morse     EXPECT_EQ(DefNum, SpillValue);
842e7084ceaSJeremy Morse   }
843e7084ceaSJeremy Morse 
844e7084ceaSJeremy Morse   // Stack slot for $rax should be a different value, today it's EmptyValue.
845e7084ceaSJeremy Morse   ValueIDNum SpillValue = MTracker->readMLoc(Spill64Loc);
846e7084ceaSJeremy Morse   EXPECT_EQ(SpillValue, DefAtSpill64);
847e7084ceaSJeremy Morse 
848e7084ceaSJeremy Morse   // If we write something to the stack, then over-write with some register
849e7084ceaSJeremy Morse   // from a completely different hierarchy, none of the "old" values should be
850e7084ceaSJeremy Morse   // readable.
851e7084ceaSJeremy Morse   // NB: slight hack, store 16 in to a 8 byte stack slot.
852e7084ceaSJeremy Morse   MF = readMIRBlock(
853e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
854e7084ceaSJeremy Morse    "    MOV64mr $rsp, 1, $noreg, 16, $noreg, $rax :: (store 8 into %stack.0)\n"
855e7084ceaSJeremy Morse    "    $xmm0 = IMPLICIT_DEF\n"
856e7084ceaSJeremy Morse    "    MOVUPDmr $rsp, 1, $noreg, 16, $noreg, killed $xmm0 :: (store (s128) into %stack.0)\n"
857e7084ceaSJeremy Morse    "    $rbx = MOV64rm $rsp, 1, $noreg, 0, $noreg :: (load 8 from %stack.0)\n"
858d391e4feSSimon Pilgrim    "    RET64\n");
859e7084ceaSJeremy Morse   setupLDVObj(MF);
860e7084ceaSJeremy Morse   TransferMap.clear();
861e7084ceaSJeremy Morse   TransferMap.resize(1);
862e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
863e7084ceaSJeremy Morse 
864e7084ceaSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
865e7084ceaSJeremy Morse     // Read subreg fields from the stack.
86614aaaa12SJeremy Morse     SpillLocationNo SpillNo = *MTracker->getOrTrackSpillLoc(L);
867e7084ceaSJeremy Morse     unsigned SpillID = MTracker->getLocID(SpillNo, SubRegIdxes[I]);
868e7084ceaSJeremy Morse     LocIdx SpillLoc = MTracker->getSpillMLoc(SpillID);
869e7084ceaSJeremy Morse     ValueIDNum SpillValue = MTracker->readMLoc(SpillLoc);
870e7084ceaSJeremy Morse 
871e7084ceaSJeremy Morse     // Value should be defined by the spill-to-xmm0 instr, get value of a def
872e7084ceaSJeremy Morse     // at the point of the spill.
873e7084ceaSJeremy Morse     ValueIDNum SpillDef(0, 4, SpillLoc);
874e7084ceaSJeremy Morse     EXPECT_EQ(SpillValue, SpillDef);
875e7084ceaSJeremy Morse   }
876e7084ceaSJeremy Morse 
877e7084ceaSJeremy Morse   // Read xmm0's position and ensure it has a value. Should be the live-in
878e7084ceaSJeremy Morse   // value to the block, as IMPLICIT_DEF isn't a real def.
87914aaaa12SJeremy Morse   SpillNo = *MTracker->getOrTrackSpillLoc(L);
880e7084ceaSJeremy Morse   SpillID = MTracker->getLocID(SpillNo, {128, 0});
881e7084ceaSJeremy Morse   LocIdx Spill128Loc = MTracker->getSpillMLoc(SpillID);
882e7084ceaSJeremy Morse   SpillValue = MTracker->readMLoc(Spill128Loc);
883e7084ceaSJeremy Morse   Register XMM0 = getRegByName("XMM0");
884e7084ceaSJeremy Morse   LocIdx Xmm0Loc = MTracker->getRegMLoc(XMM0);
885e7084ceaSJeremy Morse   EXPECT_EQ(ValueIDNum(0, 0, Xmm0Loc), SpillValue);
886e7084ceaSJeremy Morse 
887e7084ceaSJeremy Morse   // What happens if we spill ah to the stack, then load al? It should find
888e7084ceaSJeremy Morse   // the same value.
889e7084ceaSJeremy Morse   MF = readMIRBlock(
890e7084ceaSJeremy Morse    "    $rax = MOV64ri 0\n"
891e7084ceaSJeremy Morse    "    MOV8mr $rsp, 1, $noreg, 16, $noreg, $ah :: (store 1 into %stack.0)\n"
892e7084ceaSJeremy Morse    "    $al = MOV8rm $rsp, 1, $noreg, 0, $noreg :: (load 1 from %stack.0)\n"
893d391e4feSSimon Pilgrim    "    RET64\n");
894e7084ceaSJeremy Morse   setupLDVObj(MF);
895e7084ceaSJeremy Morse   TransferMap.clear();
896e7084ceaSJeremy Morse   TransferMap.resize(1);
897e7084ceaSJeremy Morse   produceMLocTransferFunction(*MF, TransferMap, 1);
898e7084ceaSJeremy Morse 
899e7084ceaSJeremy Morse   Register AL = getRegByName("AL");
900e7084ceaSJeremy Morse   Register AH = getRegByName("AH");
901e7084ceaSJeremy Morse   LocIdx AlLoc = MTracker->getRegMLoc(AL);
902e7084ceaSJeremy Morse   LocIdx AhLoc = MTracker->getRegMLoc(AH);
903e7084ceaSJeremy Morse   ValueIDNum AHDef(0, 1, AhLoc);
904e7084ceaSJeremy Morse   ValueIDNum ALValue = MTracker->readMLoc(AlLoc);
905e7084ceaSJeremy Morse   EXPECT_EQ(ALValue, AHDef);
906e7084ceaSJeremy Morse }
907e7084ceaSJeremy Morse 
TEST_F(InstrRefLDVTest,MLocSingleBlock)908a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocSingleBlock) {
909a3936a6cSJeremy Morse   // Test some very simple properties about interpreting the transfer function.
910b5426cedSJeremy Morse   setupSingleBlock();
911a3936a6cSJeremy Morse 
912a3936a6cSJeremy Morse   // We should start with a single location, the stack pointer.
913a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
914a3936a6cSJeremy Morse   LocIdx RspLoc(0);
915a3936a6cSJeremy Morse 
916a3936a6cSJeremy Morse   // Set up live-in and live-out tables for this function: two locations (we
917a3936a6cSJeremy Morse   // add one later) in a single block.
918ab49dce0SJeremy Morse   FuncValueTable MOutLocs, MInLocs;
919ab49dce0SJeremy Morse   std::tie(MOutLocs, MInLocs) = allocValueTables(1, 2);
920a3936a6cSJeremy Morse 
921a3936a6cSJeremy Morse   // Transfer function: nothing.
9224136897bSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
9234136897bSJeremy Morse   TransferFunc.resize(1);
924a3936a6cSJeremy Morse 
925a3936a6cSJeremy Morse   // Try and build value maps...
926ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
927a3936a6cSJeremy Morse 
928a3936a6cSJeremy Morse   // The result should be that RSP is marked as a live-in-PHI -- this represents
929a3936a6cSJeremy Morse   // an argument. And as there's no transfer function, the block live-out should
930a3936a6cSJeremy Morse   // be the same.
931ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
932ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
933a3936a6cSJeremy Morse 
934a3936a6cSJeremy Morse   // Try again, this time initialising the in-locs to be defined by an
935a3936a6cSJeremy Morse   // instruction. The entry block should always be re-assigned to be the
936a3936a6cSJeremy Morse   // arguments.
937ab49dce0SJeremy Morse   initValueArray(MInLocs, 1, 2);
938ab49dce0SJeremy Morse   initValueArray(MOutLocs, 1, 2);
939ab49dce0SJeremy Morse   MInLocs[0][0] = ValueIDNum(0, 1, RspLoc);
940ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
941ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
942ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 0, RspLoc));
943a3936a6cSJeremy Morse 
944a3936a6cSJeremy Morse   // Now insert something into the transfer function to assign to the single
945a3936a6cSJeremy Morse   // machine location.
946a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
947ab49dce0SJeremy Morse   initValueArray(MInLocs, 1, 2);
948ab49dce0SJeremy Morse   initValueArray(MOutLocs, 1, 2);
949ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
950ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
951ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
952a3936a6cSJeremy Morse   TransferFunc[0].clear();
953a3936a6cSJeremy Morse 
954a3936a6cSJeremy Morse   // Add a new register to be tracked, and insert it into the transfer function
955a3936a6cSJeremy Morse   // as a copy. The output of $rax should be the live-in value of $rsp.
956a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
957a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
958a3936a6cSJeremy Morse   TransferFunc[0].insert({RspLoc, ValueIDNum(0, 1, RspLoc)});
959a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, ValueIDNum(0, 0, RspLoc)});
960ab49dce0SJeremy Morse   initValueArray(MInLocs, 1, 2);
961ab49dce0SJeremy Morse   initValueArray(MOutLocs, 1, 2);
962ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
963ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], ValueIDNum(0, 0, RspLoc));
964ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], ValueIDNum(0, 0, RaxLoc));
965ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], ValueIDNum(0, 1, RspLoc));
966ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], ValueIDNum(0, 0, RspLoc)); // Rax contains RspLoc.
967a3936a6cSJeremy Morse   TransferFunc[0].clear();
968a3936a6cSJeremy Morse }
969a3936a6cSJeremy Morse 
TEST_F(InstrRefLDVTest,MLocDiamondBlocks)970a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocDiamondBlocks) {
971a3936a6cSJeremy Morse   // Test that information flows from the entry block to two successors.
972a3936a6cSJeremy Morse   //        entry
973a3936a6cSJeremy Morse   //        /  \
974a3936a6cSJeremy Morse   //      br1  br2
975a3936a6cSJeremy Morse   //        \  /
976a3936a6cSJeremy Morse   //         ret
977b5426cedSJeremy Morse   setupDiamondBlocks();
978838b4a53SJeremy Morse 
979a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
980a3936a6cSJeremy Morse   LocIdx RspLoc(0);
981a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
982a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
983838b4a53SJeremy Morse 
984ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
985ab49dce0SJeremy Morse   std::tie(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 
TEST_F(InstrRefLDVTest,MLocDiamondSpills)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);
1116*65d5becaSJeremy Morse   ASSERT_EQ(MTracker->getNumLocs(), 11u); // 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}).
1119*65d5becaSJeremy 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 
1138ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
1139*65d5becaSJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(4, 11);
114097ddf49eSJeremy Morse 
114197ddf49eSJeremy Morse   // Transfer function: start with nothing.
114297ddf49eSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
114397ddf49eSJeremy Morse   TransferFunc.resize(4);
114497ddf49eSJeremy Morse 
114597ddf49eSJeremy Morse   // Name some values.
114697ddf49eSJeremy Morse   unsigned EntryBlk = 0, Blk1 = 1, RetBlk = 3;
114797ddf49eSJeremy Morse 
114897ddf49eSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
114997ddf49eSJeremy Morse   ValueIDNum ALLiveIn(EntryBlk, 0, ALStackLoc);
115097ddf49eSJeremy Morse   ValueIDNum AHLiveIn(EntryBlk, 0, AHStackLoc);
115197ddf49eSJeremy Morse   ValueIDNum HAXLiveIn(EntryBlk, 0, HAXStackLoc);
115297ddf49eSJeremy Morse   ValueIDNum ALPHI(RetBlk, 0, ALStackLoc);
115397ddf49eSJeremy Morse   ValueIDNum AXPHI(RetBlk, 0, AXStackLoc);
115497ddf49eSJeremy Morse   ValueIDNum EAXPHI(RetBlk, 0, EAXStackLoc);
115597ddf49eSJeremy Morse   ValueIDNum HAXPHI(RetBlk, 0, HAXStackLoc);
115697ddf49eSJeremy Morse   ValueIDNum RAXPHI(RetBlk, 0, RAXStackLoc);
115797ddf49eSJeremy Morse 
115897ddf49eSJeremy Morse   ValueIDNum ALDefInBlk1(Blk1, 1, ALStackLoc);
115997ddf49eSJeremy Morse   ValueIDNum HAXDefInBlk1(Blk1, 1, HAXStackLoc);
116097ddf49eSJeremy Morse 
116197ddf49eSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AllBlocks{MBB0, MBB1, MBB2, MBB3};
116297ddf49eSJeremy Morse 
116397ddf49eSJeremy Morse   // If we put defs into one side of the diamond, for AL and HAX, then we should
116497ddf49eSJeremy Morse   // find all aliasing positions have PHIs placed. This isn't technically what
116597ddf49eSJeremy Morse   // the transfer function says to do: but we're testing that the optimisation
116697ddf49eSJeremy Morse   // to reduce IDF calculation does the right thing.
116797ddf49eSJeremy Morse   // AH should not be def'd: it don't alias AL or HAX.
116897ddf49eSJeremy Morse   //
116997ddf49eSJeremy Morse   // NB: we don't call buildMLocValueMap, because it will try to eliminate the
117097ddf49eSJeremy Morse   // upper-slot PHIs, and succeed because of our slightly cooked transfer
117197ddf49eSJeremy Morse   // function.
117297ddf49eSJeremy Morse   TransferFunc[1].insert({ALStackLoc, ALDefInBlk1});
117397ddf49eSJeremy Morse   TransferFunc[1].insert({HAXStackLoc, HAXDefInBlk1});
1174*65d5becaSJeremy Morse   initValueArray(MInLocs, 4, 11);
1175ab49dce0SJeremy Morse   placeMLocPHIs(*MF, AllBlocks, MInLocs, TransferFunc);
1176ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][ALStackLoc.asU64()], ALPHI);
1177ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][AXStackLoc.asU64()], AXPHI);
1178ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][EAXStackLoc.asU64()], EAXPHI);
1179ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][HAXStackLoc.asU64()], HAXPHI);
1180ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][RAXStackLoc.asU64()], RAXPHI);
118197ddf49eSJeremy Morse   // AH should be left untouched,
1182ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][AHStackLoc.asU64()], ValueIDNum::EmptyValue);
118397ddf49eSJeremy Morse }
118497ddf49eSJeremy Morse 
TEST_F(InstrRefLDVTest,MLocSimpleLoop)1185a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocSimpleLoop) {
1186a3936a6cSJeremy Morse   //    entry
1187a3936a6cSJeremy Morse   //     |
1188a3936a6cSJeremy Morse   //     |/-----\
1189a3936a6cSJeremy Morse   //    loopblk |
1190a3936a6cSJeremy Morse   //     |\-----/
1191a3936a6cSJeremy Morse   //     |
1192a3936a6cSJeremy Morse   //     ret
1193b5426cedSJeremy Morse   setupSimpleLoop();
1194a3936a6cSJeremy Morse 
1195a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1196a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1197a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1198a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1199a3936a6cSJeremy Morse 
1200ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
1201ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
1202a3936a6cSJeremy Morse 
1203a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1204a3936a6cSJeremy Morse   TransferFunc.resize(3);
1205a3936a6cSJeremy Morse 
1206a3936a6cSJeremy Morse   // Name some values.
1207b5426cedSJeremy Morse   unsigned EntryBlk = 0, LoopBlk = 1, RetBlk = 2;
1208b5426cedSJeremy Morse 
1209b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1210b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
1211b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(LoopBlk, 1, RspLoc);
1212b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1213b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
1214b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk2(RetBlk, 0, RaxLoc);
1215a3936a6cSJeremy Morse 
1216a3936a6cSJeremy Morse   // Begin test with all locations being live-through.
1217ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
1218ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1219ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1220ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1221ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1222ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1223ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1224ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1225ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1226a3936a6cSJeremy Morse 
1227a3936a6cSJeremy Morse   // Add a def of $rsp to the loop block: it should be in the live-outs, but
1228a3936a6cSJeremy Morse   // should cause a PHI to be placed in the live-ins. Test the transfer function
1229a3936a6cSJeremy Morse   // by copying that PHI into $rax in the loop, then back to $rsp in the ret
1230a3936a6cSJeremy Morse   // block.
1231a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1232a3936a6cSJeremy Morse   TransferFunc[1].insert({RaxLoc, RspPHIInBlk1});
1233a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1234ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
1235ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1236ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1237ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1238ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1239ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1240ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1241ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1242ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
1243a3936a6cSJeremy Morse   // Check rax as well,
1244ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1245ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
1246ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], RspPHIInBlk1);
1247ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRax);
1248ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], RspPHIInBlk1);
1249ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
1250a3936a6cSJeremy Morse   TransferFunc[1].clear();
1251a3936a6cSJeremy Morse   TransferFunc[2].clear();
1252a3936a6cSJeremy Morse 
1253a3936a6cSJeremy Morse   // As with the diamond case, a PHI will be created if there's a (implicit)
1254a3936a6cSJeremy Morse   // def in the entry block and loop block; but should be value propagated away
1255a3936a6cSJeremy Morse   // if it copies in the same value. Copy live-in $rsp to $rax, then copy it
1256a3936a6cSJeremy Morse   // into $rsp in the loop. Encoded as copying the live-in $rax value in block 1
1257a3936a6cSJeremy Morse   // to $rsp.
1258a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1259a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1260ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
1261ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1262ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1263ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1264ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1265ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1266ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1267ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1268ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1269a3936a6cSJeremy Morse   // Check $rax's values.
1270ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1271ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], LiveInRsp);
1272ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], LiveInRsp);
1273ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
1274ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
1275ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
1276a3936a6cSJeremy Morse   TransferFunc[0].clear();
1277a3936a6cSJeremy Morse   TransferFunc[1].clear();
1278a3936a6cSJeremy Morse }
1279a3936a6cSJeremy Morse 
TEST_F(InstrRefLDVTest,MLocNestedLoop)1280a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocNestedLoop) {
1281a3936a6cSJeremy Morse   //    entry
1282a3936a6cSJeremy Morse   //     |
1283a3936a6cSJeremy Morse   //    loop1
1284a3936a6cSJeremy Morse   //     ^\
1285a3936a6cSJeremy Morse   //     | \    /-\
1286a3936a6cSJeremy Morse   //     |  loop2  |
1287a3936a6cSJeremy Morse   //     |  /   \-/
1288a3936a6cSJeremy Morse   //     ^ /
1289a3936a6cSJeremy Morse   //     join
1290a3936a6cSJeremy Morse   //     |
1291a3936a6cSJeremy Morse   //     ret
1292b5426cedSJeremy Morse   setupNestedLoops();
1293a3936a6cSJeremy Morse 
1294a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1295a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1296a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1297a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1298a3936a6cSJeremy Morse 
1299ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
1300ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
1301a3936a6cSJeremy Morse 
1302a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1303a3936a6cSJeremy Morse   TransferFunc.resize(5);
1304a3936a6cSJeremy Morse 
1305b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2, JoinBlk = 3;
1306b5426cedSJeremy Morse 
1307b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1308b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
1309b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(Loop1Blk, 1, RspLoc);
1310b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Loop2Blk, 0, RspLoc);
1311b5426cedSJeremy Morse   ValueIDNum RspDefInBlk2(Loop2Blk, 1, RspLoc);
1312b5426cedSJeremy Morse   ValueIDNum RspDefInBlk3(JoinBlk, 1, RspLoc);
1313b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1314b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(Loop1Blk, 0, RaxLoc);
1315b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk2(Loop2Blk, 0, RaxLoc);
1316a3936a6cSJeremy Morse 
1317a3936a6cSJeremy Morse   // Like the other tests: first ensure that if there's nothing in the transfer
1318a3936a6cSJeremy Morse   // function, then everything is live-through (check $rsp).
1319ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1320ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1321ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1322ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1323ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1324ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1325ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1326ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1327ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1328ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1329ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1330ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1331ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1332a3936a6cSJeremy Morse 
1333a3936a6cSJeremy Morse   // A def in the inner loop means we should get PHIs at the heads of both
1334a3936a6cSJeremy Morse   // loops. Live-outs of the last three blocks will be the def, as it dominates
1335a3936a6cSJeremy Morse   // those.
1336a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1337ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1338ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1339ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1340ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1341ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1342ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1343ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1344ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
1345ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1346ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1347ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1348ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
1349ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
1350a3936a6cSJeremy Morse   TransferFunc[2].clear();
1351a3936a6cSJeremy Morse 
1352a3936a6cSJeremy Morse   // Adding a def to the outer loop header shouldn't affect this much -- the
1353a3936a6cSJeremy Morse   // live-out of block 1 changes.
1354a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1355a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1356ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1357ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1358ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1359ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1360ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1361ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1362ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1363ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk2);
1364ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1365ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1366ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1367ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk2);
1368ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk2);
1369a3936a6cSJeremy Morse   TransferFunc[1].clear();
1370a3936a6cSJeremy Morse   TransferFunc[2].clear();
1371a3936a6cSJeremy Morse 
1372a3936a6cSJeremy Morse   // Likewise, putting a def in the outer loop tail shouldn't affect where
1373a3936a6cSJeremy Morse   // the PHIs go, and should propagate into the ret block.
1374a3936a6cSJeremy Morse 
1375a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1376a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1377a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1378ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1379ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1380ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1381ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1382ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1383ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1384ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk2);
1385ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1386ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1387ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1388ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1389ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1390ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1391a3936a6cSJeremy Morse   TransferFunc[1].clear();
1392a3936a6cSJeremy Morse   TransferFunc[2].clear();
1393a3936a6cSJeremy Morse   TransferFunc[3].clear();
1394a3936a6cSJeremy Morse 
1395a3936a6cSJeremy Morse   // However: if we don't def in the inner-loop, then we just have defs in the
1396a3936a6cSJeremy Morse   // head and tail of the outer loop. The inner loop should be live-through.
1397a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1398a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1399ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1400ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1401ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1402ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1403ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1404ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1405ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1406ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1407ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1408ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1409ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1410ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1411ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1412a3936a6cSJeremy Morse   TransferFunc[1].clear();
1413a3936a6cSJeremy Morse   TransferFunc[3].clear();
1414a3936a6cSJeremy Morse 
1415a3936a6cSJeremy Morse   // Check that this still works if we copy RspDefInBlk1 to $rax and then
1416a3936a6cSJeremy Morse   // copy it back into $rsp in the inner loop.
1417a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1418a3936a6cSJeremy Morse   TransferFunc[1].insert({RaxLoc, RspDefInBlk1});
1419a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1420a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1421ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1422ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1423ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1424ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1425ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1426ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1427ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1428ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1429ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1430ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1431ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1432ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1433ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1434a3936a6cSJeremy Morse   // Look at raxes value in the relevant blocks,
1435ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], RspDefInBlk1);
1436ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], RspDefInBlk1);
1437a3936a6cSJeremy Morse   TransferFunc[1].clear();
1438a3936a6cSJeremy Morse   TransferFunc[2].clear();
1439a3936a6cSJeremy Morse   TransferFunc[3].clear();
1440a3936a6cSJeremy Morse 
1441a3936a6cSJeremy Morse   // If we have a single def in the tail of the outer loop, that should produce
1442a3936a6cSJeremy Morse   // a PHI at the loop head, and be live-through the inner loop.
1443a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1444ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1445ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1446ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1447ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1448ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1449ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk1);
1450ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk1);
1451ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1452ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1453ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1454ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk1);
1455ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1456ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1457a3936a6cSJeremy Morse   TransferFunc[3].clear();
1458a3936a6cSJeremy Morse 
1459a3936a6cSJeremy Morse   // And if we copy from $rsp to $rax in block 2, it should resolve to the PHI
1460a3936a6cSJeremy Morse   // in block 1, and we should keep that value in rax until the ret block.
1461a3936a6cSJeremy Morse   // There'll be a PHI in block 1 and 2, because we're putting a def in the
1462a3936a6cSJeremy Morse   // inner loop.
1463a3936a6cSJeremy Morse   TransferFunc[2].insert({RaxLoc, RspPHIInBlk2});
1464a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1465ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1466ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1467ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1468a3936a6cSJeremy Morse   // Examining the values of rax,
1469ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1470ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], RaxPHIInBlk1);
1471ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], RaxPHIInBlk2);
1472ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][1], RspPHIInBlk1);
1473ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][1], RspPHIInBlk1);
1474ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRax);
1475ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], RaxPHIInBlk1);
1476ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], RspPHIInBlk1);
1477ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][1], RspPHIInBlk1);
1478ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][1], RspPHIInBlk1);
1479a3936a6cSJeremy Morse   TransferFunc[2].clear();
1480a3936a6cSJeremy Morse   TransferFunc[3].clear();
1481a3936a6cSJeremy Morse }
1482a3936a6cSJeremy Morse 
TEST_F(InstrRefLDVTest,MLocNoDominatingLoop)1483a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocNoDominatingLoop) {
1484a3936a6cSJeremy Morse   //           entry
1485a3936a6cSJeremy Morse   //            / \
1486a3936a6cSJeremy Morse   //           /   \
1487a3936a6cSJeremy Morse   //          /     \
1488a3936a6cSJeremy Morse   //        head1   head2
1489a3936a6cSJeremy Morse   //        ^  \   /   ^
1490a3936a6cSJeremy Morse   //        ^   \ /    ^
1491a3936a6cSJeremy Morse   //        \-joinblk -/
1492a3936a6cSJeremy Morse   //             |
1493a3936a6cSJeremy Morse   //            ret
1494b5426cedSJeremy Morse   setupNoDominatingLoop();
1495a3936a6cSJeremy Morse 
1496a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1497a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1498a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1499a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1500a3936a6cSJeremy Morse 
1501ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
1502ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
1503a3936a6cSJeremy Morse 
1504a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1505a3936a6cSJeremy Morse   TransferFunc.resize(5);
1506a3936a6cSJeremy Morse 
1507b5426cedSJeremy Morse   unsigned EntryBlk = 0, Head1Blk = 1, Head2Blk = 2, JoinBlk = 3;
1508b5426cedSJeremy Morse 
1509b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1510b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Head1Blk, 0, RspLoc);
1511b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(Head1Blk, 1, RspLoc);
1512b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Head2Blk, 0, RspLoc);
1513b5426cedSJeremy Morse   ValueIDNum RspDefInBlk2(Head2Blk, 1, RspLoc);
1514b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3(JoinBlk, 0, RspLoc);
1515b5426cedSJeremy Morse   ValueIDNum RspDefInBlk3(JoinBlk, 1, RspLoc);
1516b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(Head1Blk, 0, RaxLoc);
1517b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk2(Head2Blk, 0, RaxLoc);
1518a3936a6cSJeremy Morse 
1519a3936a6cSJeremy Morse   // As ever, test that everything is live-through if there are no defs.
1520ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1521ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1522ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1523ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1524ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1525ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1526ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1527ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1528ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1529ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1530ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1531ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1532ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1533a3936a6cSJeremy Morse 
1534a3936a6cSJeremy Morse   // Putting a def in the 'join' block will cause us to have two distinct
1535a3936a6cSJeremy Morse   // PHIs in each loop head, then on entry to the join block.
1536a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1537ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1538ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1539ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1540ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1541ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1542ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1543ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1544ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1545ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1546ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1547ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1548ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1549ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1550a3936a6cSJeremy Morse   TransferFunc[3].clear();
1551a3936a6cSJeremy Morse 
1552a3936a6cSJeremy Morse   // We should get the same behaviour if we put the def in either of the
1553a3936a6cSJeremy Morse   // loop heads -- it should force the other head to be a PHI.
1554a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1555ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1556ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1557ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1558ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1559ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1560ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1561ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1562ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
1563ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1564ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1565ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1566ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1567ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
1568a3936a6cSJeremy Morse   TransferFunc[1].clear();
1569a3936a6cSJeremy Morse 
1570a3936a6cSJeremy Morse   // Check symmetry,
1571a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RspDefInBlk2});
1572ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1573ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1574ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1575ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1576ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1577ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1578ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1579ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspPHIInBlk3);
1580ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1581ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1582ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk2);
1583ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspPHIInBlk3);
1584ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspPHIInBlk3);
1585a3936a6cSJeremy Morse   TransferFunc[2].clear();
1586a3936a6cSJeremy Morse 
1587a3936a6cSJeremy Morse   // Test some scenarios where there _shouldn't_ be any PHIs created at heads.
1588a3936a6cSJeremy Morse   // These are those PHIs are created, but value propagation eliminates them.
1589a3936a6cSJeremy Morse   // For example, lets copy rsp-livein to $rsp inside each loop head, so that
1590a3936a6cSJeremy Morse   // there's no need for a PHI in the join block. Put a def of $rsp in block 3
1591a3936a6cSJeremy Morse   // to force PHIs elsewhere.
1592a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1593a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1594a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1595a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1596ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1597ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1598ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1599ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1600ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1601ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1602ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1603ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1604ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1605ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1606ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1607ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1608ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1609a3936a6cSJeremy Morse   TransferFunc[0].clear();
1610a3936a6cSJeremy Morse   TransferFunc[1].clear();
1611a3936a6cSJeremy Morse   TransferFunc[2].clear();
1612a3936a6cSJeremy Morse   TransferFunc[3].clear();
1613a3936a6cSJeremy Morse 
1614a3936a6cSJeremy Morse   // In fact, if we eliminate the def in block 3, none of those PHIs are
1615a3936a6cSJeremy Morse   // necessary, as we're just repeatedly copying LiveInRsp into $rsp. They
1616a3936a6cSJeremy Morse   // should all be value propagated out.
1617a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1618a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RaxPHIInBlk1});
1619a3936a6cSJeremy Morse   TransferFunc[2].insert({RspLoc, RaxPHIInBlk2});
1620ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1621ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1622ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1623ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1624ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1625ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1626ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1627ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1628ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1629ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1630ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1631ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1632ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1633a3936a6cSJeremy Morse   TransferFunc[0].clear();
1634a3936a6cSJeremy Morse   TransferFunc[1].clear();
1635a3936a6cSJeremy Morse   TransferFunc[2].clear();
1636a3936a6cSJeremy Morse }
1637a3936a6cSJeremy Morse 
TEST_F(InstrRefLDVTest,MLocBadlyNestedLoops)1638a3936a6cSJeremy Morse TEST_F(InstrRefLDVTest, MLocBadlyNestedLoops) {
1639a3936a6cSJeremy Morse   //           entry
1640a3936a6cSJeremy Morse   //             |
1641a3936a6cSJeremy Morse   //           loop1 -o
1642a3936a6cSJeremy Morse   //             | ^
1643a3936a6cSJeremy Morse   //             | ^
1644a3936a6cSJeremy Morse   //           loop2 -o
1645a3936a6cSJeremy Morse   //             | ^
1646a3936a6cSJeremy Morse   //             | ^
1647a3936a6cSJeremy Morse   //           loop3 -o
1648a3936a6cSJeremy Morse   //             |
1649a3936a6cSJeremy Morse   //            ret
1650b5426cedSJeremy Morse   setupBadlyNestedLoops();
1651a3936a6cSJeremy Morse 
1652a3936a6cSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1653a3936a6cSJeremy Morse   LocIdx RspLoc(0);
1654a3936a6cSJeremy Morse   Register RAX = getRegByName("RAX");
1655a3936a6cSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1656a3936a6cSJeremy Morse 
1657ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
1658ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
1659a3936a6cSJeremy Morse 
1660a3936a6cSJeremy Morse   SmallVector<MLocTransferMap, 1> TransferFunc;
1661a3936a6cSJeremy Morse   TransferFunc.resize(5);
1662a3936a6cSJeremy Morse 
1663b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2, Loop3Blk = 3;
1664b5426cedSJeremy Morse 
1665b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1666b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
1667b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1(Loop1Blk, 1, RspLoc);
1668b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Loop2Blk, 0, RspLoc);
1669b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3(Loop3Blk, 0, RspLoc);
1670b5426cedSJeremy Morse   ValueIDNum RspDefInBlk3(Loop3Blk, 1, RspLoc);
1671b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1672b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk3(Loop3Blk, 0, RaxLoc);
1673a3936a6cSJeremy Morse 
1674a3936a6cSJeremy Morse   // As ever, test that everything is live-through if there are no defs.
1675ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1676ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1677ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1678ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1679ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], LiveInRsp);
1680ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], LiveInRsp);
1681ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], LiveInRsp);
1682ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1683ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1684ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], LiveInRsp);
1685ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], LiveInRsp);
1686ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1687ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1688a3936a6cSJeremy Morse 
1689a3936a6cSJeremy Morse   // A def in loop3 should cause PHIs in every loop block: they're all
1690a3936a6cSJeremy Morse   // reachable from each other.
1691a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RspDefInBlk3});
1692ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1693ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1694ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1695ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1696ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1697ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1698ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1699ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk3);
1700ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1701ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1702ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1703ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk3);
1704ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk3);
1705a3936a6cSJeremy Morse   TransferFunc[3].clear();
1706a3936a6cSJeremy Morse 
1707a3936a6cSJeremy Morse   // A def in loop1 should cause a PHI in loop1, but not the other blocks.
1708a3936a6cSJeremy Morse   // loop2 and loop3 are dominated by the def in loop1, so they should have
1709a3936a6cSJeremy Morse   // that value live-through.
1710a3936a6cSJeremy Morse   TransferFunc[1].insert({RspLoc, RspDefInBlk1});
1711ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1712ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1713ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1714ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1715ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1716ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspDefInBlk1);
1717ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspDefInBlk1);
1718ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], RspDefInBlk1);
1719ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1720ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspDefInBlk1);
1721ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspDefInBlk1);
1722ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], RspDefInBlk1);
1723ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], RspDefInBlk1);
1724a3936a6cSJeremy Morse   TransferFunc[1].clear();
1725a3936a6cSJeremy Morse 
1726a3936a6cSJeremy Morse   // As with earlier tricks: copy $rsp to $rax in the entry block, then $rax
1727a3936a6cSJeremy Morse   // to $rsp in block 3. The only def of $rsp is simply copying the same value
1728a3936a6cSJeremy Morse   // back into itself, and the value of $rsp is LiveInRsp all the way through.
1729a3936a6cSJeremy Morse   // PHIs should be created, then value-propagated away...  however this
1730a3936a6cSJeremy Morse   // doesn't work in practice.
1731a3936a6cSJeremy Morse   // Consider the entry to loop3: we can determine that there's an incoming
1732a3936a6cSJeremy Morse   // PHI value from loop2, and LiveInRsp from the self-loop. This would still
1733a3936a6cSJeremy Morse   // justify having a PHI on entry to loop3. The only way to completely
1734a3936a6cSJeremy Morse   // value-propagate these PHIs away would be to speculatively explore what
1735a3936a6cSJeremy Morse   // PHIs could be eliminated and what that would lead to; which is
1736a3936a6cSJeremy Morse   // combinatorially complex.
1737a3936a6cSJeremy Morse   // Happily:
1738a3936a6cSJeremy Morse   //  a) In this scenario, we always have a tracked location for LiveInRsp
1739a3936a6cSJeremy Morse   //     anyway, so there's no loss in availability,
1740a3936a6cSJeremy Morse   //  b) Only DBG_PHIs of a register would be vunlerable to this scenario, and
1741a3936a6cSJeremy Morse   //     even then only if a true PHI became a DBG_PHI and was then optimised
1742a3936a6cSJeremy Morse   //     through branch folding to no longer be at a CFG join,
1743a3936a6cSJeremy Morse   //  c) The register allocator can spot this kind of redundant COPY easily,
1744a3936a6cSJeremy Morse   //     and eliminate it.
1745a3936a6cSJeremy Morse   //
1746a3936a6cSJeremy Morse   // This unit test left in as a reference for the limitations of this
1747a3936a6cSJeremy Morse   // approach. PHIs will be left in $rsp on entry to each block.
1748a3936a6cSJeremy Morse   TransferFunc[0].insert({RaxLoc, LiveInRsp});
1749a3936a6cSJeremy Morse   TransferFunc[3].insert({RspLoc, RaxPHIInBlk3});
1750ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
1751ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
1752ab49dce0SJeremy Morse   buildMLocValueMap(MInLocs, MOutLocs, TransferFunc);
1753ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][0], LiveInRsp);
1754ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][0], RspPHIInBlk1);
1755ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][0], RspPHIInBlk2);
1756ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][0], RspPHIInBlk3);
1757ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][0], LiveInRsp);
1758ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][0], LiveInRsp);
1759ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][0], RspPHIInBlk1);
1760ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][0], RspPHIInBlk2);
1761ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][0], LiveInRsp);
1762ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][0], LiveInRsp);
1763a3936a6cSJeremy Morse   // Check $rax's value. It should have $rsps value from the entry block
1764a3936a6cSJeremy Morse   // onwards.
1765ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[0][1], LiveInRax);
1766ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[1][1], LiveInRsp);
1767ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[2][1], LiveInRsp);
1768ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[3][1], LiveInRsp);
1769ab49dce0SJeremy Morse   EXPECT_EQ(MInLocs[4][1], LiveInRsp);
1770ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[0][1], LiveInRsp);
1771ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[1][1], LiveInRsp);
1772ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[2][1], LiveInRsp);
1773ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[3][1], LiveInRsp);
1774ab49dce0SJeremy Morse   EXPECT_EQ(MOutLocs[4][1], LiveInRsp);
1775a3936a6cSJeremy Morse }
1776b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,pickVPHILocDiamond)1777b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, pickVPHILocDiamond) {
1778b5426cedSJeremy Morse   //        entry
1779b5426cedSJeremy Morse   //        /  \
1780b5426cedSJeremy Morse   //      br1  br2
1781b5426cedSJeremy Morse   //        \  /
1782b5426cedSJeremy Morse   //         ret
1783b5426cedSJeremy Morse   setupDiamondBlocks();
1784b5426cedSJeremy Morse 
1785b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1786b5426cedSJeremy Morse   LocIdx RspLoc(0);
1787b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
1788b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1789b5426cedSJeremy Morse 
1790ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
1791ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
1792b5426cedSJeremy Morse 
1793ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
1794b5426cedSJeremy Morse 
1795b5426cedSJeremy Morse   unsigned EntryBlk = 0, Br2Blk = 2, RetBlk = 3;
1796b5426cedSJeremy Morse 
1797b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1798b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1799b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2(Br2Blk, 0, RspLoc);
1800b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3(RetBlk, 0, RspLoc);
1801b5426cedSJeremy Morse 
1802b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
1803b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
180489950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
180589950adeSJeremy Morse   VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef));
1806b5426cedSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
1807b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
1808b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
1809b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
1810b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
1811b5426cedSJeremy Morse 
1812b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
1813b5426cedSJeremy Morse   for (const auto *Pred : MBB3->predecessors())
1814b5426cedSJeremy Morse     Preds.push_back(Pred);
1815b5426cedSJeremy Morse 
1816b5426cedSJeremy Morse   // Specify the live-outs around the joining block.
1817ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
1818ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRax;
1819b5426cedSJeremy Morse 
1820b5426cedSJeremy Morse   Optional<ValueIDNum> Result;
1821b5426cedSJeremy Morse 
1822b5426cedSJeremy Morse   // Simple case: join two distinct values on entry to the block.
182389950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
182489950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
1825ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1826b5426cedSJeremy Morse   // Should have picked a PHI in $rsp in block 3.
1827b5426cedSJeremy Morse   EXPECT_TRUE(Result);
18289da51402SLuke Benes   if (Result) {
1829b5426cedSJeremy Morse     EXPECT_EQ(*Result, RspPHIInBlk3);
18309da51402SLuke Benes   }
1831b5426cedSJeremy Morse 
1832b5426cedSJeremy Morse   // If the incoming values are swapped between blocks, we should not
1833b5426cedSJeremy Morse   // successfully join. The CFG merge would select the right values, but in
1834b5426cedSJeremy Morse   // the wrong conditions.
1835b5426cedSJeremy Morse   std::swap(VLiveOuts[1], VLiveOuts[2]);
1836ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1837b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1838b5426cedSJeremy Morse 
1839b5426cedSJeremy Morse   // Swap back,
1840b5426cedSJeremy Morse   std::swap(VLiveOuts[1], VLiveOuts[2]);
1841b5426cedSJeremy Morse   // Setting one of these to being a constant should prohibit merging.
184289950adeSJeremy Morse   VLiveOuts[1].Kind = DbgValue::Const;
184389950adeSJeremy Morse   VLiveOuts[1].MO = MachineOperand::CreateImm(0);
1844ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1845b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1846b5426cedSJeremy Morse 
1847b5426cedSJeremy Morse   // Seeing both to being a constant -> still prohibit, it shouldn't become
1848b5426cedSJeremy Morse   // a value in the register file anywhere.
184989950adeSJeremy Morse   VLiveOuts[2] = VLiveOuts[1];
1850ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1851b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1852b5426cedSJeremy Morse 
1853b5426cedSJeremy Morse   // NoVals shouldn't join with anything else.
185489950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
185589950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::NoVal);
1856ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1857b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1858b5426cedSJeremy Morse 
1859b5426cedSJeremy Morse   // We might merge in another VPHI in such a join. Present pickVPHILoc with
1860b5426cedSJeremy Morse   // such a scenario: first, where one incoming edge has a VPHI with no known
1861b5426cedSJeremy Morse   // value. This represents an edge where there was a PHI value that can't be
1862b5426cedSJeremy Morse   // found in the register file -- we can't subsequently find a PHI here.
186389950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
186489950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
186589950adeSJeremy Morse   EXPECT_EQ(VLiveOuts[2].ID, ValueIDNum::EmptyValue);
1866ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1867b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1868b5426cedSJeremy Morse 
1869b5426cedSJeremy Morse   // However, if we know the value of the incoming VPHI, we can search for its
1870b5426cedSJeremy Morse   // location. Use a PHI machine-value for doing this, as VPHIs should always
1871b5426cedSJeremy Morse   // have PHI values, or they should have been eliminated.
1872ab49dce0SJeremy Morse   MOutLocs[2][0] = RspPHIInBlk2;
187389950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
187489950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
187589950adeSJeremy Morse   VLiveOuts[2].ID = RspPHIInBlk2; // Set location where PHI happens.
1876ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1877b5426cedSJeremy Morse   EXPECT_TRUE(Result);
18789da51402SLuke Benes   if (Result) {
1879b5426cedSJeremy Morse     EXPECT_EQ(*Result, RspPHIInBlk3);
18809da51402SLuke Benes   }
1881b5426cedSJeremy Morse 
1882b5426cedSJeremy Morse   // If that value isn't available from that block, don't join.
1883ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
1884ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1885b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1886b5426cedSJeremy Morse 
1887b5426cedSJeremy Morse   // Check that we don't pick values when the properties disagree, for example
1888b5426cedSJeremy Morse   // different indirectness or DIExpression.
188989950adeSJeremy Morse   DIExpression *NewExpr =
189089950adeSJeremy Morse       DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
1891b5426cedSJeremy Morse   DbgValueProperties PropsWithExpr(NewExpr, false);
189289950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
189389950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def);
1894ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1895b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1896b5426cedSJeremy Morse 
1897b5426cedSJeremy Morse   DbgValueProperties PropsWithIndirect(EmptyExpr, true);
189889950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
189989950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def);
1900ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB3, Var, VLiveOutIdx, MOutLocs, Preds);
1901b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1902b5426cedSJeremy Morse }
1903b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,pickVPHILocLoops)1904b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, pickVPHILocLoops) {
1905b5426cedSJeremy Morse   setupSimpleLoop();
1906b5426cedSJeremy Morse   //    entry
1907b5426cedSJeremy Morse   //     |
1908b5426cedSJeremy Morse   //     |/-----\
1909b5426cedSJeremy Morse   //    loopblk |
1910b5426cedSJeremy Morse   //     |\-----/
1911b5426cedSJeremy Morse   //     |
1912b5426cedSJeremy Morse   //     ret
1913b5426cedSJeremy Morse 
1914b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
1915b5426cedSJeremy Morse   LocIdx RspLoc(0);
1916b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
1917b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
1918b5426cedSJeremy Morse 
1919ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
1920ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
1921b5426cedSJeremy Morse 
1922ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
1923b5426cedSJeremy Morse 
1924b5426cedSJeremy Morse   unsigned EntryBlk = 0, LoopBlk = 1;
1925b5426cedSJeremy Morse 
1926b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
1927b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
1928b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
1929b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(LoopBlk, 0, RaxLoc);
1930b5426cedSJeremy Morse 
1931b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
1932b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
193389950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
193489950adeSJeremy Morse   VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef));
1935b5426cedSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
1936b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
1937b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
1938b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
1939b5426cedSJeremy Morse 
1940b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
1941b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
1942b5426cedSJeremy Morse     Preds.push_back(Pred);
1943b5426cedSJeremy Morse 
1944b5426cedSJeremy Morse   // Specify the live-outs around the joining block.
1945ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
1946ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
1947b5426cedSJeremy Morse 
1948b5426cedSJeremy Morse   Optional<ValueIDNum> Result;
1949b5426cedSJeremy Morse 
1950b5426cedSJeremy Morse   // See that we can merge as normal on a backedge.
195189950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
195289950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
1953ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
1954b5426cedSJeremy Morse   // Should have picked a PHI in $rsp in block 1.
1955b5426cedSJeremy Morse   EXPECT_TRUE(Result);
19569da51402SLuke Benes   if (Result) {
1957b5426cedSJeremy Morse     EXPECT_EQ(*Result, RspPHIInBlk1);
19589da51402SLuke Benes   }
1959b5426cedSJeremy Morse 
1960b5426cedSJeremy Morse   // And that, if the desired values aren't available, we don't merge.
1961ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
1962ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
1963b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1964b5426cedSJeremy Morse 
1965b5426cedSJeremy Morse   // Test the backedge behaviour: PHIs that feed back into themselves can
1966b5426cedSJeremy Morse   // carry this variables value. Feed in LiveInRsp in both $rsp and $rax
1967b5426cedSJeremy Morse   // from the entry block, but only put an appropriate backedge PHI in $rax.
1968b5426cedSJeremy Morse   // Only the $rax location can form the correct PHI.
1969ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
1970ab49dce0SJeremy Morse   MOutLocs[0][1] = LiveInRsp;
1971ab49dce0SJeremy Morse   MOutLocs[1][0] = RaxPHIInBlk1;
1972ab49dce0SJeremy Morse   MOutLocs[1][1] = RaxPHIInBlk1;
197389950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
1974b5426cedSJeremy Morse   // Crucially, a VPHI originating in this block:
197589950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
1976ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
1977b5426cedSJeremy Morse   EXPECT_TRUE(Result);
19789da51402SLuke Benes   if (Result) {
1979b5426cedSJeremy Morse     EXPECT_EQ(*Result, RaxPHIInBlk1);
19809da51402SLuke Benes   }
1981b5426cedSJeremy Morse 
1982b5426cedSJeremy Morse   // Merging should not be permitted if there's a usable PHI on the backedge,
1983b5426cedSJeremy Morse   // but it's in the wrong place. (Overwrite $rax).
1984ab49dce0SJeremy Morse   MOutLocs[1][1] = LiveInRax;
1985ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
1986b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1987b5426cedSJeremy Morse 
1988b5426cedSJeremy Morse   // Additionally, if the VPHI coming back on the loop backedge isn't from
1989b5426cedSJeremy Morse   // this block (block 1), we can't merge it.
1990ab49dce0SJeremy Morse   MOutLocs[1][1] = RaxPHIInBlk1;
199189950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
199289950adeSJeremy Morse   VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
1993ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
1994b5426cedSJeremy Morse   EXPECT_FALSE(Result);
1995b5426cedSJeremy Morse }
1996b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,pickVPHILocBadlyNestedLoops)1997b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, pickVPHILocBadlyNestedLoops) {
1998b5426cedSJeremy Morse   // Run some tests similar to pickVPHILocLoops, with more than one backedge,
1999b5426cedSJeremy Morse   // and check that we merge correctly over many candidate locations.
2000b5426cedSJeremy Morse   setupBadlyNestedLoops();
2001b5426cedSJeremy Morse   //           entry
2002b5426cedSJeremy Morse   //             |
2003b5426cedSJeremy Morse   //           loop1 -o
2004b5426cedSJeremy Morse   //             | ^
2005b5426cedSJeremy Morse   //             | ^
2006b5426cedSJeremy Morse   //           loop2 -o
2007b5426cedSJeremy Morse   //             | ^
2008b5426cedSJeremy Morse   //             | ^
2009b5426cedSJeremy Morse   //           loop3 -o
2010b5426cedSJeremy Morse   //             |
2011b5426cedSJeremy Morse   //            ret
2012b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2013b5426cedSJeremy Morse   LocIdx RspLoc(0);
2014b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2015b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2016b5426cedSJeremy Morse   Register RBX = getRegByName("RBX");
2017b5426cedSJeremy Morse   LocIdx RbxLoc = MTracker->lookupOrTrackRegister(RBX);
2018b5426cedSJeremy Morse 
2019ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
2020ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(5, 3);
2021b5426cedSJeremy Morse 
2022ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 3);
2023b5426cedSJeremy Morse 
2024b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1;
2025b5426cedSJeremy Morse 
2026b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
2027b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
2028b5426cedSJeremy Morse   ValueIDNum LiveInRbx(EntryBlk, 0, RbxLoc);
2029b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(Loop1Blk, 0, RspLoc);
2030b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1(Loop1Blk, 0, RaxLoc);
2031b5426cedSJeremy Morse   ValueIDNum RbxPHIInBlk1(Loop1Blk, 0, RbxLoc);
2032b5426cedSJeremy Morse 
2033b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
2034b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
203589950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
203689950adeSJeremy Morse   VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef));
2037b5426cedSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2038b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2039b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2040b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2041b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
2042b5426cedSJeremy Morse   VLiveOutIdx[MBB4] = &VLiveOuts[4];
2043b5426cedSJeremy Morse 
2044b5426cedSJeremy Morse   // We're going to focus on block 1.
2045b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
2046b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
2047b5426cedSJeremy Morse     Preds.push_back(Pred);
2048b5426cedSJeremy Morse 
2049b5426cedSJeremy Morse   // Specify the live-outs around the joining block. Incoming edges from the
2050b5426cedSJeremy Morse   // entry block, self, and loop2.
2051ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2052ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
2053ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRbx;
2054b5426cedSJeremy Morse 
2055b5426cedSJeremy Morse   Optional<ValueIDNum> Result;
2056b5426cedSJeremy Morse 
2057b5426cedSJeremy Morse   // See that we can merge as normal on a backedge.
205889950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
205989950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
206089950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
2061ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2062b5426cedSJeremy Morse   // Should have picked a PHI in $rsp in block 1.
2063b5426cedSJeremy Morse   EXPECT_TRUE(Result);
20649da51402SLuke Benes   if (Result) {
2065b5426cedSJeremy Morse     EXPECT_EQ(*Result, RspPHIInBlk1);
20669da51402SLuke Benes   }
2067b5426cedSJeremy Morse 
2068b5426cedSJeremy Morse   // Check too that permuting the live-out locations prevents merging
2069ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRax;
2070ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRbx;
2071ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
2072ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2073b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2074b5426cedSJeremy Morse 
2075ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2076ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
2077ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRbx;
2078b5426cedSJeremy Morse 
2079b5426cedSJeremy Morse   // Feeding a PHI back on one backedge shouldn't merge (block 1 self backedge
2080b5426cedSJeremy Morse   // wants LiveInRax).
2081ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
2082ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2083b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2084b5426cedSJeremy Morse 
2085b5426cedSJeremy Morse   // If the variables value on that edge is a VPHI feeding into itself, that's
2086b5426cedSJeremy Morse   // fine.
208789950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
208889950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
208989950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
2090ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2091b5426cedSJeremy Morse   EXPECT_TRUE(Result);
20929da51402SLuke Benes   if (Result) {
2093b5426cedSJeremy Morse     EXPECT_EQ(*Result, RspPHIInBlk1);
20949da51402SLuke Benes   }
2095b5426cedSJeremy Morse 
2096b5426cedSJeremy Morse   // Likewise: the other backedge being a VPHI from block 1 should be accepted.
2097ab49dce0SJeremy Morse   MOutLocs[2][0] = RspPHIInBlk1;
209889950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
209989950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
210089950adeSJeremy Morse   VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
2101ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2102b5426cedSJeremy Morse   EXPECT_TRUE(Result);
21039da51402SLuke Benes   if (Result) {
2104b5426cedSJeremy Morse     EXPECT_EQ(*Result, RspPHIInBlk1);
21059da51402SLuke Benes   }
2106b5426cedSJeremy Morse 
2107b5426cedSJeremy Morse   // Here's where it becomes tricky: we should not merge if there are two
2108b5426cedSJeremy Morse   // _distinct_ backedge PHIs. We can't have a PHI that happens in both rsp
2109b5426cedSJeremy Morse   // and rax for example. We can only pick one location as the live-in.
2110ab49dce0SJeremy Morse   MOutLocs[2][0] = RaxPHIInBlk1;
2111ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2112b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2113b5426cedSJeremy Morse 
2114b5426cedSJeremy Morse   // The above test sources correct machine-PHI-value from two places. Now
2115b5426cedSJeremy Morse   // try with one machine-PHI-value, but placed in two different locations
2116b5426cedSJeremy Morse   // on the backedge. Again, we can't merge a location here, there's no
2117b5426cedSJeremy Morse   // location that works on all paths.
2118ab49dce0SJeremy Morse   MOutLocs[0][0] = LiveInRsp;
2119ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
2120ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
2121ab49dce0SJeremy Morse   MOutLocs[2][1] = RspPHIInBlk1;
2122ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2123b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2124b5426cedSJeremy Morse 
2125b5426cedSJeremy Morse   // Scatter various PHI values across the available locations. Only rbx (loc 2)
2126b5426cedSJeremy Morse   // has the right value in both backedges -- that's the loc that should be
2127b5426cedSJeremy Morse   // picked.
2128ab49dce0SJeremy Morse   MOutLocs[0][2] = LiveInRsp;
2129ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
2130ab49dce0SJeremy Morse   MOutLocs[1][1] = RaxPHIInBlk1;
2131ab49dce0SJeremy Morse   MOutLocs[1][2] = RbxPHIInBlk1;
2132ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRsp;
2133ab49dce0SJeremy Morse   MOutLocs[2][1] = RspPHIInBlk1;
2134ab49dce0SJeremy Morse   MOutLocs[2][2] = RbxPHIInBlk1;
2135ab49dce0SJeremy Morse   Result = pickVPHILoc(*MBB1, Var, VLiveOutIdx, MOutLocs, Preds);
2136b5426cedSJeremy Morse   EXPECT_TRUE(Result);
21379da51402SLuke Benes   if (Result) {
2138b5426cedSJeremy Morse     EXPECT_EQ(*Result, RbxPHIInBlk1);
2139b5426cedSJeremy Morse   }
21409da51402SLuke Benes }
2141b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,vlocJoinDiamond)2142b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, vlocJoinDiamond) {
2143b5426cedSJeremy Morse   //        entry
2144b5426cedSJeremy Morse   //        /  \
2145b5426cedSJeremy Morse   //      br1  br2
2146b5426cedSJeremy Morse   //        \  /
2147b5426cedSJeremy Morse   //         ret
2148b5426cedSJeremy Morse   setupDiamondBlocks();
2149b5426cedSJeremy Morse 
2150b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2151b5426cedSJeremy Morse   LocIdx RspLoc(0);
2152b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2153b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2154b5426cedSJeremy Morse 
2155b5426cedSJeremy Morse   unsigned EntryBlk = 0, Br2Blk = 2, RetBlk = 3;
2156b5426cedSJeremy Morse 
2157b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
2158b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
2159b5426cedSJeremy Morse   ValueIDNum RspPHIInBlkBr2Blk(Br2Blk, 0, RspLoc);
2160b5426cedSJeremy Morse   ValueIDNum RspPHIInBlkRetBlk(RetBlk, 0, RspLoc);
2161b5426cedSJeremy Morse 
2162b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
2163b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
216489950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
216589950adeSJeremy Morse   VLiveOuts.resize(4, DbgValue(EmptyProps, DbgValue::Undef));
216689950adeSJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2167b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2168b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2169b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2170b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
2171b5426cedSJeremy Morse 
2172b5426cedSJeremy Morse   SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2173b5426cedSJeremy Morse   AllBlocks.insert(MBB0);
2174b5426cedSJeremy Morse   AllBlocks.insert(MBB1);
2175b5426cedSJeremy Morse   AllBlocks.insert(MBB2);
2176b5426cedSJeremy Morse   AllBlocks.insert(MBB3);
2177b5426cedSJeremy Morse 
2178b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
2179b5426cedSJeremy Morse   for (const auto *Pred : MBB3->predecessors())
2180b5426cedSJeremy Morse     Preds.push_back(Pred);
2181b5426cedSJeremy Morse 
2182b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2183b5426cedSJeremy Morse   AllVars.insert(Var);
2184b5426cedSJeremy Morse 
2185b5426cedSJeremy Morse   // vlocJoin is here to propagate incoming values, and eliminate PHIs. Start
2186b5426cedSJeremy Morse   // off by propagating a value into the merging block, number 3.
218789950adeSJeremy Morse   DbgValue JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
218889950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
218989950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
21908dda516bSJeremy Morse   bool Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2191b5426cedSJeremy Morse   EXPECT_TRUE(Result); // Output locs should have changed.
219289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
219389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
2194b5426cedSJeremy Morse 
2195b5426cedSJeremy Morse   // And if we did it a second time, leaving the live-ins as it was, then
2196b5426cedSJeremy Morse   // we should report no change.
21978dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2198b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2199b5426cedSJeremy Morse 
2200b5426cedSJeremy Morse   // If the live-in variable values are different, but there's no PHI placed
2201b5426cedSJeremy Morse   // in this block, then just pick a location. It should be the first (in RPO)
2202b5426cedSJeremy Morse   // predecessor to avoid being a backedge.
220389950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
220489950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
220589950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::NoVal);
22068dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2207b5426cedSJeremy Morse   EXPECT_TRUE(Result);
220889950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
2209b5426cedSJeremy Morse   // RPO is blocks 0 2 1 3, so LiveInRax is picked as the first predecessor
2210b5426cedSJeremy Morse   // of this join.
221189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRax);
2212b5426cedSJeremy Morse 
2213b5426cedSJeremy Morse   // No tests for whether vlocJoin will pass-through a variable with differing
2214b5426cedSJeremy Morse   // expressions / properties. Those can only come about due to assignments; and
2215b5426cedSJeremy Morse   // for any assignment at all, a PHI should have been placed at the dominance
2216b5426cedSJeremy Morse   // frontier. We rely on the IDF calculator being accurate (which is OK,
2217b5426cedSJeremy Morse   // because so does the rest of LLVM).
2218b5426cedSJeremy Morse 
2219b5426cedSJeremy Morse   // Try placing a PHI. With differing input values (LiveInRsp, LiveInRax),
2220b5426cedSJeremy Morse   // this PHI should not be eliminated.
222189950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
22228dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2223b5426cedSJeremy Morse   // Expect no change.
2224b5426cedSJeremy Morse   EXPECT_FALSE(Result);
222589950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
2226b5426cedSJeremy Morse   // This should not have been assigned a fixed value.
222789950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, ValueIDNum::EmptyValue);
222889950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 3);
2229b5426cedSJeremy Morse 
2230b5426cedSJeremy Morse   // Try a simple PHI elimination. Put a PHI in block 3, but LiveInRsp on both
2231b5426cedSJeremy Morse   // incoming edges. Re-load in and out-locs with unrelated values; they're
2232b5426cedSJeremy Morse   // irrelevant.
223389950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
223489950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
223589950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
22368dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2237b5426cedSJeremy Morse   EXPECT_TRUE(Result);
223889950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
223989950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
2240b5426cedSJeremy Morse 
2241b5426cedSJeremy Morse   // If the "current" live-in is a VPHI, but not a VPHI generated in the current
2242b5426cedSJeremy Morse   // block, then it's the remains of an earlier value propagation. We should
2243b5426cedSJeremy Morse   // value propagate through this merge. Even if the current incoming values
2244b5426cedSJeremy Morse   // disagree, because we've previously determined any VPHI here is redundant.
224589950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
224689950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
224789950adeSJeremy Morse   JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
22488dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2249b5426cedSJeremy Morse   EXPECT_TRUE(Result);
225089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
225189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRax); // from block 2
2252b5426cedSJeremy Morse 
2253b5426cedSJeremy Morse   // The above test, but test that we will install one value-propagated VPHI
2254b5426cedSJeremy Morse   // over another.
225589950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
225689950adeSJeremy Morse   VLiveOuts[2] = DbgValue(0, EmptyProps, DbgValue::VPHI);
225789950adeSJeremy Morse   JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
22588dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2259b5426cedSJeremy Morse   EXPECT_TRUE(Result);
226089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
226189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 0);
2262b5426cedSJeremy Morse 
2263b5426cedSJeremy Morse   // We shouldn't eliminate PHIs when properties disagree.
2264b5426cedSJeremy Morse   DbgValueProperties PropsWithIndirect(EmptyExpr, true);
226589950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
226689950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def);
226789950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
22688dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2269b5426cedSJeremy Morse   EXPECT_FALSE(Result);
227089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
227189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 3);
2272b5426cedSJeremy Morse 
2273b5426cedSJeremy Morse   // Even if properties disagree, we should still value-propagate if there's no
2274b5426cedSJeremy Morse   // PHI to be eliminated. The disagreeing values should work themselves out,
2275b5426cedSJeremy Morse   // seeing how we've determined no PHI is necessary.
227689950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
227789950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithIndirect, DbgValue::Def);
227889950adeSJeremy Morse   JoinedLoc = DbgValue(2, EmptyProps, DbgValue::VPHI);
22798dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2280b5426cedSJeremy Morse   EXPECT_TRUE(Result);
228189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
228289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
2283b5426cedSJeremy Morse   // Also check properties come from block 2, the first RPO predecessor to block
2284b5426cedSJeremy Morse   // three.
228589950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Properties, PropsWithIndirect);
2286b5426cedSJeremy Morse 
2287b5426cedSJeremy Morse   // Again, disagreeing properties, this time the expr, should cause a PHI to
2288b5426cedSJeremy Morse   // not be eliminated.
228989950adeSJeremy Morse   DIExpression *NewExpr =
229089950adeSJeremy Morse       DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
2291b5426cedSJeremy Morse   DbgValueProperties PropsWithExpr(NewExpr, false);
229289950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
229389950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRsp, PropsWithExpr, DbgValue::Def);
229489950adeSJeremy Morse   JoinedLoc = DbgValue(3, EmptyProps, DbgValue::VPHI);
22958dda516bSJeremy Morse   Result = vlocJoin(*MBB3, VLiveOutIdx, AllBlocks, JoinedLoc);
2296b5426cedSJeremy Morse   EXPECT_FALSE(Result);
2297b5426cedSJeremy Morse }
2298b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,vlocJoinLoops)2299b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, vlocJoinLoops) {
2300b5426cedSJeremy Morse   setupSimpleLoop();
2301b5426cedSJeremy Morse   //    entry
2302b5426cedSJeremy Morse   //     |
2303b5426cedSJeremy Morse   //     |/-----\
2304b5426cedSJeremy Morse   //    loopblk |
2305b5426cedSJeremy Morse   //     |\-----/
2306b5426cedSJeremy Morse   //     |
2307b5426cedSJeremy Morse   //     ret
2308b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2309b5426cedSJeremy Morse   LocIdx RspLoc(0);
2310b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2311b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2312b5426cedSJeremy Morse 
2313b5426cedSJeremy Morse   unsigned EntryBlk = 0, LoopBlk = 1;
2314b5426cedSJeremy Morse 
2315b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
2316b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
2317b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1(LoopBlk, 0, RspLoc);
2318b5426cedSJeremy Morse 
2319b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
2320b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
232189950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
232289950adeSJeremy Morse   VLiveOuts.resize(3, DbgValue(EmptyProps, DbgValue::Undef));
2323849b1794SJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2324b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2325b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2326b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2327b5426cedSJeremy Morse 
2328b5426cedSJeremy Morse   SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2329b5426cedSJeremy Morse   AllBlocks.insert(MBB0);
2330b5426cedSJeremy Morse   AllBlocks.insert(MBB1);
2331b5426cedSJeremy Morse   AllBlocks.insert(MBB2);
2332b5426cedSJeremy Morse 
2333b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 2> Preds;
2334b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
2335b5426cedSJeremy Morse     Preds.push_back(Pred);
2336b5426cedSJeremy Morse 
2337b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2338b5426cedSJeremy Morse   AllVars.insert(Var);
2339b5426cedSJeremy Morse 
2340b5426cedSJeremy Morse   // Test some back-edge-specific behaviours of vloc join. Mostly: the fact that
2341b5426cedSJeremy Morse   // VPHIs that arrive on backedges can be eliminated, despite having different
2342b5426cedSJeremy Morse   // values to the predecessor.
2343b5426cedSJeremy Morse 
2344b5426cedSJeremy Morse   // First: when there's no VPHI placed already, propagate the live-in value of
2345b5426cedSJeremy Morse   // the first RPO predecessor.
234689950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
234789950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
234889950adeSJeremy Morse   DbgValue JoinedLoc = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
23498dda516bSJeremy Morse   bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2350b5426cedSJeremy Morse   EXPECT_TRUE(Result);
235189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
235289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
2353b5426cedSJeremy Morse 
2354b5426cedSJeremy Morse   // If there is a VPHI: don't elimiante it if there are disagreeing values.
235589950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
235689950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
235789950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
23588dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2359b5426cedSJeremy Morse   EXPECT_FALSE(Result);
236089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
236189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2362b5426cedSJeremy Morse 
2363b5426cedSJeremy Morse   // If we feed this VPHI back into itself though, we can eliminate it.
236489950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
236589950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
236689950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
23678dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2368b5426cedSJeremy Morse   EXPECT_TRUE(Result);
236989950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
237089950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
2371b5426cedSJeremy Morse 
2372b5426cedSJeremy Morse   // Don't eliminate backedge VPHIs if the predecessors have different
2373b5426cedSJeremy Morse   // properties.
237489950adeSJeremy Morse   DIExpression *NewExpr =
237589950adeSJeremy Morse       DIExpression::prepend(EmptyExpr, DIExpression::ApplyOffset, 4);
2376b5426cedSJeremy Morse   DbgValueProperties PropsWithExpr(NewExpr, false);
237789950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
237889950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, PropsWithExpr, DbgValue::VPHI);
237989950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
23808dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2381b5426cedSJeremy Morse   EXPECT_FALSE(Result);
238289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
238389950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2384b5426cedSJeremy Morse 
2385b5426cedSJeremy Morse   // Backedges with VPHIs, but from the wrong block, shouldn't be eliminated.
238689950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
238789950adeSJeremy Morse   VLiveOuts[1] = DbgValue(0, EmptyProps, DbgValue::VPHI);
238889950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
23898dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2390b5426cedSJeremy Morse   EXPECT_FALSE(Result);
239189950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
239289950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2393b5426cedSJeremy Morse }
2394b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,vlocJoinBadlyNestedLoops)2395b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, vlocJoinBadlyNestedLoops) {
2396b5426cedSJeremy Morse   // Test PHI elimination in the presence of multiple backedges.
2397b5426cedSJeremy Morse   setupBadlyNestedLoops();
2398b5426cedSJeremy Morse   //           entry
2399b5426cedSJeremy Morse   //             |
2400b5426cedSJeremy Morse   //           loop1 -o
2401b5426cedSJeremy Morse   //             | ^
2402b5426cedSJeremy Morse   //             | ^
2403b5426cedSJeremy Morse   //           loop2 -o
2404b5426cedSJeremy Morse   //             | ^
2405b5426cedSJeremy Morse   //             | ^
2406b5426cedSJeremy Morse   //           loop3 -o
2407b5426cedSJeremy Morse   //             |
2408b5426cedSJeremy Morse   //            ret
2409b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2410b5426cedSJeremy Morse   LocIdx RspLoc(0);
2411b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2412b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2413b5426cedSJeremy Morse   Register RBX = getRegByName("RBX");
2414b5426cedSJeremy Morse   LocIdx RbxLoc = MTracker->lookupOrTrackRegister(RBX);
2415b5426cedSJeremy Morse 
2416b5426cedSJeremy Morse   unsigned EntryBlk = 0;
2417b5426cedSJeremy Morse 
2418b5426cedSJeremy Morse   ValueIDNum LiveInRsp(EntryBlk, 0, RspLoc);
2419b5426cedSJeremy Morse   ValueIDNum LiveInRax(EntryBlk, 0, RaxLoc);
2420b5426cedSJeremy Morse   ValueIDNum LiveInRbx(EntryBlk, 0, RbxLoc);
2421b5426cedSJeremy Morse 
2422b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
2423b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
242489950adeSJeremy Morse   SmallVector<DbgValue, 32> VLiveOuts;
242589950adeSJeremy Morse   VLiveOuts.resize(5, DbgValue(EmptyProps, DbgValue::Undef));
2426849b1794SJeremy Morse   InstrRefBasedLDV::LiveIdxT VLiveOutIdx;
2427b5426cedSJeremy Morse   VLiveOutIdx[MBB0] = &VLiveOuts[0];
2428b5426cedSJeremy Morse   VLiveOutIdx[MBB1] = &VLiveOuts[1];
2429b5426cedSJeremy Morse   VLiveOutIdx[MBB2] = &VLiveOuts[2];
2430b5426cedSJeremy Morse   VLiveOutIdx[MBB3] = &VLiveOuts[3];
2431b5426cedSJeremy Morse   VLiveOutIdx[MBB4] = &VLiveOuts[4];
2432b5426cedSJeremy Morse 
2433b5426cedSJeremy Morse   SmallPtrSet<const MachineBasicBlock *, 8> AllBlocks;
2434b5426cedSJeremy Morse   AllBlocks.insert(MBB0);
2435b5426cedSJeremy Morse   AllBlocks.insert(MBB1);
2436b5426cedSJeremy Morse   AllBlocks.insert(MBB2);
2437b5426cedSJeremy Morse   AllBlocks.insert(MBB3);
2438b5426cedSJeremy Morse   AllBlocks.insert(MBB4);
2439b5426cedSJeremy Morse 
2440b5426cedSJeremy Morse   // We're going to focus on block 1.
2441b5426cedSJeremy Morse   SmallVector<const MachineBasicBlock *, 3> Preds;
2442b5426cedSJeremy Morse   for (const auto *Pred : MBB1->predecessors())
2443b5426cedSJeremy Morse     Preds.push_back(Pred);
2444b5426cedSJeremy Morse 
2445b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2446b5426cedSJeremy Morse   AllVars.insert(Var);
2447b5426cedSJeremy Morse 
2448b5426cedSJeremy Morse   // Test a normal VPHI isn't eliminated.
244989950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
245089950adeSJeremy Morse   VLiveOuts[1] = DbgValue(LiveInRax, EmptyProps, DbgValue::Def);
245189950adeSJeremy Morse   VLiveOuts[2] = DbgValue(LiveInRbx, EmptyProps, DbgValue::Def);
245289950adeSJeremy Morse   DbgValue JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
24538dda516bSJeremy Morse   bool Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2454b5426cedSJeremy Morse   EXPECT_FALSE(Result);
245589950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
245689950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2457b5426cedSJeremy Morse 
2458b5426cedSJeremy Morse   // Common VPHIs on backedges should merge.
245989950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
246089950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
246189950adeSJeremy Morse   VLiveOuts[2] = DbgValue(1, EmptyProps, DbgValue::VPHI);
246289950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
24638dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2464b5426cedSJeremy Morse   EXPECT_TRUE(Result);
246589950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::Def);
246689950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.ID, LiveInRsp);
2467b5426cedSJeremy Morse 
2468b5426cedSJeremy Morse   // They shouldn't merge if one of their properties is different.
2469b5426cedSJeremy Morse   DbgValueProperties PropsWithIndirect(EmptyExpr, true);
247089950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
247189950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
247289950adeSJeremy Morse   VLiveOuts[2] = DbgValue(1, PropsWithIndirect, DbgValue::VPHI);
247389950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
24748dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2475b5426cedSJeremy Morse   EXPECT_FALSE(Result);
247689950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
247789950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2478b5426cedSJeremy Morse 
2479b5426cedSJeremy Morse   // VPHIs from different blocks should not merge.
248089950adeSJeremy Morse   VLiveOuts[0] = DbgValue(LiveInRsp, EmptyProps, DbgValue::Def);
248189950adeSJeremy Morse   VLiveOuts[1] = DbgValue(1, EmptyProps, DbgValue::VPHI);
248289950adeSJeremy Morse   VLiveOuts[2] = DbgValue(2, EmptyProps, DbgValue::VPHI);
248389950adeSJeremy Morse   JoinedLoc = DbgValue(1, EmptyProps, DbgValue::VPHI);
24848dda516bSJeremy Morse   Result = vlocJoin(*MBB1, VLiveOutIdx, AllBlocks, JoinedLoc);
2485b5426cedSJeremy Morse   EXPECT_FALSE(Result);
248689950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.Kind, DbgValue::VPHI);
248789950adeSJeremy Morse   EXPECT_EQ(JoinedLoc.BlockNo, 1);
2488b5426cedSJeremy Morse }
2489b5426cedSJeremy Morse 
2490b5426cedSJeremy Morse // Above are tests for picking VPHI locations, and eliminating VPHIs. No
2491b5426cedSJeremy Morse // unit-tests are written for evaluating the transfer function as that's
2492b5426cedSJeremy Morse // pretty straight forwards, or applying VPHI-location-picking to live-ins.
2493b5426cedSJeremy Morse // Instead, pre-set some machine locations and apply buildVLocValueMap to the
2494b5426cedSJeremy Morse // existing CFG patterns.
TEST_F(InstrRefLDVTest,VLocSingleBlock)2495b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocSingleBlock) {
2496b5426cedSJeremy Morse   setupSingleBlock();
2497b5426cedSJeremy Morse 
2498b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2499b5426cedSJeremy Morse   LocIdx RspLoc(0);
2500b5426cedSJeremy Morse 
2501ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
2502ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(1, 2);
2503b5426cedSJeremy Morse 
2504b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(0, 0, RspLoc);
2505ab49dce0SJeremy Morse   MInLocs[0][0] = MOutLocs[0][0] = LiveInRsp;
2506b5426cedSJeremy Morse 
2507b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
2508b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
2509b5426cedSJeremy Morse 
2510b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2511b5426cedSJeremy Morse   AllVars.insert(Var);
2512b5426cedSJeremy Morse 
2513b5426cedSJeremy Morse   // Mild hack: rather than constructing machine instructions in each block
2514b5426cedSJeremy Morse   // and creating lexical scopes across them, instead just tell
2515b5426cedSJeremy Morse   // buildVLocValueMap that there's an assignment in every block. That makes
2516b5426cedSJeremy Morse   // every block in scope.
2517b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2518b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
2519b5426cedSJeremy Morse 
2520b5426cedSJeremy Morse   SmallVector<VLocTracker, 1> VLocs;
25210eee8445SJeremy Morse   VLocs.resize(1, VLocTracker(Overlaps, EmptyExpr));
2522b5426cedSJeremy Morse 
2523b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
2524b5426cedSJeremy Morse 
2525b5426cedSJeremy Morse   // Test that, with no assignments at all, no mappings are created for the
2526b5426cedSJeremy Morse   // variable in this function.
2527b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2528ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2529b5426cedSJeremy Morse   EXPECT_EQ(Output.size(), 0ul);
2530b5426cedSJeremy Morse 
2531b5426cedSJeremy Morse   // If we put an assignment in the transfer function, that should... well,
2532b5426cedSJeremy Morse   // do nothing, because we don't store the live-outs.
2533b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2534b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2535ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2536b5426cedSJeremy Morse   EXPECT_EQ(Output.size(), 0ul);
2537b5426cedSJeremy Morse 
2538b5426cedSJeremy Morse   // There is pretty much nothing else of interest to test with a single block.
2539b5426cedSJeremy Morse   // It's not relevant to the SSA-construction parts of variable values.
2540b5426cedSJeremy Morse }
2541b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,VLocDiamondBlocks)2542b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocDiamondBlocks) {
2543b5426cedSJeremy Morse   setupDiamondBlocks();
2544b5426cedSJeremy Morse   //        entry
2545b5426cedSJeremy Morse   //        /  \
2546b5426cedSJeremy Morse   //      br1  br2
2547b5426cedSJeremy Morse   //        \  /
2548b5426cedSJeremy Morse   //         ret
2549b5426cedSJeremy Morse 
2550b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2551b5426cedSJeremy Morse   LocIdx RspLoc(0);
2552b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2553b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2554b5426cedSJeremy Morse 
2555b5426cedSJeremy Morse   unsigned EntryBlk = 0, RetBlk = 3;
2556b5426cedSJeremy Morse 
2557b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
2558b5426cedSJeremy Morse   ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
2559b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk3 = ValueIDNum(RetBlk, 0, RspLoc);
2560b5426cedSJeremy Morse 
2561ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
2562ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(4, 2);
2563b5426cedSJeremy Morse 
2564ab49dce0SJeremy Morse   initValueArray(MInLocs, 4, 2);
2565ab49dce0SJeremy Morse   initValueArray(MOutLocs, 4, 2);
2566b5426cedSJeremy Morse 
2567b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
2568b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
2569b5426cedSJeremy Morse 
2570b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2571b5426cedSJeremy Morse   AllVars.insert(Var);
2572b5426cedSJeremy Morse 
2573b5426cedSJeremy Morse   // Mild hack: rather than constructing machine instructions in each block
2574b5426cedSJeremy Morse   // and creating lexical scopes across them, instead just tell
2575b5426cedSJeremy Morse   // buildVLocValueMap that there's an assignment in every block. That makes
2576b5426cedSJeremy Morse   // every block in scope.
2577b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2578b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
2579b5426cedSJeremy Morse   AssignBlocks.insert(MBB1);
2580b5426cedSJeremy Morse   AssignBlocks.insert(MBB2);
2581b5426cedSJeremy Morse   AssignBlocks.insert(MBB3);
2582b5426cedSJeremy Morse 
2583b5426cedSJeremy Morse   SmallVector<VLocTracker, 1> VLocs;
25840eee8445SJeremy Morse   VLocs.resize(4, VLocTracker(Overlaps, EmptyExpr));
2585b5426cedSJeremy Morse 
2586b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
2587b5426cedSJeremy Morse 
2588b5426cedSJeremy Morse   // Start off with LiveInRsp in every location.
2589b5426cedSJeremy Morse   for (unsigned int I = 0; I < 4; ++I) {
2590ab49dce0SJeremy Morse     MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
2591ab49dce0SJeremy Morse     MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
2592b5426cedSJeremy Morse   }
2593b5426cedSJeremy Morse 
2594b5426cedSJeremy Morse   auto ClearOutputs = [&]() {
2595b5426cedSJeremy Morse     for (auto &Elem : Output)
2596b5426cedSJeremy Morse       Elem.clear();
2597b5426cedSJeremy Morse   };
2598b5426cedSJeremy Morse   Output.resize(4);
2599b5426cedSJeremy Morse 
2600b5426cedSJeremy Morse   // No assignments -> no values.
2601b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2602ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2603b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2604b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2605b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2606b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2607b5426cedSJeremy Morse 
2608b5426cedSJeremy Morse   // An assignment in the end block should also not affect other blocks; or
2609b5426cedSJeremy Morse   // produce any live-ins.
2610b5426cedSJeremy Morse   VLocs[3].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2611b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2612ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2613b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2614b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2615b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2616b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2617b5426cedSJeremy Morse   ClearOutputs();
2618b5426cedSJeremy Morse 
2619b5426cedSJeremy Morse   // Assignments in either of the side-of-diamond blocks should also not be
2620b5426cedSJeremy Morse   // propagated anywhere.
2621b5426cedSJeremy Morse   VLocs[3].Vars.clear();
2622b5426cedSJeremy Morse   VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2623b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2624ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2625b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2626b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2627b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2628b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2629b5426cedSJeremy Morse   VLocs[2].Vars.clear();
2630b5426cedSJeremy Morse   ClearOutputs();
2631b5426cedSJeremy Morse 
2632b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2633b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2634ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2635b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2636b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2637b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2638b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2639b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2640b5426cedSJeremy Morse   ClearOutputs();
2641b5426cedSJeremy Morse 
2642b5426cedSJeremy Morse   // However: putting an assignment in the first block should propagate variable
2643b5426cedSJeremy Morse   // values through to all other blocks, as it dominates.
2644b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2645b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2646ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2647b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2648b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2649b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2650b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2651b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2652b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
2653b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2654b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
2655b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2656b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
2657b5426cedSJeremy Morse   ClearOutputs();
2658b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2659b5426cedSJeremy Morse 
2660b5426cedSJeremy Morse   // Additionally, even if that value isn't available in the register file, it
2661b5426cedSJeremy Morse   // should still be propagated, as buildVLocValueMap shouldn't care about
2662b5426cedSJeremy Morse   // what's in the registers (except for PHIs).
2663b5426cedSJeremy Morse   // values through to all other blocks, as it dominates.
2664b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
2665b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2666ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2667b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2668b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2669b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2670b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2671b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2672b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRax);
2673b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2674b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
2675b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2676b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
2677b5426cedSJeremy Morse   ClearOutputs();
2678b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2679b5426cedSJeremy Morse 
2680b5426cedSJeremy Morse   // We should get a live-in to the merging block, if there are two assigns of
2681b5426cedSJeremy Morse   // the same value in either side of the diamond.
2682b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2683b5426cedSJeremy Morse   VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2684b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2685ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2686b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2687b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2688b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2689b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2690b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2691b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
2692b5426cedSJeremy Morse   ClearOutputs();
2693b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2694b5426cedSJeremy Morse   VLocs[2].Vars.clear();
2695b5426cedSJeremy Morse 
2696b5426cedSJeremy Morse   // If we assign a value in the entry block, then 'undef' on a branch, we
2697b5426cedSJeremy Morse   // shouldn't have a live-in in the merge block.
2698b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2699b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
2700b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2701ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2702b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2703b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2704b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2705b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2706b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2707b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
2708b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2709b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
2710b5426cedSJeremy Morse   ClearOutputs();
2711b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2712b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2713b5426cedSJeremy Morse 
2714b5426cedSJeremy Morse   // Having different values joining into the merge block should mean we have
2715b5426cedSJeremy Morse   // no live-in in that block. Block ones LiveInRax value doesn't appear as a
2716b5426cedSJeremy Morse   // live-in anywhere, it's block internal.
2717b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2718b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
2719b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2720ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2721b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2722b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2723b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2724b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
2725b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2726b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
2727b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2728b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
2729b5426cedSJeremy Morse   ClearOutputs();
2730b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2731b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2732b5426cedSJeremy Morse 
2733b5426cedSJeremy Morse   // But on the other hand, if there's a location in the register file where
2734b5426cedSJeremy Morse   // those two values can be joined, do so.
2735ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRax;
2736b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2737b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
2738b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2739ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2740b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2741b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2742b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2743b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
2744b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2745b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
2746b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2747b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
2748b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
2749b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, RspPHIInBlk3);
2750b5426cedSJeremy Morse   ClearOutputs();
2751b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2752b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2753b5426cedSJeremy Morse }
2754b5426cedSJeremy Morse 
TEST_F(InstrRefLDVTest,VLocSimpleLoop)2755b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocSimpleLoop) {
2756b5426cedSJeremy Morse   setupSimpleLoop();
2757b5426cedSJeremy Morse   //    entry
2758b5426cedSJeremy Morse   //     |
2759b5426cedSJeremy Morse   //     |/-----\
2760b5426cedSJeremy Morse   //    loopblk |
2761b5426cedSJeremy Morse   //     |\-----/
2762b5426cedSJeremy Morse   //     |
2763b5426cedSJeremy Morse   //     ret
2764b5426cedSJeremy Morse 
2765b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
2766b5426cedSJeremy Morse   LocIdx RspLoc(0);
2767b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
2768b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
2769b5426cedSJeremy Morse 
2770b5426cedSJeremy Morse   unsigned EntryBlk = 0, LoopBlk = 1;
2771b5426cedSJeremy Morse 
2772b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
2773b5426cedSJeremy Morse   ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
2774b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1 = ValueIDNum(LoopBlk, 0, RspLoc);
2775b5426cedSJeremy Morse   ValueIDNum RspDefInBlk1 = ValueIDNum(LoopBlk, 1, RspLoc);
2776b5426cedSJeremy Morse   ValueIDNum RaxPHIInBlk1 = ValueIDNum(LoopBlk, 0, RaxLoc);
2777b5426cedSJeremy Morse 
2778ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
2779ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(3, 2);
2780b5426cedSJeremy Morse 
2781ab49dce0SJeremy Morse   initValueArray(MInLocs, 3, 2);
2782ab49dce0SJeremy Morse   initValueArray(MOutLocs, 3, 2);
2783b5426cedSJeremy Morse 
2784b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
2785b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
2786b5426cedSJeremy Morse 
2787b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
2788b5426cedSJeremy Morse   AllVars.insert(Var);
2789b5426cedSJeremy Morse 
2790b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 4> AssignBlocks;
2791b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
2792b5426cedSJeremy Morse   AssignBlocks.insert(MBB1);
2793b5426cedSJeremy Morse   AssignBlocks.insert(MBB2);
2794b5426cedSJeremy Morse 
2795b5426cedSJeremy Morse   SmallVector<VLocTracker, 3> VLocs;
27960eee8445SJeremy Morse   VLocs.resize(3, VLocTracker(Overlaps, EmptyExpr));
2797b5426cedSJeremy Morse 
2798b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
2799b5426cedSJeremy Morse 
2800b5426cedSJeremy Morse   // Start off with LiveInRsp in every location.
2801b5426cedSJeremy Morse   for (unsigned int I = 0; I < 3; ++I) {
2802ab49dce0SJeremy Morse     MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
2803ab49dce0SJeremy Morse     MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
2804b5426cedSJeremy Morse   }
2805b5426cedSJeremy Morse 
2806b5426cedSJeremy Morse   auto ClearOutputs = [&]() {
2807b5426cedSJeremy Morse     for (auto &Elem : Output)
2808b5426cedSJeremy Morse       Elem.clear();
2809b5426cedSJeremy Morse   };
2810b5426cedSJeremy Morse   Output.resize(3);
2811b5426cedSJeremy Morse 
2812b5426cedSJeremy Morse   // Easy starter: a dominating assign should propagate to all blocks.
2813b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2814b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2815ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2816b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2817b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2818b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2819b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2820b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
2821b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2822b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
2823b5426cedSJeremy Morse   ClearOutputs();
2824b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2825b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2826b5426cedSJeremy Morse 
2827b5426cedSJeremy Morse   // Put an undef assignment in the loop. Should get no live-in value.
2828b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2829b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(EmptyProps, DbgValue::Undef)});
2830b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2831ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2832b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2833b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2834b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
2835b5426cedSJeremy Morse   ClearOutputs();
2836b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2837b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2838b5426cedSJeremy Morse 
2839b5426cedSJeremy Morse   // Assignment of the same value should naturally join.
2840b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2841b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2842b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2843ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2844b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2845b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2846b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2847b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2848b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
2849b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2850b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
2851b5426cedSJeremy Morse   ClearOutputs();
2852b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2853b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2854b5426cedSJeremy Morse 
2855b5426cedSJeremy Morse   // Assignment of different values shouldn't join with no machine PHI vals.
2856b5426cedSJeremy Morse   // Will be live-in to exit block as it's dominated.
2857b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2858b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
2859b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2860ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2861b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2862b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2863b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2864b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2865b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
2866b5426cedSJeremy Morse   ClearOutputs();
2867b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2868b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2869b5426cedSJeremy Morse 
2870b5426cedSJeremy Morse   // Install a completely unrelated PHI value, that we should not join on. Try
2871b5426cedSJeremy Morse   // with unrelated assign in loop block again.
2872ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
2873ab49dce0SJeremy Morse   MOutLocs[1][0] = RspDefInBlk1;
2874b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2875b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
2876b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2877ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2878b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2879b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
2880b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2881b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2882b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
2883b5426cedSJeremy Morse   ClearOutputs();
2884b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2885b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2886b5426cedSJeremy Morse 
2887b5426cedSJeremy Morse   // Now, if we assign RspDefInBlk1 in the loop block, we should be able to
2888b5426cedSJeremy Morse   // find the appropriate PHI.
2889ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
2890ab49dce0SJeremy Morse   MOutLocs[1][0] = RspDefInBlk1;
2891b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2892b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
2893b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2894ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2895b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2896b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2897b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2898b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2899b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
2900b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2901b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, RspDefInBlk1);
2902b5426cedSJeremy Morse   ClearOutputs();
2903b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2904b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2905b5426cedSJeremy Morse 
2906b5426cedSJeremy Morse   // If the PHI happens in a different location, the live-in should happen
2907b5426cedSJeremy Morse   // there.
2908ab49dce0SJeremy Morse   MInLocs[1][0] = LiveInRsp;
2909ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
2910ab49dce0SJeremy Morse   MInLocs[1][1] = RaxPHIInBlk1;
2911ab49dce0SJeremy Morse   MOutLocs[1][1] = RspDefInBlk1;
2912b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2913b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
2914b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2915ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2916b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2917b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2918b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2919b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2920b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, RaxPHIInBlk1);
2921b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2922b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, RspDefInBlk1);
2923b5426cedSJeremy Morse   ClearOutputs();
2924b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2925b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2926b5426cedSJeremy Morse 
2927b5426cedSJeremy Morse   // The PHI happening in both places should be handled too. Exactly where
2928b5426cedSJeremy Morse   // isn't important, but if the location picked changes, this test will let
2929b5426cedSJeremy Morse   // you know.
2930ab49dce0SJeremy Morse   MInLocs[1][0] = RaxPHIInBlk1;
2931ab49dce0SJeremy Morse   MOutLocs[1][0] = RspDefInBlk1;
2932ab49dce0SJeremy Morse   MInLocs[1][1] = RaxPHIInBlk1;
2933ab49dce0SJeremy Morse   MOutLocs[1][1] = RspDefInBlk1;
2934b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2935b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(RspDefInBlk1, EmptyProps, DbgValue::Def)});
2936b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2937ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2938b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2939b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2940b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2941b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2942b5426cedSJeremy Morse   // Today, the first register is picked.
2943b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
2944b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2945b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, RspDefInBlk1);
2946b5426cedSJeremy Morse   ClearOutputs();
2947b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2948b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2949b5426cedSJeremy Morse 
2950b5426cedSJeremy Morse   // If the loop block looked a bit like this:
2951b5426cedSJeremy Morse   //    %0 = PHI %1, %2
2952b5426cedSJeremy Morse   //    [...]
2953b5426cedSJeremy Morse   //    DBG_VALUE %0
2954b5426cedSJeremy Morse   // Then with instr-ref it becomes:
2955b5426cedSJeremy Morse   //    DBG_PHI %0
2956b5426cedSJeremy Morse   //    [...]
2957b5426cedSJeremy Morse   //    DBG_INSTR_REF
2958b5426cedSJeremy Morse   // And we would be feeding a machine PHI-value back around the loop. However:
2959b5426cedSJeremy Morse   // this does not mean we can eliminate the variable value PHI and use the
2960b5426cedSJeremy Morse   // variable value from the entry block: they are distinct values that must be
2961b5426cedSJeremy Morse   // joined at some location by the control flow.
2962b5426cedSJeremy Morse   // [This test input would never occur naturally, the machine-PHI would be
2963b5426cedSJeremy Morse   //  eliminated]
2964ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
2965ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
2966ab49dce0SJeremy Morse   MInLocs[1][1] = LiveInRax;
2967ab49dce0SJeremy Morse   MOutLocs[1][1] = LiveInRax;
2968b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2969b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(RspPHIInBlk1, EmptyProps, DbgValue::Def)});
2970b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2971ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2972b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2973b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2974b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2975b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2976b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
2977b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2978b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, RspPHIInBlk1);
2979b5426cedSJeremy Morse   ClearOutputs();
2980b5426cedSJeremy Morse   VLocs[0].Vars.clear();
2981b5426cedSJeremy Morse   VLocs[1].Vars.clear();
2982b5426cedSJeremy Morse 
2983b5426cedSJeremy Morse   // Test that we can eliminate PHIs. A PHI will be placed at the loop head
2984b5426cedSJeremy Morse   // because there's a def in in.
2985ab49dce0SJeremy Morse   MInLocs[1][0] = LiveInRsp;
2986ab49dce0SJeremy Morse   MOutLocs[1][0] = LiveInRsp;
2987b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2988b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
2989b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
2990ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
2991b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
2992b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
2993b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
2994b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
2995b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
2996b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
2997b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
2998b5426cedSJeremy Morse   ClearOutputs();
2999b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3000b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3001b5426cedSJeremy Morse }
3002b5426cedSJeremy Morse 
3003b5426cedSJeremy Morse // test phi elimination with the nested situation
TEST_F(InstrRefLDVTest,VLocNestedLoop)3004b5426cedSJeremy Morse TEST_F(InstrRefLDVTest, VLocNestedLoop) {
3005b5426cedSJeremy Morse   //    entry
3006b5426cedSJeremy Morse   //     |
3007b5426cedSJeremy Morse   //    loop1
3008b5426cedSJeremy Morse   //     ^\
3009b5426cedSJeremy Morse   //     | \    /-\
3010b5426cedSJeremy Morse   //     |  loop2  |
3011b5426cedSJeremy Morse   //     |  /   \-/
3012b5426cedSJeremy Morse   //     ^ /
3013b5426cedSJeremy Morse   //     join
3014b5426cedSJeremy Morse   //     |
3015b5426cedSJeremy Morse   //     ret
3016b5426cedSJeremy Morse   setupNestedLoops();
3017b5426cedSJeremy Morse 
3018b5426cedSJeremy Morse   ASSERT_TRUE(MTracker->getNumLocs() == 1);
3019b5426cedSJeremy Morse   LocIdx RspLoc(0);
3020b5426cedSJeremy Morse   Register RAX = getRegByName("RAX");
3021b5426cedSJeremy Morse   LocIdx RaxLoc = MTracker->lookupOrTrackRegister(RAX);
3022b5426cedSJeremy Morse 
3023b5426cedSJeremy Morse   unsigned EntryBlk = 0, Loop1Blk = 1, Loop2Blk = 2;
3024b5426cedSJeremy Morse 
3025b5426cedSJeremy Morse   ValueIDNum LiveInRsp = ValueIDNum(EntryBlk, 0, RspLoc);
3026b5426cedSJeremy Morse   ValueIDNum LiveInRax = ValueIDNum(EntryBlk, 0, RaxLoc);
3027b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk1 = ValueIDNum(Loop1Blk, 0, RspLoc);
3028b5426cedSJeremy Morse   ValueIDNum RspPHIInBlk2 = ValueIDNum(Loop2Blk, 0, RspLoc);
3029b5426cedSJeremy Morse   ValueIDNum RspDefInBlk2 = ValueIDNum(Loop2Blk, 1, RspLoc);
3030b5426cedSJeremy Morse 
3031ab49dce0SJeremy Morse   FuncValueTable MInLocs, MOutLocs;
3032ab49dce0SJeremy Morse   std::tie(MInLocs, MOutLocs) = allocValueTables(5, 2);
3033b5426cedSJeremy Morse 
3034ab49dce0SJeremy Morse   initValueArray(MInLocs, 5, 2);
3035ab49dce0SJeremy Morse   initValueArray(MOutLocs, 5, 2);
3036b5426cedSJeremy Morse 
3037b5426cedSJeremy Morse   DebugVariable Var(FuncVariable, None, nullptr);
3038b5426cedSJeremy Morse   DbgValueProperties EmptyProps(EmptyExpr, false);
3039b5426cedSJeremy Morse 
3040b5426cedSJeremy Morse   SmallSet<DebugVariable, 4> AllVars;
3041b5426cedSJeremy Morse   AllVars.insert(Var);
3042b5426cedSJeremy Morse 
3043b5426cedSJeremy Morse   SmallPtrSet<MachineBasicBlock *, 5> AssignBlocks;
3044b5426cedSJeremy Morse   AssignBlocks.insert(MBB0);
3045b5426cedSJeremy Morse   AssignBlocks.insert(MBB1);
3046b5426cedSJeremy Morse   AssignBlocks.insert(MBB2);
3047b5426cedSJeremy Morse   AssignBlocks.insert(MBB3);
3048b5426cedSJeremy Morse   AssignBlocks.insert(MBB4);
3049b5426cedSJeremy Morse 
3050b5426cedSJeremy Morse   SmallVector<VLocTracker, 5> VLocs;
30510eee8445SJeremy Morse   VLocs.resize(5, VLocTracker(Overlaps, EmptyExpr));
3052b5426cedSJeremy Morse 
3053b5426cedSJeremy Morse   InstrRefBasedLDV::LiveInsT Output;
3054b5426cedSJeremy Morse 
3055b5426cedSJeremy Morse   // Start off with LiveInRsp in every location.
3056b5426cedSJeremy Morse   for (unsigned int I = 0; I < 5; ++I) {
3057ab49dce0SJeremy Morse     MInLocs[I][0] = MInLocs[I][1] = LiveInRsp;
3058ab49dce0SJeremy Morse     MOutLocs[I][0] = MOutLocs[I][1] = LiveInRsp;
3059b5426cedSJeremy Morse   }
3060b5426cedSJeremy Morse 
3061b5426cedSJeremy Morse   auto ClearOutputs = [&]() {
3062b5426cedSJeremy Morse     for (auto &Elem : Output)
3063b5426cedSJeremy Morse       Elem.clear();
3064b5426cedSJeremy Morse   };
3065b5426cedSJeremy Morse   Output.resize(5);
3066b5426cedSJeremy Morse 
3067b5426cedSJeremy Morse   // A dominating assign should propagate to all blocks.
3068b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3069b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3070ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3071b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3072b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3073b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3074b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3075b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3076b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3077b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
3078b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3079b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
3080b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3081b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
3082b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3083b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, LiveInRsp);
3084b5426cedSJeremy Morse   ClearOutputs();
3085b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3086b5426cedSJeremy Morse 
3087b5426cedSJeremy Morse   // Test that an assign in the inner loop causes unresolved PHIs at the heads
3088b5426cedSJeremy Morse   // of both loops, and no output location. Dominated blocks do get values.
3089b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3090b5426cedSJeremy Morse   VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
3091b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3092ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3093b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3094b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3095b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3096b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3097b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3098b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3099b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
3100b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3101b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
3102b5426cedSJeremy Morse   ClearOutputs();
3103b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3104b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3105b5426cedSJeremy Morse 
3106b5426cedSJeremy Morse   // Same test, but with no assignment in block 0. We should still get values
3107b5426cedSJeremy Morse   // in dominated blocks.
3108b5426cedSJeremy Morse   VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
3109b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3110ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3111b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3112b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3113b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3114b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3115b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3116b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3117b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
3118b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3119b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
3120b5426cedSJeremy Morse   ClearOutputs();
3121b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3122b5426cedSJeremy Morse 
3123b5426cedSJeremy Morse   // Similarly, assignments in the outer loop gives location to dominated
3124b5426cedSJeremy Morse   // blocks, but no PHI locations are found at the outer loop head.
3125b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3126b5426cedSJeremy Morse   VLocs[3].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
3127b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3128ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3129b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3130b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3131b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3132b5426cedSJeremy Morse   EXPECT_EQ(Output[3].size(), 0ul);
3133b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3134b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3135b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
3136b5426cedSJeremy Morse   ClearOutputs();
3137b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3138b5426cedSJeremy Morse   VLocs[3].Vars.clear();
3139b5426cedSJeremy Morse 
3140b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3141b5426cedSJeremy Morse   VLocs[1].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
3142b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3143ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3144b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3145b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3146b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3147b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3148b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3149b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3150b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRax);
3151b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3152b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
3153b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3154b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
3155b5426cedSJeremy Morse   ClearOutputs();
3156b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3157b5426cedSJeremy Morse   VLocs[1].Vars.clear();
3158b5426cedSJeremy Morse 
3159b5426cedSJeremy Morse   // With an assignment of the same value in the inner loop, we should work out
3160b5426cedSJeremy Morse   // that all PHIs can be eliminated and the same value is live-through the
3161b5426cedSJeremy Morse   // whole function.
3162b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3163b5426cedSJeremy Morse   VLocs[2].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3164b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3165ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3166b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3167b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 1ul);
3168b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 1ul);
3169b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3170b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3171b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3172b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, LiveInRsp);
3173b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3174b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, LiveInRsp);
3175b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3176b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRsp);
3177b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3178b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, LiveInRsp);
3179b5426cedSJeremy Morse   ClearOutputs();
3180b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3181b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3182b5426cedSJeremy Morse 
3183b5426cedSJeremy Morse   // If we have an assignment in the inner loop, and a PHI for it at the inner
3184b5426cedSJeremy Morse   // loop head, we could find a live-in location for the inner loop. But because
3185b5426cedSJeremy Morse   // the outer loop has no PHI, we can't find a variable value for outer loop
3186b5426cedSJeremy Morse   // head, so can't have a live-in value for the inner loop head.
3187ab49dce0SJeremy Morse   MInLocs[2][0] = RspPHIInBlk2;
3188ab49dce0SJeremy Morse   MOutLocs[2][0] = LiveInRax;
3189b5426cedSJeremy Morse   // NB: all other machine locations are LiveInRsp, disallowing a PHI in block
3190b5426cedSJeremy Morse   // one. Even though RspPHIInBlk2 isn't available later in the function, we
3191b5426cedSJeremy Morse   // should still produce a live-in value. The fact it's unavailable is a
3192b5426cedSJeremy Morse   // different concern.
3193b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3194b5426cedSJeremy Morse   VLocs[2].Vars.insert({Var, DbgValue(LiveInRax, EmptyProps, DbgValue::Def)});
3195b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3196ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3197b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3198b5426cedSJeremy Morse   EXPECT_EQ(Output[1].size(), 0ul);
3199b5426cedSJeremy Morse   EXPECT_EQ(Output[2].size(), 0ul);
3200b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3201b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3202b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3203b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, LiveInRax);
3204b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3205b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, LiveInRax);
3206b5426cedSJeremy Morse   ClearOutputs();
3207b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3208b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3209b5426cedSJeremy Morse 
3210b5426cedSJeremy Morse   // Have an assignment in inner loop that can have a PHI resolved; and add a
3211b5426cedSJeremy Morse   // machine value PHI to the outer loop head, so that we can find a location
3212b5426cedSJeremy Morse   // all the way through the function.
3213ab49dce0SJeremy Morse   MInLocs[1][0] = RspPHIInBlk1;
3214ab49dce0SJeremy Morse   MOutLocs[1][0] = RspPHIInBlk1;
3215ab49dce0SJeremy Morse   MInLocs[2][0] = RspPHIInBlk2;
3216ab49dce0SJeremy Morse   MOutLocs[2][0] = RspDefInBlk2;
3217ab49dce0SJeremy Morse   MInLocs[3][0] = RspDefInBlk2;
3218ab49dce0SJeremy Morse   MOutLocs[3][0] = RspDefInBlk2;
3219b5426cedSJeremy Morse   VLocs[0].Vars.insert({Var, DbgValue(LiveInRsp, EmptyProps, DbgValue::Def)});
3220b5426cedSJeremy Morse   VLocs[2].Vars.insert({Var, DbgValue(RspDefInBlk2, EmptyProps, DbgValue::Def)});
3221b5426cedSJeremy Morse   buildVLocValueMap(OutermostLoc, AllVars, AssignBlocks, Output,
3222ab49dce0SJeremy Morse                     MOutLocs, MInLocs, VLocs);
3223b5426cedSJeremy Morse   EXPECT_EQ(Output[0].size(), 0ul);
3224b5426cedSJeremy Morse   ASSERT_EQ(Output[1].size(), 1ul);
3225b5426cedSJeremy Morse   ASSERT_EQ(Output[2].size(), 1ul);
3226b5426cedSJeremy Morse   ASSERT_EQ(Output[3].size(), 1ul);
3227b5426cedSJeremy Morse   ASSERT_EQ(Output[4].size(), 1ul);
3228b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.Kind, DbgValue::Def);
3229b5426cedSJeremy Morse   EXPECT_EQ(Output[1][0].second.ID, RspPHIInBlk1);
3230b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.Kind, DbgValue::Def);
3231b5426cedSJeremy Morse   EXPECT_EQ(Output[2][0].second.ID, RspPHIInBlk2);
3232b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.Kind, DbgValue::Def);
3233b5426cedSJeremy Morse   EXPECT_EQ(Output[3][0].second.ID, RspDefInBlk2);
3234b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.Kind, DbgValue::Def);
3235b5426cedSJeremy Morse   EXPECT_EQ(Output[4][0].second.ID, RspDefInBlk2);
3236b5426cedSJeremy Morse   ClearOutputs();
3237b5426cedSJeremy Morse   VLocs[0].Vars.clear();
3238b5426cedSJeremy Morse   VLocs[2].Vars.clear();
3239b5426cedSJeremy Morse }
3240b5426cedSJeremy Morse 
3241