[llvm] [InstCombine] Fold (bw-1) - ctlz(x&-x) to cttz (PR #205383)
via llvm-commits
llvm-commits at lists.llvm.org
Tue Jun 23 09:58:46 PDT 2026
https://github.com/AZero13 created https://github.com/llvm/llvm-project/pull/205383
Works for non-powers of 2.
Alive2: https://alive2.llvm.org/ce/z/-cbxFz
>From 18312768edfce5ad4018e92daddb322eaaf5eef0 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Tue, 23 Jun 2026 12:07:43 -0400
Subject: [PATCH 1/2] Pre-commit test (NFC)
---
.../InstCombine/select-ctlz-to-cttz.ll | 38 +++++++++++++++++++
1 file changed, 38 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll b/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
index d1f25b19d35a0..63e3d4adf2758 100644
--- a/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
+++ b/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
@@ -340,3 +340,41 @@ define i4 @PR45762_logical(i3 %x4) {
%sel_71 = select i1 %t12, i4 %one_hot_16, i4 %umul_23
ret i4 %sel_71
}
+
+define i32 @select_clz_to_ctz_sub_constant_for_zero(i32 %a) {
+; CHECK-LABEL: @select_clz_to_ctz_sub_constant_for_zero(
+; CHECK-NEXT: [[SUB:%.*]] = sub i32 0, [[A:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i32 [[A]], [[SUB]]
+; CHECK-NEXT: [[LZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[AND]], i1 false)
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
+; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 31, [[LZ]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[SUB1]]
+; CHECK-NEXT: ret i32 [[COND]]
+;
+ %sub = sub i32 0, %a
+ %and = and i32 %a, %sub
+ %lz = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 %and, i1 false)
+ %tobool = icmp eq i32 %a, 0
+ %sub1 = sub nsw i32 31, %lz
+ %cond = select i1 %tobool, i32 32, i32 %sub1
+ ret i32 %cond
+}
+
+define i33 @select_clz_to_ctz_sub_constant_for_zero_33(i33 %a) {
+; CHECK-LABEL: @select_clz_to_ctz_sub_constant_for_zero_33(
+; CHECK-NEXT: [[SUB:%.*]] = sub i33 0, [[A:%.*]]
+; CHECK-NEXT: [[AND:%.*]] = and i33 [[A]], [[SUB]]
+; CHECK-NEXT: [[LZ:%.*]] = tail call range(i33 0, 34) i33 @llvm.ctlz.i33(i33 [[AND]], i1 false)
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i33 [[A]], 0
+; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i33 32, [[LZ]]
+; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i33 33, i33 [[SUB1]]
+; CHECK-NEXT: ret i33 [[COND]]
+;
+ %sub = sub i33 0, %a
+ %and = and i33 %a, %sub
+ %lz = tail call range(i33 0, 34) i33 @llvm.ctlz.i33(i33 %and, i1 false)
+ %tobool = icmp eq i33 %a, 0
+ %sub1 = sub nsw i33 32, %lz
+ %cond = select i1 %tobool, i33 33, i33 %sub1
+ ret i33 %cond
+}
>From 3bb4ad991d0e65b75e36b9e28392798090a90070 Mon Sep 17 00:00:00 2001
From: AZero13 <gfunni234 at gmail.com>
Date: Tue, 23 Jun 2026 12:18:49 -0400
Subject: [PATCH 2/2] [InstCombine] Fold (bw-1) - ctlz(x&-x) to cttz
Works for non-powers of 2.
Alive2: https://alive2.llvm.org/ce/z/-cbxFz
---
.../Transforms/InstCombine/InstCombineSelect.cpp | 12 ++++++++----
.../Transforms/InstCombine/select-ctlz-to-cttz.ll | 14 ++------------
2 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 78be7c6ea2900..af10ac712886a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1504,17 +1504,21 @@ static Instruction *foldSelectCtlzToCttz(ICmpInst *ICI, Value *TrueVal,
Value *FalseVal,
InstCombiner::BuilderTy &Builder) {
unsigned BitWidth = TrueVal->getType()->getScalarSizeInBits();
- if (!isPowerOf2_32(BitWidth) || !ICI->isEquality() ||
- !match(ICI->getOperand(1), m_Zero()))
+ if (!ICI->isEquality() || !match(ICI->getOperand(1), m_Zero()))
return nullptr;
if (ICI->getPredicate() == ICmpInst::ICMP_NE)
std::swap(TrueVal, FalseVal);
Value *Ctlz;
- if (!match(FalseVal,
- m_Xor(m_Value(Ctlz), m_SpecificInt(BitWidth - 1))))
+ if (match(FalseVal,
+ m_Xor(m_Value(Ctlz), m_SpecificIntAllowPoison(BitWidth - 1)))) {
+ if (!isPowerOf2_32(BitWidth))
+ return nullptr;
+ } else if (!match(FalseVal, m_Sub(m_SpecificIntAllowPoison(BitWidth - 1),
+ m_Value(Ctlz)))) {
return nullptr;
+ }
if (!match(Ctlz, m_Ctlz(m_Value(), m_Value())))
return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll b/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
index 63e3d4adf2758..9b85008bbcac6 100644
--- a/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
+++ b/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
@@ -343,12 +343,7 @@ define i4 @PR45762_logical(i3 %x4) {
define i32 @select_clz_to_ctz_sub_constant_for_zero(i32 %a) {
; CHECK-LABEL: @select_clz_to_ctz_sub_constant_for_zero(
-; CHECK-NEXT: [[SUB:%.*]] = sub i32 0, [[A:%.*]]
-; CHECK-NEXT: [[AND:%.*]] = and i32 [[A]], [[SUB]]
-; CHECK-NEXT: [[LZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[AND]], i1 false)
-; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
-; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i32 31, [[LZ]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i32 32, i32 [[SUB1]]
+; CHECK-NEXT: [[COND:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[A:%.*]], i1 false)
; CHECK-NEXT: ret i32 [[COND]]
;
%sub = sub i32 0, %a
@@ -362,12 +357,7 @@ define i32 @select_clz_to_ctz_sub_constant_for_zero(i32 %a) {
define i33 @select_clz_to_ctz_sub_constant_for_zero_33(i33 %a) {
; CHECK-LABEL: @select_clz_to_ctz_sub_constant_for_zero_33(
-; CHECK-NEXT: [[SUB:%.*]] = sub i33 0, [[A:%.*]]
-; CHECK-NEXT: [[AND:%.*]] = and i33 [[A]], [[SUB]]
-; CHECK-NEXT: [[LZ:%.*]] = tail call range(i33 0, 34) i33 @llvm.ctlz.i33(i33 [[AND]], i1 false)
-; CHECK-NEXT: [[TOBOOL:%.*]] = icmp eq i33 [[A]], 0
-; CHECK-NEXT: [[SUB1:%.*]] = sub nsw i33 32, [[LZ]]
-; CHECK-NEXT: [[COND:%.*]] = select i1 [[TOBOOL]], i33 33, i33 [[SUB1]]
+; CHECK-NEXT: [[COND:%.*]] = call range(i33 0, 34) i33 @llvm.cttz.i33(i33 [[A:%.*]], i1 false)
; CHECK-NEXT: ret i33 [[COND]]
;
%sub = sub i33 0, %a
More information about the llvm-commits
mailing list