[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