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