1 //===- DependencyGraphTest.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/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h" 10 #include "llvm/Analysis/AliasAnalysis.h" 11 #include "llvm/Analysis/AssumptionCache.h" 12 #include "llvm/Analysis/BasicAliasAnalysis.h" 13 #include "llvm/Analysis/TargetLibraryInfo.h" 14 #include "llvm/AsmParser/Parser.h" 15 #include "llvm/IR/DataLayout.h" 16 #include "llvm/IR/Dominators.h" 17 #include "llvm/SandboxIR/Context.h" 18 #include "llvm/SandboxIR/Function.h" 19 #include "llvm/SandboxIR/Instruction.h" 20 #include "llvm/Support/SourceMgr.h" 21 #include "gmock/gmock-matchers.h" 22 #include "gtest/gtest.h" 23 24 using namespace llvm; 25 26 struct DependencyGraphTest : public testing::Test { 27 LLVMContext C; 28 std::unique_ptr<Module> M; 29 std::unique_ptr<AssumptionCache> AC; 30 std::unique_ptr<DominatorTree> DT; 31 std::unique_ptr<BasicAAResult> BAA; 32 std::unique_ptr<AAResults> AA; 33 34 void parseIR(LLVMContext &C, const char *IR) { 35 SMDiagnostic Err; 36 M = parseAssemblyString(IR, Err, C); 37 if (!M) 38 Err.print("DependencyGraphTest", errs()); 39 } 40 41 AAResults &getAA(llvm::Function &LLVMF) { 42 TargetLibraryInfoImpl TLII; 43 TargetLibraryInfo TLI(TLII); 44 AA = std::make_unique<AAResults>(TLI); 45 AC = std::make_unique<AssumptionCache>(LLVMF); 46 DT = std::make_unique<DominatorTree>(LLVMF); 47 BAA = std::make_unique<BasicAAResult>(M->getDataLayout(), LLVMF, TLI, *AC, 48 DT.get()); 49 AA->addAAResult(*BAA); 50 return *AA; 51 } 52 /// \Returns true if there is a dependency: SrcN->DstN. 53 bool memDependency(sandboxir::DGNode *SrcN, sandboxir::DGNode *DstN) { 54 if (auto *MemDstN = dyn_cast<sandboxir::MemDGNode>(DstN)) 55 return MemDstN->hasMemPred(SrcN); 56 return false; 57 } 58 }; 59 60 TEST_F(DependencyGraphTest, isStackSaveOrRestoreIntrinsic) { 61 parseIR(C, R"IR( 62 declare void @llvm.sideeffect() 63 define void @foo(i8 %v1, ptr %ptr) { 64 %add = add i8 %v1, %v1 65 %stacksave = call ptr @llvm.stacksave() 66 call void @llvm.stackrestore(ptr %stacksave) 67 call void @llvm.sideeffect() 68 ret void 69 } 70 )IR"); 71 llvm::Function *LLVMF = &*M->getFunction("foo"); 72 sandboxir::Context Ctx(C); 73 sandboxir::Function *F = Ctx.createFunction(LLVMF); 74 auto *BB = &*F->begin(); 75 auto It = BB->begin(); 76 auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 77 auto *StackSave = cast<sandboxir::CallInst>(&*It++); 78 auto *StackRestore = cast<sandboxir::CallInst>(&*It++); 79 auto *Other = cast<sandboxir::CallInst>(&*It++); 80 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 81 82 using DGNode = sandboxir::DGNode; 83 EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Add)); 84 EXPECT_TRUE(DGNode::isStackSaveOrRestoreIntrinsic(StackSave)); 85 EXPECT_TRUE(DGNode::isStackSaveOrRestoreIntrinsic(StackRestore)); 86 EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Other)); 87 EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Ret)); 88 } 89 90 TEST_F(DependencyGraphTest, Instruction_isMemDepCandidate) { 91 parseIR(C, R"IR( 92 declare void @llvm.fake.use(...) 93 declare void @llvm.sideeffect() 94 declare void @llvm.pseudoprobe(i64, i64, i32, i64) 95 declare void @bar() 96 define void @foo(i8 %v1, ptr %ptr) { 97 %add0 = add i8 %v1, %v1 98 %ld0 = load i8, ptr %ptr 99 store i8 %v1, ptr %ptr 100 call void @llvm.sideeffect() 101 call void @llvm.pseudoprobe(i64 42, i64 1, i32 0, i64 -1) 102 call void @llvm.fake.use(ptr %ptr) 103 call void @bar() 104 ret void 105 } 106 )IR"); 107 llvm::Function *LLVMF = &*M->getFunction("foo"); 108 sandboxir::Context Ctx(C); 109 sandboxir::Function *F = Ctx.createFunction(LLVMF); 110 auto *BB = &*F->begin(); 111 auto It = BB->begin(); 112 auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 113 auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); 114 auto *St0 = cast<sandboxir::StoreInst>(&*It++); 115 auto *SideEffect0 = cast<sandboxir::CallInst>(&*It++); 116 auto *PseudoProbe0 = cast<sandboxir::CallInst>(&*It++); 117 auto *OtherIntrinsic0 = cast<sandboxir::CallInst>(&*It++); 118 auto *CallBar = cast<sandboxir::CallInst>(&*It++); 119 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 120 121 using DGNode = sandboxir::DGNode; 122 123 EXPECT_FALSE(DGNode::isMemDepCandidate(Add0)); 124 EXPECT_TRUE(DGNode::isMemDepCandidate(Ld0)); 125 EXPECT_TRUE(DGNode::isMemDepCandidate(St0)); 126 EXPECT_FALSE(DGNode::isMemDepCandidate(SideEffect0)); 127 EXPECT_FALSE(DGNode::isMemDepCandidate(PseudoProbe0)); 128 EXPECT_TRUE(DGNode::isMemDepCandidate(OtherIntrinsic0)); 129 EXPECT_TRUE(DGNode::isMemDepCandidate(CallBar)); 130 EXPECT_FALSE(DGNode::isMemDepCandidate(Ret)); 131 } 132 133 TEST_F(DependencyGraphTest, Instruction_isMemIntrinsic) { 134 parseIR(C, R"IR( 135 declare void @llvm.sideeffect() 136 declare void @llvm.pseudoprobe(i64) 137 declare void @llvm.assume(i1) 138 139 define void @foo(ptr %ptr, i1 %cond) { 140 call void @llvm.sideeffect() 141 call void @llvm.pseudoprobe(i64 42) 142 call void @llvm.assume(i1 %cond) 143 ret void 144 } 145 )IR"); 146 llvm::Function *LLVMF = &*M->getFunction("foo"); 147 sandboxir::Context Ctx(C); 148 sandboxir::Function *F = Ctx.createFunction(LLVMF); 149 auto *BB = &*F->begin(); 150 auto It = BB->begin(); 151 auto *SideEffect = cast<sandboxir::IntrinsicInst>(&*It++); 152 auto *PseudoProbe = cast<sandboxir::IntrinsicInst>(&*It++); 153 auto *OtherIntrinsic = cast<sandboxir::IntrinsicInst>(&*It++); 154 155 using DGNode = sandboxir::DGNode; 156 EXPECT_FALSE(DGNode::isMemIntrinsic(SideEffect)); 157 EXPECT_FALSE(DGNode::isMemIntrinsic(PseudoProbe)); 158 EXPECT_TRUE(DGNode::isMemIntrinsic(OtherIntrinsic)); 159 } 160 161 TEST_F(DependencyGraphTest, MemDGNode) { 162 parseIR(C, R"IR( 163 declare void @llvm.sideeffect() 164 declare void @llvm.pseudoprobe(i64, i64, i32, i64) 165 declare void @llvm.fake.use(...) 166 declare void @bar() 167 define void @foo(i8 %v1, ptr %ptr) { 168 store i8 %v1, ptr %ptr 169 %ld0 = load i8, ptr %ptr 170 %add = add i8 %v1, %v1 171 %stacksave = call ptr @llvm.stacksave() 172 call void @llvm.stackrestore(ptr %stacksave) 173 call void @llvm.sideeffect() 174 call void @llvm.pseudoprobe(i64 42, i64 1, i32 0, i64 -1) 175 call void @llvm.fake.use(ptr %ptr) 176 call void @bar() 177 ret void 178 } 179 )IR"); 180 llvm::Function *LLVMF = &*M->getFunction("foo"); 181 sandboxir::Context Ctx(C); 182 183 auto *F = Ctx.createFunction(LLVMF); 184 auto *BB = &*F->begin(); 185 auto It = BB->begin(); 186 auto *Store = cast<sandboxir::StoreInst>(&*It++); 187 auto *Load = cast<sandboxir::LoadInst>(&*It++); 188 auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 189 auto *StackSave = cast<sandboxir::CallInst>(&*It++); 190 auto *StackRestore = cast<sandboxir::CallInst>(&*It++); 191 auto *SideEffect = cast<sandboxir::CallInst>(&*It++); 192 auto *PseudoProbe = cast<sandboxir::CallInst>(&*It++); 193 auto *FakeUse = cast<sandboxir::CallInst>(&*It++); 194 auto *Call = cast<sandboxir::CallInst>(&*It++); 195 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 196 197 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 198 DAG.extend({&*BB->begin(), BB->getTerminator()}); 199 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Store))); 200 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Load))); 201 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Add))); 202 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(StackSave))); 203 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(StackRestore))); 204 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(SideEffect))); 205 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(PseudoProbe))); 206 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(FakeUse))); 207 EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Call))); 208 EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Ret))); 209 } 210 211 TEST_F(DependencyGraphTest, Basic) { 212 parseIR(C, R"IR( 213 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 214 store i8 %v0, ptr %ptr 215 store i8 %v1, ptr %ptr 216 ret void 217 } 218 )IR"); 219 llvm::Function *LLVMF = &*M->getFunction("foo"); 220 sandboxir::Context Ctx(C); 221 auto *F = Ctx.createFunction(LLVMF); 222 auto *BB = &*F->begin(); 223 auto It = BB->begin(); 224 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 225 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 226 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 227 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 228 auto Span = DAG.extend({&*BB->begin(), BB->getTerminator()}); 229 // Check extend(). 230 EXPECT_EQ(Span.top(), &*BB->begin()); 231 EXPECT_EQ(Span.bottom(), BB->getTerminator()); 232 233 auto *N0 = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 234 auto *N1 = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 235 auto *N2 = DAG.getNode(Ret); 236 237 // Check getInstruction(). 238 EXPECT_EQ(N0->getInstruction(), S0); 239 EXPECT_EQ(N1->getInstruction(), S1); 240 // Check hasMemPred() 241 EXPECT_TRUE(N1->hasMemPred(N0)); 242 EXPECT_FALSE(N0->hasMemPred(N1)); 243 244 // Check preds(). 245 EXPECT_TRUE(N0->preds(DAG).empty()); 246 EXPECT_THAT(N1->preds(DAG), testing::ElementsAre(N0)); 247 248 // Check memPreds(). 249 EXPECT_TRUE(N0->memPreds().empty()); 250 EXPECT_THAT(N1->memPreds(), testing::ElementsAre(N0)); 251 EXPECT_TRUE(N2->preds(DAG).empty()); 252 253 // Check UnscheduledSuccs. 254 EXPECT_EQ(N0->getNumUnscheduledSuccs(), 1u); // N1 255 EXPECT_EQ(N1->getNumUnscheduledSuccs(), 0u); 256 EXPECT_EQ(N2->getNumUnscheduledSuccs(), 0u); 257 258 // Check decrUnscheduledSuccs. 259 N0->decrUnscheduledSuccs(); 260 EXPECT_EQ(N0->getNumUnscheduledSuccs(), 0u); 261 #ifndef NDEBUG 262 EXPECT_DEATH(N0->decrUnscheduledSuccs(), ".*Counting.*"); 263 #endif // NDEBUG 264 265 // Check scheduled(), setScheduled(). 266 EXPECT_FALSE(N0->scheduled()); 267 N0->setScheduled(true); 268 EXPECT_TRUE(N0->scheduled()); 269 } 270 271 TEST_F(DependencyGraphTest, Preds) { 272 parseIR(C, R"IR( 273 declare ptr @bar(i8) 274 define i8 @foo(i8 %v0, i8 %v1) { 275 %add0 = add i8 %v0, %v0 276 %add1 = add i8 %v1, %v1 277 %add2 = add i8 %add0, %add1 278 %ptr = call ptr @bar(i8 %add1) 279 store i8 %add2, ptr %ptr 280 ret i8 %add2 281 } 282 )IR"); 283 llvm::Function *LLVMF = &*M->getFunction("foo"); 284 sandboxir::Context Ctx(C); 285 auto *F = Ctx.createFunction(LLVMF); 286 auto *BB = &*F->begin(); 287 auto It = BB->begin(); 288 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 289 DAG.extend({&*BB->begin(), BB->getTerminator()}); 290 291 auto *AddN0 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 292 auto *AddN1 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 293 auto *AddN2 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 294 auto *CallN = DAG.getNode(cast<sandboxir::CallInst>(&*It++)); 295 auto *StN = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 296 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 297 298 // Check preds(). 299 EXPECT_THAT(AddN0->preds(DAG), testing::ElementsAre()); 300 EXPECT_THAT(AddN1->preds(DAG), testing::ElementsAre()); 301 EXPECT_THAT(AddN2->preds(DAG), testing::ElementsAre(AddN0, AddN1)); 302 EXPECT_THAT(CallN->preds(DAG), testing::ElementsAre(AddN1)); 303 EXPECT_THAT(StN->preds(DAG), 304 testing::UnorderedElementsAre(CallN, CallN, AddN2)); 305 EXPECT_THAT(RetN->preds(DAG), testing::ElementsAre(AddN2)); 306 307 // Check UnscheduledSuccs. 308 EXPECT_EQ(AddN0->getNumUnscheduledSuccs(), 1u); // AddN2 309 EXPECT_EQ(AddN1->getNumUnscheduledSuccs(), 2u); // AddN2, CallN 310 EXPECT_EQ(AddN2->getNumUnscheduledSuccs(), 2u); // StN, RetN 311 EXPECT_EQ(CallN->getNumUnscheduledSuccs(), 2u); // StN, StN 312 EXPECT_EQ(StN->getNumUnscheduledSuccs(), 0u); 313 EXPECT_EQ(RetN->getNumUnscheduledSuccs(), 0u); 314 } 315 316 TEST_F(DependencyGraphTest, MemDGNode_getPrevNode_getNextNode) { 317 parseIR(C, R"IR( 318 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 319 store i8 %v0, ptr %ptr 320 add i8 %v0, %v0 321 store i8 %v1, ptr %ptr 322 ret void 323 } 324 )IR"); 325 llvm::Function *LLVMF = &*M->getFunction("foo"); 326 sandboxir::Context Ctx(C); 327 auto *F = Ctx.createFunction(LLVMF); 328 auto *BB = &*F->begin(); 329 auto It = BB->begin(); 330 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 331 [[maybe_unused]] auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 332 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 333 [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 334 335 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 336 DAG.extend({&*BB->begin(), BB->getTerminator()}); 337 338 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 339 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 340 341 EXPECT_EQ(S0N->getPrevNode(), nullptr); 342 EXPECT_EQ(S0N->getNextNode(), S1N); 343 344 EXPECT_EQ(S1N->getPrevNode(), S0N); 345 EXPECT_EQ(S1N->getNextNode(), nullptr); 346 } 347 348 TEST_F(DependencyGraphTest, DGNodeRange) { 349 parseIR(C, R"IR( 350 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 351 add i8 %v0, %v0 352 store i8 %v0, ptr %ptr 353 add i8 %v0, %v0 354 store i8 %v1, ptr %ptr 355 ret void 356 } 357 )IR"); 358 llvm::Function *LLVMF = &*M->getFunction("foo"); 359 sandboxir::Context Ctx(C); 360 auto *F = Ctx.createFunction(LLVMF); 361 auto *BB = &*F->begin(); 362 auto It = BB->begin(); 363 auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 364 auto *S0 = cast<sandboxir::StoreInst>(&*It++); 365 auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++); 366 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 367 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 368 369 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 370 DAG.extend({&*BB->begin(), BB->getTerminator()}); 371 372 auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 373 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 374 375 // Check getTopMemDGNode(). 376 using B = sandboxir::MemDGNodeIntervalBuilder; 377 using InstrInterval = sandboxir::Interval<sandboxir::Instruction>; 378 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, S0), DAG), S0N); 379 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, Ret), DAG), S0N); 380 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add1), DAG), S0N); 381 EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add0), DAG), nullptr); 382 383 // Check getBotMemDGNode(). 384 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(S1, S1), DAG), S1N); 385 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, S1), DAG), S1N); 386 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, Ret), DAG), S1N); 387 EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Ret, Ret), DAG), nullptr); 388 389 // Check empty range. 390 EXPECT_THAT(sandboxir::MemDGNodeIntervalBuilder::makeEmpty(), 391 testing::ElementsAre()); 392 393 // Returns the pointers in Range. 394 auto getPtrVec = [](const auto &Range) { 395 SmallVector<const sandboxir::DGNode *> Vec; 396 for (const sandboxir::DGNode &N : Range) 397 Vec.push_back(&N); 398 return Vec; 399 }; 400 // Both TopN and BotN are memory. 401 EXPECT_THAT( 402 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, S1}, DAG)), 403 testing::ElementsAre(S0N, S1N)); 404 // Only TopN is memory. 405 EXPECT_THAT( 406 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Ret}, DAG)), 407 testing::ElementsAre(S0N, S1N)); 408 EXPECT_THAT( 409 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Add1}, DAG)), 410 testing::ElementsAre(S0N)); 411 // Only BotN is memory. 412 EXPECT_THAT( 413 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S1}, DAG)), 414 testing::ElementsAre(S0N, S1N)); 415 EXPECT_THAT( 416 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S0}, DAG)), 417 testing::ElementsAre(S0N)); 418 // Neither TopN or BotN is memory. 419 EXPECT_THAT( 420 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Ret}, DAG)), 421 testing::ElementsAre(S0N, S1N)); 422 EXPECT_THAT( 423 getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Add0}, DAG)), 424 testing::ElementsAre()); 425 } 426 427 TEST_F(DependencyGraphTest, AliasingStores) { 428 parseIR(C, R"IR( 429 define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 430 store i8 %v0, ptr %ptr 431 store i8 %v1, ptr %ptr 432 ret void 433 } 434 )IR"); 435 llvm::Function *LLVMF = &*M->getFunction("foo"); 436 sandboxir::Context Ctx(C); 437 auto *F = Ctx.createFunction(LLVMF); 438 auto *BB = &*F->begin(); 439 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 440 DAG.extend({&*BB->begin(), BB->getTerminator()}); 441 auto It = BB->begin(); 442 auto *Store0N = cast<sandboxir::MemDGNode>( 443 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 444 auto *Store1N = cast<sandboxir::MemDGNode>( 445 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 446 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 447 EXPECT_TRUE(Store0N->memPreds().empty()); 448 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 449 EXPECT_TRUE(RetN->preds(DAG).empty()); 450 } 451 452 TEST_F(DependencyGraphTest, NonAliasingStores) { 453 parseIR(C, R"IR( 454 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) { 455 store i8 %v0, ptr %ptr0 456 store i8 %v1, ptr %ptr1 457 ret void 458 } 459 )IR"); 460 llvm::Function *LLVMF = &*M->getFunction("foo"); 461 sandboxir::Context Ctx(C); 462 auto *F = Ctx.createFunction(LLVMF); 463 auto *BB = &*F->begin(); 464 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 465 DAG.extend({&*BB->begin(), BB->getTerminator()}); 466 auto It = BB->begin(); 467 auto *Store0N = cast<sandboxir::MemDGNode>( 468 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 469 auto *Store1N = cast<sandboxir::MemDGNode>( 470 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 471 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 472 // We expect no dependencies because the stores don't alias. 473 EXPECT_TRUE(Store0N->memPreds().empty()); 474 EXPECT_TRUE(Store1N->memPreds().empty()); 475 EXPECT_TRUE(RetN->preds(DAG).empty()); 476 } 477 478 TEST_F(DependencyGraphTest, VolatileLoads) { 479 parseIR(C, R"IR( 480 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) { 481 %ld0 = load volatile i8, ptr %ptr0 482 %ld1 = load volatile i8, ptr %ptr1 483 ret void 484 } 485 )IR"); 486 llvm::Function *LLVMF = &*M->getFunction("foo"); 487 sandboxir::Context Ctx(C); 488 auto *F = Ctx.createFunction(LLVMF); 489 auto *BB = &*F->begin(); 490 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 491 DAG.extend({&*BB->begin(), BB->getTerminator()}); 492 auto It = BB->begin(); 493 auto *Ld0N = cast<sandboxir::MemDGNode>( 494 DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 495 auto *Ld1N = cast<sandboxir::MemDGNode>( 496 DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 497 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 498 EXPECT_TRUE(Ld0N->memPreds().empty()); 499 EXPECT_THAT(Ld1N->memPreds(), testing::ElementsAre(Ld0N)); 500 EXPECT_TRUE(RetN->preds(DAG).empty()); 501 } 502 503 TEST_F(DependencyGraphTest, VolatileSotres) { 504 parseIR(C, R"IR( 505 define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v) { 506 store volatile i8 %v, ptr %ptr0 507 store volatile i8 %v, ptr %ptr1 508 ret void 509 } 510 )IR"); 511 llvm::Function *LLVMF = &*M->getFunction("foo"); 512 sandboxir::Context Ctx(C); 513 auto *F = Ctx.createFunction(LLVMF); 514 auto *BB = &*F->begin(); 515 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 516 DAG.extend({&*BB->begin(), BB->getTerminator()}); 517 auto It = BB->begin(); 518 auto *Store0N = cast<sandboxir::MemDGNode>( 519 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 520 auto *Store1N = cast<sandboxir::MemDGNode>( 521 DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 522 auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 523 EXPECT_TRUE(Store0N->memPreds().empty()); 524 EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 525 EXPECT_TRUE(RetN->preds(DAG).empty()); 526 } 527 528 TEST_F(DependencyGraphTest, Call) { 529 parseIR(C, R"IR( 530 declare void @bar1() 531 declare void @bar2() 532 define void @foo(float %v1, float %v2) { 533 call void @bar1() 534 %add = fadd float %v1, %v2 535 call void @bar2() 536 ret void 537 } 538 )IR"); 539 Function *LLVMF = M->getFunction("foo"); 540 541 sandboxir::Context Ctx(C); 542 auto *F = Ctx.createFunction(LLVMF); 543 auto *BB = &*F->begin(); 544 545 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 546 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 547 548 auto It = BB->begin(); 549 auto *Call1N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 550 auto *AddN = DAG.getNode(&*It++); 551 auto *Call2N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 552 553 EXPECT_THAT(Call1N->memPreds(), testing::ElementsAre()); 554 EXPECT_THAT(AddN->preds(DAG), testing::ElementsAre()); 555 EXPECT_THAT(Call2N->memPreds(), testing::ElementsAre(Call1N)); 556 } 557 558 // Check that there is a dependency: stacksave -> alloca -> stackrestore. 559 TEST_F(DependencyGraphTest, StackSaveRestoreInAlloca) { 560 parseIR(C, R"IR( 561 declare ptr @llvm.stacksave() 562 declare void @llvm.stackrestore(ptr %ptr) 563 564 define void @foo() { 565 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 566 %alloca0 = alloca inalloca i8 ; Should depend on stacksave 567 call void @llvm.stackrestore(ptr %stack0) ; Should depend transiently on %alloca0 568 ret void 569 } 570 )IR"); 571 Function *LLVMF = M->getFunction("foo"); 572 573 sandboxir::Context Ctx(C); 574 auto *F = Ctx.createFunction(LLVMF); 575 auto *BB = &*F->begin(); 576 577 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 578 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 579 580 auto It = BB->begin(); 581 auto *StackSaveN = DAG.getNode(&*It++); 582 auto *AllocaN = DAG.getNode(&*It++); 583 auto *StackRestoreN = DAG.getNode(&*It++); 584 585 EXPECT_TRUE(memDependency(AllocaN, StackRestoreN)); 586 EXPECT_TRUE(memDependency(StackSaveN, AllocaN)); 587 } 588 589 // Checks that stacksave and stackrestore depend on other mem instrs. 590 TEST_F(DependencyGraphTest, StackSaveRestoreDependOnOtherMem) { 591 parseIR(C, R"IR( 592 declare ptr @llvm.stacksave() 593 declare void @llvm.stackrestore(ptr %ptr) 594 595 define void @foo(i8 %v0, i8 %v1, ptr %ptr) { 596 store volatile i8 %v0, ptr %ptr, align 4 597 %stack0 = call ptr @llvm.stacksave() ; Should depend on store 598 call void @llvm.stackrestore(ptr %stack0) ; Should depend on stacksave 599 store volatile i8 %v1, ptr %ptr, align 4 ; Should depend on stackrestore 600 ret void 601 } 602 )IR"); 603 Function *LLVMF = M->getFunction("foo"); 604 605 sandboxir::Context Ctx(C); 606 auto *F = Ctx.createFunction(LLVMF); 607 auto *BB = &*F->begin(); 608 609 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 610 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 611 612 auto It = BB->begin(); 613 auto *Store0N = DAG.getNode(&*It++); 614 auto *StackSaveN = DAG.getNode(&*It++); 615 auto *StackRestoreN = DAG.getNode(&*It++); 616 auto *Store1N = DAG.getNode(&*It++); 617 618 EXPECT_TRUE(memDependency(Store0N, StackSaveN)); 619 EXPECT_TRUE(memDependency(StackSaveN, StackRestoreN)); 620 EXPECT_TRUE(memDependency(StackRestoreN, Store1N)); 621 } 622 623 // Make sure there is a dependency between a stackrestore and an alloca. 624 TEST_F(DependencyGraphTest, StackRestoreAndInAlloca) { 625 parseIR(C, R"IR( 626 declare void @llvm.stackrestore(ptr %ptr) 627 628 define void @foo(ptr %ptr) { 629 call void @llvm.stackrestore(ptr %ptr) 630 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 631 ret void 632 } 633 )IR"); 634 Function *LLVMF = M->getFunction("foo"); 635 636 sandboxir::Context Ctx(C); 637 auto *F = Ctx.createFunction(LLVMF); 638 auto *BB = &*F->begin(); 639 640 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 641 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 642 643 auto It = BB->begin(); 644 auto *StackRestoreN = DAG.getNode(&*It++); 645 auto *AllocaN = DAG.getNode(&*It++); 646 647 EXPECT_TRUE(memDependency(StackRestoreN, AllocaN)); 648 } 649 650 // Make sure there is a dependency between the alloca and stacksave 651 TEST_F(DependencyGraphTest, StackSaveAndInAlloca) { 652 parseIR(C, R"IR( 653 declare ptr @llvm.stacksave() 654 655 define void @foo(ptr %ptr) { 656 %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 657 %stack0 = call ptr @llvm.stacksave() ; Should depend on alloca0 658 ret void 659 } 660 )IR"); 661 Function *LLVMF = M->getFunction("foo"); 662 663 sandboxir::Context Ctx(C); 664 auto *F = Ctx.createFunction(LLVMF); 665 auto *BB = &*F->begin(); 666 667 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 668 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 669 670 auto It = BB->begin(); 671 auto *AllocaN = DAG.getNode(&*It++); 672 auto *StackSaveN = DAG.getNode(&*It++); 673 674 EXPECT_TRUE(memDependency(AllocaN, StackSaveN)); 675 } 676 677 // A non-InAlloca in a stacksave-stackrestore region does not need extra 678 // dependencies. 679 TEST_F(DependencyGraphTest, StackSaveRestoreNoInAlloca) { 680 parseIR(C, R"IR( 681 declare ptr @llvm.stacksave() 682 declare void @llvm.stackrestore(ptr %ptr) 683 declare void @use(ptr %ptr) 684 685 define void @foo() { 686 %stack = call ptr @llvm.stacksave() 687 %alloca1 = alloca i8 ; No dependency 688 call void @llvm.stackrestore(ptr %stack) 689 ret void 690 } 691 )IR"); 692 Function *LLVMF = M->getFunction("foo"); 693 694 sandboxir::Context Ctx(C); 695 auto *F = Ctx.createFunction(LLVMF); 696 auto *BB = &*F->begin(); 697 698 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 699 DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 700 701 auto It = BB->begin(); 702 auto *StackSaveN = DAG.getNode(&*It++); 703 auto *AllocaN = DAG.getNode(&*It++); 704 auto *StackRestoreN = DAG.getNode(&*It++); 705 706 EXPECT_FALSE(memDependency(StackSaveN, AllocaN)); 707 EXPECT_FALSE(memDependency(AllocaN, StackRestoreN)); 708 } 709 710 TEST_F(DependencyGraphTest, Extend) { 711 parseIR(C, R"IR( 712 define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) { 713 store i8 %v1, ptr %ptr 714 store i8 %v2, ptr %ptr 715 store i8 %v3, ptr %ptr 716 store i8 %v4, ptr %ptr 717 store i8 %v5, ptr %ptr 718 ret void 719 } 720 )IR"); 721 llvm::Function *LLVMF = &*M->getFunction("foo"); 722 sandboxir::Context Ctx(C); 723 auto *F = Ctx.createFunction(LLVMF); 724 auto *BB = &*F->begin(); 725 auto It = BB->begin(); 726 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 727 auto *S2 = cast<sandboxir::StoreInst>(&*It++); 728 auto *S3 = cast<sandboxir::StoreInst>(&*It++); 729 auto *S4 = cast<sandboxir::StoreInst>(&*It++); 730 auto *S5 = cast<sandboxir::StoreInst>(&*It++); 731 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 732 { 733 // Scenario 1: Build new DAG 734 auto NewIntvl = DAG.extend({S3, S3}); 735 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S3, S3)); 736 EXPECT_EQ(DAG.getInterval().top(), S3); 737 EXPECT_EQ(DAG.getInterval().bottom(), S3); 738 [[maybe_unused]] auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 739 // Check UnscheduledSuccs. 740 EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 0u); 741 } 742 { 743 // Scenario 2: Extend below 744 auto NewIntvl = DAG.extend({S5, S5}); 745 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S4, S5)); 746 auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 747 auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 748 auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 749 EXPECT_TRUE(S4N->hasMemPred(S3N)); 750 EXPECT_TRUE(S5N->hasMemPred(S4N)); 751 EXPECT_TRUE(S5N->hasMemPred(S3N)); 752 // Check UnscheduledSuccs. 753 EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 2u); // S4N, S5N 754 EXPECT_EQ(S4N->getNumUnscheduledSuccs(), 1u); // S5N 755 EXPECT_EQ(S5N->getNumUnscheduledSuccs(), 0u); 756 } 757 { 758 // Scenario 3: Extend above 759 auto NewIntvl = DAG.extend({S1, S2}); 760 EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S1, S2)); 761 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 762 auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 763 auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 764 auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 765 auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 766 767 EXPECT_TRUE(S2N->hasMemPred(S1N)); 768 769 EXPECT_TRUE(S3N->hasMemPred(S2N)); 770 EXPECT_TRUE(S3N->hasMemPred(S1N)); 771 772 EXPECT_TRUE(S4N->hasMemPred(S3N)); 773 EXPECT_TRUE(S4N->hasMemPred(S2N)); 774 EXPECT_TRUE(S4N->hasMemPred(S1N)); 775 776 EXPECT_TRUE(S5N->hasMemPred(S4N)); 777 EXPECT_TRUE(S5N->hasMemPred(S3N)); 778 EXPECT_TRUE(S5N->hasMemPred(S2N)); 779 EXPECT_TRUE(S5N->hasMemPred(S1N)); 780 781 // Check UnscheduledSuccs. 782 EXPECT_EQ(S1N->getNumUnscheduledSuccs(), 4u); // S2N, S3N, S4N, S5N 783 EXPECT_EQ(S2N->getNumUnscheduledSuccs(), 3u); // S3N, S4N, S5N 784 EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 2u); // S4N, S5N 785 EXPECT_EQ(S4N->getNumUnscheduledSuccs(), 1u); // S5N 786 EXPECT_EQ(S5N->getNumUnscheduledSuccs(), 0u); 787 } 788 789 { 790 // Check UnscheduledSuccs when a node is scheduled 791 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 792 DAG.extend({S2, S2}); 793 auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 794 S2N->setScheduled(true); 795 796 DAG.extend({S1, S1}); 797 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 798 EXPECT_EQ(S1N->getNumUnscheduledSuccs(), 0u); // S1 is scheduled 799 } 800 } 801 802 TEST_F(DependencyGraphTest, CreateInstrCallback) { 803 parseIR(C, R"IR( 804 define void @foo(ptr %ptr, ptr noalias %ptr2, i8 %v1, i8 %v2, i8 %v3, i8 %arg) { 805 store i8 %v1, ptr %ptr 806 store i8 %v2, ptr %ptr 807 store i8 %v3, ptr %ptr 808 ret void 809 } 810 )IR"); 811 llvm::Function *LLVMF = &*M->getFunction("foo"); 812 sandboxir::Context Ctx(C); 813 auto *F = Ctx.createFunction(LLVMF); 814 auto *BB = &*F->begin(); 815 auto It = BB->begin(); 816 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 817 auto *S2 = cast<sandboxir::StoreInst>(&*It++); 818 auto *S3 = cast<sandboxir::StoreInst>(&*It++); 819 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 820 821 // Check new instruction callback. 822 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 823 DAG.extend({S1, Ret}); 824 auto *Arg = F->getArg(3); 825 auto *Ptr = S1->getPointerOperand(); 826 { 827 sandboxir::StoreInst *NewS = 828 sandboxir::StoreInst::create(Arg, Ptr, Align(8), S3->getIterator(), 829 /*IsVolatile=*/true, Ctx); 830 auto *NewSN = DAG.getNode(NewS); 831 EXPECT_TRUE(NewSN != nullptr); 832 833 // Check the MemDGNode chain. 834 auto *S2MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 835 auto *NewMemSN = cast<sandboxir::MemDGNode>(NewSN); 836 auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 837 EXPECT_EQ(S2MemN->getNextNode(), NewMemSN); 838 EXPECT_EQ(NewMemSN->getPrevNode(), S2MemN); 839 EXPECT_EQ(NewMemSN->getNextNode(), S3MemN); 840 EXPECT_EQ(S3MemN->getPrevNode(), NewMemSN); 841 } 842 843 { 844 // Also check if new node is at the end of the BB, after Ret. 845 sandboxir::StoreInst *NewS = 846 sandboxir::StoreInst::create(Arg, Ptr, Align(8), BB->end(), 847 /*IsVolatile=*/true, Ctx); 848 // Check the MemDGNode chain. 849 auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 850 auto *NewMemSN = cast<sandboxir::MemDGNode>(DAG.getNode(NewS)); 851 EXPECT_EQ(S3MemN->getNextNode(), NewMemSN); 852 EXPECT_EQ(NewMemSN->getPrevNode(), S3MemN); 853 EXPECT_EQ(NewMemSN->getNextNode(), nullptr); 854 } 855 856 // TODO: Check the dependencies to/from NewSN after they land. 857 } 858 859 TEST_F(DependencyGraphTest, EraseInstrCallback) { 860 parseIR(C, R"IR( 861 define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %arg) { 862 store i8 %v1, ptr %ptr 863 store i8 %v2, ptr %ptr 864 store i8 %v3, ptr %ptr 865 ret void 866 } 867 )IR"); 868 llvm::Function *LLVMF = &*M->getFunction("foo"); 869 sandboxir::Context Ctx(C); 870 auto *F = Ctx.createFunction(LLVMF); 871 auto *BB = &*F->begin(); 872 auto It = BB->begin(); 873 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 874 auto *S2 = cast<sandboxir::StoreInst>(&*It++); 875 auto *S3 = cast<sandboxir::StoreInst>(&*It++); 876 877 // Check erase instruction callback. 878 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 879 DAG.extend({S1, S3}); 880 S2->eraseFromParent(); 881 auto *DeletedN = DAG.getNodeOrNull(S2); 882 EXPECT_TRUE(DeletedN == nullptr); 883 884 // Check the MemDGNode chain. 885 auto *S1MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 886 auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 887 EXPECT_EQ(S1MemN->getNextNode(), S3MemN); 888 EXPECT_EQ(S3MemN->getPrevNode(), S1MemN); 889 890 // Check the chain when we erase the top node. 891 S1->eraseFromParent(); 892 EXPECT_EQ(S3MemN->getPrevNode(), nullptr); 893 894 // TODO: Check the dependencies to/from NewSN after they land. 895 } 896 897 TEST_F(DependencyGraphTest, MoveInstrCallback) { 898 parseIR(C, R"IR( 899 define void @foo(ptr %ptr, ptr %ptr2, i8 %v1, i8 %v2, i8 %v3, i8 %arg) { 900 %ld0 = load i8, ptr %ptr2 901 store i8 %v1, ptr %ptr 902 store i8 %v2, ptr %ptr 903 store i8 %v3, ptr %ptr 904 ret void 905 } 906 )IR"); 907 llvm::Function *LLVMF = &*M->getFunction("foo"); 908 sandboxir::Context Ctx(C); 909 auto *F = Ctx.createFunction(LLVMF); 910 auto *BB = &*F->begin(); 911 auto It = BB->begin(); 912 auto *Ld = cast<sandboxir::LoadInst>(&*It++); 913 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 914 auto *S2 = cast<sandboxir::StoreInst>(&*It++); 915 auto *S3 = cast<sandboxir::StoreInst>(&*It++); 916 917 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 918 DAG.extend({Ld, S3}); 919 auto *LdN = cast<sandboxir::MemDGNode>(DAG.getNode(Ld)); 920 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 921 auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 922 EXPECT_EQ(S1N->getPrevNode(), LdN); 923 S1->moveBefore(Ld); 924 EXPECT_EQ(S1N->getPrevNode(), nullptr); 925 EXPECT_EQ(S1N->getNextNode(), LdN); 926 EXPECT_EQ(LdN->getPrevNode(), S1N); 927 EXPECT_EQ(LdN->getNextNode(), S2N); 928 } 929 930 // Check that the mem chain is maintained correctly when the move destination is 931 // not a mem node. 932 TEST_F(DependencyGraphTest, MoveInstrCallbackWithNonMemInstrs) { 933 parseIR(C, R"IR( 934 define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %arg) { 935 %ld = load i8, ptr %ptr 936 %zext1 = zext i8 %arg to i32 937 %zext2 = zext i8 %arg to i32 938 store i8 %v1, ptr %ptr 939 store i8 %v2, ptr %ptr 940 ret void 941 } 942 )IR"); 943 llvm::Function *LLVMF = &*M->getFunction("foo"); 944 sandboxir::Context Ctx(C); 945 auto *F = Ctx.createFunction(LLVMF); 946 auto *BB = &*F->begin(); 947 auto It = BB->begin(); 948 auto *Ld = cast<sandboxir::LoadInst>(&*It++); 949 [[maybe_unused]] auto *Zext1 = cast<sandboxir::CastInst>(&*It++); 950 auto *Zext2 = cast<sandboxir::CastInst>(&*It++); 951 auto *S1 = cast<sandboxir::StoreInst>(&*It++); 952 auto *S2 = cast<sandboxir::StoreInst>(&*It++); 953 auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 954 955 sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 956 DAG.extend({Ld, S2}); 957 auto *LdN = cast<sandboxir::MemDGNode>(DAG.getNode(Ld)); 958 auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 959 auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 960 EXPECT_EQ(LdN->getNextNode(), S1N); 961 EXPECT_EQ(S1N->getNextNode(), S2N); 962 963 S1->moveBefore(Zext2); 964 EXPECT_EQ(LdN->getNextNode(), S1N); 965 EXPECT_EQ(S1N->getNextNode(), S2N); 966 967 // Try move right after the end of the DAGInterval. 968 S1->moveBefore(Ret); 969 EXPECT_EQ(S2N->getNextNode(), S1N); 970 EXPECT_EQ(S1N->getNextNode(), nullptr); 971 } 972