[llvm] [TypePromotion] Support trunc-to-i1 conditions (PR #216311)
Vito Kortbeek via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 14 05:38:19 PDT 2026
https://github.com/vkortbeek-gf updated https://github.com/llvm/llvm-project/pull/216311
>From 664db42366f4ef438e0c64aedff9d71e27b8833f Mon Sep 17 00:00:00 2001
From: Vito Kortbeek <vito.kortbeek at globalfoundries.com>
Date: Fri, 14 Aug 2026 13:42:40 +0200
Subject: [PATCH] [TypePromotion] Support trunc-to-i1 conditions
InstCombine may rewrite `icmp ne (X & 1), 0` to `trunc X to i1` (#178977).
Start TypePromotion searches from operands of scalar trunc-to-i1 instructions,
treating the trunc as a boolean boundary without promoting its result or
traversing its users.
Assisted-by: AI
---
llvm/lib/CodeGen/TypePromotion.cpp | 40 ++++++++++++++-----
.../Transforms/TypePromotion/ARM/casts.ll | 27 +++++++++++++
2 files changed, 58 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/CodeGen/TypePromotion.cpp b/llvm/lib/CodeGen/TypePromotion.cpp
index e9f54fd556bbd..59ea4281f6ee4 100644
--- a/llvm/lib/CodeGen/TypePromotion.cpp
+++ b/llvm/lib/CodeGen/TypePromotion.cpp
@@ -9,9 +9,9 @@
/// \file
/// This is an opcode based type promotion pass for small types that would
/// otherwise be promoted during legalisation. This works around the limitations
-/// of selection dag for cyclic regions. The search begins from icmp
-/// instructions operands where a tree, consisting of non-wrapping or safe
-/// wrapping instructions, is built, checked and promoted if possible.
+/// of selection dag for cyclic regions. The search begins from operands of icmp
+/// and scalar trunc-to-i1 instructions. A tree consisting of non-wrapping or
+/// safe wrapping instructions is then built, checked and promoted if possible.
///
//===----------------------------------------------------------------------===//
@@ -156,6 +156,8 @@ class TypePromotionImpl {
bool isSource(Value *V);
// Should V be a root in the promotion tree?
bool isSink(Value *V);
+ // Is V a supported truncation to i1?
+ bool isSupportedTruncToI1(Value *V);
// Should we change the result type of V? It will result in the users of V
// being visited.
bool shouldPromote(Value *V);
@@ -203,6 +205,11 @@ static bool GenerateSignBits(Instruction *I) {
Opc == Instruction::SRem || Opc == Instruction::SExt;
}
+static bool isTruncToI1(Value *V) {
+ auto *Trunc = dyn_cast<TruncInst>(V);
+ return Trunc && Trunc->getType()->isIntegerTy(1);
+}
+
bool TypePromotionImpl::EqualTypeSize(Value *V) {
return V->getType()->getScalarSizeInBits() == TypeSize;
}
@@ -270,6 +277,10 @@ bool TypePromotionImpl::isSink(Value *V) {
return isa<CallInst>(V);
}
+bool TypePromotionImpl::isSupportedTruncToI1(Value *V) {
+ return isTruncToI1(V) && EqualTypeSize(cast<TruncInst>(V)->getOperand(0));
+}
+
/// Return whether this instruction can safely wrap.
bool TypePromotionImpl::isSafeWrap(Instruction *I) {
// We can support a potentially wrapping Add/Sub instruction (I) if:
@@ -389,7 +400,7 @@ bool TypePromotionImpl::shouldPromote(Value *V) {
if (!I)
return false;
- if (isa<ICmpInst>(I))
+ if (isa<ICmpInst>(I) || isSupportedTruncToI1(I))
return false;
return true;
@@ -523,8 +534,8 @@ void IRPromoter::PromoteTree() {
}
}
- // Mutate the result type, unless this is an icmp or switch.
- if (!isa<ICmpInst>(I) && !isa<SwitchInst>(I)) {
+ // Mutate the result type, unless this is an icmp, switch, or trunc to i1.
+ if (!isa<ICmpInst>(I) && !isa<SwitchInst>(I) && !isTruncToI1(I)) {
I->mutateType(ExtTy);
Promoted.insert(I);
}
@@ -642,7 +653,7 @@ void IRPromoter::ConvertTruncs() {
IRBuilder<> Builder{Ctx};
for (auto *V : Visited) {
- if (!isa<TruncInst>(V) || Sources.count(V))
+ if (!isa<TruncInst>(V) || isTruncToI1(V) || Sources.count(V))
continue;
auto *Trunc = cast<TruncInst>(V);
@@ -681,7 +692,7 @@ void IRPromoter::Mutate() {
}
}
for (auto *V : Visited) {
- if (!isa<TruncInst>(V) || Sources.count(V))
+ if (!isa<TruncInst>(V) || isTruncToI1(V) || Sources.count(V))
continue;
auto *Trunc = cast<TruncInst>(V);
TruncTysMap[Trunc].push_back(Trunc->getDestTy());
@@ -742,8 +753,9 @@ bool TypePromotionImpl::isSupportedValue(Value *V) {
case Instruction::Select:
case Instruction::Ret:
case Instruction::Load:
- case Instruction::Trunc:
return isSupportedType(I);
+ case Instruction::Trunc:
+ return isSupportedTruncToI1(I) || isSupportedType(I);
case Instruction::BitCast:
return I->getOperand(0)->getType() == I->getType();
case Instruction::ZExt:
@@ -1011,6 +1023,16 @@ bool TypePromotionImpl::run(Function &F, const TargetMachine *TM,
}
}
}
+ } else if (isTruncToI1(&I)) {
+ // Like an unsigned icmp, a scalar trunc to i1 is a boolean boundary.
+ auto *Trunc = cast<TruncInst>(&I);
+ LLVM_DEBUG(dbgs() << "IR Promotion: Searching from: " << *Trunc
+ << "\n");
+
+ if (auto *OpI = dyn_cast<Instruction>(Trunc->getOperand(0))) {
+ if (auto PromotedWidth = GetPromoteWidth(OpI))
+ MadeChange |= TryToPromote(OpI, PromotedWidth, LI);
+ }
}
}
if (!InstsToRemove.empty()) {
diff --git a/llvm/test/Transforms/TypePromotion/ARM/casts.ll b/llvm/test/Transforms/TypePromotion/ARM/casts.ll
index 7c3a87db41aa1..eee8b4e3ccbe8 100644
--- a/llvm/test/Transforms/TypePromotion/ARM/casts.ll
+++ b/llvm/test/Transforms/TypePromotion/ARM/casts.ll
@@ -795,6 +795,33 @@ exit:
ret i32 %retval
}
+define i8 @loop_trunc_i1(i8 zeroext %x) {
+; CHECK-LABEL: @loop_trunc_i1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[TMP0:%.*]] = zext i8 [[X:%.*]] to i32
+; CHECK-NEXT: br label [[LOOP:%.*]]
+; CHECK: loop:
+; CHECK-NEXT: [[VALUE:%.*]] = phi i32 [ [[TMP0]], [[ENTRY:%.*]] ], [ [[NEXT:%.*]], [[LOOP]] ]
+; CHECK-NEXT: [[NEXT]] = lshr i32 [[VALUE]], 1
+; CHECK-NEXT: [[COND:%.*]] = trunc i32 [[VALUE]] to i1
+; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]]
+; CHECK: exit:
+; CHECK-NEXT: [[TMP1:%.*]] = trunc i32 [[NEXT]] to i8
+; CHECK-NEXT: ret i8 [[TMP1]]
+;
+entry:
+ br label %loop
+
+loop:
+ %value = phi i8 [ %x, %entry ], [ %next, %loop ]
+ %next = lshr i8 %value, 1
+ %cond = trunc i8 %value to i1
+ br i1 %cond, label %loop, label %exit
+
+exit:
+ ret i8 %next
+}
+
define void @search_back_through_trunc(ptr %a, ptr %b, ptr %c, ptr %d, ptr %e) {
; CHECK-LABEL: @search_back_through_trunc(
; CHECK-NEXT: entry:
More information about the llvm-commits
mailing list