[llvm] c427727 - [CodeMoverUtils] Enhance isSafeToMoveBefore() when control flow equivalence is satisfied
via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 27 15:38:47 PDT 2021
Author: Congzhe Cao
Date: 2021-09-27T18:37:36-04:00
New Revision: c42772752a51849d311d5a379a042528c75795a8
URL: https://github.com/llvm/llvm-project/commit/c42772752a51849d311d5a379a042528c75795a8
DIFF: https://github.com/llvm/llvm-project/commit/c42772752a51849d311d5a379a042528c75795a8.diff
LOG: [CodeMoverUtils] Enhance isSafeToMoveBefore() when control flow equivalence is satisfied
With improved analysis in determining CFG equivalence that does
not require strict dominance and post-dominance conditions, we
now relax isSafeToMoveBefore() such that an instruction I can
be moved before InsertPoint even if they do not strictly dominate
each other, as long as they follow the same control flow path.
For example, we can move Instruction 0 before Instruction 1,
and vice versa.
```
if (cond1)
// Instruction 0: %add = add i32 1, 2
if (cond1)
// Instruction 1: %add2 = add i32 2, 1
```
Reviewed By: Whitney
Differential Revision: https://reviews.llvm.org/D110456
Added:
Modified:
llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h
llvm/lib/Transforms/Utils/CodeMoverUtils.cpp
llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp
Removed:
################################################################################
diff --git a/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h b/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h
index c9fd651e00606..0f32a97f9fccf 100644
--- a/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h
+++ b/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h
@@ -63,6 +63,19 @@ void moveInstructionsToTheEnd(BasicBlock &FromBB, BasicBlock &ToBB,
DominatorTree &DT, const PostDominatorTree &PDT,
DependenceInfo &DI);
+/// In case that two BBs \p ThisBlock and \p OtherBlock are control flow
+/// equivalent but they do not strictly dominate and post-dominate each
+/// other, we determine if \p ThisBlock is reached after \p OtherBlock
+/// in the control flow.
+bool nonStrictlyPostDominate(const BasicBlock *ThisBlock,
+ const BasicBlock *OtherBlock,
+ const DominatorTree *DT,
+ const PostDominatorTree *PDT);
+
+// Check if I0 is reached before I1 in the control flow.
+bool isReachedBefore(const Instruction *I0, const Instruction *I1,
+ const DominatorTree *DT, const PostDominatorTree *PDT);
+
} // end namespace llvm
#endif // LLVM_TRANSFORMS_UTILS_CODEMOVERUTILS_H
diff --git a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp
index 8792ee2f5a224..ea29d4ec5beaf 100644
--- a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp
+++ b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp
@@ -332,12 +332,12 @@ bool llvm::isSafeToMoveBefore(Instruction &I, Instruction &InsertPoint,
if (!isControlFlowEquivalent(I, InsertPoint, DT, *PDT))
return reportInvalidCandidate(I, NotControlFlowEquivalent);
- if (!DT.dominates(&InsertPoint, &I))
+ if (isReachedBefore(&I, &InsertPoint, &DT, PDT))
for (const Use &U : I.uses())
if (auto *UserInst = dyn_cast<Instruction>(U.getUser()))
if (UserInst != &InsertPoint && !DT.dominates(&InsertPoint, U))
return false;
- if (!DT.dominates(&I, &InsertPoint))
+ if (isReachedBefore(&InsertPoint, &I, &DT, PDT))
for (const Value *Op : I.operands())
if (auto *OpInst = dyn_cast<Instruction>(Op)) {
if (&InsertPoint == OpInst)
@@ -432,3 +432,47 @@ void llvm::moveInstructionsToTheEnd(BasicBlock &FromBB, BasicBlock &ToBB,
I.moveBefore(MovePos);
}
}
+
+bool llvm::nonStrictlyPostDominate(const BasicBlock *ThisBlock,
+ const BasicBlock *OtherBlock,
+ const DominatorTree *DT,
+ const PostDominatorTree *PDT) {
+ assert(isControlFlowEquivalent(*ThisBlock, *OtherBlock, *DT, *PDT) &&
+ "ThisBlock and OtherBlock must be CFG equivalent!");
+ const BasicBlock *CommonDominator =
+ DT->findNearestCommonDominator(ThisBlock, OtherBlock);
+ if (CommonDominator == nullptr)
+ return false;
+
+ /// Recursively check the predecessors of \p ThisBlock up to
+ /// their common dominator, and see if any of them post-dominates
+ /// \p OtherBlock.
+ SmallVector<const BasicBlock *, 8> WorkList;
+ SmallPtrSet<const BasicBlock *, 8> Visited;
+ WorkList.push_back(ThisBlock);
+ while (!WorkList.empty()) {
+ const BasicBlock *CurBlock = WorkList.back();
+ WorkList.pop_back();
+ Visited.insert(CurBlock);
+ if (PDT->dominates(CurBlock, OtherBlock))
+ return true;
+
+ for (auto *Pred : predecessors(CurBlock)) {
+ if (Pred == CommonDominator || Visited.count(Pred))
+ continue;
+ WorkList.push_back(Pred);
+ }
+ }
+ return false;
+}
+
+bool llvm::isReachedBefore(const Instruction *I0, const Instruction *I1,
+ const DominatorTree *DT,
+ const PostDominatorTree *PDT) {
+ const BasicBlock *BB0 = I0->getParent();
+ const BasicBlock *BB1 = I1->getParent();
+ if (BB0 == BB1)
+ return DT->dominates(I0, I1);
+
+ return nonStrictlyPostDominate(BB1, BB0, DT, PDT);
+}
diff --git a/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp b/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp
index 134858c53d61e..8554d1a33cade 100644
--- a/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp
+++ b/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp
@@ -638,12 +638,14 @@ TEST(CodeMoverUtils, IsSafeToMoveTest4) {
if.then.first:
%add = add i32 %op0, %op1
%user = add i32 %add, 1
+ %add2 = add i32 %op0, 1
br label %if.end.first
if.end.first:
br i1 %cond, label %if.end.second, label %if.then.second
if.then.second:
%sub_op0 = add i32 %op0, 1
%sub = sub i32 %sub_op0, %op1
+ %sub2 = sub i32 %op0, 1
br label %if.end.second
if.end.second:
ret void
@@ -653,7 +655,9 @@ TEST(CodeMoverUtils, IsSafeToMoveTest4) {
[&](Function &F, DominatorTree &DT, PostDominatorTree &PDT,
DependenceInfo &DI) {
Instruction *AddInst = getInstructionByName(F, "add");
+ Instruction *AddInst2 = getInstructionByName(F, "add2");
Instruction *SubInst = getInstructionByName(F, "sub");
+ Instruction *SubInst2 = getInstructionByName(F, "sub2");
// Cannot move as %user uses %add and %sub doesn't dominates %user.
EXPECT_FALSE(isSafeToMoveBefore(*AddInst, *SubInst, DT, &PDT, &DI));
@@ -661,6 +665,14 @@ TEST(CodeMoverUtils, IsSafeToMoveTest4) {
// Cannot move as %sub_op0 is an operand of %sub and %add doesn't
// dominates %sub_op0.
EXPECT_FALSE(isSafeToMoveBefore(*SubInst, *AddInst, DT, &PDT, &DI));
+
+ // Can move as %add2 and %sub2 are control flow equivalent,
+ // although %add2 does not strictly dominate %sub2.
+ EXPECT_TRUE(isSafeToMoveBefore(*AddInst2, *SubInst2, DT, &PDT, &DI));
+
+ // Can move as %add2 and %sub2 are control flow equivalent,
+ // although %add2 does not strictly dominate %sub2.
+ EXPECT_TRUE(isSafeToMoveBefore(*SubInst2, *AddInst2, DT, &PDT, &DI));
});
}
More information about the llvm-commits
mailing list