[PowerPC] Generate Power9 extswsli extend sign and shift immediate instruction
[llvm-core.git] / test / CodeGen / AArch64 / signed-truncation-check.ll
blob6b5fffefe36731cbcab6a5ddf0309bdb631a5dbd
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
13 ;   add          + icmp uge
14 ;   add          + icmp ult/ule
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:
23 ; CHECK:       // %bb.0:
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
28 ; CHECK-NEXT:    ret
29   %tmp0 = shl i16 %x, 8 ; 16-8
30   %tmp1 = ashr exact i16 %tmp0, 8 ; 16-8
31   %tmp2 = icmp eq i16 %tmp1, %x
32   ret i1 %tmp2
35 define i1 @shifts_eqcmp_i32_i16(i32 %x) nounwind {
36 ; CHECK-LABEL: shifts_eqcmp_i32_i16:
37 ; CHECK:       // %bb.0:
38 ; CHECK-NEXT:    sxth w8, w0
39 ; CHECK-NEXT:    cmp w8, w0
40 ; CHECK-NEXT:    cset w0, eq
41 ; CHECK-NEXT:    ret
42   %tmp0 = shl i32 %x, 16 ; 32-16
43   %tmp1 = ashr exact i32 %tmp0, 16 ; 32-16
44   %tmp2 = icmp eq i32 %tmp1, %x
45   ret i1 %tmp2
48 define i1 @shifts_eqcmp_i32_i8(i32 %x) nounwind {
49 ; CHECK-LABEL: shifts_eqcmp_i32_i8:
50 ; CHECK:       // %bb.0:
51 ; CHECK-NEXT:    sxtb w8, w0
52 ; CHECK-NEXT:    cmp w8, w0
53 ; CHECK-NEXT:    cset w0, eq
54 ; CHECK-NEXT:    ret
55   %tmp0 = shl i32 %x, 24 ; 32-8
56   %tmp1 = ashr exact i32 %tmp0, 24 ; 32-8
57   %tmp2 = icmp eq i32 %tmp1, %x
58   ret i1 %tmp2
61 define i1 @shifts_eqcmp_i64_i32(i64 %x) nounwind {
62 ; CHECK-LABEL: shifts_eqcmp_i64_i32:
63 ; CHECK:       // %bb.0:
64 ; CHECK-NEXT:    sxtw x8, w0
65 ; CHECK-NEXT:    cmp x8, x0
66 ; CHECK-NEXT:    cset w0, eq
67 ; CHECK-NEXT:    ret
68   %tmp0 = shl i64 %x, 32 ; 64-32
69   %tmp1 = ashr exact i64 %tmp0, 32 ; 64-32
70   %tmp2 = icmp eq i64 %tmp1, %x
71   ret i1 %tmp2
74 define i1 @shifts_eqcmp_i64_i16(i64 %x) nounwind {
75 ; CHECK-LABEL: shifts_eqcmp_i64_i16:
76 ; CHECK:       // %bb.0:
77 ; CHECK-NEXT:    sxth x8, w0
78 ; CHECK-NEXT:    cmp x8, x0
79 ; CHECK-NEXT:    cset w0, eq
80 ; CHECK-NEXT:    ret
81   %tmp0 = shl i64 %x, 48 ; 64-16
82   %tmp1 = ashr exact i64 %tmp0, 48 ; 64-16
83   %tmp2 = icmp eq i64 %tmp1, %x
84   ret i1 %tmp2
87 define i1 @shifts_eqcmp_i64_i8(i64 %x) nounwind {
88 ; CHECK-LABEL: shifts_eqcmp_i64_i8:
89 ; CHECK:       // %bb.0:
90 ; CHECK-NEXT:    sxtb x8, w0
91 ; CHECK-NEXT:    cmp x8, x0
92 ; CHECK-NEXT:    cset w0, eq
93 ; CHECK-NEXT:    ret
94   %tmp0 = shl i64 %x, 56 ; 64-8
95   %tmp1 = ashr exact i64 %tmp0, 56 ; 64-8
96   %tmp2 = icmp eq i64 %tmp1, %x
97   ret i1 %tmp2
100 ; ---------------------------------------------------------------------------- ;
101 ; add + icmp uge
102 ; ---------------------------------------------------------------------------- ;
104 define i1 @add_ugecmp_i16_i8(i16 %x) nounwind {
105 ; CHECK-LABEL: add_ugecmp_i16_i8:
106 ; CHECK:       // %bb.0:
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
111 ; CHECK-NEXT:    ret
112   %tmp0 = add i16 %x, -128 ; ~0U << (8-1)
113   %tmp1 = icmp uge i16 %tmp0, -256 ; ~0U << 8
114   ret i1 %tmp1
117 define i1 @add_ugecmp_i32_i16(i32 %x) nounwind {
118 ; CHECK-LABEL: add_ugecmp_i32_i16:
119 ; CHECK:       // %bb.0:
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
124 ; CHECK-NEXT:    ret
125   %tmp0 = add i32 %x, -32768 ; ~0U << (16-1)
126   %tmp1 = icmp uge i32 %tmp0, -65536 ; ~0U << 16
127   ret i1 %tmp1
130 define i1 @add_ugecmp_i32_i8(i32 %x) nounwind {
131 ; CHECK-LABEL: add_ugecmp_i32_i8:
132 ; CHECK:       // %bb.0:
133 ; CHECK-NEXT:    sub w8, w0, #128 // =128
134 ; CHECK-NEXT:    cmn w8, #257 // =257
135 ; CHECK-NEXT:    cset w0, hi
136 ; CHECK-NEXT:    ret
137   %tmp0 = add i32 %x, -128 ; ~0U << (8-1)
138   %tmp1 = icmp uge i32 %tmp0, -256 ; ~0U << 8
139   ret i1 %tmp1
142 define i1 @add_ugecmp_i64_i32(i64 %x) nounwind {
143 ; CHECK-LABEL: add_ugecmp_i64_i32:
144 ; CHECK:       // %bb.0:
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
150 ; CHECK-NEXT:    ret
151   %tmp0 = add i64 %x, -2147483648 ; ~0U << (32-1)
152   %tmp1 = icmp uge i64 %tmp0, -4294967296 ; ~0U << 32
153   ret i1 %tmp1
156 define i1 @add_ugecmp_i64_i16(i64 %x) nounwind {
157 ; CHECK-LABEL: add_ugecmp_i64_i16:
158 ; CHECK:       // %bb.0:
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
163 ; CHECK-NEXT:    ret
164   %tmp0 = add i64 %x, -32768 ; ~0U << (16-1)
165   %tmp1 = icmp uge i64 %tmp0, -65536 ; ~0U << 16
166   ret i1 %tmp1
169 define i1 @add_ugecmp_i64_i8(i64 %x) nounwind {
170 ; CHECK-LABEL: add_ugecmp_i64_i8:
171 ; CHECK:       // %bb.0:
172 ; CHECK-NEXT:    sub x8, x0, #128 // =128
173 ; CHECK-NEXT:    cmn x8, #257 // =257
174 ; CHECK-NEXT:    cset w0, hi
175 ; CHECK-NEXT:    ret
176   %tmp0 = add i64 %x, -128 ; ~0U << (8-1)
177   %tmp1 = icmp uge i64 %tmp0, -256 ; ~0U << 8
178   ret i1 %tmp1
181 ; ---------------------------------------------------------------------------- ;
182 ; add + icmp ult
183 ; ---------------------------------------------------------------------------- ;
185 define i1 @add_ultcmp_i16_i8(i16 %x) nounwind {
186 ; CHECK-LABEL: add_ultcmp_i16_i8:
187 ; CHECK:       // %bb.0:
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
192 ; CHECK-NEXT:    ret
193   %tmp0 = add i16 %x, 128 ; 1U << (8-1)
194   %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
195   ret i1 %tmp1
198 define i1 @add_ultcmp_i32_i16(i32 %x) nounwind {
199 ; CHECK-LABEL: add_ultcmp_i32_i16:
200 ; CHECK:       // %bb.0:
201 ; CHECK-NEXT:    sxth w8, w0
202 ; CHECK-NEXT:    cmp w8, w0
203 ; CHECK-NEXT:    cset w0, eq
204 ; CHECK-NEXT:    ret
205   %tmp0 = add i32 %x, 32768 ; 1U << (16-1)
206   %tmp1 = icmp ult i32 %tmp0, 65536 ; 1U << 16
207   ret i1 %tmp1
210 define i1 @add_ultcmp_i32_i8(i32 %x) nounwind {
211 ; CHECK-LABEL: add_ultcmp_i32_i8:
212 ; CHECK:       // %bb.0:
213 ; CHECK-NEXT:    sxtb w8, w0
214 ; CHECK-NEXT:    cmp w8, w0
215 ; CHECK-NEXT:    cset w0, eq
216 ; CHECK-NEXT:    ret
217   %tmp0 = add i32 %x, 128 ; 1U << (8-1)
218   %tmp1 = icmp ult i32 %tmp0, 256 ; 1U << 8
219   ret i1 %tmp1
222 define i1 @add_ultcmp_i64_i32(i64 %x) nounwind {
223 ; CHECK-LABEL: add_ultcmp_i64_i32:
224 ; CHECK:       // %bb.0:
225 ; CHECK-NEXT:    sxtw x8, w0
226 ; CHECK-NEXT:    cmp x8, x0
227 ; CHECK-NEXT:    cset w0, eq
228 ; CHECK-NEXT:    ret
229   %tmp0 = add i64 %x, 2147483648 ; 1U << (32-1)
230   %tmp1 = icmp ult i64 %tmp0, 4294967296 ; 1U << 32
231   ret i1 %tmp1
234 define i1 @add_ultcmp_i64_i16(i64 %x) nounwind {
235 ; CHECK-LABEL: add_ultcmp_i64_i16:
236 ; CHECK:       // %bb.0:
237 ; CHECK-NEXT:    sxth x8, w0
238 ; CHECK-NEXT:    cmp x8, x0
239 ; CHECK-NEXT:    cset w0, eq
240 ; CHECK-NEXT:    ret
241   %tmp0 = add i64 %x, 32768 ; 1U << (16-1)
242   %tmp1 = icmp ult i64 %tmp0, 65536 ; 1U << 16
243   ret i1 %tmp1
246 define i1 @add_ultcmp_i64_i8(i64 %x) nounwind {
247 ; CHECK-LABEL: add_ultcmp_i64_i8:
248 ; CHECK:       // %bb.0:
249 ; CHECK-NEXT:    sxtb x8, w0
250 ; CHECK-NEXT:    cmp x8, x0
251 ; CHECK-NEXT:    cset w0, eq
252 ; CHECK-NEXT:    ret
253   %tmp0 = add i64 %x, 128 ; 1U << (8-1)
254   %tmp1 = icmp ult i64 %tmp0, 256 ; 1U << 8
255   ret i1 %tmp1
258 ; Slightly more canonical variant
259 define i1 @add_ulecmp_i16_i8(i16 %x) nounwind {
260 ; CHECK-LABEL: add_ulecmp_i16_i8:
261 ; CHECK:       // %bb.0:
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
266 ; CHECK-NEXT:    ret
267   %tmp0 = add i16 %x, 128 ; 1U << (8-1)
268   %tmp1 = icmp ule i16 %tmp0, 255 ; (1U << 8) - 1
269   ret i1 %tmp1
272 ; Negative tests
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:
278 ; CHECK:       // %bb.0:
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
283 ; CHECK-NEXT:    ret
284   %tmp0 = add i16 %x, %y
285   %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
286   ret i1 %tmp1
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:
292 ; CHECK:       // %bb.0:
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
297 ; CHECK-NEXT:    ret
298   %tmp0 = add i16 %x, 128 ; 1U << (8-1)
299   %tmp1 = icmp ult i16 %tmp0, %y
300   ret i1 %tmp1
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:
306 ; CHECK:       // %bb.0:
307 ; CHECK-NEXT:    and w8, w0, #0xffff
308 ; CHECK-NEXT:    add w8, w8, #128 // =128
309 ; CHECK-NEXT:    lsr w0, w8, #16
310 ; CHECK-NEXT:    ret
311   %tmp0 = add i16 %x, 128 ; 1U << (8-1)
312   %tmp1 = icmp ult i16 %tmp0, 128 ; 1U << (8-1)
313   ret i1 %tmp1
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:
319 ; CHECK:       // %bb.0:
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
324 ; CHECK-NEXT:    ret
325   %tmp0 = add i16 %x, 192 ; (1U << (8-1)) + (1U << (8-1-1))
326   %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
327   ret i1 %tmp1
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:
333 ; CHECK:       // %bb.0:
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
338 ; CHECK-NEXT:    ret
339   %tmp0 = add i16 %x, 128 ; 1U << (8-1)
340   %tmp1 = icmp ult i16 %tmp0, 768 ; (1U << 8)) + (1U << (8+1))
341   ret i1 %tmp1
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:
347 ; CHECK:       // %bb.0:
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
352 ; CHECK-NEXT:    ret
353   %tmp0 = add i16 %x, 64 ; 1U << (8-1-1)
354   %tmp1 = icmp ult i16 %tmp0, 256 ; 1U << 8
355   ret i1 %tmp1
358 ; Bad 'destination type'
359 define i1 @add_ultcmp_bad_i16_i4(i16 %x) nounwind {
360 ; CHECK-LABEL: add_ultcmp_bad_i16_i4:
361 ; CHECK:       // %bb.0:
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
366 ; CHECK-NEXT:    ret
367   %tmp0 = add i16 %x, 8 ; 1U << (4-1)
368   %tmp1 = icmp ult i16 %tmp0, 16 ; 1U << 4
369   ret i1 %tmp1
372 ; Bad storage type
373 define i1 @add_ultcmp_bad_i24_i8(i24 %x) nounwind {
374 ; CHECK-LABEL: add_ultcmp_bad_i24_i8:
375 ; CHECK:       // %bb.0:
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
380 ; CHECK-NEXT:    ret
381   %tmp0 = add i24 %x, 128 ; 1U << (8-1)
382   %tmp1 = icmp ult i24 %tmp0, 256 ; 1U << 8
383   ret i1 %tmp1
386 define i1 @add_ulecmp_bad_i16_i8(i16 %x) nounwind {
387 ; CHECK-LABEL: add_ulecmp_bad_i16_i8:
388 ; CHECK:       // %bb.0:
389 ; CHECK-NEXT:    orr w0, wzr, #0x1
390 ; CHECK-NEXT:    ret
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
393   ret i1 %tmp1