xref: /llvm-project/llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp (revision b41987beaedaa6ea78fd8dd11ba8c3b21eb8fa88)
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