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