-
Notifications
You must be signed in to change notification settings - Fork 13.7k
[JumpThreading] Remove deleted BB from Unreachable #126984
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Although an unreachable BB is skipped by processBlock, its successor can still be handled by processBlock, and maybeMergeBasicBlockIntoOnlyPred may merge the two BBs and delete the unreachable BB. Then the garbage pointer is left in Unreachable set. This patch removes the invalid BB pointer from the Unreachable set.
@llvm/pr-subscribers-llvm-transforms Author: None (weiguozhi) ChangesAlthough an unreachable BB is skipped by processBlock, its successor can still be handled by processBlock, and maybeMergeBasicBlockIntoOnlyPred may merge the two BBs and delete the unreachable BB. Then the garbage pointer is left in Unreachable set. This patch removes the invalid BB pointer from the Unreachable set. Full diff: https://github.com/llvm/llvm-project/pull/126984.diff 2 Files Affected:
diff --git a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
index 7d11fc0ad6938..84292c716a0a9 100644
--- a/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
+++ b/llvm/include/llvm/Transforms/Scalar/JumpThreading.h
@@ -94,6 +94,10 @@ class JumpThreadingPass : public PassInfoMixin<JumpThreadingPass> {
SmallPtrSet<const BasicBlock *, 16> LoopHeaders;
#endif
+ // JumpThreading must not processes blocks unreachable from entry. It's a
+ // waste of compute time and can potentially lead to hangs.
+ SmallPtrSet<BasicBlock *, 16> Unreachable;
+
unsigned BBDupThreshold;
unsigned DefaultBBDupThreshold;
diff --git a/llvm/lib/Transforms/Scalar/JumpThreading.cpp b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
index 7b221a814aabd..dfa49ba183779 100644
--- a/llvm/lib/Transforms/Scalar/JumpThreading.cpp
+++ b/llvm/lib/Transforms/Scalar/JumpThreading.cpp
@@ -307,12 +307,11 @@ bool JumpThreadingPass::runImpl(Function &F_, FunctionAnalysisManager *FAM_,
else
BBDupThreshold = DefaultBBDupThreshold;
- // JumpThreading must not processes blocks unreachable from entry. It's a
- // waste of compute time and can potentially lead to hangs.
- SmallPtrSet<BasicBlock *, 16> Unreachable;
assert(DTU && "DTU isn't passed into JumpThreading before using it.");
assert(DTU->hasDomTree() && "JumpThreading relies on DomTree to proceed.");
DominatorTree &DT = DTU->getDomTree();
+
+ Unreachable.clear();
for (auto &BB : *F)
if (!DT.isReachableFromEntry(&BB))
Unreachable.insert(&BB);
@@ -1902,6 +1901,9 @@ bool JumpThreadingPass::maybeMergeBasicBlockIntoOnlyPred(BasicBlock *BB) {
LVI->eraseBlock(SinglePred);
MergeBasicBlockIntoOnlyPred(BB, DTU.get());
+ if (Unreachable.count(SinglePred) && DTU->isBBPendingDeletion(SinglePred))
+ Unreachable.erase(SinglePred);
+
// Now that BB is merged into SinglePred (i.e. SinglePred code followed by
// BB code within one basic block `BB`), we need to invalidate the LVI
// information associated with BB, because the LVI information need not be
|
Ugh. I've encountered essentially the same problem elsewhere in LLVM (although I don't remember where). Meanwhile, in the inliner, when all call sites of a given
I have a few questions about this:
Thanks! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we bail out of maybeMergeBasicBlockIntoOnlyPred on unreachable pred instead?
A live basic block in Unreachable is not a problem. A deleted basic block in Unreachable is a problem. Here the SinglePred has not been deleted, but it is marked so in DTU. It will be actually deleted when we call DTU->flush() later.
Maybe @nikic's suggestion can accomplish this. I will try it. |
…ed is in Unreachable. Merge SinglePred and its successor may delete SinglePred, and causes garbage pointer in Unreachable. Bail out maybeMergeBasicBlockIntoOnlyPred if we found this case.
Done. But it causes regression in pr62908.ll. |
ping |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this again, I'm not sure I fully understand what problem you're trying to solve here.
This code uses DTU so block deletion is deferred, so there are no problems with address reuse. Why is it problematic to merge into an unreachable block?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you please regenerate the test so the whole IR is visible?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
As you have noticed MergeBasicBlockIntoOnlyPred can mark an unreachable block for deletion. The deletion is deferred until In later optimizations new basic blocks can be generated, if we are unlucky a new BB may be created at the deleted BB address, then the new BB pointer is automatically contained in Unreachable unexpectedly. And the new BB will be skipped by the following optimization. This part is a random behavior, so we got indeterministic result on our real code. |
I think the last bit I'm still missing is when JumpThreading calls DTU->flush() during the transform. I thought JT only flushes DT updates after everything is done, at which point the Unreachable set is not relevant anymore. |
DTU->flush() is called in the chain:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, thanks for the explanation. I think what JumpThreading does with BPI/BFI is unnecessarily complicated (why do we ever compute a fresh BPI/BFI if we're only doing updates?) and could maybe be cleaned up to avoid this flush, but let's land this fix for now.
Although an unreachable BB is skipped by processBlock, its successor can still be handled by processBlock, and maybeMergeBasicBlockIntoOnlyPred may merge the two BBs and delete the unreachable BB. Then the garbage pointer is left in Unreachable set. This patch avoids merging a BB into unreachable predecessor.
Although an unreachable BB is skipped by processBlock, its successor can still be handled by processBlock, and maybeMergeBasicBlockIntoOnlyPred may merge the two BBs and delete the unreachable BB. Then the garbage pointer is left in Unreachable set. This patch removes the invalid BB pointer from the Unreachable set.