1 ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2 ; RUN: llc -mtriple=aarch64-unknown-linux-gnu < %s | FileCheck %s
4 ; https://bugs.llvm.org/show_bug.cgi?id=38149
6 ; We are truncating from wider width, and then sign-extending
7 ; back to the original width. Then we equality-comparing orig and src.
8 ; If they don't match, then we had signed truncation during truncation.
10 ; This can be expressed in a several ways in IR:
11 ; trunc + sext + icmp eq <- not canonical
12 ; shl + ashr + icmp eq
15 ; However only the simplest form (with two shifts) gets lowered best.
17 ; ---------------------------------------------------------------------------- ;
18 ; shl + ashr + icmp eq
19 ; ---------------------------------------------------------------------------- ;
21 define i1 @shifts_eqcmp_i16_i8(i16 %x) nounwind {
22 ; CHECK-LABEL: shifts_eqcmp_i16_i8:
24 ; CHECK-NEXT: sxtb w8, w0
25 ; CHECK-NEXT: and w8, w8, #0xffff
26 ; CHECK-NEXT: cmp w8, w0, uxth
27 ; CHECK-NEXT: cset w0, eq
29 %tmp0 = shl i16 %x, 8 ; 16-8
30 %tmp1 = ashr exact i16 %tmp0, 8 ; 16-8
31 %tmp2 = icmp eq i16 %tmp1, %x
35 define i1 @shifts_eqcmp_i32_i16(i32 %x) nounwind {
36 ; CHECK-LABEL: shifts_eqcmp_i32_i16:
38 ; CHECK-NEXT: sxth w8, w0
39 ; CHECK-NEXT: cmp w8, w0
40 ; CHECK-NEXT: cset w0, eq
42 %tmp0 = shl i32 %x, 16 ; 32-16
43 %tmp1 = ashr exact i32 %tmp0, 16 ; 32-16
44 %tmp2 = icmp eq i32 %tmp1, %x
48 define i1 @shifts_eqcmp_i32_i8(i32 %x) nounwind {
49 ; CHECK-LABEL: shifts_eqcmp_i32_i8:
51 ; CHECK-NEXT: sxtb w8, w0
52 ; CHECK-NEXT: cmp w8, w0
53 ; CHECK-NEXT: cset w0, eq
55 %tmp0 = shl i32 %x, 24 ; 32-8
56 %tmp1 = ashr exact i32 %tmp0, 24 ; 32-8
57 %tmp2 = icmp eq i32 %tmp1, %x
61 define i1 @shifts_eqcmp_i64_i32(i64 %x) nounwind {
62 ; CHECK-LABEL: shifts_eqcmp_i64_i32:
64 ; CHECK-NEXT: sxtw x8, w0
65 ; CHECK-NEXT: cmp x8, x0
66 ; CHECK-NEXT: cset w0, eq
68 %tmp0 = shl i64 %x, 32 ; 64-32
69 %tmp1 = ashr exact i64 %tmp0, 32 ; 64-32
70 %tmp2 = icmp eq i64 %tmp1, %x
74 define i1 @shifts_eqcmp_i64_i16(i64 %x) nounwind {
75 ; CHECK-LABEL: shifts_eqcmp_i64_i16:
77 ; CHECK-NEXT: sxth x8, w0
78 ; CHECK-NEXT: cmp x8, x0
79 ; CHECK-NEXT: cset w0, eq
81 %tmp0 = shl i64 %x, 48 ; 64-16
82 %tmp1 = ashr exact i64 %tmp0, 48 ; 64-16
83 %tmp2 = icmp eq i64 %tmp1, %x
87 define i1 @shifts_eqcmp_i64_i8(i64 %x) nounwind {
88 ; CHECK-LABEL: shifts_eqcmp_i64_i8:
90 ; CHECK-NEXT: sxtb x8, w0
91 ; CHECK-NEXT: cmp x8, x0
92 ; CHECK-NEXT: cset w0, eq
94 %tmp0 = shl i64 %x, 56 ; 64-8
95 %tmp1 = ashr exact i64 %tmp0, 56 ; 64-8
96 %tmp2 = icmp eq i64 %tmp1, %x
100 ; ---------------------------------------------------------------------------- ;
102 ; ---------------------------------------------------------------------------- ;
104 define i1 @add_ugecmp_i16_i8(i16 %x) nounwind {
105 ; CHECK-LABEL: add_ugecmp_i16_i8:
107 ; CHECK-NEXT: sub w8, w0, #128 // =128
108 ; CHECK-NEXT: ubfx w8, w8, #8, #8
109 ; CHECK-NEXT: cmp w8, #254 // =254
110 ; CHECK-NEXT: cset w0, hi
112 %tmp0 = add i16 %x, -128 ; ~0U << (8-1)
113 %tmp1 = icmp uge i16 %tmp0, -256 ; ~0U << 8
117 define i1 @add_ugecmp_i32_i16(i32 %x) nounwind {
118 ; CHECK-LABEL: add_ugecmp_i32_i16:
120 ; CHECK-NEXT: sub w8, w0, #8, lsl #12 // =32768
121 ; CHECK-NEXT: orr w9, wzr, #0xfffeffff
122 ; CHECK-NEXT: cmp w8, w9
123 ; CHECK-NEXT: cset w0, hi
125 %tmp0 = add i32 %x, -32768 ; ~0U << (16-1)
126 %tmp1 = icmp uge i32 %tmp0, -65536 ; ~0U << 16
130 define i1 @add_ugecmp_i32_i8(i32 %x) nounwind {
131 ; CHECK-LABEL: add_ugecmp_i32_i8:
133 ; CHECK-NEXT: sub w8, w0, #128 // =128
134 ; CHECK-NEXT: cmn w8, #257 // =257
135 ; CHECK-NEXT: cset w0, hi
137 %tmp0 = add i32 %x, -128 ; ~0U << (8-1)
138 %tmp1 = icmp uge i32 %tmp0, -256 ; ~0U << 8
142 define i1 @add_ugecmp_i64_i32(i64 %x) nounwind {
143 ; CHECK-LABEL: add_ugecmp_i64_i32:
145 ; CHECK-NEXT: mov x8, #-2147483648
146 ; CHECK-NEXT: add x8, x0, x8
147 ; CHECK-NEXT: orr x9, xzr, #0xfffffffeffffffff
148 ; CHECK-NEXT: cmp x8, x9
149 ; CHECK-NEXT: cset w0, hi
151 %tmp0 = add i64 %x, -2147483648 ; ~0U << (32-1)
152 %tmp1 = icmp uge i64 %tmp0, -4294967296 ; ~0U << 32
156 define i1 @add_ugecmp_i64_i16(i64 %x) nounwind {
157 ; CHECK-LABEL: add_ugecmp_i64_i16:
159 ; CHECK-NEXT: sub x8, x0, #8, lsl #12 // =32768
160 ; CHECK-NEXT: orr x9, xzr, #0xfffffffffffeffff
161 ; CHECK-NEXT: cmp x8, x9
162 ; CHECK-NEXT: cset w0, hi
164 %tmp0 = add i64 %x, -32768 ; ~0U << (16-1)
165 %tmp1 = icmp uge i64 %tmp0, -65536 ; ~0U << 16
169 define i1 @add_ugecmp_i64_i8(i64 %x) nounwind {
170 ; CHECK-LABEL: add_ugecmp_i64_i8:
172 ; CHECK-NEXT: sub x8, x0, #128 // =128
173 ; CHECK-NEXT: cmn x8, #257 // =257
174 ; CHECK-NEXT: cset w0, hi
176 %tmp0 = add i64 %x, -128 ; ~0U << (8-1)
177 %tmp1 = icmp uge i64 %tmp0, -256 ; ~0U << 8
181 ; ---------------------------------------------------------------------------- ;
183 ; ---------------------------------------------------------------------------- ;
185 define i1 @add_ultcmp_i16_i8(i16 %x) nounwind {
186 ; CHECK-LABEL: add_ultcmp_i16_i8:
188 ; CHECK-NEXT: sxtb w8, w0
189 ; CHECK-NEXT: and w8, w8, #0xffff
190 ; CHECK-NEXT: cmp w8, w0, uxth
191 ; CHECK-NEXT: cset w0, eq
193 %tmp0 = add i16 %x, 128 ; 1U << (8-1)
194 %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
198 define i1 @add_ultcmp_i32_i16(i32 %x) nounwind {
199 ; CHECK-LABEL: add_ultcmp_i32_i16:
201 ; CHECK-NEXT: sxth w8, w0
202 ; CHECK-NEXT: cmp w8, w0
203 ; CHECK-NEXT: cset w0, eq
205 %tmp0 = add i32 %x, 32768 ; 1U << (16-1)
206 %tmp1 = icmp ult i32 %tmp0, 65536 ; 1U << 16
210 define i1 @add_ultcmp_i32_i8(i32 %x) nounwind {
211 ; CHECK-LABEL: add_ultcmp_i32_i8:
213 ; CHECK-NEXT: sxtb w8, w0
214 ; CHECK-NEXT: cmp w8, w0
215 ; CHECK-NEXT: cset w0, eq
217 %tmp0 = add i32 %x, 128 ; 1U << (8-1)
218 %tmp1 = icmp ult i32 %tmp0, 256 ; 1U << 8
222 define i1 @add_ultcmp_i64_i32(i64 %x) nounwind {
223 ; CHECK-LABEL: add_ultcmp_i64_i32:
225 ; CHECK-NEXT: sxtw x8, w0
226 ; CHECK-NEXT: cmp x8, x0
227 ; CHECK-NEXT: cset w0, eq
229 %tmp0 = add i64 %x, 2147483648 ; 1U << (32-1)
230 %tmp1 = icmp ult i64 %tmp0, 4294967296 ; 1U << 32
234 define i1 @add_ultcmp_i64_i16(i64 %x) nounwind {
235 ; CHECK-LABEL: add_ultcmp_i64_i16:
237 ; CHECK-NEXT: sxth x8, w0
238 ; CHECK-NEXT: cmp x8, x0
239 ; CHECK-NEXT: cset w0, eq
241 %tmp0 = add i64 %x, 32768 ; 1U << (16-1)
242 %tmp1 = icmp ult i64 %tmp0, 65536 ; 1U << 16
246 define i1 @add_ultcmp_i64_i8(i64 %x) nounwind {
247 ; CHECK-LABEL: add_ultcmp_i64_i8:
249 ; CHECK-NEXT: sxtb x8, w0
250 ; CHECK-NEXT: cmp x8, x0
251 ; CHECK-NEXT: cset w0, eq
253 %tmp0 = add i64 %x, 128 ; 1U << (8-1)
254 %tmp1 = icmp ult i64 %tmp0, 256 ; 1U << 8
258 ; Slightly more canonical variant
259 define i1 @add_ulecmp_i16_i8(i16 %x) nounwind {
260 ; CHECK-LABEL: add_ulecmp_i16_i8:
262 ; CHECK-NEXT: sxtb w8, w0
263 ; CHECK-NEXT: and w8, w8, #0xffff
264 ; CHECK-NEXT: cmp w8, w0, uxth
265 ; CHECK-NEXT: cset w0, eq
267 %tmp0 = add i16 %x, 128 ; 1U << (8-1)
268 %tmp1 = icmp ule i16 %tmp0, 255 ; (1U << 8) - 1
273 ; ---------------------------------------------------------------------------- ;
275 ; Adding not a constant
276 define i1 @add_ultcmp_bad_i16_i8_add(i16 %x, i16 %y) nounwind {
277 ; CHECK-LABEL: add_ultcmp_bad_i16_i8_add:
279 ; CHECK-NEXT: add w8, w0, w1
280 ; CHECK-NEXT: and w8, w8, #0xffff
281 ; CHECK-NEXT: cmp w8, #256 // =256
282 ; CHECK-NEXT: cset w0, lo
284 %tmp0 = add i16 %x, %y
285 %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
289 ; Comparing not with a constant
290 define i1 @add_ultcmp_bad_i16_i8_cmp(i16 %x, i16 %y) nounwind {
291 ; CHECK-LABEL: add_ultcmp_bad_i16_i8_cmp:
293 ; CHECK-NEXT: add w8, w0, #128 // =128
294 ; CHECK-NEXT: and w8, w8, #0xffff
295 ; CHECK-NEXT: cmp w8, w1, uxth
296 ; CHECK-NEXT: cset w0, lo
298 %tmp0 = add i16 %x, 128 ; 1U << (8-1)
299 %tmp1 = icmp ult i16 %tmp0, %y
303 ; Second constant is not larger than the first one
304 define i1 @add_ultcmp_bad_i8_i16(i16 %x) nounwind {
305 ; CHECK-LABEL: add_ultcmp_bad_i8_i16:
307 ; CHECK-NEXT: and w8, w0, #0xffff
308 ; CHECK-NEXT: add w8, w8, #128 // =128
309 ; CHECK-NEXT: lsr w0, w8, #16
311 %tmp0 = add i16 %x, 128 ; 1U << (8-1)
312 %tmp1 = icmp ult i16 %tmp0, 128 ; 1U << (8-1)
316 ; First constant is not power of two
317 define i1 @add_ultcmp_bad_i16_i8_c0notpoweroftwo(i16 %x) nounwind {
318 ; CHECK-LABEL: add_ultcmp_bad_i16_i8_c0notpoweroftwo:
320 ; CHECK-NEXT: add w8, w0, #192 // =192
321 ; CHECK-NEXT: and w8, w8, #0xffff
322 ; CHECK-NEXT: cmp w8, #256 // =256
323 ; CHECK-NEXT: cset w0, lo
325 %tmp0 = add i16 %x, 192 ; (1U << (8-1)) + (1U << (8-1-1))
326 %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
330 ; Second constant is not power of two
331 define i1 @add_ultcmp_bad_i16_i8_c1notpoweroftwo(i16 %x) nounwind {
332 ; CHECK-LABEL: add_ultcmp_bad_i16_i8_c1notpoweroftwo:
334 ; CHECK-NEXT: add w8, w0, #128 // =128
335 ; CHECK-NEXT: and w8, w8, #0xffff
336 ; CHECK-NEXT: cmp w8, #768 // =768
337 ; CHECK-NEXT: cset w0, lo
339 %tmp0 = add i16 %x, 128 ; 1U << (8-1)
340 %tmp1 = icmp ult i16 %tmp0, 768 ; (1U << 8)) + (1U << (8+1))
344 ; Magic check fails, 64 << 1 != 256
345 define i1 @add_ultcmp_bad_i16_i8_magic(i16 %x) nounwind {
346 ; CHECK-LABEL: add_ultcmp_bad_i16_i8_magic:
348 ; CHECK-NEXT: add w8, w0, #64 // =64
349 ; CHECK-NEXT: and w8, w8, #0xffff
350 ; CHECK-NEXT: cmp w8, #256 // =256
351 ; CHECK-NEXT: cset w0, lo
353 %tmp0 = add i16 %x, 64 ; 1U << (8-1-1)
354 %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
358 ; Bad 'destination type'
359 define i1 @add_ultcmp_bad_i16_i4(i16 %x) nounwind {
360 ; CHECK-LABEL: add_ultcmp_bad_i16_i4:
362 ; CHECK-NEXT: add w8, w0, #8 // =8
363 ; CHECK-NEXT: and w8, w8, #0xffff
364 ; CHECK-NEXT: cmp w8, #16 // =16
365 ; CHECK-NEXT: cset w0, lo
367 %tmp0 = add i16 %x, 8 ; 1U << (4-1)
368 %tmp1 = icmp ult i16 %tmp0, 16 ; 1U << 4
373 define i1 @add_ultcmp_bad_i24_i8(i24 %x) nounwind {
374 ; CHECK-LABEL: add_ultcmp_bad_i24_i8:
376 ; CHECK-NEXT: add w8, w0, #128 // =128
377 ; CHECK-NEXT: and w8, w8, #0xffffff
378 ; CHECK-NEXT: cmp w8, #256 // =256
379 ; CHECK-NEXT: cset w0, lo
381 %tmp0 = add i24 %x, 128 ; 1U << (8-1)
382 %tmp1 = icmp ult i24 %tmp0, 256 ; 1U << 8
386 define i1 @add_ulecmp_bad_i16_i8(i16 %x) nounwind {
387 ; CHECK-LABEL: add_ulecmp_bad_i16_i8:
389 ; CHECK-NEXT: orr w0, wzr, #0x1
391 %tmp0 = add i16 %x, 128 ; 1U << (8-1)
392 %tmp1 = icmp ule i16 %tmp0, -1 ; when we +1 it, it will wrap to 0