diff --git a/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h b/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h --- a/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h +++ b/llvm/include/llvm/Transforms/Utils/CodeMoverUtils.h @@ -63,6 +63,19 @@ 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 --- a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp +++ b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp @@ -332,12 +332,12 @@ 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(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(Op)) { if (&InsertPoint == OpInst) @@ -432,3 +432,47 @@ 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 WorkList; + SmallPtrSet 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 --- a/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp +++ b/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp @@ -638,12 +638,14 @@ 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 @@ [&](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 @@ // 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)); }); }