Skip to content

Commit 426148b

Browse files
authored
[SandboxVec][DAG] Implement DAG maintainance on Instruction removal (#127361)
This patch implements dependency maintenance upon receiveing the notification that an instruction gets deleted.
1 parent 8e16e5c commit 426148b

File tree

2 files changed

+71
-10
lines changed

2 files changed

+71
-10
lines changed

llvm/lib/Transforms/Vectorize/SandboxVectorizer/DependencyGraph.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -483,19 +483,37 @@ void DependencyGraph::notifyEraseInstr(Instruction *I) {
483483
if (Ctx->getTracker().getState() == Tracker::TrackerState::Reverting)
484484
// We don't maintain the DAG while reverting.
485485
return;
486-
// Update the MemDGNode chain if this is a memory node.
487-
if (auto *MemN = dyn_cast_or_null<MemDGNode>(getNodeOrNull(I))) {
486+
auto *N = getNode(I);
487+
if (N == nullptr)
488+
// Early return if there is no DAG node for `I`.
489+
return;
490+
if (auto *MemN = dyn_cast<MemDGNode>(getNode(I))) {
491+
// Update the MemDGNode chain if this is a memory node.
488492
auto *PrevMemN = getMemDGNodeBefore(MemN, /*IncludingN=*/false);
489493
auto *NextMemN = getMemDGNodeAfter(MemN, /*IncludingN=*/false);
490494
if (PrevMemN != nullptr)
491495
PrevMemN->NextMemN = NextMemN;
492496
if (NextMemN != nullptr)
493497
NextMemN->PrevMemN = PrevMemN;
494-
}
495498

499+
// Drop the memory dependencies from both predecessors and successors.
500+
while (!MemN->memPreds().empty()) {
501+
auto *PredN = *MemN->memPreds().begin();
502+
MemN->removeMemPred(PredN);
503+
}
504+
while (!MemN->memSuccs().empty()) {
505+
auto *SuccN = *MemN->memSuccs().begin();
506+
SuccN->removeMemPred(MemN);
507+
}
508+
// NOTE: The unscheduled succs for MemNodes get updated be setMemPred().
509+
} else {
510+
// If this is a non-mem node we only need to update UnscheduledSuccs.
511+
if (!N->scheduled())
512+
for (auto *PredN : N->preds(*this))
513+
PredN->decrUnscheduledSuccs();
514+
}
515+
// Finally erase the Node.
496516
InstrToNodeMap.erase(I);
497-
498-
// TODO: Update the dependencies.
499517
}
500518

501519
void DependencyGraph::notifySetUse(const Use &U, Value *NewSrc) {

llvm/unittests/Transforms/Vectorize/SandboxVectorizer/DependencyGraphTest.cpp

Lines changed: 48 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -940,10 +940,11 @@ define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %new1, i8 %new2) {
940940

941941
TEST_F(DependencyGraphTest, EraseInstrCallback) {
942942
parseIR(C, R"IR(
943-
define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %arg) {
943+
define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %arg) {
944944
store i8 %v1, ptr %ptr
945945
store i8 %v2, ptr %ptr
946946
store i8 %v3, ptr %ptr
947+
store i8 %v4, ptr %ptr
947948
ret void
948949
}
949950
)IR");
@@ -955,25 +956,67 @@ define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %arg) {
955956
auto *S1 = cast<sandboxir::StoreInst>(&*It++);
956957
auto *S2 = cast<sandboxir::StoreInst>(&*It++);
957958
auto *S3 = cast<sandboxir::StoreInst>(&*It++);
959+
auto *S4NotInDAG = cast<sandboxir::StoreInst>(&*It++);
958960

959961
// Check erase instruction callback.
960962
sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx);
961963
DAG.extend({S1, S3});
964+
auto *S1MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S1));
965+
auto *S2MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S2));
966+
auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3));
967+
EXPECT_EQ(S1MemN->getNumUnscheduledSuccs(), 2u);
968+
EXPECT_EQ(S2MemN->getNumUnscheduledSuccs(), 1u);
969+
EXPECT_EQ(S3MemN->getNumUnscheduledSuccs(), 0u);
962970
S2->eraseFromParent();
963-
auto *DeletedN = DAG.getNodeOrNull(S2);
971+
// Check that the DAG Node for S2 no longer exists.
972+
auto *DeletedN = DAG.getNode(S2);
964973
EXPECT_TRUE(DeletedN == nullptr);
974+
// Check that dependencies are maintained.
975+
EXPECT_THAT(S3MemN->preds(DAG), testing::UnorderedElementsAre(S1MemN));
976+
// Also check that UnscheduledSuccs was updated for S1.
977+
EXPECT_EQ(S1MemN->getNumUnscheduledSuccs(), 1u);
965978

966979
// Check the MemDGNode chain.
967-
auto *S1MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S1));
968-
auto *S3MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S3));
969980
EXPECT_EQ(S1MemN->getNextNode(), S3MemN);
970981
EXPECT_EQ(S3MemN->getPrevNode(), S1MemN);
971982

972983
// Check the chain when we erase the top node.
973984
S1->eraseFromParent();
974985
EXPECT_EQ(S3MemN->getPrevNode(), nullptr);
975986

976-
// TODO: Check the dependencies to/from NewSN after they land.
987+
// Check that we don't crash if we erase a node not in the DAG.
988+
S4NotInDAG->eraseFromParent();
989+
}
990+
991+
// Same but check that we don't update UnscheduledSuccs when Node is scheduled.
992+
TEST_F(DependencyGraphTest, EraseInstrCallbackScheduled) {
993+
parseIR(C, R"IR(
994+
define void @foo(ptr %ptr, i8 %v1, i8 %v2, i8 %v3, i8 %v4, i8 %arg) {
995+
store i8 %v1, ptr %ptr
996+
store i8 %v2, ptr %ptr
997+
ret void
998+
}
999+
)IR");
1000+
llvm::Function *LLVMF = &*M->getFunction("foo");
1001+
sandboxir::Context Ctx(C);
1002+
auto *F = Ctx.createFunction(LLVMF);
1003+
auto *BB = &*F->begin();
1004+
auto It = BB->begin();
1005+
auto *S1 = cast<sandboxir::StoreInst>(&*It++);
1006+
auto *S2 = cast<sandboxir::StoreInst>(&*It++);
1007+
1008+
sandboxir::DependencyGraph DAG(getAA(*LLVMF), Ctx);
1009+
DAG.extend({S1, S2});
1010+
auto *S1MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S1));
1011+
auto *S2MemN = cast<sandboxir::MemDGNode>(DAG.getNode(S2));
1012+
EXPECT_EQ(S1MemN->getNumUnscheduledSuccs(), 1u);
1013+
EXPECT_EQ(S2MemN->getNumUnscheduledSuccs(), 0u);
1014+
// Mark S2 as scheduled and erase it.
1015+
S2MemN->setScheduled(true);
1016+
S2->eraseFromParent();
1017+
EXPECT_EQ(DAG.getNode(S2), nullptr);
1018+
// Check that we did not update S1's UnscheduledSuccs
1019+
EXPECT_EQ(S1MemN->getNumUnscheduledSuccs(), 1u);
9771020
}
9781021

9791022
TEST_F(DependencyGraphTest, MoveInstrCallback) {

0 commit comments

Comments
 (0)