[llvm] [SandboxVec][DAG] Build actual dependencies (PR #111094)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Oct 8 15:34:59 PDT 2024
================
@@ -313,3 +342,278 @@ define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
getPtrVec(sandboxir::MemDGNodeIntervalBuilder::make({Add0, Add0}, DAG)),
testing::ElementsAre());
}
+
+TEST_F(DependencyGraphTest, AliasingStores) {
+ parseIR(C, R"IR(
+define void @foo(ptr %ptr, i8 %v0, i8 %v1) {
+ store i8 %v0, ptr %ptr
+ store i8 %v1, ptr %ptr
+ ret void
+}
+)IR");
+ llvm::Function *LLVMF = &*M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()});
+ auto It = BB->begin();
+ auto *Store0N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++));
+ auto *Store1N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++));
+ auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++));
+ EXPECT_TRUE(Store0N->memPreds().empty());
+ EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N));
+ EXPECT_TRUE(RetN->memPreds().empty());
+}
+
+TEST_F(DependencyGraphTest, NonAliasingStores) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v0, i8 %v1) {
+ store i8 %v0, ptr %ptr0
+ store i8 %v1, ptr %ptr1
+ ret void
+}
+)IR");
+ llvm::Function *LLVMF = &*M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()});
+ auto It = BB->begin();
+ auto *Store0N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++));
+ auto *Store1N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++));
+ auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++));
+ // We expect no dependencies because the stores don't alias.
+ EXPECT_TRUE(Store0N->memPreds().empty());
+ EXPECT_TRUE(Store1N->memPreds().empty());
+ EXPECT_TRUE(RetN->memPreds().empty());
+}
+
+TEST_F(DependencyGraphTest, VolatileLoads) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1) {
+ %ld0 = load volatile i8, ptr %ptr0
+ %ld1 = load volatile i8, ptr %ptr1
+ ret void
+}
+)IR");
+ llvm::Function *LLVMF = &*M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()});
+ auto It = BB->begin();
+ auto *Ld0N = DAG.getNode(cast<sandboxir::LoadInst>(&*It++));
+ auto *Ld1N = DAG.getNode(cast<sandboxir::LoadInst>(&*It++));
+ auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++));
+ EXPECT_TRUE(Ld0N->memPreds().empty());
+ EXPECT_THAT(Ld1N->memPreds(), testing::ElementsAre(Ld0N));
+ EXPECT_TRUE(RetN->memPreds().empty());
+}
+
+TEST_F(DependencyGraphTest, VolatileSotres) {
+ parseIR(C, R"IR(
+define void @foo(ptr noalias %ptr0, ptr noalias %ptr1, i8 %v) {
+ store volatile i8 %v, ptr %ptr0
+ store volatile i8 %v, ptr %ptr1
+ ret void
+}
+)IR");
+ llvm::Function *LLVMF = &*M->getFunction("foo");
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()});
+ auto It = BB->begin();
+ auto *Store0N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++));
+ auto *Store1N = DAG.getNode(cast<sandboxir::StoreInst>(&*It++));
+ auto *RetN = DAG.getNode(cast<sandboxir::ReturnInst>(&*It++));
+ EXPECT_TRUE(Store0N->memPreds().empty());
+ EXPECT_THAT(Store1N->memPreds(), testing::ElementsAre(Store0N));
+ EXPECT_TRUE(RetN->memPreds().empty());
+}
+
+TEST_F(DependencyGraphTest, Call) {
+ parseIR(C, R"IR(
+declare void @bar1()
+declare void @bar2()
+define void @foo(float %v1, float %v2) {
+ call void @bar1()
+ %add = fadd float %v1, %v2
+ call void @bar2()
+ ret void
+}
+)IR");
+ Function *LLVMF = M->getFunction("foo");
+
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()});
+
+ auto It = BB->begin();
+ auto *Call1N = DAG.getNode(&*It++);
+ auto *AddN = DAG.getNode(&*It++);
+ auto *Call2N = DAG.getNode(&*It++);
+
+ EXPECT_THAT(Call1N->memPreds(), testing::ElementsAre());
+ EXPECT_THAT(AddN->memPreds(), testing::ElementsAre());
+ EXPECT_THAT(Call2N->memPreds(), testing::ElementsAre(Call1N));
+}
+
+// Check that there is a dependency: stacksave -> alloca -> stackrestore.
+TEST_F(DependencyGraphTest, StackSaveRestoreInAlloca) {
+ parseIR(C, R"IR(
+declare ptr @llvm.stacksave()
+declare void @llvm.stackrestore(ptr %ptr)
+
+define void @foo() {
+ %stack0 = call ptr @llvm.stacksave() ; Should depend on store
+ %alloca0 = alloca inalloca i8 ; Should depend on stacksave
+ call void @llvm.stackrestore(ptr %stack0) ; Should depend transiently on %alloca0
+ ret void
+}
+)IR");
+ Function *LLVMF = M->getFunction("foo");
+
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()});
+
+ auto It = BB->begin();
+ auto *StackSaveN = DAG.getNode(&*It++);
+ auto *AllocaN = DAG.getNode(&*It++);
+ auto *StackRestoreN = DAG.getNode(&*It++);
+
+ EXPECT_TRUE(dependency(AllocaN, StackRestoreN));
+ EXPECT_TRUE(dependency(StackSaveN, AllocaN));
+}
+
+// Checks that stacksave and stackrestore depend on other mem instrs.
+TEST_F(DependencyGraphTest, StackSaveRestoreDependOnOtherMem) {
+ parseIR(C, R"IR(
+declare ptr @llvm.stacksave()
+declare void @llvm.stackrestore(ptr %ptr)
+
+define void @foo(i8 %v0, i8 %v1, ptr %ptr) {
+ store volatile i8 %v0, ptr %ptr, align 4
+ %stack0 = call ptr @llvm.stacksave() ; Should depend on store
+ call void @llvm.stackrestore(ptr %stack0) ; Should depend on stacksave
+ store volatile i8 %v1, ptr %ptr, align 4 ; Should depend on stackrestore
+ ret void
+}
+)IR");
+ Function *LLVMF = M->getFunction("foo");
+
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()});
+
+ auto It = BB->begin();
+ auto *Store0N = DAG.getNode(&*It++);
+ auto *StackSaveN = DAG.getNode(&*It++);
+ auto *StackRestoreN = DAG.getNode(&*It++);
+ auto *Store1N = DAG.getNode(&*It++);
+
+ EXPECT_TRUE(dependency(Store0N, StackSaveN));
+ EXPECT_TRUE(dependency(StackSaveN, StackRestoreN));
+ EXPECT_TRUE(dependency(StackRestoreN, Store1N));
+}
+
+// Make sure there is a dependency between a stackrestore and an alloca.
+TEST_F(DependencyGraphTest, StackRestoreAndInAlloca) {
+ parseIR(C, R"IR(
+declare void @llvm.stackrestore(ptr %ptr)
+
+define void @foo(ptr %ptr) {
+ call void @llvm.stackrestore(ptr %ptr)
+ %alloca0 = alloca inalloca i8 ; Should depend on stackrestore
+ ret void
+}
+)IR");
+ Function *LLVMF = M->getFunction("foo");
+
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()});
+
+ auto It = BB->begin();
+ auto *StackRestoreN = DAG.getNode(&*It++);
+ auto *AllocaN = DAG.getNode(&*It++);
+
+ EXPECT_TRUE(dependency(StackRestoreN, AllocaN));
+}
+
+// Make sure there is a dependency between the alloca and stacksave
+TEST_F(DependencyGraphTest, StackSaveAndInAlloca) {
+ parseIR(C, R"IR(
+declare ptr @llvm.stacksave()
+
+define void @foo(ptr %ptr) {
+ %alloca0 = alloca inalloca i8 ; Should depend on stackrestore
+ %stack0 = call ptr @llvm.stacksave() ; Should depend on alloca0
+ ret void
+}
+)IR");
+ Function *LLVMF = M->getFunction("foo");
+
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()});
+
+ auto It = BB->begin();
+ auto *AllocaN = DAG.getNode(&*It++);
+ auto *StackSaveN = DAG.getNode(&*It++);
+
+ EXPECT_TRUE(dependency(AllocaN, StackSaveN));
+}
+
+// A non-InAlloca in a stacksave-stackrestore region does not need extra
+// dependencies.
+TEST_F(DependencyGraphTest, StackSaveRestoreNoInAlloca) {
+ parseIR(C, R"IR(
+declare ptr @llvm.stacksave()
+declare void @llvm.stackrestore(ptr %ptr)
+declare void @use(ptr %ptr)
+
+define void @foo() {
+ %stack = call ptr @llvm.stacksave()
+ %alloca1 = alloca i8 ; No dependency
+ call void @llvm.stackrestore(ptr %stack)
+ ret void
+}
+)IR");
+ Function *LLVMF = M->getFunction("foo");
+
+ sandboxir::Context Ctx(C);
+ auto *F = Ctx.createFunction(LLVMF);
+ auto *BB = &*F->begin();
+
+ sandboxir::DependencyGraph DAG(getAA(*LLVMF));
+ DAG.extend({&*BB->begin(), BB->getTerminator()->getPrevNode()});
+
+ auto It = BB->begin();
+ auto *StackSaveN = DAG.getNode(&*It++);
+ auto *AllocaN = DAG.getNode(&*It++);
+ auto *StackRestoreN = DAG.getNode(&*It++);
+
+ EXPECT_FALSE(dependency(StackSaveN, AllocaN));
+ EXPECT_FALSE(dependency(AllocaN, StackRestoreN));
+}
----------------
vporpo wrote:
The dependency type is not visible externally, these are all private members. We don't really need to know the exact dependency ype for our use case.
https://github.com/llvm/llvm-project/pull/111094
More information about the llvm-commits
mailing list