[llvm] [InstCombine] Add cast support in simplifyUsingControlFlow (PR #142263)

Andreas Jonson via llvm-commits llvm-commits at lists.llvm.org
Sat May 31 01:46:03 PDT 2025


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

Common patterns where phi node can be replaced by trunc, zext or sext.

proof: https://alive2.llvm.org/ce/z/Rppn3Y

closes https://github.com/llvm/llvm-project/issues/54561 https://github.com/llvm/llvm-project/issues/67842 https://github.com/llvm/llvm-project/issues/67843

>From 5a78d3197fa8ea8332eb574bba7a8ba562e2c2ef Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 31 May 2025 10:42:44 +0200
Subject: [PATCH 1/2] [InstCombine] Change value to avoid change of purpose of
 test with new fold (NFC)

---
 llvm/test/DebugInfo/X86/instcombine-fold-cast-into-phi.ll | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/llvm/test/DebugInfo/X86/instcombine-fold-cast-into-phi.ll b/llvm/test/DebugInfo/X86/instcombine-fold-cast-into-phi.ll
index a91a983be49bc..3ec226fc58d6b 100644
--- a/llvm/test/DebugInfo/X86/instcombine-fold-cast-into-phi.ll
+++ b/llvm/test/DebugInfo/X86/instcombine-fold-cast-into-phi.ll
@@ -4,7 +4,7 @@
 ;; user (otherwise the dbg use becomes poison after the original phi is
 ;; deleted). Check the new phi inherits the DebugLoc.
 
-; CHECK: %[[phi:.*]] = phi i8 [ 1, %{{.*}} ], [ 0, %{{.*}} ], !dbg ![[dbg:[0-9]+]]
+; CHECK: %[[phi:.*]] = phi i8 [ 2, %{{.*}} ], [ 0, %{{.*}} ], !dbg ![[dbg:[0-9]+]]
 ; CHECK: #dbg_value(i8 %[[phi]], ![[#]], !DIExpression(DW_OP_LLVM_convert, 8, DW_ATE_signed, DW_OP_LLVM_convert, 32, DW_ATE_signed, DW_OP_stack_value)
 ; CHECK: ![[dbg]] = !DILocation(line: 123,
 
@@ -19,7 +19,7 @@ if.then:                                          ; preds = entry
   br label %if.end
 
 if.end:                                           ; preds = %if.then, %entry
-  %p.0 = phi i32 [ 1, %if.then ], [ 0, %entry ], !dbg !13
+  %p.0 = phi i32 [ 2, %if.then ], [ 0, %entry ], !dbg !13
   call void @llvm.dbg.value(metadata i32 %p.0, metadata !4, metadata !DIExpression()), !dbg !13
   %x = trunc i32 %p.0 to i8
   %callff = call float @ff(i8  %x)

>From c82012005a95fba319961d62c19e5148b6f20571 Mon Sep 17 00:00:00 2001
From: Andreas Jonson <andjo403 at hotmail.com>
Date: Sat, 31 May 2025 10:43:42 +0200
Subject: [PATCH 2/2] [InstCombine] Add cast support in
 simplifyUsingControlFlow

---
 .../Transforms/InstCombine/InstCombinePHI.cpp | 46 +++++++++++++++----
 .../Transforms/InstCombine/phi-int-users.ll   |  2 +-
 .../InstCombine/simple_phi_condition.ll       | 12 +++--
 3 files changed, 44 insertions(+), 16 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
index a842a5edcb8a3..a79d34d2a1898 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombinePHI.cpp
@@ -1325,8 +1325,12 @@ static Value *simplifyUsingControlFlow(InstCombiner &Self, PHINode &PN,
     return nullptr;
   }
 
-  if (Cond->getType() != PN.getType())
-    return nullptr;
+  unsigned CondBitWidth = Cond->getType()->getScalarSizeInBits();
+  unsigned PNBitWidth = PN.getType()->getScalarSizeInBits();
+  Instruction::CastOps CastType =
+      CondBitWidth == PNBitWidth  ? Instruction::BitCast
+      : CondBitWidth < PNBitWidth ? Instruction::ZExt
+                                  : Instruction::Trunc;
 
   // Check that edges outgoing from the idom's terminators dominate respective
   // inputs of the Phi.
@@ -1335,6 +1339,20 @@ static Value *simplifyUsingControlFlow(InstCombiner &Self, PHINode &PN,
     auto *Input = cast<ConstantInt>(std::get<0>(Pair));
     BasicBlock *Pred = std::get<1>(Pair);
     auto IsCorrectInput = [&](ConstantInt *Input) {
+      if (CastType != Instruction::BitCast) {
+        APInt InputValue = Input->getValue();
+        if (CastType == Instruction::Trunc)
+          InputValue = InputValue.zext(CondBitWidth);
+        else if (CastType == Instruction::ZExt &&
+                 InputValue.isIntN(CondBitWidth))
+          InputValue = InputValue.trunc(CondBitWidth);
+        else if (InputValue.isSignedIntN(CondBitWidth)) {
+          CastType = Instruction::SExt;
+          InputValue = InputValue.trunc(CondBitWidth);
+        } else
+          return false;
+        Input = ConstantInt::get(Context, InputValue);
+      }
       // The input needs to be dominated by the corresponding edge of the idom.
       // This edge cannot be a multi-edge, as that would imply that multiple
       // different condition values follow the same edge.
@@ -1360,19 +1378,27 @@ static Value *simplifyUsingControlFlow(InstCombiner &Self, PHINode &PN,
     Invert = NeedsInvert;
   }
 
-  if (!*Invert)
+  if (!*Invert && CastType == Instruction::BitCast)
     return Cond;
 
-  // This Phi is actually opposite to branching condition of IDom. We invert
-  // the condition that will potentially open up some opportunities for
-  // sinking.
   auto InsertPt = BB->getFirstInsertionPt();
-  if (InsertPt != BB->end()) {
-    Self.Builder.SetInsertPoint(&*BB, InsertPt);
-    return Self.Builder.CreateNot(Cond);
+  if (InsertPt == BB->end())
+    return nullptr;
+
+  Self.Builder.SetInsertPoint(&*BB, InsertPt);
+
+  if (CastType != Instruction::BitCast) {
+    Cond = Self.Builder.CreateCast(CastType, Cond, PN.getType());
+    if (auto *Trunc = dyn_cast<TruncInst>(Cond))
+      Trunc->setHasNoUnsignedWrap(true);
+    if (!*Invert)
+      return Cond;
   }
 
-  return nullptr;
+  // This Phi is actually opposite to branching condition of IDom. We invert
+  // the condition that will potentially open up some opportunities for
+  // sinking.
+  return Self.Builder.CreateNot(Cond);
 }
 
 // Fold  iv = phi(start, iv.next = iv2.next op start)
diff --git a/llvm/test/Transforms/InstCombine/phi-int-users.ll b/llvm/test/Transforms/InstCombine/phi-int-users.ll
index 6c98cc8a1c900..cc70feb160a08 100644
--- a/llvm/test/Transforms/InstCombine/phi-int-users.ll
+++ b/llvm/test/Transforms/InstCombine/phi-int-users.ll
@@ -13,7 +13,7 @@ define void @f1(i1 %a) {
 ; CHECK:       [[BB2]]:
 ; CHECK-NEXT:    br label %[[BB3]]
 ; CHECK:       [[BB3]]:
-; CHECK-NEXT:    [[PHI:%.*]] = phi i64 [ 0, %[[BB2]] ], [ 1, %[[BB1]] ]
+; CHECK-NEXT:    [[PHI:%.*]] = zext i1 [[A]] to i64
 ; CHECK-NEXT:    [[INTTOPTR:%.*]] = inttoptr i64 [[PHI]] to ptr
 ; CHECK-NEXT:    store i32 0, ptr [[INTTOPTR]], align 4
 ; CHECK-NEXT:    br label %[[BB1]]
diff --git a/llvm/test/Transforms/InstCombine/simple_phi_condition.ll b/llvm/test/Transforms/InstCombine/simple_phi_condition.ll
index 544ebaecaa752..5e299e945c51d 100644
--- a/llvm/test/Transforms/InstCombine/simple_phi_condition.ll
+++ b/llvm/test/Transforms/InstCombine/simple_phi_condition.ll
@@ -669,7 +669,7 @@ define i32 @test_phi_to_zext(i8 noundef %0) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    br label [[BB5]]
 ; CHECK:       bb5:
-; CHECK-NEXT:    [[DOT0:%.*]] = phi i32 [ 1, [[BB1]] ], [ 0, [[BB4]] ], [ 255, [[BB3]] ]
+; CHECK-NEXT:    [[DOT0:%.*]] = zext i8 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[DOT0]]
 ;
 start:
@@ -713,7 +713,7 @@ define i32 @test_phi_to_sext(i8 noundef %0) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    br label [[BB5]]
 ; CHECK:       bb5:
-; CHECK-NEXT:    [[DOT0:%.*]] = phi i32 [ 1, [[BB1]] ], [ 0, [[BB4]] ], [ -1, [[BB3]] ]
+; CHECK-NEXT:    [[DOT0:%.*]] = sext i8 [[TMP0]] to i32
 ; CHECK-NEXT:    ret i32 [[DOT0]]
 ;
 start:
@@ -757,7 +757,8 @@ define i32 @test_phi_to_sext_inverted(i8 noundef %0) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    br label [[BB5]]
 ; CHECK:       bb5:
-; CHECK-NEXT:    [[DOT0:%.*]] = phi i32 [ -2, [[BB1]] ], [ -1, [[BB4]] ], [ 0, [[BB3]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = xor i8 [[TMP0]], -1
+; CHECK-NEXT:    [[DOT0:%.*]] = sext i8 [[TMP1]] to i32
 ; CHECK-NEXT:    ret i32 [[DOT0]]
 ;
 start:
@@ -843,7 +844,7 @@ define i8 @test_phi_to_trunc(i32 %0) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    br label [[BB5]]
 ; CHECK:       bb5:
-; CHECK-NEXT:    [[DOT0:%.*]] = phi i8 [ -1, [[BB1]] ], [ 1, [[BB4]] ], [ 0, [[START:%.*]] ]
+; CHECK-NEXT:    [[DOT0:%.*]] = trunc nuw i32 [[TMP0]] to i8
 ; CHECK-NEXT:    ret i8 [[DOT0]]
 ;
 start:
@@ -882,7 +883,8 @@ define i8 @test_phi_to_trunc_inverted(i32 %0) {
 ; CHECK:       bb1:
 ; CHECK-NEXT:    br label [[BB5]]
 ; CHECK:       bb5:
-; CHECK-NEXT:    [[DOT0:%.*]] = phi i8 [ 0, [[BB1]] ], [ -2, [[BB4]] ], [ -1, [[START:%.*]] ]
+; CHECK-NEXT:    [[TMP1:%.*]] = trunc nuw i32 [[TMP0]] to i8
+; CHECK-NEXT:    [[DOT0:%.*]] = xor i8 [[TMP1]], -1
 ; CHECK-NEXT:    ret i8 [[DOT0]]
 ;
 start:



More information about the llvm-commits mailing list