Skip to content

Commit 171ee2b

Browse files
committed
[InstCombine] Add CTLZ -> CTTZ simplification
1 parent f422303 commit 171ee2b

File tree

2 files changed

+24
-22
lines changed

2 files changed

+24
-22
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -585,6 +585,18 @@ static Instruction *foldCttzCtlz(IntrinsicInst &II, InstCombinerImpl &IC) {
585585
IC.Builder.CreateBinaryIntrinsic(Intrinsic::ctlz, C, Op1);
586586
return BinaryOperator::CreateSub(ConstCtlz, X);
587587
}
588+
589+
// ctlz(~x & (x - 1)) -> bitwidth - cttz(x, false)
590+
if (Op0->hasOneUse() &&
591+
match(Op0,
592+
m_c_And(m_Not(m_Value(X)), m_Add(m_Deferred(X), m_AllOnes())))) {
593+
Type *Ty = II.getType();
594+
unsigned BitWidth = Ty->getScalarSizeInBits();
595+
auto *Cttz = IC.Builder.CreateIntrinsic(Intrinsic::cttz, Ty,
596+
{X, IC.Builder.getFalse()});
597+
auto *Bw = ConstantInt::get(Ty, APInt(BitWidth, BitWidth));
598+
return IC.replaceInstUsesWith(II, IC.Builder.CreateSub(Bw, Cttz));
599+
}
588600
}
589601

590602
// cttz(Pow2) -> Log2(Pow2)

llvm/test/Transforms/InstCombine/ctlz-cttz.ll

Lines changed: 12 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,8 @@
55
define i8 @ctlz_to_sub_bw_cttz(i8 %a0) {
66
; CHECK-LABEL: define i8 @ctlz_to_sub_bw_cttz(
77
; CHECK-SAME: i8 [[A0:%.*]]) {
8-
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[A0]], -1
9-
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A0]], -1
10-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DEC]], [[NOT]]
11-
; CHECK-NEXT: [[CLZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.ctlz.i8(i8 [[AND]], i1 false)
8+
; CHECK-NEXT: [[TMP1:%.*]] = call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0]], i1 false)
9+
; CHECK-NEXT: [[CLZ:%.*]] = sub nuw nsw i8 8, [[TMP1]]
1210
; CHECK-NEXT: ret i8 [[CLZ]]
1311
;
1412
%dec = add i8 %a0, -1
@@ -21,10 +19,8 @@ define i8 @ctlz_to_sub_bw_cttz(i8 %a0) {
2119
define i8 @ctlz_to_sub_bw_cttz_poison(i8 %a0) {
2220
; CHECK-LABEL: define i8 @ctlz_to_sub_bw_cttz_poison(
2321
; CHECK-SAME: i8 [[A0:%.*]]) {
24-
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[A0]], -1
25-
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A0]], -1
26-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DEC]], [[NOT]]
27-
; CHECK-NEXT: [[CLZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.ctlz.i8(i8 [[AND]], i1 true)
22+
; CHECK-NEXT: [[TMP1:%.*]] = call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0]], i1 false)
23+
; CHECK-NEXT: [[CLZ:%.*]] = sub nuw nsw i8 8, [[TMP1]]
2824
; CHECK-NEXT: ret i8 [[CLZ]]
2925
;
3026
%dec = add i8 %a0, -1
@@ -73,9 +69,8 @@ define i8 @ctlz_to_sub_bw_cttz_multi_use_dec(i8 %a0) {
7369
; CHECK-SAME: i8 [[A0:%.*]]) {
7470
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[A0]], -1
7571
; CHECK-NEXT: call void @use(i8 [[DEC]])
76-
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A0]], -1
77-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DEC]], [[NOT]]
78-
; CHECK-NEXT: [[CLZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.ctlz.i8(i8 [[AND]], i1 false)
72+
; CHECK-NEXT: [[TMP1:%.*]] = call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0]], i1 false)
73+
; CHECK-NEXT: [[CLZ:%.*]] = sub nuw nsw i8 8, [[TMP1]]
7974
; CHECK-NEXT: ret i8 [[CLZ]]
8075
;
8176
%dec = add i8 %a0, -1
@@ -89,11 +84,10 @@ define i8 @ctlz_to_sub_bw_cttz_multi_use_dec(i8 %a0) {
8984
define i8 @ctlz_to_sub_bw_cttz_multi_use_not(i8 %a0) {
9085
; CHECK-LABEL: define i8 @ctlz_to_sub_bw_cttz_multi_use_not(
9186
; CHECK-SAME: i8 [[A0:%.*]]) {
92-
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[A0]], -1
9387
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A0]], -1
9488
; CHECK-NEXT: call void @use(i8 [[NOT]])
95-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DEC]], [[NOT]]
96-
; CHECK-NEXT: [[CLZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.ctlz.i8(i8 [[AND]], i1 false)
89+
; CHECK-NEXT: [[TMP1:%.*]] = call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0]], i1 false)
90+
; CHECK-NEXT: [[CLZ:%.*]] = sub nuw nsw i8 8, [[TMP1]]
9791
; CHECK-NEXT: ret i8 [[CLZ]]
9892
;
9993
%dec = add i8 %a0, -1
@@ -125,10 +119,8 @@ define i8 @ctlz_to_sub_bw_cttz_multi_use_and(i8 %a0) {
125119
define i8 @ctlz_to_sub_bw_cttz_commute_and(i8 %a0) {
126120
; CHECK-LABEL: define i8 @ctlz_to_sub_bw_cttz_commute_and(
127121
; CHECK-SAME: i8 [[A0:%.*]]) {
128-
; CHECK-NEXT: [[DEC:%.*]] = add i8 [[A0]], -1
129-
; CHECK-NEXT: [[NOT:%.*]] = xor i8 [[A0]], -1
130-
; CHECK-NEXT: [[AND:%.*]] = and i8 [[DEC]], [[NOT]]
131-
; CHECK-NEXT: [[CLZ:%.*]] = tail call range(i8 0, 9) i8 @llvm.ctlz.i8(i8 [[AND]], i1 false)
122+
; CHECK-NEXT: [[TMP1:%.*]] = call range(i8 0, 9) i8 @llvm.cttz.i8(i8 [[A0]], i1 false)
123+
; CHECK-NEXT: [[CLZ:%.*]] = sub nuw nsw i8 8, [[TMP1]]
132124
; CHECK-NEXT: ret i8 [[CLZ]]
133125
;
134126
%dec = add i8 %a0, -1
@@ -141,10 +133,8 @@ define i8 @ctlz_to_sub_bw_cttz_commute_and(i8 %a0) {
141133
define <2 x i8> @ctlz_to_sub_bw_cttz_vec_splat(<2 x i8> %a0) {
142134
; CHECK-LABEL: define <2 x i8> @ctlz_to_sub_bw_cttz_vec_splat(
143135
; CHECK-SAME: <2 x i8> [[A0:%.*]]) {
144-
; CHECK-NEXT: [[DEC:%.*]] = add <2 x i8> [[A0]], splat (i8 -1)
145-
; CHECK-NEXT: [[NOT:%.*]] = xor <2 x i8> [[A0]], splat (i8 -1)
146-
; CHECK-NEXT: [[AND:%.*]] = and <2 x i8> [[DEC]], [[NOT]]
147-
; CHECK-NEXT: [[CLZ:%.*]] = tail call range(i8 0, 9) <2 x i8> @llvm.ctlz.v2i8(<2 x i8> [[AND]], i1 false)
136+
; CHECK-NEXT: [[TMP1:%.*]] = call range(i8 0, 9) <2 x i8> @llvm.cttz.v2i8(<2 x i8> [[A0]], i1 false)
137+
; CHECK-NEXT: [[CLZ:%.*]] = sub nuw nsw <2 x i8> splat (i8 8), [[TMP1]]
148138
; CHECK-NEXT: ret <2 x i8> [[CLZ]]
149139
;
150140
%dec = add <2 x i8> %a0, <i8 -1, i8 -1>

0 commit comments

Comments
 (0)