Skip to content

Commit 64b2676

Browse files
committed
[InstCombine] fold ctlz/cttz-of-select with 1 or more constant arms
Building on: 4c44b02 ...and adding handling for the extra operand in these intrinsics. This pattern is discussed in: https://llvm.org/PR50140
1 parent 4819cd1 commit 64b2676

File tree

3 files changed

+26
-17
lines changed

3 files changed

+26
-17
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1080,6 +1080,11 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
10801080
case Intrinsic::ctlz:
10811081
if (auto *I = foldCttzCtlz(*II, *this))
10821082
return I;
1083+
1084+
// If the operand is a select with constant arm(s), try to hoist ctlz/cttz.
1085+
if (auto *Sel = dyn_cast<SelectInst>(II->getArgOperand(0)))
1086+
if (Instruction *R = FoldOpIntoSelect(*II, Sel))
1087+
return R;
10831088
break;
10841089

10851090
case Intrinsic::ctpop:

llvm/lib/Transforms/InstCombine/InstructionCombining.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -941,8 +941,14 @@ static Value *foldOperationIntoSelectOperand(Instruction &I, Value *SO,
941941
if (auto *II = dyn_cast<IntrinsicInst>(&I)) {
942942
assert(canConstantFoldCallTo(II, cast<Function>(II->getCalledOperand())) &&
943943
"Expected constant-foldable intrinsic");
944+
Intrinsic::ID IID = II->getIntrinsicID();
945+
SmallVector<Value *, 2> Args = {SO};
944946

945-
return Builder.CreateIntrinsic(II->getIntrinsicID(), I.getType(), SO);
947+
// Propagate the zero-is-undef argument to the new instruction.
948+
if (IID == Intrinsic::ctlz || IID == Intrinsic::cttz)
949+
Args.push_back(II->getArgOperand(1));
950+
951+
return Builder.CreateIntrinsic(IID, I.getType(), Args);
946952
}
947953

948954
assert(I.isBinaryOp() && "Unexpected opcode for select folding");

llvm/test/Transforms/InstCombine/intrinsic-select.ll

Lines changed: 14 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,7 @@ declare <3 x i7> @llvm.ctpop.v3i7(<3 x i7>)
1414

1515
define i32 @ctlz_sel_const_true_false(i1 %b) {
1616
; CHECK-LABEL: @ctlz_sel_const_true_false(
17-
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 5, i32 -7
18-
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.ctlz.i32(i32 [[S]], i1 true), !range [[RNG0:![0-9]+]]
17+
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i32 29, i32 0
1918
; CHECK-NEXT: ret i32 [[C]]
2019
;
2120
%s = select i1 %b, i32 5, i32 -7
@@ -25,8 +24,8 @@ define i32 @ctlz_sel_const_true_false(i1 %b) {
2524

2625
define i32 @ctlz_sel_const_true(i1 %b, i32 %x) {
2726
; CHECK-LABEL: @ctlz_sel_const_true(
28-
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 5, i32 [[X:%.*]]
29-
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.ctlz.i32(i32 [[S]], i1 false), !range [[RNG1:![0-9]+]]
27+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.ctlz.i32(i32 [[X:%.*]], i1 false), !range [[RNG0:![0-9]+]]
28+
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i32 29, i32 [[TMP1]]
3029
; CHECK-NEXT: ret i32 [[C]]
3130
;
3231
%s = select i1 %b, i32 5, i32 %x
@@ -36,8 +35,8 @@ define i32 @ctlz_sel_const_true(i1 %b, i32 %x) {
3635

3736
define <3 x i17> @ctlz_sel_const_false(<3 x i1> %b, <3 x i17> %x) {
3837
; CHECK-LABEL: @ctlz_sel_const_false(
39-
; CHECK-NEXT: [[S:%.*]] = select <3 x i1> [[B:%.*]], <3 x i17> [[X:%.*]], <3 x i17> <i17 7, i17 -1, i17 0>
40-
; CHECK-NEXT: [[C:%.*]] = call <3 x i17> @llvm.ctlz.v3i17(<3 x i17> [[S]], i1 true)
38+
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i17> @llvm.ctlz.v3i17(<3 x i17> [[X:%.*]], i1 true)
39+
; CHECK-NEXT: [[C:%.*]] = select <3 x i1> [[B:%.*]], <3 x i17> [[TMP1]], <3 x i17> <i17 14, i17 0, i17 undef>
4140
; CHECK-NEXT: ret <3 x i17> [[C]]
4241
;
4342
%s = select <3 x i1> %b, <3 x i17> %x, <3 x i17> <i17 7, i17 -1, i17 0>
@@ -49,7 +48,7 @@ define i32 @ctlz_sel_const_true_false_extra_use(i1 %b) {
4948
; CHECK-LABEL: @ctlz_sel_const_true_false_extra_use(
5049
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 -1, i32 7
5150
; CHECK-NEXT: call void @use(i32 [[S]])
52-
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.ctlz.i32(i32 [[S]], i1 true), !range [[RNG2:![0-9]+]]
51+
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.ctlz.i32(i32 [[S]], i1 true), !range [[RNG1:![0-9]+]]
5352
; CHECK-NEXT: ret i32 [[C]]
5453
;
5554
%s = select i1 %b, i32 -1, i32 7
@@ -60,8 +59,7 @@ define i32 @ctlz_sel_const_true_false_extra_use(i1 %b) {
6059

6160
define i32 @cttz_sel_const_true_false(i1 %b) {
6261
; CHECK-LABEL: @cttz_sel_const_true_false(
63-
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 4, i32 -7
64-
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.cttz.i32(i32 [[S]], i1 true), !range [[RNG1]]
62+
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i32 2, i32 0
6563
; CHECK-NEXT: ret i32 [[C]]
6664
;
6765
%s = select i1 %b, i32 4, i32 -7
@@ -71,8 +69,8 @@ define i32 @cttz_sel_const_true_false(i1 %b) {
7169

7270
define i32 @cttz_sel_const_true(i1 %b, i32 %x) {
7371
; CHECK-LABEL: @cttz_sel_const_true(
74-
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 5, i32 [[X:%.*]]
75-
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.cttz.i32(i32 [[S]], i1 true), !range [[RNG1]]
72+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.cttz.i32(i32 [[X:%.*]], i1 true), !range [[RNG0]]
73+
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i32 0, i32 [[TMP1]]
7674
; CHECK-NEXT: ret i32 [[C]]
7775
;
7876
%s = select i1 %b, i32 5, i32 %x
@@ -82,8 +80,8 @@ define i32 @cttz_sel_const_true(i1 %b, i32 %x) {
8280

8381
define <3 x i5> @cttz_sel_const_false(<3 x i1> %b, <3 x i5> %x) {
8482
; CHECK-LABEL: @cttz_sel_const_false(
85-
; CHECK-NEXT: [[S:%.*]] = select <3 x i1> [[B:%.*]], <3 x i5> [[X:%.*]], <3 x i5> <i5 7, i5 -1, i5 0>
86-
; CHECK-NEXT: [[C:%.*]] = call <3 x i5> @llvm.cttz.v3i5(<3 x i5> [[S]], i1 false)
83+
; CHECK-NEXT: [[TMP1:%.*]] = call <3 x i5> @llvm.cttz.v3i5(<3 x i5> [[X:%.*]], i1 false)
84+
; CHECK-NEXT: [[C:%.*]] = select <3 x i1> [[B:%.*]], <3 x i5> [[TMP1]], <3 x i5> <i5 0, i5 0, i5 5>
8785
; CHECK-NEXT: ret <3 x i5> [[C]]
8886
;
8987
%s = select <3 x i1> %b, <3 x i5> %x, <3 x i5> <i5 7, i5 -1, i5 0>
@@ -95,7 +93,7 @@ define i32 @cttz_sel_const_true_false_extra_use(i1 %b) {
9593
; CHECK-LABEL: @cttz_sel_const_true_false_extra_use(
9694
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 5, i32 -8
9795
; CHECK-NEXT: call void @use(i32 [[S]])
98-
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.cttz.i32(i32 [[S]], i1 true), !range [[RNG1]]
96+
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.cttz.i32(i32 [[S]], i1 true), !range [[RNG0]]
9997
; CHECK-NEXT: ret i32 [[C]]
10098
;
10199
%s = select i1 %b, i32 5, i32 -8
@@ -116,7 +114,7 @@ define i32 @ctpop_sel_const_true_false(i1 %b) {
116114

117115
define i32 @ctpop_sel_const_true(i1 %b, i32 %x) {
118116
; CHECK-LABEL: @ctpop_sel_const_true(
119-
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG1]]
117+
; CHECK-NEXT: [[TMP1:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]]), !range [[RNG0]]
120118
; CHECK-NEXT: [[C:%.*]] = select i1 [[B:%.*]], i32 2, i32 [[TMP1]]
121119
; CHECK-NEXT: ret i32 [[C]]
122120
;
@@ -140,7 +138,7 @@ define i32 @ctpop_sel_const_true_false_extra_use(i1 %b) {
140138
; CHECK-LABEL: @ctpop_sel_const_true_false_extra_use(
141139
; CHECK-NEXT: [[S:%.*]] = select i1 [[B:%.*]], i32 5, i32 7
142140
; CHECK-NEXT: call void @use(i32 [[S]])
143-
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.ctpop.i32(i32 [[S]]), !range [[RNG3:![0-9]+]]
141+
; CHECK-NEXT: [[C:%.*]] = call i32 @llvm.ctpop.i32(i32 [[S]]), !range [[RNG2:![0-9]+]]
144142
; CHECK-NEXT: ret i32 [[C]]
145143
;
146144
%s = select i1 %b, i32 5, i32 7

0 commit comments

Comments
 (0)