[Support] Recycler: Implement move constructor (#120555)
[llvm-project.git] / llvm / test / Transforms / InstCombine / fold-log2-ceil-idiom.ll
blob656673e7cb20ea5075aefee0c8f60f4a0110b7e8
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
2 ; RUN: opt < %s -passes=instcombine -S | FileCheck %s
4 define i32 @log2_ceil_idiom(i32 %x) {
5 ; CHECK-LABEL: define i32 @log2_ceil_idiom(
6 ; CHECK-SAME: i32 [[X:%.*]]) {
7 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], -1
8 ; CHECK-NEXT:    [[TMP2:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[TMP1]], i1 false)
9 ; CHECK-NEXT:    [[RET:%.*]] = sub nuw nsw i32 32, [[TMP2]]
10 ; CHECK-NEXT:    ret i32 [[RET]]
12   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
13   %xor = xor i32 %ctlz, 31
14   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
15   %cmp = icmp ugt i32 %ctpop, 1
16   %zext = zext i1 %cmp to i32
17   %ret = add i32 %xor, %zext
18   ret i32 %ret
21 define i5 @log2_ceil_idiom_trunc(i32 %x) {
22 ; CHECK-LABEL: define i5 @log2_ceil_idiom_trunc(
23 ; CHECK-SAME: i32 [[X:%.*]]) {
24 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], -1
25 ; CHECK-NEXT:    [[TMP2:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[TMP1]], i1 false)
26 ; CHECK-NEXT:    [[TMP3:%.*]] = sub nsw i32 0, [[TMP2]]
27 ; CHECK-NEXT:    [[RET:%.*]] = trunc i32 [[TMP3]] to i5
28 ; CHECK-NEXT:    ret i5 [[RET]]
30   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
31   %trunc = trunc i32 %ctlz to i5
32   %xor = xor i5 %trunc, 31
33   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
34   %cmp = icmp ugt i32 %ctpop, 1
35   %zext = zext i1 %cmp to i5
36   %ret = add i5 %xor, %zext
37   ret i5 %ret
40 define i64 @log2_ceil_idiom_zext(i32 %x) {
41 ; CHECK-LABEL: define i64 @log2_ceil_idiom_zext(
42 ; CHECK-SAME: i32 [[X:%.*]]) {
43 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], -1
44 ; CHECK-NEXT:    [[TMP2:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[TMP1]], i1 false)
45 ; CHECK-NEXT:    [[TMP3:%.*]] = sub nuw nsw i32 32, [[TMP2]]
46 ; CHECK-NEXT:    [[RET:%.*]] = zext nneg i32 [[TMP3]] to i64
47 ; CHECK-NEXT:    ret i64 [[RET]]
49   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
50   %xor = xor i32 %ctlz, 31
51   %ext = zext nneg i32 %xor to i64
52   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
53   %cmp = icmp ugt i32 %ctpop, 1
54   %zext = zext i1 %cmp to i64
55   %ret = add i64 %ext, %zext
56   ret i64 %ret
59 define i32 @log2_ceil_idiom_power2_test2(i32 %x) {
60 ; CHECK-LABEL: define i32 @log2_ceil_idiom_power2_test2(
61 ; CHECK-SAME: i32 [[X:%.*]]) {
62 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], -1
63 ; CHECK-NEXT:    [[TMP2:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[TMP1]], i1 false)
64 ; CHECK-NEXT:    [[RET:%.*]] = sub nuw nsw i32 32, [[TMP2]]
65 ; CHECK-NEXT:    ret i32 [[RET]]
67   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
68   %xor = xor i32 %ctlz, 31
69   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
70   %cmp = icmp ne i32 %ctpop, 1
71   %zext = zext i1 %cmp to i32
72   %ret = add i32 %xor, %zext
73   ret i32 %ret
76 define i32 @log2_ceil_idiom_commuted(i32 %x) {
77 ; CHECK-LABEL: define i32 @log2_ceil_idiom_commuted(
78 ; CHECK-SAME: i32 [[X:%.*]]) {
79 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], -1
80 ; CHECK-NEXT:    [[TMP2:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[TMP1]], i1 false)
81 ; CHECK-NEXT:    [[RET:%.*]] = sub nuw nsw i32 32, [[TMP2]]
82 ; CHECK-NEXT:    ret i32 [[RET]]
84   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
85   %xor = xor i32 %ctlz, 31
86   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
87   %cmp = icmp ugt i32 %ctpop, 1
88   %zext = zext i1 %cmp to i32
89   %ret = add i32 %zext, %xor
90   ret i32 %ret
93 define i32 @log2_ceil_idiom_multiuse1(i32 %x) {
94 ; CHECK-LABEL: define i32 @log2_ceil_idiom_multiuse1(
95 ; CHECK-SAME: i32 [[X:%.*]]) {
96 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
97 ; CHECK-NEXT:    call void @use32(i32 [[CTPOP]])
98 ; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[X]], -1
99 ; CHECK-NEXT:    [[TMP2:%.*]] = call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[TMP1]], i1 false)
100 ; CHECK-NEXT:    [[RET:%.*]] = sub nuw nsw i32 32, [[TMP2]]
101 ; CHECK-NEXT:    ret i32 [[RET]]
103   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
104   %xor = xor i32 %ctlz, 31
105   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
106   call void @use32(i32 %ctpop)
107   %cmp = icmp ugt i32 %ctpop, 1
108   %zext = zext i1 %cmp to i32
109   %ret = add i32 %xor, %zext
110   ret i32 %ret
113 ; Negative tests
115 define i32 @log2_ceil_idiom_x_may_be_zero(i32 %x) {
116 ; CHECK-LABEL: define i32 @log2_ceil_idiom_x_may_be_zero(
117 ; CHECK-SAME: i32 [[X:%.*]]) {
118 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 false)
119 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 31
120 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
121 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
122 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
123 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[XOR]], [[ZEXT]]
124 ; CHECK-NEXT:    ret i32 [[RET]]
126   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 false)
127   %xor = xor i32 %ctlz, 31
128   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
129   %cmp = icmp ugt i32 %ctpop, 1
130   %zext = zext i1 %cmp to i32
131   %ret = add i32 %xor, %zext
132   ret i32 %ret
135 define i4 @log2_ceil_idiom_trunc_too_short(i32 %x) {
136 ; CHECK-LABEL: define i4 @log2_ceil_idiom_trunc_too_short(
137 ; CHECK-SAME: i32 [[X:%.*]]) {
138 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
139 ; CHECK-NEXT:    [[TRUNC:%.*]] = trunc i32 [[CTLZ]] to i4
140 ; CHECK-NEXT:    [[XOR:%.*]] = xor i4 [[TRUNC]], -1
141 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
142 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
143 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i4
144 ; CHECK-NEXT:    [[RET:%.*]] = add i4 [[XOR]], [[ZEXT]]
145 ; CHECK-NEXT:    ret i4 [[RET]]
147   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
148   %trunc = trunc i32 %ctlz to i4
149   %xor = xor i4 %trunc, 31
150   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
151   %cmp = icmp ugt i32 %ctpop, 1
152   %zext = zext i1 %cmp to i4
153   %ret = add i4 %xor, %zext
154   ret i4 %ret
157 define i32 @log2_ceil_idiom_mismatched_operands(i32 %x, i32 %y) {
158 ; CHECK-LABEL: define i32 @log2_ceil_idiom_mismatched_operands(
159 ; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
160 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
161 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 31
162 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[Y]])
163 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
164 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
165 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[XOR]], [[ZEXT]]
166 ; CHECK-NEXT:    ret i32 [[RET]]
168   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
169   %xor = xor i32 %ctlz, 31
170   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %y)
171   %cmp = icmp ugt i32 %ctpop, 1
172   %zext = zext i1 %cmp to i32
173   %ret = add i32 %xor, %zext
174   ret i32 %ret
177 define i32 @log2_ceil_idiom_wrong_constant(i32 %x) {
178 ; CHECK-LABEL: define i32 @log2_ceil_idiom_wrong_constant(
179 ; CHECK-SAME: i32 [[X:%.*]]) {
180 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
181 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 30
182 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
183 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
184 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
185 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[XOR]], [[ZEXT]]
186 ; CHECK-NEXT:    ret i32 [[RET]]
188   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
189   %xor = xor i32 %ctlz, 30
190   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
191   %cmp = icmp ugt i32 %ctpop, 1
192   %zext = zext i1 %cmp to i32
193   %ret = add i32 %xor, %zext
194   ret i32 %ret
197 define i32 @log2_ceil_idiom_not_a_power2_test1(i32 %x) {
198 ; CHECK-LABEL: define i32 @log2_ceil_idiom_not_a_power2_test1(
199 ; CHECK-SAME: i32 [[X:%.*]]) {
200 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
201 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 31
202 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
203 ; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[CTPOP]], 1
204 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
205 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[XOR]], [[ZEXT]]
206 ; CHECK-NEXT:    ret i32 [[RET]]
208   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
209   %xor = xor i32 %ctlz, 31
210   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
211   %cmp = icmp eq i32 %ctpop, 1
212   %zext = zext i1 %cmp to i32
213   %ret = add i32 %xor, %zext
214   ret i32 %ret
217 define i32 @log2_ceil_idiom_not_a_power2_test2(i32 %x) {
218 ; CHECK-LABEL: define i32 @log2_ceil_idiom_not_a_power2_test2(
219 ; CHECK-SAME: i32 [[X:%.*]]) {
220 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
221 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 31
222 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
223 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 2
224 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
225 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[XOR]], [[ZEXT]]
226 ; CHECK-NEXT:    ret i32 [[RET]]
228   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
229   %xor = xor i32 %ctlz, 31
230   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
231   %cmp = icmp ugt i32 %ctpop, 2
232   %zext = zext i1 %cmp to i32
233   %ret = add i32 %xor, %zext
234   ret i32 %ret
237 define i32 @log2_ceil_idiom_multiuse2(i32 %x) {
238 ; CHECK-LABEL: define i32 @log2_ceil_idiom_multiuse2(
239 ; CHECK-SAME: i32 [[X:%.*]]) {
240 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
241 ; CHECK-NEXT:    call void @use32(i32 [[CTLZ]])
242 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 31
243 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
244 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
245 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
246 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[XOR]], [[ZEXT]]
247 ; CHECK-NEXT:    ret i32 [[RET]]
249   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
250   call void @use32(i32 %ctlz)
251   %xor = xor i32 %ctlz, 31
252   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
253   %cmp = icmp ugt i32 %ctpop, 1
254   %zext = zext i1 %cmp to i32
255   %ret = add i32 %xor, %zext
256   ret i32 %ret
259 define i32 @log2_ceil_idiom_multiuse3(i32 %x) {
260 ; CHECK-LABEL: define i32 @log2_ceil_idiom_multiuse3(
261 ; CHECK-SAME: i32 [[X:%.*]]) {
262 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
263 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 31
264 ; CHECK-NEXT:    call void @use32(i32 [[XOR]])
265 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
266 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
267 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i32
268 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i32 [[XOR]], [[ZEXT]]
269 ; CHECK-NEXT:    ret i32 [[RET]]
271   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
272   %xor = xor i32 %ctlz, 31
273   call void @use32(i32 %xor)
274   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
275   %cmp = icmp ugt i32 %ctpop, 1
276   %zext = zext i1 %cmp to i32
277   %ret = add i32 %xor, %zext
278   ret i32 %ret
281 define i5 @log2_ceil_idiom_trunc_multiuse4(i32 %x) {
282 ; CHECK-LABEL: define i5 @log2_ceil_idiom_trunc_multiuse4(
283 ; CHECK-SAME: i32 [[X:%.*]]) {
284 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
285 ; CHECK-NEXT:    [[TRUNC:%.*]] = trunc nuw i32 [[CTLZ]] to i5
286 ; CHECK-NEXT:    call void @use5(i5 [[TRUNC]])
287 ; CHECK-NEXT:    [[XOR:%.*]] = xor i5 [[TRUNC]], -1
288 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
289 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
290 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i5
291 ; CHECK-NEXT:    [[RET:%.*]] = add i5 [[XOR]], [[ZEXT]]
292 ; CHECK-NEXT:    ret i5 [[RET]]
294   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
295   %trunc = trunc i32 %ctlz to i5
296   call void @use5(i5 %trunc)
297   %xor = xor i5 %trunc, 31
298   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
299   %cmp = icmp ugt i32 %ctpop, 1
300   %zext = zext i1 %cmp to i5
301   %ret = add i5 %xor, %zext
302   ret i5 %ret
305 define i64 @log2_ceil_idiom_zext_multiuse5(i32 %x) {
306 ; CHECK-LABEL: define i64 @log2_ceil_idiom_zext_multiuse5(
307 ; CHECK-SAME: i32 [[X:%.*]]) {
308 ; CHECK-NEXT:    [[CTLZ:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctlz.i32(i32 [[X]], i1 true)
309 ; CHECK-NEXT:    [[XOR:%.*]] = xor i32 [[CTLZ]], 31
310 ; CHECK-NEXT:    [[EXT:%.*]] = zext nneg i32 [[XOR]] to i64
311 ; CHECK-NEXT:    call void @use64(i64 [[EXT]])
312 ; CHECK-NEXT:    [[CTPOP:%.*]] = tail call range(i32 0, 33) i32 @llvm.ctpop.i32(i32 [[X]])
313 ; CHECK-NEXT:    [[CMP:%.*]] = icmp samesign ugt i32 [[CTPOP]], 1
314 ; CHECK-NEXT:    [[ZEXT:%.*]] = zext i1 [[CMP]] to i64
315 ; CHECK-NEXT:    [[RET:%.*]] = add nuw nsw i64 [[EXT]], [[ZEXT]]
316 ; CHECK-NEXT:    ret i64 [[RET]]
318   %ctlz = tail call i32 @llvm.ctlz.i32(i32 %x, i1 true)
319   %xor = xor i32 %ctlz, 31
320   %ext = zext nneg i32 %xor to i64
321   call void @use64(i64 %ext)
322   %ctpop = tail call i32 @llvm.ctpop.i32(i32 %x)
323   %cmp = icmp ugt i32 %ctpop, 1
324   %zext = zext i1 %cmp to i64
325   %ret = add i64 %ext, %zext
326   ret i64 %ret
329 declare void @use5(i5)
330 declare void @use32(i32)
331 declare void @use64(i64)
333 declare i32 @llvm.ctlz.i32(i32, i1)
334 declare i32 @llvm.ctpop.i32(i32)