[llvm] [InstCombine] Fold ctlz(zext(bitreverse(x))) to cttz(x) (PR #218279)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Aug 23 12:51:17 PDT 2026
https://github.com/OmarAzizi updated https://github.com/llvm/llvm-project/pull/218279
>From 5e6a28c69a6030a30e0d0a977879257a21340cb5 Mon Sep 17 00:00:00 2001
From: OmarAzizi <oalazizi75 at gmail.com>
Date: Sun, 23 Aug 2026 22:03:46 +0300
Subject: [PATCH 1/2] [InstCombine] Fold ctlz(zext(bitreverse(x))) to cttz(x)
---
.../InstCombine/InstCombineCalls.cpp | 19 +++++++++
.../InstCombine/ctlz-cttz-bitreverse.ll | 41 +++++++++++++++++++
2 files changed, 60 insertions(+)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index 8a9c99eb36f66..a8484f24d1452 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -612,6 +612,25 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
auto *Bw = ConstantInt::get(Ty, APInt(BitWidth, BitWidth));
return IC.replaceInstUsesWith(II, IC.Builder.CreateSub(Bw, Cttz));
}
+
+ // ctlz(zext(bitreverse(x))) -> zext(cttz(x) | (WideBits - NarrowBits))
+ // [poison-on-zero]
+ // ctlz(zext(bitreverse(x))) -> zext(cttz(x) + (WideBits - NarrowBits))
+ // [defined-on-zero]
+ if (match(Op0, m_OneUse(m_ZExt(m_BitReverse(m_Value(X)))))) {
+ Type *NarrowTy = X->getType();
+ unsigned WideBits = II.getType()->getScalarSizeInBits();
+ unsigned NarrowBits = NarrowTy->getScalarSizeInBits();
+ bool IsPoison = match(Op1, m_One());
+
+ auto *Cttz = IC.Builder.CreateBinaryIntrinsic(
+ Intrinsic::cttz, X, ConstantInt::getBool(II.getContext(), IsPoison));
+ auto *Diff = ConstantInt::get(NarrowTy, WideBits - NarrowBits);
+ Value *Combined = IsPoison ? IC.Builder.CreateOr(Cttz, Diff)
+ : IC.Builder.CreateNUWAdd(Cttz, Diff);
+ auto *ZextResult = IC.Builder.CreateZExt(Combined, II.getType());
+ return IC.replaceInstUsesWith(II, ZextResult);
+ }
}
// cttz(Pow2) -> Log2(Pow2)
diff --git a/llvm/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll b/llvm/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll
index ec822f4b8fb3a..3624c8a9e5418 100644
--- a/llvm/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll
+++ b/llvm/test/Transforms/InstCombine/ctlz-cttz-bitreverse.ll
@@ -61,6 +61,47 @@ define i32 @cttz_false_bitreverse(i32 %x) {
ret i32 %b
}
+define i32 @ctlz_true_zext_bitreverse(i16 %x) {
+; CHECK-LABEL: @ctlz_true_zext_bitreverse(
+; CHECK-NEXT: [[TMP1:%.*]] = call range(i16 0, 17) i16 @llvm.cttz.i16(i16 [[X:%.*]], i1 true)
+; CHECK-NEXT: [[TMP2:%.*]] = or disjoint i16 [[TMP1]], 16
+; CHECK-NEXT: [[B:%.*]] = zext nneg i16 [[TMP2]] to i32
+; CHECK-NEXT: ret i32 [[B]]
+;
+ %a = tail call i16 @llvm.bitreverse.i16(i16 %x)
+ %z = zext i16 %a to i32
+ %b = tail call i32 @llvm.ctlz.i32(i32 %z, i1 true)
+ ret i32 %b
+}
+
+define i32 @ctlz_false_zext_bitreverse(i16 %x) {
+; CHECK-LABEL: @ctlz_false_zext_bitreverse(
+; CHECK-NEXT: [[TMP1:%.*]] = call range(i16 0, 17) i16 @llvm.cttz.i16(i16 [[X:%.*]], i1 false)
+; CHECK-NEXT: [[TMP2:%.*]] = add nuw nsw i16 [[TMP1]], 16
+; CHECK-NEXT: [[B:%.*]] = zext nneg i16 [[TMP2]] to i32
+; CHECK-NEXT: ret i32 [[B]]
+;
+ %a = tail call i16 @llvm.bitreverse.i16(i16 %x)
+ %z = zext i16 %a to i32
+ %b = tail call i32 @llvm.ctlz.i32(i32 %z, i1 false)
+ ret i32 %b
+}
+
+define i64 @ctlz_i32_zext_bitreverse(i32 %x) {
+; CHECK-LABEL: @ctlz_i32_zext_bitreverse(
+; CHECK-NEXT: [[TMP1:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
+; CHECK-NEXT: [[TMP2:%.*]] = or disjoint i32 [[TMP1]], 32
+; CHECK-NEXT: [[B:%.*]] = zext nneg i32 [[TMP2]] to i64
+; CHECK-NEXT: ret i64 [[B]]
+;
+ %a = tail call i32 @llvm.bitreverse.i32(i32 %x)
+ %z = zext i32 %a to i64
+ %b = tail call i64 @llvm.ctlz.i64(i64 %z, i1 true)
+ ret i64 %b
+}
+
+declare i64 @llvm.ctlz.i64(i64, i1)
+declare i16 @llvm.bitreverse.i16(i16)
declare i32 @llvm.bitreverse.i32(i32)
declare <2 x i64> @llvm.bitreverse.v2i64(<2 x i64>)
declare i32 @llvm.ctlz.i32(i32, i1)
>From 516f6c9d1f481099c03b7d045248ebd1874ae662 Mon Sep 17 00:00:00 2001
From: OmarAzizi <oalazizi75 at gmail.com>
Date: Sun, 23 Aug 2026 22:50:56 +0300
Subject: [PATCH 2/2] [InstCombine] Simplify to always emit add nuw
---
llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
index a8484f24d1452..688bcd9536f33 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
@@ -626,8 +626,7 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
auto *Cttz = IC.Builder.CreateBinaryIntrinsic(
Intrinsic::cttz, X, ConstantInt::getBool(II.getContext(), IsPoison));
auto *Diff = ConstantInt::get(NarrowTy, WideBits - NarrowBits);
- Value *Combined = IsPoison ? IC.Builder.CreateOr(Cttz, Diff)
- : IC.Builder.CreateNUWAdd(Cttz, Diff);
+ Value *Combined = IC.Builder.CreateNUWAdd(Cttz, Diff);
auto *ZextResult = IC.Builder.CreateZExt(Combined, II.getType());
return IC.replaceInstUsesWith(II, ZextResult);
}
More information about the llvm-commits
mailing list