[llvm] [InstCombine] Fold shl of constant by cttz into multiply of lowest set bit (PR #214517)
via llvm-commits
llvm-commits at lists.llvm.org
Thu Aug 6 08:51:47 PDT 2026
https://github.com/milkHongYe created https://github.com/llvm/llvm-project/pull/214517
Currently, `C << cttz(X, true)` where C is a scalar constant generates a DeBruijn lookup table on RV64I (13 instructions).
And this patch adds a fold in InstCombine:
`C << cttz(X, true) --> (-X & X) * C`
This reduces the instruction count from 13 to 3 on RV64I.
The fold requires:
- C is a scalar constant (m_APInt)
- cttz is_zero_poison = true, guaranteeing X != 0
- cttz has a single use (to avoid increasing instruction count)
>From eaa2f15c096b73e480a94755de27fc8752a5f5a7 Mon Sep 17 00:00:00 2001
From: milkHongYe <1483685464 at qq.com>
Date: Thu, 6 Aug 2026 23:28:11 +0800
Subject: [PATCH] [InstCombine] Fold shl of constant by cttz into multiply of
lowest set bit
---
.../Transforms/InstCombine/InstCombineShifts.cpp | 13 +++++++++++++
llvm/test/Transforms/InstCombine/shift.ll | 5 +++--
2 files changed, 16 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
index 241bc3bba51c2..5eaa326faaf10 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp
@@ -1382,6 +1382,19 @@ Instruction *InstCombinerImpl::visitShl(BinaryOperator &I) {
}
}
+ // C << (cttz X, true) --> (-X & X) * C (C must be a scalar constant, cttz
+ // must have one use)
+ {
+ Value *X;
+ const APInt *C;
+ if (match(Op0, m_APInt(C)) &&
+ match(Op1, m_OneUse(m_Cttz(m_Value(X), m_One())))) {
+ Value *NegX = Builder.CreateNeg(X, "neg");
+ Value *LowBit = Builder.CreateAnd(NegX, X);
+ return BinaryOperator::CreateMul(LowBit, Op0);
+ }
+ }
+
return nullptr;
}
diff --git a/llvm/test/Transforms/InstCombine/shift.ll b/llvm/test/Transforms/InstCombine/shift.ll
index d63ba48830068..4c05a56b1dbc0 100644
--- a/llvm/test/Transforms/InstCombine/shift.ll
+++ b/llvm/test/Transforms/InstCombine/shift.ll
@@ -2097,8 +2097,9 @@ define i32 @shl1_cttz_extra_use(i32 %x) {
define i32 @shl2_cttz(i32 %x) {
; CHECK-LABEL: @shl2_cttz(
-; CHECK-NEXT: [[TZ:%.*]] = call range(i32 0, 33) i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true)
-; CHECK-NEXT: [[SHL:%.*]] = shl i32 2, [[TZ]]
+; CHECK-NEXT: [[NEG:%.*]] = sub i32 0, [[X:%.*]]
+; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[X]], [[NEG]]
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[TMP1]], 1
; CHECK-NEXT: ret i32 [[SHL]]
;
%tz = call i32 @llvm.cttz.i32(i32 %x, i1 true)
More information about the llvm-commits
mailing list