• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt -instcombine -S < %s | FileCheck %s
3
4declare i3 @llvm.cttz.i3(i3, i1)
5declare i32 @llvm.cttz.i32(i32, i1 immarg)
6declare i32 @llvm.ctlz.i32(i32, i1 immarg)
7declare i64 @llvm.cttz.i64(i64, i1 immarg)
8declare i64 @llvm.ctlz.i64(i64, i1 immarg)
9
10declare <2 x i32> @llvm.ctlz.v2i32(<2 x i32>, i1)
11declare <2 x i32> @llvm.cttz.v2i32(<2 x i32>, i1)
12
13
14declare void @use(i32)
15declare void @use2(i1)
16
17define i32 @select_clz_to_ctz(i32 %a) {
18; CHECK-LABEL: @select_clz_to_ctz(
19; CHECK-NEXT:    [[COND:%.*]] = call i32 @llvm.cttz.i32(i32 [[A:%.*]], i1 true), !range !0
20; CHECK-NEXT:    ret i32 [[COND]]
21;
22  %sub = sub i32 0, %a
23  %and = and i32 %sub, %a
24  %lz = tail call i32 @llvm.ctlz.i32(i32 %and, i1 true)
25  %tobool = icmp eq i32 %a, 0
26  %sub1 = xor i32 %lz, 31
27  %cond = select i1 %tobool, i32 %lz, i32 %sub1
28  ret i32 %cond
29}
30
31define i32 @select_clz_to_ctz_preserve_flag(i32 %a) {
32; CHECK-LABEL: @select_clz_to_ctz_preserve_flag(
33; CHECK-NEXT:    [[COND:%.*]] = call i32 @llvm.cttz.i32(i32 [[A:%.*]], i1 false), !range !0
34; CHECK-NEXT:    ret i32 [[COND]]
35;
36  %sub = sub i32 0, %a
37  %and = and i32 %sub, %a
38  %lz = tail call i32 @llvm.ctlz.i32(i32 %and, i1 false)
39  %tobool = icmp eq i32 %a, 0
40  %sub1 = xor i32 %lz, 31
41  %cond = select i1 %tobool, i32 %lz, i32 %sub1
42  ret i32 %cond
43}
44
45define <2 x i32> @select_clz_to_ctz_vec(<2 x i32> %a) {
46; CHECK-LABEL: @select_clz_to_ctz_vec(
47; CHECK-NEXT:    [[COND:%.*]] = call <2 x i32> @llvm.cttz.v2i32(<2 x i32> [[A:%.*]], i1 true)
48; CHECK-NEXT:    ret <2 x i32> [[COND]]
49;
50  %sub = sub <2 x i32> zeroinitializer, %a
51  %and = and <2 x i32> %sub, %a
52  %lz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %and, i1 true)
53  %tobool = icmp eq <2 x i32> %a, zeroinitializer
54  %sub1 = xor <2 x i32> %lz, <i32 31, i32 31>
55  %cond = select <2 x i1> %tobool, <2 x i32> %lz, <2 x i32> %sub1
56  ret <2 x i32> %cond
57}
58
59define i32 @select_clz_to_ctz_extra_use(i32 %a) {
60; CHECK-LABEL: @select_clz_to_ctz_extra_use(
61; CHECK-NEXT:    [[SUB:%.*]] = sub i32 0, [[A:%.*]]
62; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SUB]], [[A]]
63; CHECK-NEXT:    [[LZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[AND]], i1 true), !range !0
64; CHECK-NEXT:    [[SUB1:%.*]] = xor i32 [[LZ]], 31
65; CHECK-NEXT:    call void @use(i32 [[SUB1]])
66; CHECK-NEXT:    [[COND:%.*]] = call i32 @llvm.cttz.i32(i32 [[A]], i1 true), !range !0
67; CHECK-NEXT:    ret i32 [[COND]]
68;
69  %sub = sub i32 0, %a
70  %and = and i32 %sub, %a
71  %lz = tail call i32 @llvm.ctlz.i32(i32 %and, i1 true)
72  %tobool = icmp eq i32 %a, 0
73  %sub1 = xor i32 %lz, 31
74  call void @use(i32 %sub1)
75  %cond = select i1 %tobool, i32 %lz, i32 %sub1
76  ret i32 %cond
77}
78
79define i32 @select_clz_to_ctz_and_commuted(i32 %a) {
80; CHECK-LABEL: @select_clz_to_ctz_and_commuted(
81; CHECK-NEXT:    [[COND:%.*]] = call i32 @llvm.cttz.i32(i32 [[A:%.*]], i1 true), !range !0
82; CHECK-NEXT:    ret i32 [[COND]]
83;
84  %sub = sub i32 0, %a
85  %and = and i32 %a, %sub
86  %lz = tail call i32 @llvm.ctlz.i32(i32 %and, i1 true)
87  %tobool = icmp eq i32 %a, 0
88  %sub1 = xor i32 %lz, 31
89  %cond = select i1 %tobool, i32 %lz, i32 %sub1
90  ret i32 %cond
91}
92
93define i32 @select_clz_to_ctz_icmp_ne(i32 %a) {
94; CHECK-LABEL: @select_clz_to_ctz_icmp_ne(
95; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp ne i32 [[A:%.*]], 0
96; CHECK-NEXT:    call void @use2(i1 [[TOBOOL]])
97; CHECK-NEXT:    [[COND:%.*]] = call i32 @llvm.cttz.i32(i32 [[A]], i1 true), !range !0
98; CHECK-NEXT:    ret i32 [[COND]]
99;
100  %sub = sub i32 0, %a
101  %and = and i32 %sub, %a
102  %lz = tail call i32 @llvm.ctlz.i32(i32 %and, i1 true)
103  %tobool = icmp ne i32 %a, 0
104  call void @use2(i1 %tobool)
105  %sub1 = xor i32 %lz, 31
106  %cond = select i1 %tobool, i32 %sub1, i32 %lz
107  ret i32 %cond
108}
109
110define i64 @select_clz_to_ctz_i64(i64 %a) {
111; CHECK-LABEL: @select_clz_to_ctz_i64(
112; CHECK-NEXT:    [[COND:%.*]] = call i64 @llvm.cttz.i64(i64 [[A:%.*]], i1 true), !range !1
113; CHECK-NEXT:    ret i64 [[COND]]
114;
115  %sub = sub i64 0, %a
116  %and = and i64 %sub, %a
117  %lz = tail call i64 @llvm.ctlz.i64(i64 %and, i1 true)
118  %tobool = icmp eq i64 %a, 0
119  %sub1 = xor i64 %lz, 63
120  %cond = select i1 %tobool, i64 %lz, i64 %sub1
121  ret i64 %cond
122}
123
124; Negative tests
125
126define i32 @select_clz_to_ctz_wrong_sub(i32 %a) {
127; CHECK-LABEL: @select_clz_to_ctz_wrong_sub(
128; CHECK-NEXT:    [[SUB:%.*]] = sub i32 1, [[A:%.*]]
129; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SUB]], [[A]]
130; CHECK-NEXT:    [[LZ:%.*]] = tail call i32 @llvm.ctlz.i32(i32 [[AND]], i1 true), !range !0
131; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i32 [[A]], 0
132; CHECK-NEXT:    [[SUB1:%.*]] = xor i32 [[LZ]], 31
133; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TOBOOL]], i32 [[LZ]], i32 [[SUB1]]
134; CHECK-NEXT:    ret i32 [[COND]]
135;
136  %sub = sub i32 1, %a
137  %and = and i32 %sub, %a
138  %lz = tail call i32 @llvm.ctlz.i32(i32 %and, i1 true)
139  %tobool = icmp eq i32 %a, 0
140  %sub1 = xor i32 %lz, 31
141  %cond = select i1 %tobool, i32 %lz, i32 %sub1
142  ret i32 %cond
143}
144
145define i64 @select_clz_to_ctz_i64_wrong_xor(i64 %a) {
146; CHECK-LABEL: @select_clz_to_ctz_i64_wrong_xor(
147; CHECK-NEXT:    [[SUB:%.*]] = sub i64 0, [[A:%.*]]
148; CHECK-NEXT:    [[AND:%.*]] = and i64 [[SUB]], [[A]]
149; CHECK-NEXT:    [[LZ:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[AND]], i1 true), !range !1
150; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i64 [[A]], 0
151; CHECK-NEXT:    [[SUB11:%.*]] = or i64 [[LZ]], 64
152; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TOBOOL]], i64 [[LZ]], i64 [[SUB11]]
153; CHECK-NEXT:    ret i64 [[COND]]
154;
155  %sub = sub i64 0, %a
156  %and = and i64 %sub, %a
157  %lz = tail call i64 @llvm.ctlz.i64(i64 %and, i1 true)
158  %tobool = icmp eq i64 %a, 0
159  %sub1 = xor i64 %lz, 64
160  %cond = select i1 %tobool, i64 %lz, i64 %sub1
161  ret i64 %cond
162}
163
164define i64 @select_clz_to_ctz_i64_wrong_icmp_cst(i64 %a) {
165; CHECK-LABEL: @select_clz_to_ctz_i64_wrong_icmp_cst(
166; CHECK-NEXT:    [[SUB:%.*]] = sub i64 0, [[A:%.*]]
167; CHECK-NEXT:    [[AND:%.*]] = and i64 [[SUB]], [[A]]
168; CHECK-NEXT:    [[LZ:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[AND]], i1 true), !range !1
169; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq i64 [[A]], 1
170; CHECK-NEXT:    [[SUB1:%.*]] = xor i64 [[LZ]], 63
171; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TOBOOL]], i64 [[LZ]], i64 [[SUB1]]
172; CHECK-NEXT:    ret i64 [[COND]]
173;
174  %sub = sub i64 0, %a
175  %and = and i64 %sub, %a
176  %lz = tail call i64 @llvm.ctlz.i64(i64 %and, i1 true)
177  %tobool = icmp eq i64 %a, 1
178  %sub1 = xor i64 %lz, 63
179  %cond = select i1 %tobool, i64 %lz, i64 %sub1
180  ret i64 %cond
181}
182
183define i64 @select_clz_to_ctz_i64_wrong_icmp_pred(i64 %a) {
184; CHECK-LABEL: @select_clz_to_ctz_i64_wrong_icmp_pred(
185; CHECK-NEXT:    [[SUB:%.*]] = sub i64 0, [[A:%.*]]
186; CHECK-NEXT:    [[AND:%.*]] = and i64 [[SUB]], [[A]]
187; CHECK-NEXT:    [[LZ:%.*]] = tail call i64 @llvm.ctlz.i64(i64 [[AND]], i1 true), !range !1
188; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp slt i64 [[A]], 0
189; CHECK-NEXT:    [[SUB1:%.*]] = xor i64 [[LZ]], 63
190; CHECK-NEXT:    [[COND:%.*]] = select i1 [[TOBOOL]], i64 [[LZ]], i64 [[SUB1]]
191; CHECK-NEXT:    ret i64 [[COND]]
192;
193  %sub = sub i64 0, %a
194  %and = and i64 %sub, %a
195  %lz = tail call i64 @llvm.ctlz.i64(i64 %and, i1 true)
196  %tobool = icmp slt i64 %a, 0
197  %sub1 = xor i64 %lz, 63
198  %cond = select i1 %tobool, i64 %lz, i64 %sub1
199  ret i64 %cond
200}
201
202define <2 x i32> @select_clz_to_ctz_vec_with_undef(<2 x i32> %a) {
203; CHECK-LABEL: @select_clz_to_ctz_vec_with_undef(
204; CHECK-NEXT:    [[SUB:%.*]] = sub <2 x i32> zeroinitializer, [[A:%.*]]
205; CHECK-NEXT:    [[AND:%.*]] = and <2 x i32> [[SUB]], [[A]]
206; CHECK-NEXT:    [[LZ:%.*]] = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> [[AND]], i1 true)
207; CHECK-NEXT:    [[TOBOOL:%.*]] = icmp eq <2 x i32> [[A]], zeroinitializer
208; CHECK-NEXT:    [[SUB1:%.*]] = xor <2 x i32> [[LZ]], <i32 31, i32 undef>
209; CHECK-NEXT:    [[COND:%.*]] = select <2 x i1> [[TOBOOL]], <2 x i32> [[LZ]], <2 x i32> [[SUB1]]
210; CHECK-NEXT:    ret <2 x i32> [[COND]]
211;
212  %sub = sub <2 x i32> zeroinitializer, %a
213  %and = and <2 x i32> %sub, %a
214  %lz = tail call <2 x i32> @llvm.ctlz.v2i32(<2 x i32> %and, i1 true)
215  %tobool = icmp eq <2 x i32> %a, zeroinitializer
216  %sub1 = xor <2 x i32> %lz, <i32 31, i32 undef>
217  %cond = select <2 x i1> %tobool, <2 x i32> %lz, <2 x i32> %sub1
218  ret <2 x i32> %cond
219}
220
221define i4 @PR45762(i3 %x4) {
222; CHECK-LABEL: @PR45762(
223; CHECK-NEXT:    [[T4:%.*]] = call i3 @llvm.cttz.i3(i3 [[X4:%.*]], i1 false), !range !2
224; CHECK-NEXT:    [[T7:%.*]] = zext i3 [[T4]] to i4
225; CHECK-NEXT:    [[ONE_HOT_16:%.*]] = shl i4 1, [[T7]]
226; CHECK-NEXT:    [[TMP1:%.*]] = icmp eq i3 [[X4]], 0
227; CHECK-NEXT:    [[UMUL_23:%.*]] = select i1 [[TMP1]], i4 0, i4 [[T7]]
228; CHECK-NEXT:    [[SEL_71:%.*]] = shl i4 [[ONE_HOT_16]], [[UMUL_23]]
229; CHECK-NEXT:    ret i4 [[SEL_71]]
230;
231  %t4 = call i3 @llvm.cttz.i3(i3 %x4, i1 false)
232  %t5 = icmp eq i3 %x4, 0
233  %t6 = select i1 %t5, i3 3, i3 %t4
234  %t7 = zext i3 %t6 to i4
235  %one_hot_16 = shl i4 1, %t7
236  %t8 = lshr i4 %one_hot_16, 0
237  %bit_slice_61 = trunc i4 %t8 to i1
238  %t9 = lshr i4 %one_hot_16, 1
239  %bit_slice_62 = trunc i4 %t9 to i1
240  %t10 = lshr i4 %one_hot_16, 2
241  %bit_slice_64 = trunc i4 %t10 to i1
242  %t11 = or i1 %bit_slice_61, %bit_slice_62
243  %or_69 = or i1 %t11, %bit_slice_64
244  %umul_23 = mul i4 %one_hot_16, %one_hot_16
245  %t12 = icmp eq i1 %or_69, false
246  %sel_71 = select i1 %t12, i4 %one_hot_16, i4 %umul_23
247  ret i4 %sel_71
248}
249