[llvm] Fix O(n^2) complexity in SliceUpIllegalIntegerPHI (PR #175468)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Jan 11 15:00:21 PST 2026
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-llvm-transforms
Author: Kirill Pertsev (kika)
<details>
<summary>Changes</summary>
Fixes #<!-- -->175465
This is all based on my understanding of the LLVM codebase and reading comments in the code.
Take it with a grain of salt. But I does what it promises to do and do not fail any tests.
Test is not added, because there's no change in functionality and no new features, the only possible test is the repro case for the fixed issue.
### InstCombine pass
The catchswitch predecessor check added in LLVM 15 was placed inside the per-PHI processing loop, causing getFirstInsertionPt() to be called repeatedly for the same predecessor blocks across all PHIs in a network.
For code patterns with many PHIs sharing common predecessors (e.g., Rust drop flags for large structs), this resulted in O(PHIs × blocks) complexity.
Move the check outside the loop by collecting all unique predecessor blocks first and checking each only once, reducing complexity to O(unique blocks).
Should fix https://github.com/rust-lang/rust/issues/129713
---
Full diff: https://github.com/llvm/llvm-project/pull/175468.diff
1 Files Affected:
- (modified) llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp (+15-7)
``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index ba1865a2b5469..78d45b691c8fc 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -1129,13 +1129,6 @@ Instruction *InstCombinerImpl::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) {
return nullptr;
}
- // If the incoming value is a PHI node before a catchswitch, we cannot
- // extract the value within that BB because we cannot insert any non-PHI
- // instructions in the BB.
- for (auto *Pred : PN->blocks())
- if (Pred->getFirstInsertionPt() == Pred->end())
- return nullptr;
-
for (User *U : PN->users()) {
Instruction *UserI = cast<Instruction>(U);
@@ -1172,6 +1165,21 @@ Instruction *InstCombinerImpl::SliceUpIllegalIntegerPHI(PHINode &FirstPhi) {
if (PHIUsers.empty())
return replaceInstUsesWith(FirstPhi, PoisonValue::get(FirstPhi.getType()));
+ // If the incoming value is a PHI node before a catchswitch, we cannot
+ // extract the value within that BB because we cannot insert any non-PHI
+ // instructions in the BB. Check all unique predecessor blocks once.
+ {
+ SmallPtrSet<BasicBlock *, 16> CheckedBlocks;
+ for (PHINode *PN : PHIsToSlice) {
+ for (BasicBlock *Pred : PN->blocks()) {
+ if (CheckedBlocks.insert(Pred).second) {
+ if (Pred->getFirstInsertionPt() == Pred->end())
+ return nullptr;
+ }
+ }
+ }
+ }
+
// If this phi node is transformable, create new PHIs for all the pieces
// extracted out of it. First, sort the users by their offset and size.
array_pod_sort(PHIUsers.begin(), PHIUsers.end());
``````````
</details>
https://github.com/llvm/llvm-project/pull/175468
More information about the llvm-commits
mailing list