[llvm] 700febc - [InstCombine] Fix incorrect is_zero_poison when folding select+ctlz to cttz (#202388)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jun 8 13:48:02 PDT 2026
Author: Justin Lebar
Date: 2026-06-08T20:47:58Z
New Revision: 700febc04caa41923eaf4b3911db26cb13482a83
URL: https://github.com/llvm/llvm-project/commit/700febc04caa41923eaf4b3911db26cb13482a83
DIFF: https://github.com/llvm/llvm-project/commit/700febc04caa41923eaf4b3911db26cb13482a83.diff
LOG: [InstCombine] Fix incorrect is_zero_poison when folding select+ctlz to cttz (#202388)
foldSelectCtlzToCttz folds
%lz = call i32 @llvm.ctlz.i32(i32 (x & -x), i1 is_zero_poison)
%r = select (icmp eq x, 0), i32 32, i32 (xor %lz, 31)
into
%r = call i32 @llvm.cttz.i32(i32 x, i1 is_zero_poison)
The original select's result is defined when x is zero, even if
is_zero_poison is true. Therefore in the new cttz call, we need to pass
false for the second param, we can't reuse is_zero_poison.
Added:
Modified:
llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 730dc53fcc557..df9ba225657d3 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -1496,8 +1496,6 @@ static Value *foldAbsDiff(ICmpInst *Cmp, Value *TVal, Value *FVal,
/// Fold the following code sequence:
/// \code
/// int a = ctlz(x & -x);
-// x ? 31 - a : a;
-// // or
// x ? 31 - a : 32;
/// \code
///
@@ -1522,7 +1520,7 @@ static Instruction *foldSelectCtlzToCttz(ICmpInst *ICI, Value *TrueVal,
if (!match(Ctlz, m_Ctlz(m_Value(), m_Value())))
return nullptr;
- if (TrueVal != Ctlz && !match(TrueVal, m_SpecificInt(BitWidth)))
+ if (!match(TrueVal, m_SpecificInt(BitWidth)))
return nullptr;
Value *X = ICI->getOperand(0);
@@ -1530,9 +1528,11 @@ static Instruction *foldSelectCtlzToCttz(ICmpInst *ICI, Value *TrueVal,
if (!match(II->getOperand(0), m_c_And(m_Specific(X), m_Neg(m_Specific(X)))))
return nullptr;
+ // The original select returns the constant bitwidth when x == 0, so the
+ // result is defined there; the cttz must use is_zero_poison = false.
Function *F = Intrinsic::getOrInsertDeclaration(
II->getModule(), Intrinsic::cttz, II->getType());
- return CallInst::Create(F, {X, II->getArgOperand(1)});
+ return CallInst::Create(F, {X, Builder.getFalse()});
}
/// Attempt to fold a cttz/ctlz followed by a icmp plus select into a single
diff --git a/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll b/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
index fa689108ce187..d1f25b19d35a0 100644
--- a/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
+++ b/llvm/test/Transforms/InstCombine/select-ctlz-to-cttz.ll
@@ -56,6 +56,29 @@ define i32 @select_clz_to_ctz_constant_for_zero(i32 %a) {
ret i32 %cond
}
+; The zero case selects the constant 32 (defined), but the ctlz has
+; is_zero_poison=true. The result cttz must use is_zero_poison=false, otherwise
+; the a==0 case becomes poison instead of 32. The extra use of the ctlz blocks
+; the standalone xor->cttz rewrite so the select reaches foldSelectCtlzToCttz.
+define i32 @select_clz_to_ctz_constant_for_zero_poison_flag(i32 %a) {
+; CHECK-LABEL: @select_clz_to_ctz_constant_for_zero_poison_flag(
+; 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 true)
+; CHECK-NEXT: call void @use(i32 [[LZ]])
+; 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
+ %and = and i32 %sub, %a
+ %lz = tail call i32 @llvm.ctlz.i32(i32 %and, i1 true)
+ call void @use(i32 %lz)
+ %tobool = icmp eq i32 %a, 0
+ %sub1 = xor i32 %lz, 31
+ %cond = select i1 %tobool, i32 32, i32 %sub1
+ ret i32 %cond
+}
+
define <2 x i32> @select_clz_to_ctz_vec(<2 x i32> %a) {
; CHECK-LABEL: @select_clz_to_ctz_vec(
; CHECK-NEXT: [[COND:%.*]] = call range(i32 0, 33) <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[A:%.*]], i1 true)
More information about the llvm-commits
mailing list