[llvm] [InstCombine] Simplify multi use cast of Phi with constant inputs (PR #186621)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Sat Mar 14 13:27:38 PDT 2026


https://github.com/andjo403 created https://github.com/llvm/llvm-project/pull/186621

Regression noticed in https://github.com/llvm/llvm-project/pull/184182

for icmp there is a similar fold here https://github.com/andjo403/llvm-project/blob/393db14ac027412180d94ddcd35fb25b09a45913/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp#L1346-L1361

>From 579fe671a22c336663b26235f224ea28d1ee0f2b Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 14 Mar 2026 21:17:31 +0100
Subject: [PATCH 1/2] [InstCombine] Pre commit tests (NFC)

---
 llvm/test/Transforms/InstCombine/cast_phi.ll | 100 +++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/llvm/test/Transforms/InstCombine/cast_phi.ll b/llvm/test/Transforms/InstCombine/cast_phi.ll
index e8db72c8d849e..d82180a222ccc 100644
--- a/llvm/test/Transforms/InstCombine/cast_phi.ll
+++ b/llvm/test/Transforms/InstCombine/cast_phi.ll
@@ -378,3 +378,103 @@ exit:
   %ext = zext i8 %iv to i32
   ret i32 %ext
 }
+
+
+declare void @use8(i8)
+declare void @use32(i32)
+
+define i32 @zext_constants_multi_use(i8 %x) {
+; CHECK-LABEL: @zext_constants_multi_use(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 42
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       f:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[P:%.*]] = phi i8 [ 5, [[T]] ], [ -1, [[F]] ]
+; CHECK-NEXT:    call void @use8(i8 [[P]])
+; CHECK-NEXT:    [[R:%.*]] = zext i8 [[P]] to i32
+; CHECK-NEXT:    ret i32 [[R]]
+;
+entry:
+  %cmp = icmp eq i8 %x, 42
+  br i1 %cmp, label %t, label %f
+
+t:
+  br label %exit
+
+f:
+  br label %exit
+
+exit:
+  %p = phi i8 [ 5, %t ], [ -1, %f ]
+  call void @use8(i8 %p)
+  %r = zext i8 %p to i32
+  ret i32 %r
+}
+
+define i32 @sext_constants_multi_use(i8 %x) {
+; CHECK-LABEL: @sext_constants_multi_use(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 42
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       f:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[P:%.*]] = phi i8 [ 5, [[T]] ], [ -1, [[F]] ]
+; CHECK-NEXT:    call void @use8(i8 [[P]])
+; CHECK-NEXT:    [[R:%.*]] = sext i8 [[P]] to i32
+; CHECK-NEXT:    ret i32 [[R]]
+;
+entry:
+  %cmp = icmp eq i8 %x, 42
+  br i1 %cmp, label %t, label %f
+
+t:
+  br label %exit
+
+f:
+  br label %exit
+
+exit:
+  %p = phi i8 [ 5, %t ], [ -1, %f ]
+  call void @use8(i8 %p)
+  %r = sext i8 %p to i32
+  ret i32 %r
+}
+
+define i8 @trunc_constants_multi_use(i8 %x) {
+; CHECK-LABEL: @trunc_constants_multi_use(
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i8 [[X:%.*]], 42
+; CHECK-NEXT:    br i1 [[CMP]], label [[T:%.*]], label [[F:%.*]]
+; CHECK:       t:
+; CHECK-NEXT:    br label [[EXIT:%.*]]
+; CHECK:       f:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 5, [[T]] ], [ -1, [[F]] ]
+; CHECK-NEXT:    call void @use32(i32 [[P]])
+; CHECK-NEXT:    [[R:%.*]] = trunc nsw i32 [[P]] to i8
+; CHECK-NEXT:    ret i8 [[R]]
+;
+entry:
+  %cmp = icmp eq i8 %x, 42
+  br i1 %cmp, label %t, label %f
+
+t:
+  br label %exit
+
+f:
+  br label %exit
+
+exit:
+  %p = phi i32 [ 5, %t ], [ -1, %f ]
+  call void @use32(i32 %p)
+  %r = trunc i32 %p to i8
+  ret i8 %r
+}

>From 393db14ac027412180d94ddcd35fb25b09a45913 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 14 Mar 2026 21:22:15 +0100
Subject: [PATCH 2/2] [InstCombine] Simplify multi use cast of Phi with
 constant inputs

---
 llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp | 7 ++++++-
 llvm/test/Transforms/InstCombine/cast_phi.ll         | 6 +++---
 2 files changed, 9 insertions(+), 4 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
index f2a2e21f6fc95..fcd46b3ba4a17 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp
@@ -237,7 +237,12 @@ Instruction *InstCombinerImpl::commonCastTransforms(CastInst &CI) {
     // legal type.
     if (!Src->getType()->isIntegerTy() || !CI.getType()->isIntegerTy() ||
         shouldChangeType(CI.getSrcTy(), CI.getType()))
-      if (Instruction *NV = foldOpIntoPhi(CI, PN))
+      if (Instruction *NV =
+              foldOpIntoPhi(CI, PN,
+                            is_contained({Instruction::Trunc, Instruction::ZExt,
+                                          Instruction::SExt},
+                                         CI.getOpcode()) &&
+                                all_of(PN->operands(), IsaPred<ConstantInt>)))
         return NV;
   }
 
diff --git a/llvm/test/Transforms/InstCombine/cast_phi.ll b/llvm/test/Transforms/InstCombine/cast_phi.ll
index d82180a222ccc..59929ee420f49 100644
--- a/llvm/test/Transforms/InstCombine/cast_phi.ll
+++ b/llvm/test/Transforms/InstCombine/cast_phi.ll
@@ -393,9 +393,9 @@ define i32 @zext_constants_multi_use(i8 %x) {
 ; CHECK:       f:
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
+; CHECK-NEXT:    [[R:%.*]] = phi i32 [ 5, [[T]] ], [ 255, [[F]] ]
 ; CHECK-NEXT:    [[P:%.*]] = phi i8 [ 5, [[T]] ], [ -1, [[F]] ]
 ; CHECK-NEXT:    call void @use8(i8 [[P]])
-; CHECK-NEXT:    [[R:%.*]] = zext i8 [[P]] to i32
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
 entry:
@@ -425,9 +425,9 @@ define i32 @sext_constants_multi_use(i8 %x) {
 ; CHECK:       f:
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
+; CHECK-NEXT:    [[R:%.*]] = phi i32 [ 5, [[T]] ], [ -1, [[F]] ]
 ; CHECK-NEXT:    [[P:%.*]] = phi i8 [ 5, [[T]] ], [ -1, [[F]] ]
 ; CHECK-NEXT:    call void @use8(i8 [[P]])
-; CHECK-NEXT:    [[R:%.*]] = sext i8 [[P]] to i32
 ; CHECK-NEXT:    ret i32 [[R]]
 ;
 entry:
@@ -457,9 +457,9 @@ define i8 @trunc_constants_multi_use(i8 %x) {
 ; CHECK:       f:
 ; CHECK-NEXT:    br label [[EXIT]]
 ; CHECK:       exit:
+; CHECK-NEXT:    [[R:%.*]] = phi i8 [ 5, [[T]] ], [ -1, [[F]] ]
 ; CHECK-NEXT:    [[P:%.*]] = phi i32 [ 5, [[T]] ], [ -1, [[F]] ]
 ; CHECK-NEXT:    call void @use32(i32 [[P]])
-; CHECK-NEXT:    [[R:%.*]] = trunc nsw i32 [[P]] to i8
 ; CHECK-NEXT:    ret i8 [[R]]
 ;
 entry:



More information about the llvm-commits mailing list