[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