[llvm] Fix O(n^2) complexity in SliceUpIllegalIntegerPHI (PR #175468)

Kirill Pertsev via llvm-commits llvm-commits at lists.llvm.org
Sun Jan 11 14:59:36 PST 2026


https://github.com/kika created https://github.com/llvm/llvm-project/pull/175468

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

>From c0388e49fd9faacf1df946d3aa575c61573e7616 Mon Sep 17 00:00:00 2001
From: Kirill Pertsev <kika at kikap.com>
Date: Sun, 11 Jan 2026 18:53:04 -0400
Subject: [PATCH] Fix O(n^2) complexity in SliceUpIllegalIntegerPHI

---
 .../Transforms/InstCombine/InstCombinePHI.cpp | 22 +++++++++++++------
 1 file changed, 15 insertions(+), 7 deletions(-)

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());



More information about the llvm-commits mailing list