[llvm-branch-commits] [llvm] [InstCombine] Fold trunc(ctpop(A)) + trunc(ctpop(B)) -> trunc(ctpop(A) + ctpop(B)) (PR #231332)
Luke Lau via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Mon Oct 12 16:57:35 PDT 2026
https://github.com/lukel97 created https://github.com/llvm/llvm-project/pull/231332
This allows the combine added in #231321 to kick in and fold the motivating ctpop case in automotive-bitcount:
```c
static char bits[256] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
int CDECL ntbl_bitcount(long int x)
{
return
bits[ (int) (x & 0x0000000FUL) ] +
bits[ (int)((x & 0x000000F0UL) >> 4) ] +
bits[ (int)((x & 0x00000F00UL) >> 8) ] +
bits[ (int)((x & 0x0000F000UL) >> 12)] +
bits[ (int)((x & 0x000F0000UL) >> 16)] +
bits[ (int)((x & 0x00F00000UL) >> 20)] +
bits[ (int)((x & 0x0F000000UL) >> 24)] +
bits[ (int)((x & 0xF0000000UL) >> 28)];
}
```
>From c8581528a14aa4c8963d37d038a48378ae3d3270 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 13 Oct 2026 00:46:04 +0100
Subject: [PATCH 1/2] Precommit tests
---
llvm/test/Transforms/InstCombine/ctpop.ll | 17 +++++++++++++++++
1 file changed, 17 insertions(+)
diff --git a/llvm/test/Transforms/InstCombine/ctpop.ll b/llvm/test/Transforms/InstCombine/ctpop.ll
index 5bb8dafaf37c4..30c7ca40534e1 100644
--- a/llvm/test/Transforms/InstCombine/ctpop.ll
+++ b/llvm/test/Transforms/InstCombine/ctpop.ll
@@ -263,6 +263,23 @@ define <2 x i32> @ctpop_add_no_common_bits_vec_use2(<2 x i32> %a, <2 x i32> %b,
ret <2 x i32> %res
}
+define i32 @ctpop_add_trunc(i64 %a, i64 %b) {
+; CHECK-LABEL: @ctpop_add_trunc(
+; CHECK-NEXT: [[CTPOP1:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[A:%.*]])
+; CHECK-NEXT: [[T1:%.*]] = trunc nuw nsw i64 [[CTPOP1]] to i32
+; CHECK-NEXT: [[CTPOP2:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[B:%.*]])
+; CHECK-NEXT: [[T2:%.*]] = trunc nuw nsw i64 [[CTPOP2]] to i32
+; CHECK-NEXT: [[RES:%.*]] = add nuw nsw i32 [[T1]], [[T2]]
+; CHECK-NEXT: ret i32 [[RES]]
+;
+ %ctpop1 = call i64 @llvm.ctpop.i64(i64 %a)
+ %t1 = trunc i64 %ctpop1 to i32
+ %ctpop2 = call i64 @llvm.ctpop.i64(i64 %b)
+ %t2 = trunc i64 %ctpop2 to i32
+ %res = add i32 %t1, %t2
+ ret i32 %res
+}
+
define i8 @ctpop_rotate_left(i8 %a, i8 %amt) {
; CHECK-LABEL: @ctpop_rotate_left(
; CHECK-NEXT: [[RES:%.*]] = call range(i8 0, 9) i8 @llvm.ctpop.i8(i8 [[A:%.*]])
>From 7466db2e5c13bfafe27692db5e4a8c31aee6bf16 Mon Sep 17 00:00:00 2001
From: Luke Lau <luke at igalia.com>
Date: Tue, 13 Oct 2026 00:17:04 +0100
Subject: [PATCH 2/2] [InstCombine] Fold trunc(ctpop(A)) + trunc(ctpop(B)) ->
trunc(ctpop(A) + ctpop(B))
This allows the combine added in #231321 to kick in and fold the motivating ctpop case in automotive-bitcount:
```c
static char bits[256] = {0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, 6, 6, 7, 6, 7, 7, 8};
int CDECL ntbl_bitcount(long int x)
{
return
bits[ (int) (x & 0x0000000FUL) ] +
bits[ (int)((x & 0x000000F0UL) >> 4) ] +
bits[ (int)((x & 0x00000F00UL) >> 8) ] +
bits[ (int)((x & 0x0000F000UL) >> 12)] +
bits[ (int)((x & 0x000F0000UL) >> 16)] +
bits[ (int)((x & 0x00F00000UL) >> 20)] +
bits[ (int)((x & 0x0F000000UL) >> 24)] +
bits[ (int)((x & 0xF0000000UL) >> 28)];
}
```
---
.../InstCombine/InstCombineAddSub.cpp | 6 ++++++
llvm/test/Transforms/InstCombine/ctpop.ll | 18 +++++-------------
2 files changed, 11 insertions(+), 13 deletions(-)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
index 9ff6991388433..72e6fb80beb10 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
@@ -2046,6 +2046,12 @@ Instruction *InstCombinerImpl::visitAdd(BinaryOperator &I) {
Builder.CreateIntrinsic(Intrinsic::umax, {I.getType()}, {A, B}));
}
+ // trunc(ctpop(A)) + trunc(ctpop(B)) => trunc(ctpop(A) + ctpop(B))
+ if (match(LHS, m_OneUse(m_Trunc(m_Value(A, m_Ctpop(m_Value()))))) &&
+ match(RHS, m_OneUse(m_Trunc(m_Value(B, m_Ctpop(m_Value()))))) &&
+ A->getType() == B->getType())
+ return new TruncInst(Builder.CreateAdd(A, B), I.getType());
+
// ctpop(A) + ctpop(B) => ctpop(A | B) if A and B have no bits set in common.
if (match(LHS, m_OneUse(m_Ctpop(m_Value(A)))) &&
match(RHS, m_OneUse(m_Ctpop(m_Value(B)))) &&
diff --git a/llvm/test/Transforms/InstCombine/ctpop.ll b/llvm/test/Transforms/InstCombine/ctpop.ll
index 30c7ca40534e1..1886f0bbef0a9 100644
--- a/llvm/test/Transforms/InstCombine/ctpop.ll
+++ b/llvm/test/Transforms/InstCombine/ctpop.ll
@@ -266,10 +266,9 @@ define <2 x i32> @ctpop_add_no_common_bits_vec_use2(<2 x i32> %a, <2 x i32> %b,
define i32 @ctpop_add_trunc(i64 %a, i64 %b) {
; CHECK-LABEL: @ctpop_add_trunc(
; CHECK-NEXT: [[CTPOP1:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[A:%.*]])
-; CHECK-NEXT: [[T1:%.*]] = trunc nuw nsw i64 [[CTPOP1]] to i32
; CHECK-NEXT: [[CTPOP2:%.*]] = call range(i64 0, 65) i64 @llvm.ctpop.i64(i64 [[B:%.*]])
-; CHECK-NEXT: [[T2:%.*]] = trunc nuw nsw i64 [[CTPOP2]] to i32
-; CHECK-NEXT: [[RES:%.*]] = add nuw nsw i32 [[T1]], [[T2]]
+; CHECK-NEXT: [[TMP1:%.*]] = add nuw nsw i64 [[CTPOP1]], [[CTPOP2]]
+; CHECK-NEXT: [[RES:%.*]] = trunc nuw nsw i64 [[TMP1]] to i32
; CHECK-NEXT: ret i32 [[RES]]
;
%ctpop1 = call i64 @llvm.ctpop.i64(i64 %a)
@@ -536,19 +535,12 @@ define i32 @ctpop_add_no_common_bits_shifted(i32 %x) {
ret i32 %r
}
-; TODO: We can combine these two ctpops through the truncs
-
define i32 @ctpop_add_no_common_bits_shifted_trunc(i64 %x) {
; CHECK-LABEL: @ctpop_add_no_common_bits_shifted_trunc(
-; CHECK-NEXT: [[LO:%.*]] = and i64 [[X:%.*]], 15
-; CHECK-NEXT: [[C0:%.*]] = call range(i64 0, 5) i64 @llvm.ctpop.i64(i64 [[LO]])
-; CHECK-NEXT: [[T0:%.*]] = trunc nuw nsw i64 [[C0]] to i32
-; CHECK-NEXT: [[S:%.*]] = lshr i64 [[X]], 8
-; CHECK-NEXT: [[HI:%.*]] = and i64 [[S]], 15
-; CHECK-NEXT: [[C1:%.*]] = call range(i64 0, 5) i64 @llvm.ctpop.i64(i64 [[HI]])
+; CHECK-NEXT: [[TMP1:%.*]] = and i64 [[X:%.*]], 3855
+; CHECK-NEXT: [[C1:%.*]] = call range(i64 0, 9) i64 @llvm.ctpop.i64(i64 [[TMP1]])
; CHECK-NEXT: [[T1:%.*]] = trunc nuw nsw i64 [[C1]] to i32
-; CHECK-NEXT: [[R:%.*]] = add nuw nsw i32 [[T0]], [[T1]]
-; CHECK-NEXT: ret i32 [[R]]
+; CHECK-NEXT: ret i32 [[T1]]
;
%lo = and i64 %x, 15
%c0 = call i64 @llvm.ctpop.i64(i64 %lo)
More information about the llvm-branch-commits
mailing list