1318d2f5eSvporpo //===- DependencyGraphTest.cpp --------------------------------------------===// 2318d2f5eSvporpo // 3318d2f5eSvporpo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4318d2f5eSvporpo // See https://llvm.org/LICENSE.txt for license information. 5318d2f5eSvporpo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6318d2f5eSvporpo // 7318d2f5eSvporpo //===----------------------------------------------------------------------===// 8318d2f5eSvporpo 9318d2f5eSvporpo #include "llvm/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.h" 1004a8bffdSvporpo #include "llvm/Analysis/AliasAnalysis.h" 1104a8bffdSvporpo #include "llvm/Analysis/AssumptionCache.h" 1204a8bffdSvporpo #include "llvm/Analysis/BasicAliasAnalysis.h" 1304a8bffdSvporpo #include "llvm/Analysis/TargetLibraryInfo.h" 14318d2f5eSvporpo #include "llvm/AsmParser/Parser.h" 1504a8bffdSvporpo #include "llvm/IR/DataLayout.h" 1604a8bffdSvporpo #include "llvm/IR/Dominators.h" 172018f4ccSVasileios Porpodas #include "llvm/SandboxIR/Context.h" 18e22b07e7Svporpo #include "llvm/SandboxIR/Function.h" 192018f4ccSVasileios Porpodas #include "llvm/SandboxIR/Instruction.h" 20318d2f5eSvporpo #include "llvm/Support/SourceMgr.h" 21318d2f5eSvporpo #include "gmock/gmock-matchers.h" 22318d2f5eSvporpo #include "gtest/gtest.h" 23318d2f5eSvporpo 24318d2f5eSvporpo using namespace llvm; 25318d2f5eSvporpo 26318d2f5eSvporpo struct DependencyGraphTest : public testing::Test { 27318d2f5eSvporpo LLVMContext C; 28318d2f5eSvporpo std::unique_ptr<Module> M; 2904a8bffdSvporpo std::unique_ptr<AssumptionCache> AC; 3004a8bffdSvporpo std::unique_ptr<DominatorTree> DT; 3104a8bffdSvporpo std::unique_ptr<BasicAAResult> BAA; 3204a8bffdSvporpo std::unique_ptr<AAResults> AA; 33318d2f5eSvporpo 34318d2f5eSvporpo void parseIR(LLVMContext &C, const char *IR) { 35318d2f5eSvporpo SMDiagnostic Err; 36318d2f5eSvporpo M = parseAssemblyString(IR, Err, C); 37318d2f5eSvporpo if (!M) 38318d2f5eSvporpo Err.print("DependencyGraphTest", errs()); 39318d2f5eSvporpo } 4004a8bffdSvporpo 4104a8bffdSvporpo AAResults &getAA(llvm::Function &LLVMF) { 4204a8bffdSvporpo TargetLibraryInfoImpl TLII; 4304a8bffdSvporpo TargetLibraryInfo TLI(TLII); 4404a8bffdSvporpo AA = std::make_unique<AAResults>(TLI); 4504a8bffdSvporpo AC = std::make_unique<AssumptionCache>(LLVMF); 4604a8bffdSvporpo DT = std::make_unique<DominatorTree>(LLVMF); 4704a8bffdSvporpo BAA = std::make_unique<BasicAAResult>(M->getDataLayout(), LLVMF, TLI, *AC, 4804a8bffdSvporpo DT.get()); 4904a8bffdSvporpo AA->addAAResult(*BAA); 5004a8bffdSvporpo return *AA; 5104a8bffdSvporpo } 5204a8bffdSvporpo /// \Returns true if there is a dependency: SrcN->DstN. 53a4916d20Svporpo bool memDependency(sandboxir::DGNode *SrcN, sandboxir::DGNode *DstN) { 54a4916d20Svporpo if (auto *MemDstN = dyn_cast<sandboxir::MemDGNode>(DstN)) 55a4916d20Svporpo return MemDstN->hasMemPred(SrcN); 56a4916d20Svporpo return false; 5704a8bffdSvporpo } 58318d2f5eSvporpo }; 59318d2f5eSvporpo 607b9c6a7cSvporpo TEST_F(DependencyGraphTest, isStackSaveOrRestoreIntrinsic) { 617b9c6a7cSvporpo parseIR(C, R"IR( 627b9c6a7cSvporpo declare void @llvm.sideeffect() 637b9c6a7cSvporpo define void @foo(i8 %v1, ptr %ptr) { 647b9c6a7cSvporpo %add = add i8 %v1, %v1 657b9c6a7cSvporpo %stacksave = call ptr @llvm.stacksave() 667b9c6a7cSvporpo call void @llvm.stackrestore(ptr %stacksave) 677b9c6a7cSvporpo call void @llvm.sideeffect() 687b9c6a7cSvporpo ret void 697b9c6a7cSvporpo } 707b9c6a7cSvporpo )IR"); 717b9c6a7cSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 727b9c6a7cSvporpo sandboxir::Context Ctx(C); 737b9c6a7cSvporpo sandboxir::Function *F = Ctx.createFunction(LLVMF); 747b9c6a7cSvporpo auto *BB = &*F->begin(); 757b9c6a7cSvporpo auto It = BB->begin(); 767b9c6a7cSvporpo auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 777b9c6a7cSvporpo auto *StackSave = cast<sandboxir::CallInst>(&*It++); 787b9c6a7cSvporpo auto *StackRestore = cast<sandboxir::CallInst>(&*It++); 797b9c6a7cSvporpo auto *Other = cast<sandboxir::CallInst>(&*It++); 807b9c6a7cSvporpo auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 817b9c6a7cSvporpo 827b9c6a7cSvporpo using DGNode = sandboxir::DGNode; 837b9c6a7cSvporpo EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Add)); 847b9c6a7cSvporpo EXPECT_TRUE(DGNode::isStackSaveOrRestoreIntrinsic(StackSave)); 857b9c6a7cSvporpo EXPECT_TRUE(DGNode::isStackSaveOrRestoreIntrinsic(StackRestore)); 867b9c6a7cSvporpo EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Other)); 877b9c6a7cSvporpo EXPECT_FALSE(DGNode::isStackSaveOrRestoreIntrinsic(Ret)); 887b9c6a7cSvporpo } 897b9c6a7cSvporpo 907b9c6a7cSvporpo TEST_F(DependencyGraphTest, Instruction_isMemDepCandidate) { 917b9c6a7cSvporpo parseIR(C, R"IR( 927b9c6a7cSvporpo declare void @llvm.fake.use(...) 937b9c6a7cSvporpo declare void @llvm.sideeffect() 947b9c6a7cSvporpo declare void @llvm.pseudoprobe(i64, i64, i32, i64) 957b9c6a7cSvporpo declare void @bar() 967b9c6a7cSvporpo define void @foo(i8 %v1, ptr %ptr) { 977b9c6a7cSvporpo %add0 = add i8 %v1, %v1 987b9c6a7cSvporpo %ld0 = load i8, ptr %ptr 997b9c6a7cSvporpo store i8 %v1, ptr %ptr 1007b9c6a7cSvporpo call void @llvm.sideeffect() 1017b9c6a7cSvporpo call void @llvm.pseudoprobe(i64 42, i64 1, i32 0, i64 -1) 1027b9c6a7cSvporpo call void @llvm.fake.use(ptr %ptr) 1037b9c6a7cSvporpo call void @bar() 1047b9c6a7cSvporpo ret void 1057b9c6a7cSvporpo } 1067b9c6a7cSvporpo )IR"); 1077b9c6a7cSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 1087b9c6a7cSvporpo sandboxir::Context Ctx(C); 1097b9c6a7cSvporpo sandboxir::Function *F = Ctx.createFunction(LLVMF); 1107b9c6a7cSvporpo auto *BB = &*F->begin(); 1117b9c6a7cSvporpo auto It = BB->begin(); 1127b9c6a7cSvporpo auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 1137b9c6a7cSvporpo auto *Ld0 = cast<sandboxir::LoadInst>(&*It++); 1147b9c6a7cSvporpo auto *St0 = cast<sandboxir::StoreInst>(&*It++); 1157b9c6a7cSvporpo auto *SideEffect0 = cast<sandboxir::CallInst>(&*It++); 1167b9c6a7cSvporpo auto *PseudoProbe0 = cast<sandboxir::CallInst>(&*It++); 1177b9c6a7cSvporpo auto *OtherIntrinsic0 = cast<sandboxir::CallInst>(&*It++); 1187b9c6a7cSvporpo auto *CallBar = cast<sandboxir::CallInst>(&*It++); 1197b9c6a7cSvporpo auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 1207b9c6a7cSvporpo 1217b9c6a7cSvporpo using DGNode = sandboxir::DGNode; 1227b9c6a7cSvporpo 1237b9c6a7cSvporpo EXPECT_FALSE(DGNode::isMemDepCandidate(Add0)); 1247b9c6a7cSvporpo EXPECT_TRUE(DGNode::isMemDepCandidate(Ld0)); 1257b9c6a7cSvporpo EXPECT_TRUE(DGNode::isMemDepCandidate(St0)); 1267b9c6a7cSvporpo EXPECT_FALSE(DGNode::isMemDepCandidate(SideEffect0)); 1277b9c6a7cSvporpo EXPECT_FALSE(DGNode::isMemDepCandidate(PseudoProbe0)); 1287b9c6a7cSvporpo EXPECT_TRUE(DGNode::isMemDepCandidate(OtherIntrinsic0)); 1297b9c6a7cSvporpo EXPECT_TRUE(DGNode::isMemDepCandidate(CallBar)); 1307b9c6a7cSvporpo EXPECT_FALSE(DGNode::isMemDepCandidate(Ret)); 1317b9c6a7cSvporpo } 1327b9c6a7cSvporpo 1337b9c6a7cSvporpo TEST_F(DependencyGraphTest, Instruction_isMemIntrinsic) { 1347b9c6a7cSvporpo parseIR(C, R"IR( 1357b9c6a7cSvporpo declare void @llvm.sideeffect() 1367b9c6a7cSvporpo declare void @llvm.pseudoprobe(i64) 1377b9c6a7cSvporpo declare void @llvm.assume(i1) 1387b9c6a7cSvporpo 1397b9c6a7cSvporpo define void @foo(ptr %ptr, i1 %cond) { 1407b9c6a7cSvporpo call void @llvm.sideeffect() 1417b9c6a7cSvporpo call void @llvm.pseudoprobe(i64 42) 1427b9c6a7cSvporpo call void @llvm.assume(i1 %cond) 1437b9c6a7cSvporpo ret void 1447b9c6a7cSvporpo } 1457b9c6a7cSvporpo )IR"); 1467b9c6a7cSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 1477b9c6a7cSvporpo sandboxir::Context Ctx(C); 1487b9c6a7cSvporpo sandboxir::Function *F = Ctx.createFunction(LLVMF); 1497b9c6a7cSvporpo auto *BB = &*F->begin(); 1507b9c6a7cSvporpo auto It = BB->begin(); 1517b9c6a7cSvporpo auto *SideEffect = cast<sandboxir::IntrinsicInst>(&*It++); 1527b9c6a7cSvporpo auto *PseudoProbe = cast<sandboxir::IntrinsicInst>(&*It++); 1537b9c6a7cSvporpo auto *OtherIntrinsic = cast<sandboxir::IntrinsicInst>(&*It++); 1547b9c6a7cSvporpo 1557b9c6a7cSvporpo using DGNode = sandboxir::DGNode; 1567b9c6a7cSvporpo EXPECT_FALSE(DGNode::isMemIntrinsic(SideEffect)); 1577b9c6a7cSvporpo EXPECT_FALSE(DGNode::isMemIntrinsic(PseudoProbe)); 1587b9c6a7cSvporpo EXPECT_TRUE(DGNode::isMemIntrinsic(OtherIntrinsic)); 1597b9c6a7cSvporpo } 1607b9c6a7cSvporpo 161fd5e220fSvporpo TEST_F(DependencyGraphTest, MemDGNode) { 1628f31ee99Svporpo parseIR(C, R"IR( 1638f31ee99Svporpo declare void @llvm.sideeffect() 1648f31ee99Svporpo declare void @llvm.pseudoprobe(i64, i64, i32, i64) 1658f31ee99Svporpo declare void @llvm.fake.use(...) 1668f31ee99Svporpo declare void @bar() 1678f31ee99Svporpo define void @foo(i8 %v1, ptr %ptr) { 1688f31ee99Svporpo store i8 %v1, ptr %ptr 1698f31ee99Svporpo %ld0 = load i8, ptr %ptr 1708f31ee99Svporpo %add = add i8 %v1, %v1 1718f31ee99Svporpo %stacksave = call ptr @llvm.stacksave() 1728f31ee99Svporpo call void @llvm.stackrestore(ptr %stacksave) 1738f31ee99Svporpo call void @llvm.sideeffect() 1748f31ee99Svporpo call void @llvm.pseudoprobe(i64 42, i64 1, i32 0, i64 -1) 1758f31ee99Svporpo call void @llvm.fake.use(ptr %ptr) 1768f31ee99Svporpo call void @bar() 1778f31ee99Svporpo ret void 1788f31ee99Svporpo } 1798f31ee99Svporpo )IR"); 1808f31ee99Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 1818f31ee99Svporpo sandboxir::Context Ctx(C); 18204a8bffdSvporpo 1838f31ee99Svporpo auto *F = Ctx.createFunction(LLVMF); 1848f31ee99Svporpo auto *BB = &*F->begin(); 1858f31ee99Svporpo auto It = BB->begin(); 1868f31ee99Svporpo auto *Store = cast<sandboxir::StoreInst>(&*It++); 1878f31ee99Svporpo auto *Load = cast<sandboxir::LoadInst>(&*It++); 1888f31ee99Svporpo auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 1898f31ee99Svporpo auto *StackSave = cast<sandboxir::CallInst>(&*It++); 1908f31ee99Svporpo auto *StackRestore = cast<sandboxir::CallInst>(&*It++); 1918f31ee99Svporpo auto *SideEffect = cast<sandboxir::CallInst>(&*It++); 1928f31ee99Svporpo auto *PseudoProbe = cast<sandboxir::CallInst>(&*It++); 1938f31ee99Svporpo auto *FakeUse = cast<sandboxir::CallInst>(&*It++); 1948f31ee99Svporpo auto *Call = cast<sandboxir::CallInst>(&*It++); 1958f31ee99Svporpo auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 1968f31ee99Svporpo 19731a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 1988f31ee99Svporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 199fd5e220fSvporpo EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Store))); 200fd5e220fSvporpo EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Load))); 201fd5e220fSvporpo EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Add))); 202fd5e220fSvporpo EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(StackSave))); 203fd5e220fSvporpo EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(StackRestore))); 204fd5e220fSvporpo EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(SideEffect))); 205fd5e220fSvporpo EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(PseudoProbe))); 206fd5e220fSvporpo EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(FakeUse))); 207fd5e220fSvporpo EXPECT_TRUE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Call))); 208fd5e220fSvporpo EXPECT_FALSE(isa<llvm::sandboxir::MemDGNode>(DAG.getNode(Ret))); 2098f31ee99Svporpo } 2108f31ee99Svporpo 211318d2f5eSvporpo TEST_F(DependencyGraphTest, Basic) { 212318d2f5eSvporpo parseIR(C, R"IR( 213318d2f5eSvporpo define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 214318d2f5eSvporpo store i8 %v0, ptr %ptr 215318d2f5eSvporpo store i8 %v1, ptr %ptr 216318d2f5eSvporpo ret void 217318d2f5eSvporpo } 218318d2f5eSvporpo )IR"); 219318d2f5eSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 220318d2f5eSvporpo sandboxir::Context Ctx(C); 221318d2f5eSvporpo auto *F = Ctx.createFunction(LLVMF); 222318d2f5eSvporpo auto *BB = &*F->begin(); 223318d2f5eSvporpo auto It = BB->begin(); 224318d2f5eSvporpo auto *S0 = cast<sandboxir::StoreInst>(&*It++); 225318d2f5eSvporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 226318d2f5eSvporpo auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 22731a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 2280c9f7ef5Svporpo auto Span = DAG.extend({&*BB->begin(), BB->getTerminator()}); 2290c9f7ef5Svporpo // Check extend(). 2300c9f7ef5Svporpo EXPECT_EQ(Span.top(), &*BB->begin()); 2310c9f7ef5Svporpo EXPECT_EQ(Span.bottom(), BB->getTerminator()); 232318d2f5eSvporpo 233a4916d20Svporpo auto *N0 = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 234a4916d20Svporpo auto *N1 = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 235a4916d20Svporpo auto *N2 = DAG.getNode(Ret); 236a4916d20Svporpo 237318d2f5eSvporpo // Check getInstruction(). 238318d2f5eSvporpo EXPECT_EQ(N0->getInstruction(), S0); 239318d2f5eSvporpo EXPECT_EQ(N1->getInstruction(), S1); 240318d2f5eSvporpo // Check hasMemPred() 241318d2f5eSvporpo EXPECT_TRUE(N1->hasMemPred(N0)); 242318d2f5eSvporpo EXPECT_FALSE(N0->hasMemPred(N1)); 243318d2f5eSvporpo 244747d8f3fSvporpo // Check preds(). 245747d8f3fSvporpo EXPECT_TRUE(N0->preds(DAG).empty()); 246747d8f3fSvporpo EXPECT_THAT(N1->preds(DAG), testing::ElementsAre(N0)); 247747d8f3fSvporpo 248318d2f5eSvporpo // Check memPreds(). 249318d2f5eSvporpo EXPECT_TRUE(N0->memPreds().empty()); 250318d2f5eSvporpo EXPECT_THAT(N1->memPreds(), testing::ElementsAre(N0)); 251a4916d20Svporpo EXPECT_TRUE(N2->preds(DAG).empty()); 252fc08ad66Svporpo 253fc08ad66Svporpo // Check UnscheduledSuccs. 254fc08ad66Svporpo EXPECT_EQ(N0->getNumUnscheduledSuccs(), 1u); // N1 255fc08ad66Svporpo EXPECT_EQ(N1->getNumUnscheduledSuccs(), 0u); 256fc08ad66Svporpo EXPECT_EQ(N2->getNumUnscheduledSuccs(), 0u); 2571d09925bSvporpo 2581d09925bSvporpo // Check decrUnscheduledSuccs. 2591d09925bSvporpo N0->decrUnscheduledSuccs(); 2601d09925bSvporpo EXPECT_EQ(N0->getNumUnscheduledSuccs(), 0u); 2611d09925bSvporpo #ifndef NDEBUG 2621d09925bSvporpo EXPECT_DEATH(N0->decrUnscheduledSuccs(), ".*Counting.*"); 2631d09925bSvporpo #endif // NDEBUG 2641d09925bSvporpo 2651d09925bSvporpo // Check scheduled(), setScheduled(). 2661d09925bSvporpo EXPECT_FALSE(N0->scheduled()); 2671d09925bSvporpo N0->setScheduled(true); 2681d09925bSvporpo EXPECT_TRUE(N0->scheduled()); 269318d2f5eSvporpo } 270fd5e220fSvporpo 271747d8f3fSvporpo TEST_F(DependencyGraphTest, Preds) { 272747d8f3fSvporpo parseIR(C, R"IR( 273747d8f3fSvporpo declare ptr @bar(i8) 274747d8f3fSvporpo define i8 @foo(i8 %v0, i8 %v1) { 275747d8f3fSvporpo %add0 = add i8 %v0, %v0 276747d8f3fSvporpo %add1 = add i8 %v1, %v1 277747d8f3fSvporpo %add2 = add i8 %add0, %add1 278747d8f3fSvporpo %ptr = call ptr @bar(i8 %add1) 279747d8f3fSvporpo store i8 %add2, ptr %ptr 280747d8f3fSvporpo ret i8 %add2 281747d8f3fSvporpo } 282747d8f3fSvporpo )IR"); 283747d8f3fSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 284747d8f3fSvporpo sandboxir::Context Ctx(C); 285747d8f3fSvporpo auto *F = Ctx.createFunction(LLVMF); 286747d8f3fSvporpo auto *BB = &*F->begin(); 287747d8f3fSvporpo auto It = BB->begin(); 28831a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 289747d8f3fSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 290747d8f3fSvporpo 291747d8f3fSvporpo auto *AddN0 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 292747d8f3fSvporpo auto *AddN1 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 293747d8f3fSvporpo auto *AddN2 = DAG.getNode(cast<sandboxir::BinaryOperator>(&*It++)); 294747d8f3fSvporpo auto *CallN = DAG.getNode(cast<sandboxir::CallInst>(&*It++)); 295747d8f3fSvporpo auto *StN = DAG.getNode(cast<sandboxir::StoreInst>(&*It++)); 296747d8f3fSvporpo auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 297747d8f3fSvporpo 298747d8f3fSvporpo // Check preds(). 299747d8f3fSvporpo EXPECT_THAT(AddN0->preds(DAG), testing::ElementsAre()); 300747d8f3fSvporpo EXPECT_THAT(AddN1->preds(DAG), testing::ElementsAre()); 301747d8f3fSvporpo EXPECT_THAT(AddN2->preds(DAG), testing::ElementsAre(AddN0, AddN1)); 302747d8f3fSvporpo EXPECT_THAT(CallN->preds(DAG), testing::ElementsAre(AddN1)); 303747d8f3fSvporpo EXPECT_THAT(StN->preds(DAG), 304747d8f3fSvporpo testing::UnorderedElementsAre(CallN, CallN, AddN2)); 305747d8f3fSvporpo EXPECT_THAT(RetN->preds(DAG), testing::ElementsAre(AddN2)); 306fc08ad66Svporpo 307fc08ad66Svporpo // Check UnscheduledSuccs. 308fc08ad66Svporpo EXPECT_EQ(AddN0->getNumUnscheduledSuccs(), 1u); // AddN2 309fc08ad66Svporpo EXPECT_EQ(AddN1->getNumUnscheduledSuccs(), 2u); // AddN2, CallN 310fc08ad66Svporpo EXPECT_EQ(AddN2->getNumUnscheduledSuccs(), 2u); // StN, RetN 311fc08ad66Svporpo EXPECT_EQ(CallN->getNumUnscheduledSuccs(), 2u); // StN, StN 312fc08ad66Svporpo EXPECT_EQ(StN->getNumUnscheduledSuccs(), 0u); 313fc08ad66Svporpo EXPECT_EQ(RetN->getNumUnscheduledSuccs(), 0u); 314747d8f3fSvporpo } 315747d8f3fSvporpo 316fd5e220fSvporpo TEST_F(DependencyGraphTest, MemDGNode_getPrevNode_getNextNode) { 317fd5e220fSvporpo parseIR(C, R"IR( 318fd5e220fSvporpo define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 319fd5e220fSvporpo store i8 %v0, ptr %ptr 320fd5e220fSvporpo add i8 %v0, %v0 321fd5e220fSvporpo store i8 %v1, ptr %ptr 322fd5e220fSvporpo ret void 323fd5e220fSvporpo } 324fd5e220fSvporpo )IR"); 325fd5e220fSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 326fd5e220fSvporpo sandboxir::Context Ctx(C); 327fd5e220fSvporpo auto *F = Ctx.createFunction(LLVMF); 328fd5e220fSvporpo auto *BB = &*F->begin(); 329fd5e220fSvporpo auto It = BB->begin(); 330fd5e220fSvporpo auto *S0 = cast<sandboxir::StoreInst>(&*It++); 331fd5e220fSvporpo [[maybe_unused]] auto *Add = cast<sandboxir::BinaryOperator>(&*It++); 332fd5e220fSvporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 333fd5e220fSvporpo [[maybe_unused]] auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 334fd5e220fSvporpo 33531a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 336fd5e220fSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 337fd5e220fSvporpo 338fd5e220fSvporpo auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 339fd5e220fSvporpo auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 340fd5e220fSvporpo 341fd5e220fSvporpo EXPECT_EQ(S0N->getPrevNode(), nullptr); 342fd5e220fSvporpo EXPECT_EQ(S0N->getNextNode(), S1N); 343fd5e220fSvporpo 344fd5e220fSvporpo EXPECT_EQ(S1N->getPrevNode(), S0N); 345fd5e220fSvporpo EXPECT_EQ(S1N->getNextNode(), nullptr); 346fd5e220fSvporpo } 347fd5e220fSvporpo 348fd5e220fSvporpo TEST_F(DependencyGraphTest, DGNodeRange) { 349fd5e220fSvporpo parseIR(C, R"IR( 350fd5e220fSvporpo define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 351fd5e220fSvporpo add i8 %v0, %v0 352fd5e220fSvporpo store i8 %v0, ptr %ptr 353fd5e220fSvporpo add i8 %v0, %v0 354fd5e220fSvporpo store i8 %v1, ptr %ptr 355fd5e220fSvporpo ret void 356fd5e220fSvporpo } 357fd5e220fSvporpo )IR"); 358fd5e220fSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 359fd5e220fSvporpo sandboxir::Context Ctx(C); 360fd5e220fSvporpo auto *F = Ctx.createFunction(LLVMF); 361fd5e220fSvporpo auto *BB = &*F->begin(); 362fd5e220fSvporpo auto It = BB->begin(); 363fd5e220fSvporpo auto *Add0 = cast<sandboxir::BinaryOperator>(&*It++); 364fd5e220fSvporpo auto *S0 = cast<sandboxir::StoreInst>(&*It++); 365fd5e220fSvporpo auto *Add1 = cast<sandboxir::BinaryOperator>(&*It++); 366fd5e220fSvporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 367fd5e220fSvporpo auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 368fd5e220fSvporpo 36931a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 370fd5e220fSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 371fd5e220fSvporpo 372fd5e220fSvporpo auto *S0N = cast<sandboxir::MemDGNode>(DAG.getNode(S0)); 373fd5e220fSvporpo auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 374fd5e220fSvporpo 37569c00679Svporpo // Check getTopMemDGNode(). 37669c00679Svporpo using B = sandboxir::MemDGNodeIntervalBuilder; 37769c00679Svporpo using InstrInterval = sandboxir::Interval<sandboxir::Instruction>; 37869c00679Svporpo EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, S0), DAG), S0N); 37969c00679Svporpo EXPECT_EQ(B::getTopMemDGNode(InstrInterval(S0, Ret), DAG), S0N); 38069c00679Svporpo EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add1), DAG), S0N); 38169c00679Svporpo EXPECT_EQ(B::getTopMemDGNode(InstrInterval(Add0, Add0), DAG), nullptr); 38269c00679Svporpo 38369c00679Svporpo // Check getBotMemDGNode(). 38469c00679Svporpo EXPECT_EQ(B::getBotMemDGNode(InstrInterval(S1, S1), DAG), S1N); 38569c00679Svporpo EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, S1), DAG), S1N); 38669c00679Svporpo EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Add0, Ret), DAG), S1N); 38769c00679Svporpo EXPECT_EQ(B::getBotMemDGNode(InstrInterval(Ret, Ret), DAG), nullptr); 38869c00679Svporpo 389fd5e220fSvporpo // Check empty range. 390fd5e220fSvporpo EXPECT_THAT(sandboxir::MemDGNodeIntervalBuilder::makeEmpty(), 391fd5e220fSvporpo testing::ElementsAre()); 392fd5e220fSvporpo 393fd5e220fSvporpo // Returns the pointers in Range. 394fd5e220fSvporpo auto getPtrVec = [](const auto &Range) { 395fd5e220fSvporpo SmallVector<const sandboxir::DGNode *> Vec; 396fd5e220fSvporpo for (const sandboxir::DGNode &N : Range) 397fd5e220fSvporpo Vec.push_back(&N); 398fd5e220fSvporpo return Vec; 399fd5e220fSvporpo }; 400fd5e220fSvporpo // Both TopN and BotN are memory. 401fd5e220fSvporpo EXPECT_THAT( 402fd5e220fSvporpo getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, S1}, DAG)), 403fd5e220fSvporpo testing::ElementsAre(S0N, S1N)); 404fd5e220fSvporpo // Only TopN is memory. 405fd5e220fSvporpo EXPECT_THAT( 406fd5e220fSvporpo getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Ret}, DAG)), 407fd5e220fSvporpo testing::ElementsAre(S0N, S1N)); 408fd5e220fSvporpo EXPECT_THAT( 409fd5e220fSvporpo getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({S0, Add1}, DAG)), 410fd5e220fSvporpo testing::ElementsAre(S0N)); 411fd5e220fSvporpo // Only BotN is memory. 412fd5e220fSvporpo EXPECT_THAT( 413fd5e220fSvporpo getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S1}, DAG)), 414fd5e220fSvporpo testing::ElementsAre(S0N, S1N)); 415fd5e220fSvporpo EXPECT_THAT( 416fd5e220fSvporpo getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, S0}, DAG)), 417fd5e220fSvporpo testing::ElementsAre(S0N)); 418fd5e220fSvporpo // Neither TopN or BotN is memory. 419fd5e220fSvporpo EXPECT_THAT( 420fd5e220fSvporpo getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Ret}, DAG)), 421fd5e220fSvporpo testing::ElementsAre(S0N, S1N)); 422fd5e220fSvporpo EXPECT_THAT( 423fd5e220fSvporpo getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Add0}, DAG)), 424fd5e220fSvporpo testing::ElementsAre()); 425fd5e220fSvporpo } 42604a8bffdSvporpo 42704a8bffdSvporpo TEST_F(DependencyGraphTest, AliasingStores) { 42804a8bffdSvporpo parseIR(C, R"IR( 42904a8bffdSvporpo define void @foo(ptr %ptr, i8 %v0, i8 %v1) { 43004a8bffdSvporpo store i8 %v0, ptr %ptr 43104a8bffdSvporpo store i8 %v1, ptr %ptr 43204a8bffdSvporpo ret void 43304a8bffdSvporpo } 43404a8bffdSvporpo )IR"); 43504a8bffdSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 43604a8bffdSvporpo sandboxir::Context Ctx(C); 43704a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 43804a8bffdSvporpo auto *BB = &*F->begin(); 43931a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 44004a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 44104a8bffdSvporpo auto It = BB->begin(); 442a4916d20Svporpo auto *Store0N = cast<sandboxir::MemDGNode>( 443a4916d20Svporpo DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 444a4916d20Svporpo auto *Store1N = cast<sandboxir::MemDGNode>( 445a4916d20Svporpo DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 44604a8bffdSvporpo auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 44704a8bffdSvporpo EXPECT_TRUE(Store0N->memPreds().empty()); 44804a8bffdSvporpo EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 449a4916d20Svporpo EXPECT_TRUE(RetN->preds(DAG).empty()); 45004a8bffdSvporpo } 45104a8bffdSvporpo 45204a8bffdSvporpo TEST_F(DependencyGraphTest, NonAliasingStores) { 45304a8bffdSvporpo parseIR(C, R"IR( 45404a8bffdSvporpo define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) { 45504a8bffdSvporpo store i8 %v0, ptr %ptr0 45604a8bffdSvporpo store i8 %v1, ptr %ptr1 45704a8bffdSvporpo ret void 45804a8bffdSvporpo } 45904a8bffdSvporpo )IR"); 46004a8bffdSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 46104a8bffdSvporpo sandboxir::Context Ctx(C); 46204a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 46304a8bffdSvporpo auto *BB = &*F->begin(); 46431a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 46504a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 46604a8bffdSvporpo auto It = BB->begin(); 467a4916d20Svporpo auto *Store0N = cast<sandboxir::MemDGNode>( 468a4916d20Svporpo DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 469a4916d20Svporpo auto *Store1N = cast<sandboxir::MemDGNode>( 470a4916d20Svporpo DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 47104a8bffdSvporpo auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 47204a8bffdSvporpo // We expect no dependencies because the stores don't alias. 47304a8bffdSvporpo EXPECT_TRUE(Store0N->memPreds().empty()); 47404a8bffdSvporpo EXPECT_TRUE(Store1N->memPreds().empty()); 475a4916d20Svporpo EXPECT_TRUE(RetN->preds(DAG).empty()); 47604a8bffdSvporpo } 47704a8bffdSvporpo 47804a8bffdSvporpo TEST_F(DependencyGraphTest, VolatileLoads) { 47904a8bffdSvporpo parseIR(C, R"IR( 48004a8bffdSvporpo define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) { 48104a8bffdSvporpo %ld0 = load volatile i8, ptr %ptr0 48204a8bffdSvporpo %ld1 = load volatile i8, ptr %ptr1 48304a8bffdSvporpo ret void 48404a8bffdSvporpo } 48504a8bffdSvporpo )IR"); 48604a8bffdSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 48704a8bffdSvporpo sandboxir::Context Ctx(C); 48804a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 48904a8bffdSvporpo auto *BB = &*F->begin(); 49031a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 49104a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 49204a8bffdSvporpo auto It = BB->begin(); 493a4916d20Svporpo auto *Ld0N = cast<sandboxir::MemDGNode>( 494a4916d20Svporpo DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 495a4916d20Svporpo auto *Ld1N = cast<sandboxir::MemDGNode>( 496a4916d20Svporpo DAG.getNode(cast<sandboxir::LoadInst>(&*It++))); 49704a8bffdSvporpo auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 49804a8bffdSvporpo EXPECT_TRUE(Ld0N->memPreds().empty()); 49904a8bffdSvporpo EXPECT_THAT(Ld1N->memPreds(), testing::ElementsAre(Ld0N)); 500a4916d20Svporpo EXPECT_TRUE(RetN->preds(DAG).empty()); 50104a8bffdSvporpo } 50204a8bffdSvporpo 50304a8bffdSvporpo TEST_F(DependencyGraphTest, VolatileSotres) { 50404a8bffdSvporpo parseIR(C, R"IR( 50504a8bffdSvporpo define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v) { 50604a8bffdSvporpo store volatile i8 %v, ptr %ptr0 50704a8bffdSvporpo store volatile i8 %v, ptr %ptr1 50804a8bffdSvporpo ret void 50904a8bffdSvporpo } 51004a8bffdSvporpo )IR"); 51104a8bffdSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 51204a8bffdSvporpo sandboxir::Context Ctx(C); 51304a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 51404a8bffdSvporpo auto *BB = &*F->begin(); 51531a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 51604a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()}); 51704a8bffdSvporpo auto It = BB->begin(); 518a4916d20Svporpo auto *Store0N = cast<sandboxir::MemDGNode>( 519a4916d20Svporpo DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 520a4916d20Svporpo auto *Store1N = cast<sandboxir::MemDGNode>( 521a4916d20Svporpo DAG.getNode(cast<sandboxir::StoreInst>(&*It++))); 52204a8bffdSvporpo auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++)); 52304a8bffdSvporpo EXPECT_TRUE(Store0N->memPreds().empty()); 52404a8bffdSvporpo EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N)); 525a4916d20Svporpo EXPECT_TRUE(RetN->preds(DAG).empty()); 52604a8bffdSvporpo } 52704a8bffdSvporpo 52804a8bffdSvporpo TEST_F(DependencyGraphTest, Call) { 52904a8bffdSvporpo parseIR(C, R"IR( 53004a8bffdSvporpo declare void @bar1() 53104a8bffdSvporpo declare void @bar2() 53204a8bffdSvporpo define void @foo(float %v1, float %v2) { 53304a8bffdSvporpo call void @bar1() 53404a8bffdSvporpo %add = fadd float %v1, %v2 53504a8bffdSvporpo call void @bar2() 53604a8bffdSvporpo ret void 53704a8bffdSvporpo } 53804a8bffdSvporpo )IR"); 53904a8bffdSvporpo Function *LLVMF = M->getFunction("foo"); 54004a8bffdSvporpo 54104a8bffdSvporpo sandboxir::Context Ctx(C); 54204a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 54304a8bffdSvporpo auto *BB = &*F->begin(); 54404a8bffdSvporpo 54531a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 54604a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 54704a8bffdSvporpo 54804a8bffdSvporpo auto It = BB->begin(); 549a4916d20Svporpo auto *Call1N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 55004a8bffdSvporpo auto *AddN = DAG.getNode(&*It++); 551a4916d20Svporpo auto *Call2N = cast<sandboxir::MemDGNode>(DAG.getNode(&*It++)); 55204a8bffdSvporpo 55304a8bffdSvporpo EXPECT_THAT(Call1N->memPreds(), testing::ElementsAre()); 554a4916d20Svporpo EXPECT_THAT(AddN->preds(DAG), testing::ElementsAre()); 55504a8bffdSvporpo EXPECT_THAT(Call2N->memPreds(), testing::ElementsAre(Call1N)); 55604a8bffdSvporpo } 55704a8bffdSvporpo 55804a8bffdSvporpo // Check that there is a dependency: stacksave -> alloca -> stackrestore. 55904a8bffdSvporpo TEST_F(DependencyGraphTest, StackSaveRestoreInAlloca) { 56004a8bffdSvporpo parseIR(C, R"IR( 56104a8bffdSvporpo declare ptr @llvm.stacksave() 56204a8bffdSvporpo declare void @llvm.stackrestore(ptr %ptr) 56304a8bffdSvporpo 56404a8bffdSvporpo define void @foo() { 56504a8bffdSvporpo %stack0 = call ptr @llvm.stacksave() ; Should depend on store 56604a8bffdSvporpo %alloca0 = alloca inalloca i8 ; Should depend on stacksave 56704a8bffdSvporpo call void @llvm.stackrestore(ptr %stack0) ; Should depend transiently on %alloca0 56804a8bffdSvporpo ret void 56904a8bffdSvporpo } 57004a8bffdSvporpo )IR"); 57104a8bffdSvporpo Function *LLVMF = M->getFunction("foo"); 57204a8bffdSvporpo 57304a8bffdSvporpo sandboxir::Context Ctx(C); 57404a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 57504a8bffdSvporpo auto *BB = &*F->begin(); 57604a8bffdSvporpo 57731a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 57804a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 57904a8bffdSvporpo 58004a8bffdSvporpo auto It = BB->begin(); 58104a8bffdSvporpo auto *StackSaveN = DAG.getNode(&*It++); 58204a8bffdSvporpo auto *AllocaN = DAG.getNode(&*It++); 58304a8bffdSvporpo auto *StackRestoreN = DAG.getNode(&*It++); 58404a8bffdSvporpo 585a4916d20Svporpo EXPECT_TRUE(memDependency(AllocaN, StackRestoreN)); 586a4916d20Svporpo EXPECT_TRUE(memDependency(StackSaveN, AllocaN)); 58704a8bffdSvporpo } 58804a8bffdSvporpo 58904a8bffdSvporpo // Checks that stacksave and stackrestore depend on other mem instrs. 59004a8bffdSvporpo TEST_F(DependencyGraphTest, StackSaveRestoreDependOnOtherMem) { 59104a8bffdSvporpo parseIR(C, R"IR( 59204a8bffdSvporpo declare ptr @llvm.stacksave() 59304a8bffdSvporpo declare void @llvm.stackrestore(ptr %ptr) 59404a8bffdSvporpo 59504a8bffdSvporpo define void @foo(i8 %v0, i8 %v1, ptr %ptr) { 59604a8bffdSvporpo store volatile i8 %v0, ptr %ptr, align 4 59704a8bffdSvporpo %stack0 = call ptr @llvm.stacksave() ; Should depend on store 59804a8bffdSvporpo call void @llvm.stackrestore(ptr %stack0) ; Should depend on stacksave 59904a8bffdSvporpo store volatile i8 %v1, ptr %ptr, align 4 ; Should depend on stackrestore 60004a8bffdSvporpo ret void 60104a8bffdSvporpo } 60204a8bffdSvporpo )IR"); 60304a8bffdSvporpo Function *LLVMF = M->getFunction("foo"); 60404a8bffdSvporpo 60504a8bffdSvporpo sandboxir::Context Ctx(C); 60604a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 60704a8bffdSvporpo auto *BB = &*F->begin(); 60804a8bffdSvporpo 60931a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 61004a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 61104a8bffdSvporpo 61204a8bffdSvporpo auto It = BB->begin(); 61304a8bffdSvporpo auto *Store0N = DAG.getNode(&*It++); 61404a8bffdSvporpo auto *StackSaveN = DAG.getNode(&*It++); 61504a8bffdSvporpo auto *StackRestoreN = DAG.getNode(&*It++); 61604a8bffdSvporpo auto *Store1N = DAG.getNode(&*It++); 61704a8bffdSvporpo 618a4916d20Svporpo EXPECT_TRUE(memDependency(Store0N, StackSaveN)); 619a4916d20Svporpo EXPECT_TRUE(memDependency(StackSaveN, StackRestoreN)); 620a4916d20Svporpo EXPECT_TRUE(memDependency(StackRestoreN, Store1N)); 62104a8bffdSvporpo } 62204a8bffdSvporpo 62304a8bffdSvporpo // Make sure there is a dependency between a stackrestore and an alloca. 62404a8bffdSvporpo TEST_F(DependencyGraphTest, StackRestoreAndInAlloca) { 62504a8bffdSvporpo parseIR(C, R"IR( 62604a8bffdSvporpo declare void @llvm.stackrestore(ptr %ptr) 62704a8bffdSvporpo 62804a8bffdSvporpo define void @foo(ptr %ptr) { 62904a8bffdSvporpo call void @llvm.stackrestore(ptr %ptr) 63004a8bffdSvporpo %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 63104a8bffdSvporpo ret void 63204a8bffdSvporpo } 63304a8bffdSvporpo )IR"); 63404a8bffdSvporpo Function *LLVMF = M->getFunction("foo"); 63504a8bffdSvporpo 63604a8bffdSvporpo sandboxir::Context Ctx(C); 63704a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 63804a8bffdSvporpo auto *BB = &*F->begin(); 63904a8bffdSvporpo 64031a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 64104a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 64204a8bffdSvporpo 64304a8bffdSvporpo auto It = BB->begin(); 64404a8bffdSvporpo auto *StackRestoreN = DAG.getNode(&*It++); 64504a8bffdSvporpo auto *AllocaN = DAG.getNode(&*It++); 64604a8bffdSvporpo 647a4916d20Svporpo EXPECT_TRUE(memDependency(StackRestoreN, AllocaN)); 64804a8bffdSvporpo } 64904a8bffdSvporpo 65004a8bffdSvporpo // Make sure there is a dependency between the alloca and stacksave 65104a8bffdSvporpo TEST_F(DependencyGraphTest, StackSaveAndInAlloca) { 65204a8bffdSvporpo parseIR(C, R"IR( 65304a8bffdSvporpo declare ptr @llvm.stacksave() 65404a8bffdSvporpo 65504a8bffdSvporpo define void @foo(ptr %ptr) { 65604a8bffdSvporpo %alloca0 = alloca inalloca i8 ; Should depend on stackrestore 65704a8bffdSvporpo %stack0 = call ptr @llvm.stacksave() ; Should depend on alloca0 65804a8bffdSvporpo ret void 65904a8bffdSvporpo } 66004a8bffdSvporpo )IR"); 66104a8bffdSvporpo Function *LLVMF = M->getFunction("foo"); 66204a8bffdSvporpo 66304a8bffdSvporpo sandboxir::Context Ctx(C); 66404a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 66504a8bffdSvporpo auto *BB = &*F->begin(); 66604a8bffdSvporpo 66731a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 66804a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 66904a8bffdSvporpo 67004a8bffdSvporpo auto It = BB->begin(); 67104a8bffdSvporpo auto *AllocaN = DAG.getNode(&*It++); 67204a8bffdSvporpo auto *StackSaveN = DAG.getNode(&*It++); 67304a8bffdSvporpo 674a4916d20Svporpo EXPECT_TRUE(memDependency(AllocaN, StackSaveN)); 67504a8bffdSvporpo } 67604a8bffdSvporpo 67704a8bffdSvporpo // A non-InAlloca in a stacksave-stackrestore region does not need extra 67804a8bffdSvporpo // dependencies. 67904a8bffdSvporpo TEST_F(DependencyGraphTest, StackSaveRestoreNoInAlloca) { 68004a8bffdSvporpo parseIR(C, R"IR( 68104a8bffdSvporpo declare ptr @llvm.stacksave() 68204a8bffdSvporpo declare void @llvm.stackrestore(ptr %ptr) 68304a8bffdSvporpo declare void @use(ptr %ptr) 68404a8bffdSvporpo 68504a8bffdSvporpo define void @foo() { 68604a8bffdSvporpo %stack = call ptr @llvm.stacksave() 68704a8bffdSvporpo %alloca1 = alloca i8 ; No dependency 68804a8bffdSvporpo call void @llvm.stackrestore(ptr %stack) 68904a8bffdSvporpo ret void 69004a8bffdSvporpo } 69104a8bffdSvporpo )IR"); 69204a8bffdSvporpo Function *LLVMF = M->getFunction("foo"); 69304a8bffdSvporpo 69404a8bffdSvporpo sandboxir::Context Ctx(C); 69504a8bffdSvporpo auto *F = Ctx.createFunction(LLVMF); 69604a8bffdSvporpo auto *BB = &*F->begin(); 69704a8bffdSvporpo 69831a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 69904a8bffdSvporpo DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()}); 70004a8bffdSvporpo 70104a8bffdSvporpo auto It = BB->begin(); 70204a8bffdSvporpo auto *StackSaveN = DAG.getNode(&*It++); 70304a8bffdSvporpo auto *AllocaN = DAG.getNode(&*It++); 70404a8bffdSvporpo auto *StackRestoreN = DAG.getNode(&*It++); 70504a8bffdSvporpo 706a4916d20Svporpo EXPECT_FALSE(memDependency(StackSaveN, AllocaN)); 707a4916d20Svporpo EXPECT_FALSE(memDependency(AllocaN, StackRestoreN)); 70804a8bffdSvporpo } 709e8dd95e9Svporpo 710e8dd95e9Svporpo TEST_F(DependencyGraphTest, Extend) { 711e8dd95e9Svporpo parseIR(C, R"IR( 712e8dd95e9Svporpo define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %v5) { 713e8dd95e9Svporpo store i8 %v1, ptr %ptr 714e8dd95e9Svporpo store i8 %v2, ptr %ptr 715e8dd95e9Svporpo store i8 %v3, ptr %ptr 716e8dd95e9Svporpo store i8 %v4, ptr %ptr 717e8dd95e9Svporpo store i8 %v5, ptr %ptr 718e8dd95e9Svporpo ret void 719e8dd95e9Svporpo } 720e8dd95e9Svporpo )IR"); 721e8dd95e9Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 722e8dd95e9Svporpo sandboxir::Context Ctx(C); 723e8dd95e9Svporpo auto *F = Ctx.createFunction(LLVMF); 724e8dd95e9Svporpo auto *BB = &*F->begin(); 725e8dd95e9Svporpo auto It = BB->begin(); 726e8dd95e9Svporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 727e8dd95e9Svporpo auto *S2 = cast<sandboxir::StoreInst>(&*It++); 728e8dd95e9Svporpo auto *S3 = cast<sandboxir::StoreInst>(&*It++); 729e8dd95e9Svporpo auto *S4 = cast<sandboxir::StoreInst>(&*It++); 730e8dd95e9Svporpo auto *S5 = cast<sandboxir::StoreInst>(&*It++); 73131a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 732e8dd95e9Svporpo { 733e8dd95e9Svporpo // Scenario 1: Build new DAG 734e8dd95e9Svporpo auto NewIntvl = DAG.extend({S3, S3}); 735e8dd95e9Svporpo EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S3, S3)); 736e8dd95e9Svporpo EXPECT_EQ(DAG.getInterval().top(), S3); 737e8dd95e9Svporpo EXPECT_EQ(DAG.getInterval().bottom(), S3); 738e8dd95e9Svporpo [[maybe_unused]] auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 739fc08ad66Svporpo // Check UnscheduledSuccs. 740fc08ad66Svporpo EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 0u); 741e8dd95e9Svporpo } 742e8dd95e9Svporpo { 743e8dd95e9Svporpo // Scenario 2: Extend below 744e8dd95e9Svporpo auto NewIntvl = DAG.extend({S5, S5}); 745e8dd95e9Svporpo EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S4, S5)); 746e8dd95e9Svporpo auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 747e8dd95e9Svporpo auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 748e8dd95e9Svporpo auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 749e8dd95e9Svporpo EXPECT_TRUE(S4N->hasMemPred(S3N)); 750e8dd95e9Svporpo EXPECT_TRUE(S5N->hasMemPred(S4N)); 751e8dd95e9Svporpo EXPECT_TRUE(S5N->hasMemPred(S3N)); 752fc08ad66Svporpo // Check UnscheduledSuccs. 753fc08ad66Svporpo EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 2u); // S4N, S5N 754fc08ad66Svporpo EXPECT_EQ(S4N->getNumUnscheduledSuccs(), 1u); // S5N 755fc08ad66Svporpo EXPECT_EQ(S5N->getNumUnscheduledSuccs(), 0u); 756e8dd95e9Svporpo } 757e8dd95e9Svporpo { 758e8dd95e9Svporpo // Scenario 3: Extend above 759e8dd95e9Svporpo auto NewIntvl = DAG.extend({S1, S2}); 760e8dd95e9Svporpo EXPECT_EQ(NewIntvl, sandboxir::Interval<sandboxir::Instruction>(S1, S2)); 761e8dd95e9Svporpo auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 762e8dd95e9Svporpo auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 763e8dd95e9Svporpo auto *S3N = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 764e8dd95e9Svporpo auto *S4N = cast<sandboxir::MemDGNode>(DAG.getNode(S4)); 765e8dd95e9Svporpo auto *S5N = cast<sandboxir::MemDGNode>(DAG.getNode(S5)); 766e8dd95e9Svporpo 767e8dd95e9Svporpo EXPECT_TRUE(S2N->hasMemPred(S1N)); 768e8dd95e9Svporpo 769e8dd95e9Svporpo EXPECT_TRUE(S3N->hasMemPred(S2N)); 770e8dd95e9Svporpo EXPECT_TRUE(S3N->hasMemPred(S1N)); 771e8dd95e9Svporpo 772e8dd95e9Svporpo EXPECT_TRUE(S4N->hasMemPred(S3N)); 773e8dd95e9Svporpo EXPECT_TRUE(S4N->hasMemPred(S2N)); 774e8dd95e9Svporpo EXPECT_TRUE(S4N->hasMemPred(S1N)); 775e8dd95e9Svporpo 776e8dd95e9Svporpo EXPECT_TRUE(S5N->hasMemPred(S4N)); 777e8dd95e9Svporpo EXPECT_TRUE(S5N->hasMemPred(S3N)); 778e8dd95e9Svporpo EXPECT_TRUE(S5N->hasMemPred(S2N)); 779e8dd95e9Svporpo EXPECT_TRUE(S5N->hasMemPred(S1N)); 780fc08ad66Svporpo 781fc08ad66Svporpo // Check UnscheduledSuccs. 782fc08ad66Svporpo EXPECT_EQ(S1N->getNumUnscheduledSuccs(), 4u); // S2N, S3N, S4N, S5N 783fc08ad66Svporpo EXPECT_EQ(S2N->getNumUnscheduledSuccs(), 3u); // S3N, S4N, S5N 784fc08ad66Svporpo EXPECT_EQ(S3N->getNumUnscheduledSuccs(), 2u); // S4N, S5N 785fc08ad66Svporpo EXPECT_EQ(S4N->getNumUnscheduledSuccs(), 1u); // S5N 786fc08ad66Svporpo EXPECT_EQ(S5N->getNumUnscheduledSuccs(), 0u); 787e8dd95e9Svporpo } 7881d09925bSvporpo 7891d09925bSvporpo { 7901d09925bSvporpo // Check UnscheduledSuccs when a node is scheduled 79131a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 7921d09925bSvporpo DAG.extend({S2, S2}); 7931d09925bSvporpo auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 7941d09925bSvporpo S2N->setScheduled(true); 7951d09925bSvporpo 7961d09925bSvporpo DAG.extend({S1, S1}); 7971d09925bSvporpo auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 7981d09925bSvporpo EXPECT_EQ(S1N->getNumUnscheduledSuccs(), 0u); // S1 is scheduled 7991d09925bSvporpo } 800e8dd95e9Svporpo } 80131a4d2c2Svporpo 80231a4d2c2Svporpo TEST_F(DependencyGraphTest, CreateInstrCallback) { 80331a4d2c2Svporpo parseIR(C, R"IR( 8047a38445eSvporpo define void @foo(ptr %ptr, ptr noalias %ptr2, i8 %v1, i8 %v2, i8 %v3, i8 %arg) { 80531a4d2c2Svporpo store i8 %v1, ptr %ptr 80631a4d2c2Svporpo store i8 %v2, ptr %ptr 80731a4d2c2Svporpo store i8 %v3, ptr %ptr 80831a4d2c2Svporpo ret void 80931a4d2c2Svporpo } 81031a4d2c2Svporpo )IR"); 81131a4d2c2Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 81231a4d2c2Svporpo sandboxir::Context Ctx(C); 81331a4d2c2Svporpo auto *F = Ctx.createFunction(LLVMF); 81431a4d2c2Svporpo auto *BB = &*F->begin(); 81531a4d2c2Svporpo auto It = BB->begin(); 81631a4d2c2Svporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 817eeb55d3aSvporpo auto *S2 = cast<sandboxir::StoreInst>(&*It++); 81831a4d2c2Svporpo auto *S3 = cast<sandboxir::StoreInst>(&*It++); 819eeb55d3aSvporpo auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 82031a4d2c2Svporpo 82131a4d2c2Svporpo // Check new instruction callback. 82231a4d2c2Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 823eeb55d3aSvporpo DAG.extend({S1, Ret}); 82431a4d2c2Svporpo auto *Arg = F->getArg(3); 82531a4d2c2Svporpo auto *Ptr = S1->getPointerOperand(); 826eeb55d3aSvporpo { 82731a4d2c2Svporpo sandboxir::StoreInst *NewS = 82831a4d2c2Svporpo sandboxir::StoreInst::create(Arg, Ptr, Align(8), S3->getIterator(), 82931a4d2c2Svporpo /*IsVolatile=*/true, Ctx); 83031a4d2c2Svporpo auto *NewSN = DAG.getNode(NewS); 83131a4d2c2Svporpo EXPECT_TRUE(NewSN != nullptr); 832eeb55d3aSvporpo 833eeb55d3aSvporpo // Check the MemDGNode chain. 834eeb55d3aSvporpo auto *S2MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 835eeb55d3aSvporpo auto *NewMemSN = cast<sandboxir::MemDGNode>(NewSN); 836eeb55d3aSvporpo auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 837eeb55d3aSvporpo EXPECT_EQ(S2MemN->getNextNode(), NewMemSN); 838eeb55d3aSvporpo EXPECT_EQ(NewMemSN->getPrevNode(), S2MemN); 839eeb55d3aSvporpo EXPECT_EQ(NewMemSN->getNextNode(), S3MemN); 840eeb55d3aSvporpo EXPECT_EQ(S3MemN->getPrevNode(), NewMemSN); 841eeb55d3aSvporpo } 842eeb55d3aSvporpo 843eeb55d3aSvporpo { 844eeb55d3aSvporpo // Also check if new node is at the end of the BB, after Ret. 845eeb55d3aSvporpo sandboxir::StoreInst *NewS = 846eeb55d3aSvporpo sandboxir::StoreInst::create(Arg, Ptr, Align(8), BB->end(), 847eeb55d3aSvporpo /*IsVolatile=*/true, Ctx); 848eeb55d3aSvporpo // Check the MemDGNode chain. 849eeb55d3aSvporpo auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 850eeb55d3aSvporpo auto *NewMemSN = cast<sandboxir::MemDGNode>(DAG.getNode(NewS)); 851eeb55d3aSvporpo EXPECT_EQ(S3MemN->getNextNode(), NewMemSN); 852eeb55d3aSvporpo EXPECT_EQ(NewMemSN->getPrevNode(), S3MemN); 853eeb55d3aSvporpo EXPECT_EQ(NewMemSN->getNextNode(), nullptr); 854eeb55d3aSvporpo } 855eeb55d3aSvporpo 85631a4d2c2Svporpo // TODO: Check the dependencies to/from NewSN after they land. 85731a4d2c2Svporpo } 8586e482148Svporpo 8596e482148Svporpo TEST_F(DependencyGraphTest, EraseInstrCallback) { 8606e482148Svporpo parseIR(C, R"IR( 8616e482148Svporpo define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %arg) { 8626e482148Svporpo store i8 %v1, ptr %ptr 8636e482148Svporpo store i8 %v2, ptr %ptr 8646e482148Svporpo store i8 %v3, ptr %ptr 8656e482148Svporpo ret void 8666e482148Svporpo } 8676e482148Svporpo )IR"); 8686e482148Svporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 8696e482148Svporpo sandboxir::Context Ctx(C); 8706e482148Svporpo auto *F = Ctx.createFunction(LLVMF); 8716e482148Svporpo auto *BB = &*F->begin(); 8726e482148Svporpo auto It = BB->begin(); 8736e482148Svporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 8746e482148Svporpo auto *S2 = cast<sandboxir::StoreInst>(&*It++); 8756e482148Svporpo auto *S3 = cast<sandboxir::StoreInst>(&*It++); 8766e482148Svporpo 8776e482148Svporpo // Check erase instruction callback. 8786e482148Svporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 8796e482148Svporpo DAG.extend({S1, S3}); 8806e482148Svporpo S2->eraseFromParent(); 8816e482148Svporpo auto *DeletedN = DAG.getNodeOrNull(S2); 8826e482148Svporpo EXPECT_TRUE(DeletedN == nullptr); 883cafb6b99Svporpo 884cafb6b99Svporpo // Check the MemDGNode chain. 885cafb6b99Svporpo auto *S1MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 886cafb6b99Svporpo auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3)); 887cafb6b99Svporpo EXPECT_EQ(S1MemN->getNextNode(), S3MemN); 888cafb6b99Svporpo EXPECT_EQ(S3MemN->getPrevNode(), S1MemN); 889cafb6b99Svporpo 890cafb6b99Svporpo // Check the chain when we erase the top node. 891cafb6b99Svporpo S1->eraseFromParent(); 892cafb6b99Svporpo EXPECT_EQ(S3MemN->getPrevNode(), nullptr); 893cafb6b99Svporpo 8946e482148Svporpo // TODO: Check the dependencies to/from NewSN after they land. 8956e482148Svporpo } 8967a38445eSvporpo 8977a38445eSvporpo TEST_F(DependencyGraphTest, MoveInstrCallback) { 8987a38445eSvporpo parseIR(C, R"IR( 8997a38445eSvporpo define void @foo(ptr %ptr, ptr %ptr2, i8 %v1, i8 %v2, i8 %v3, i8 %arg) { 9007a38445eSvporpo %ld0 = load i8, ptr %ptr2 9017a38445eSvporpo store i8 %v1, ptr %ptr 9027a38445eSvporpo store i8 %v2, ptr %ptr 9037a38445eSvporpo store i8 %v3, ptr %ptr 9047a38445eSvporpo ret void 9057a38445eSvporpo } 9067a38445eSvporpo )IR"); 9077a38445eSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 9087a38445eSvporpo sandboxir::Context Ctx(C); 9097a38445eSvporpo auto *F = Ctx.createFunction(LLVMF); 9107a38445eSvporpo auto *BB = &*F->begin(); 9117a38445eSvporpo auto It = BB->begin(); 9127a38445eSvporpo auto *Ld = cast<sandboxir::LoadInst>(&*It++); 9137a38445eSvporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 9147a38445eSvporpo auto *S2 = cast<sandboxir::StoreInst>(&*It++); 9157a38445eSvporpo auto *S3 = cast<sandboxir::StoreInst>(&*It++); 9167a38445eSvporpo 9177a38445eSvporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 9187a38445eSvporpo DAG.extend({Ld, S3}); 9197a38445eSvporpo auto *LdN = cast<sandboxir::MemDGNode>(DAG.getNode(Ld)); 9207a38445eSvporpo auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 9217a38445eSvporpo auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 9227a38445eSvporpo EXPECT_EQ(S1N->getPrevNode(), LdN); 9237a38445eSvporpo S1->moveBefore(Ld); 9247a38445eSvporpo EXPECT_EQ(S1N->getPrevNode(), nullptr); 9257a38445eSvporpo EXPECT_EQ(S1N->getNextNode(), LdN); 9267a38445eSvporpo EXPECT_EQ(LdN->getPrevNode(), S1N); 9277a38445eSvporpo EXPECT_EQ(LdN->getNextNode(), S2N); 9287a38445eSvporpo } 929*b41987beSvporpo 930*b41987beSvporpo // Check that the mem chain is maintained correctly when the move destination is 931*b41987beSvporpo // not a mem node. 932*b41987beSvporpo TEST_F(DependencyGraphTest, MoveInstrCallbackWithNonMemInstrs) { 933*b41987beSvporpo parseIR(C, R"IR( 934*b41987beSvporpo define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %arg) { 935*b41987beSvporpo %ld = load i8, ptr %ptr 936*b41987beSvporpo %zext1 = zext i8 %arg to i32 937*b41987beSvporpo %zext2 = zext i8 %arg to i32 938*b41987beSvporpo store i8 %v1, ptr %ptr 939*b41987beSvporpo store i8 %v2, ptr %ptr 940*b41987beSvporpo ret void 941*b41987beSvporpo } 942*b41987beSvporpo )IR"); 943*b41987beSvporpo llvm::Function *LLVMF = &*M->getFunction("foo"); 944*b41987beSvporpo sandboxir::Context Ctx(C); 945*b41987beSvporpo auto *F = Ctx.createFunction(LLVMF); 946*b41987beSvporpo auto *BB = &*F->begin(); 947*b41987beSvporpo auto It = BB->begin(); 948*b41987beSvporpo auto *Ld = cast<sandboxir::LoadInst>(&*It++); 949*b41987beSvporpo [[maybe_unused]] auto *Zext1 = cast<sandboxir::CastInst>(&*It++); 950*b41987beSvporpo auto *Zext2 = cast<sandboxir::CastInst>(&*It++); 951*b41987beSvporpo auto *S1 = cast<sandboxir::StoreInst>(&*It++); 952*b41987beSvporpo auto *S2 = cast<sandboxir::StoreInst>(&*It++); 953*b41987beSvporpo auto *Ret = cast<sandboxir::ReturnInst>(&*It++); 954*b41987beSvporpo 955*b41987beSvporpo sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx); 956*b41987beSvporpo DAG.extend({Ld, S2}); 957*b41987beSvporpo auto *LdN = cast<sandboxir::MemDGNode>(DAG.getNode(Ld)); 958*b41987beSvporpo auto *S1N = cast<sandboxir::MemDGNode>(DAG.getNode(S1)); 959*b41987beSvporpo auto *S2N = cast<sandboxir::MemDGNode>(DAG.getNode(S2)); 960*b41987beSvporpo EXPECT_EQ(LdN->getNextNode(), S1N); 961*b41987beSvporpo EXPECT_EQ(S1N->getNextNode(), S2N); 962*b41987beSvporpo 963*b41987beSvporpo S1->moveBefore(Zext2); 964*b41987beSvporpo EXPECT_EQ(LdN->getNextNode(), S1N); 965*b41987beSvporpo EXPECT_EQ(S1N->getNextNode(), S2N); 966*b41987beSvporpo 967*b41987beSvporpo // Try move right after the end of the DAGInterval. 968*b41987beSvporpo S1->moveBefore(Ret); 969*b41987beSvporpo EXPECT_EQ(S2N->getNextNode(), S1N); 970*b41987beSvporpo EXPECT_EQ(S1N->getNextNode(), nullptr); 971*b41987beSvporpo } 972