[RISCV][VLOPT] Add vector narrowing integer right shift instructions to isSupportedIn...
[llvm-project.git] / llvm / test / CodeGen / AArch64 / arm64_32.ll
blobcddadcab9cde18b7583564f0c1084cbdebac321b
1 ; RUN: llc -mtriple=arm64_32-apple-ios7.0 %s -filetype=obj -o - -disable-post-ra -frame-pointer=non-leaf | \
2 ; RUN:     llvm-objdump --private-headers - | \
3 ; RUN:     FileCheck %s --check-prefix=CHECK-MACHO
4 ; RUN: llc -mtriple=arm64_32-apple-ios7.0 %s -o - -aarch64-enable-atomic-cfg-tidy=0 -disable-post-ra -frame-pointer=non-leaf | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-OPT
5 ; RUN: llc -mtriple=arm64_32-apple-ios7.0 %s -o - -fast-isel -aarch64-enable-atomic-cfg-tidy=0 -disable-post-ra -frame-pointer=non-leaf | FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-FAST
7 ; CHECK-MACHO: Mach header
8 ; CHECK-MACHO: MH_MAGIC ARM64_32 V8
10 @var64 = global i64 zeroinitializer, align 8
11 @var32 = global i32 zeroinitializer, align 4
13 @var_got = external global i8
15 define ptr @test_global_addr() {
16 ; CHECK-LABEL: test_global_addr:
17 ; CHECK: adrp [[PAGE:x[0-9]+]], _var32@PAGE
18 ; CHECK-OPT: add x0, [[PAGE]], _var32@PAGEOFF
19 ; CHECK-FAST: add [[TMP:x[0-9]+]], [[PAGE]], _var32@PAGEOFF
20 ; CHECK-FAST: and x0, [[TMP]], #0xffffffff
21   ret ptr @var32
24 ; ADRP is necessarily 64-bit. The important point to check is that, however that
25 ; gets truncated to 32-bits, it's free. No need to zero out higher bits of that
26 ; register.
27 define i64 @test_global_addr_extension() {
28 ; CHECK-LABEL: test_global_addr_extension:
29 ; CHECK: adrp [[PAGE:x[0-9]+]], _var32@PAGE
30 ; CHECK: add x0, [[PAGE]], _var32@PAGEOFF
31 ; CHECK-NOT: and
32 ; CHECK: ret
34   ret i64 ptrtoint(ptr @var32 to i64)
37 define i32 @test_global_value() {
38 ; CHECK-LABEL: test_global_value:
39 ; CHECK: adrp x[[PAGE:[0-9]+]], _var32@PAGE
40 ; CHECK: ldr w0, [x[[PAGE]], _var32@PAGEOFF]
41   %val = load i32, ptr @var32, align 4
42   ret i32 %val
45 ; Because the addition may wrap, it is not safe to use "ldr w0, [xN, #32]" here.
46 define i32 @test_unsafe_indexed_add() {
47 ; CHECK-LABEL: test_unsafe_indexed_add:
48 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
49 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32
50 ; CHECK: ldr w0, [x[[ADDR]]]
51   %addr_int = ptrtoint ptr @var32 to i32
52   %addr_plus_32 = add i32 %addr_int, 32
53   %addr = inttoptr i32 %addr_plus_32 to ptr
54   %val = load i32, ptr %addr, align 4
55   ret i32 %val
58 ; Since we've promised there is no unsigned overflow, @var32 must be at least
59 ; 32-bytes below 2^32, and we can use the load this time.
60 define i32 @test_safe_indexed_add() {
61 ; CHECK-LABEL: test_safe_indexed_add:
62 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
63 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32
64 ; CHECK: ldr w0, [x[[ADDR]]]
65   %addr_int = ptrtoint ptr @var32 to i64
66   %addr_plus_32 = add nuw i64 %addr_int, 32
67   %addr = inttoptr i64 %addr_plus_32 to ptr
68   %val = load i32, ptr %addr, align 4
69   ret i32 %val
72 define i32 @test_safe_indexed_or(i32 %in) {
73 ; CHECK-LABEL: test_safe_indexed_or:
74 ; CHECK: and [[TMP:w[0-9]+]], {{w[0-9]+}}, #0xfffffff0
75 ; CHECK: orr w[[ADDR:[0-9]+]], [[TMP]], #0x4
76 ; CHECK: ldr w0, [x[[ADDR]]]
77   %addr_int = and i32 %in, -16
78   %addr_plus_4 = or i32 %addr_int, 4
79   %addr = inttoptr i32 %addr_plus_4 to ptr
80   %val = load i32, ptr %addr, align 4
81   ret i32 %val
85 ; Promising nsw is not sufficient because the addressing mode basically
86 ; calculates "zext(base) + zext(offset)" and nsw only guarantees
87 ; "sext(base) + sext(offset) == base + offset".
88 define i32 @test_unsafe_nsw_indexed_add() {
89 ; CHECK-LABEL: test_unsafe_nsw_indexed_add:
90 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
91 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32
92 ; CHECK-NOT: ubfx
93 ; CHECK: ldr w0, [x[[ADDR]]]
94   %addr_int = ptrtoint ptr @var32 to i32
95   %addr_plus_32 = add nsw i32 %addr_int, 32
96   %addr = inttoptr i32 %addr_plus_32 to ptr
97   %val = load i32, ptr %addr, align 4
98   ret i32 %val
101 ; Because the addition may wrap, it is not safe to use "ldr w0, [xN, #32]" here.
102 define i32 @test_unsafe_unscaled_add() {
103 ; CHECK-LABEL: test_unsafe_unscaled_add:
104 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
105 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3
106 ; CHECK: ldr w0, [x[[ADDR]]]
107   %addr_int = ptrtoint ptr @var32 to i32
108   %addr_plus_3 = add i32 %addr_int, 3
109   %addr = inttoptr i32 %addr_plus_3 to ptr
110   %val = load i32, ptr %addr, align 1
111   ret i32 %val
114 ; Since we've promised there is no unsigned overflow, @var32 must be at least
115 ; 32-bytes below 2^32, and we can use the load this time.
116 define i32 @test_safe_unscaled_add() {
117 ; CHECK-LABEL: test_safe_unscaled_add:
118 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
119 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3
120 ; CHECK: ldr w0, [x[[ADDR]]]
121   %addr_int = ptrtoint ptr @var32 to i32
122   %addr_plus_3 = add nuw i32 %addr_int, 3
123   %addr = inttoptr i32 %addr_plus_3 to ptr
124   %val = load i32, ptr %addr, align 1
125   ret i32 %val
128 ; Promising nsw is not sufficient because the addressing mode basically
129 ; calculates "zext(base) + zext(offset)" and nsw only guarantees
130 ; "sext(base) + sext(offset) == base + offset".
131 define i32 @test_unsafe_nsw_unscaled_add() {
132 ; CHECK-LABEL: test_unsafe_nsw_unscaled_add:
133 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
134 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3
135 ; CHECK-NOT: ubfx
136 ; CHECK: ldr w0, [x[[ADDR]]]
137   %addr_int = ptrtoint ptr @var32 to i32
138   %addr_plus_3 = add nsw i32 %addr_int, 3
139   %addr = inttoptr i32 %addr_plus_3 to ptr
140   %val = load i32, ptr %addr, align 1
141   ret i32 %val
144 ; Because the addition may wrap, it is not safe to use "ldur w0, [xN, #-3]"
145 ; here.
146 define i32 @test_unsafe_negative_unscaled_add() {
147 ; CHECK-LABEL: test_unsafe_negative_unscaled_add:
148 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
149 ; CHECK: sub w[[ADDR:[0-9]+]], w[[VAR32]], #3
150 ; CHECK: ldr w0, [x[[ADDR]]]
151   %addr_int = ptrtoint ptr @var32 to i32
152   %addr_minus_3 = add i32 %addr_int, -3
153   %addr = inttoptr i32 %addr_minus_3 to ptr
154   %val = load i32, ptr %addr, align 1
155   ret i32 %val
158 define ptr @test_got_addr() {
159 ; CHECK-LABEL: test_got_addr:
160 ; CHECK: adrp x[[PAGE:[0-9]+]], _var_got@GOTPAGE
161 ; CHECK-OPT: ldr w0, [x[[PAGE]], _var_got@GOTPAGEOFF]
162 ; CHECK-FAST: ldr w[[TMP:[0-9]+]], [x[[PAGE]], _var_got@GOTPAGEOFF]
163 ; CHECK-FAST: and x0, x[[TMP]], #0xffffffff
164   ret ptr @var_got
167 define float @test_va_arg_f32(ptr %list) {
168 ; CHECK-LABEL: test_va_arg_f32:
170 ; CHECK: ldr w[[START:[0-9]+]], [x0]
171 ; CHECK: add [[AFTER:w[0-9]+]], w[[START]], #8
172 ; CHECK: str [[AFTER]], [x0]
174   ; Floating point arguments get promoted to double as per C99.
175 ; CHECK: ldr [[DBL:d[0-9]+]], [x[[START]]]
176 ; CHECK: fcvt s0, [[DBL]]
177   %res = va_arg ptr %list, float
178   ret float %res
181 ; Interesting point is that the slot is 4 bytes.
182 define i8 @test_va_arg_i8(ptr %list) {
183 ; CHECK-LABEL: test_va_arg_i8:
185 ; CHECK: ldr w[[START:[0-9]+]], [x0]
186 ; CHECK: add [[AFTER:w[0-9]+]], w[[START]], #4
187 ; CHECK: str [[AFTER]], [x0]
189   ; i8 gets promoted to int (again, as per C99).
190 ; CHECK: ldr w0, [x[[START]]]
192   %res = va_arg ptr %list, i8
193   ret i8 %res
196 ; Interesting point is that the slot needs aligning (again, min size is 4
197 ; bytes).
198 define i64 @test_va_arg_i64(ptr %list) {
199 ; CHECK-LABEL: test_va_arg_i64:
201   ; Update the list for the next user (minimum slot size is 4, but the actual
202   ; argument is 8 which had better be reflected!)
203 ; CHECK: ldr w[[UNALIGNED_START:[0-9]+]], [x0]
204 ; CHECK: add [[ALIGN_TMP:x[0-9]+]], x[[UNALIGNED_START]], #7
205 ; CHECK: and x[[START:[0-9]+]], [[ALIGN_TMP]], #0x1fffffff8
206 ; CHECK: add w[[AFTER:[0-9]+]], w[[START]], #8
207 ; CHECK: str w[[AFTER]], [x0]
209 ; CHECK: ldr x0, [x[[START]]]
211   %res = va_arg ptr %list, i64
212   ret i64 %res
215 declare void @bar(...)
216 define void @test_va_call(i8 %l, i8 %r, float %in, ptr %ptr) {
217 ; CHECK-LABEL: test_va_call:
218 ; CHECK: add [[SUM:w[0-9]+]], {{w[0-9]+}}, w1
220 ; CHECK-DAG: str w2, [sp, #32]
221 ; CHECK-DAG: str xzr, [sp, #24]
222 ; CHECK-DAG: str s0, [sp, #16]
223 ; CHECK-DAG: str xzr, [sp, #8]
224 ; CHECK-DAG: str [[SUM]], [sp]
226   ; Add them to ensure real promotion occurs.
227   %sum = add i8 %l, %r
228   call void(...) @bar(i8 %sum, i64 0, float %in, double 0.0, ptr %ptr)
229   ret void
232 declare ptr @llvm.frameaddress(i32)
234 define ptr @test_frameaddr() {
235 ; CHECK-LABEL: test_frameaddr:
236 ; CHECK-OPT: ldr x0, [x29]
237 ; CHECK-FAST: ldr [[TMP:x[0-9]+]], [x29]
238 ; CHECK-FAST: and x0, [[TMP]], #0xffffffff
239   %val = call ptr @llvm.frameaddress(i32 1)
240   ret ptr %val
243 declare ptr @llvm.returnaddress(i32)
245 define ptr @test_toplevel_returnaddr() {
246 ; CHECK-LABEL: test_toplevel_returnaddr:
247 ; CHECK-OPT: mov x0, x30
248 ; CHECK-FAST: and x0, x30, #0xffffffff
249   %val = call ptr @llvm.returnaddress(i32 0)
250   ret ptr %val
253 define ptr @test_deep_returnaddr() {
254 ; CHECK-LABEL: test_deep_returnaddr:
255 ; CHECK: ldr x[[FRAME_REC:[0-9]+]], [x29]
256 ; CHECK-OPT: ldr x30, [x[[FRAME_REC]], #8]
257 ; CHECK-OPT: hint #7
258 ; CHECK-OPT: mov x0, x30
259 ; CHECK-FAST: ldr [[TMP:x[0-9]+]], [x[[FRAME_REC]], #8]
260 ; CHECK-FAST: and x0, [[TMP]], #0xffffffff
261   %val = call ptr @llvm.returnaddress(i32 1)
262   ret ptr %val
265 define void @test_indirect_call(ptr %func) {
266 ; CHECK-LABEL: test_indirect_call:
267 ; CHECK: blr x0
268   call void() %func()
269   ret void
272 ; Safe to use the unextended address here
273 define void @test_indirect_safe_call(ptr %weird_funcs) {
274 ; CHECK-LABEL: test_indirect_safe_call:
275 ; CHECK: add w[[ADDR32:[0-9]+]], w0, #4
276 ; CHECK-OPT-NOT: ubfx
277 ; CHECK: blr x[[ADDR32]]
278   %addr = getelementptr i32, ptr %weird_funcs, i32 1
279   call void() %addr()
280   ret void
283 declare void @simple()
284 define void @test_simple_tail_call() {
285 ; CHECK-LABEL: test_simple_tail_call:
286 ; CHECK: b _simple
287   tail call void @simple()
288   ret void
291 define void @test_indirect_tail_call(ptr %func) {
292 ; CHECK-LABEL: test_indirect_tail_call:
293 ; CHECK: br x0
294   tail call void() %func()
295   ret void
298 ; Safe to use the unextended address here
299 define void @test_indirect_safe_tail_call(ptr %weird_funcs) {
300 ; CHECK-LABEL: test_indirect_safe_tail_call:
301 ; CHECK: add w[[ADDR32:[0-9]+]], w0, #4
302 ; CHECK-OPT-NOT: ubfx
303 ; CHECK-OPT: br x[[ADDR32]]
304   %addr = getelementptr i32, ptr %weird_funcs, i32 1
305   tail call void() %addr()
306   ret void
309 ; For the "armv7k" slice, Clang will be emitting some small structs as [N x
310 ; i32]. For ABI compatibility with arm64_32 these need to be passed in *X*
311 ; registers (e.g. [2 x i32] would be packed into a single register).
313 define i32 @test_in_smallstruct_low([3 x i32] %in) {
314 ; CHECK-LABEL: test_in_smallstruct_low:
315 ; CHECK: mov x0, x1
316   %val = extractvalue [3 x i32] %in, 2
317   ret i32 %val
320 define i32 @test_in_smallstruct_high([3 x i32] %in) {
321 ; CHECK-LABEL: test_in_smallstruct_high:
322 ; CHECK: lsr x0, x0, #32
323   %val = extractvalue [3 x i32] %in, 1
324   ret i32 %val
327 ; The 64-bit DarwinPCS ABI has the quirk that structs on the stack are always
328 ; 64-bit aligned. This must not happen for arm64_32 since othwerwise va_arg will
329 ; be incompatible with the armv7k ABI.
330 define i32 @test_in_smallstruct_stack([8 x i64], i32, [3 x i32] %in) {
331 ; CHECK-LABEL: test_in_smallstruct_stack:
332 ; CHECK: ldr w0, [sp, #4]
333   %val = extractvalue [3 x i32] %in, 0
334   ret i32 %val
337 define [2 x i32] @test_ret_smallstruct([3 x i32] %in) {
338 ; CHECK-LABEL: test_ret_smallstruct:
339 ; CHECK: mov x0, #1
340 ; CHECK: movk x0, #2, lsl #32
342   ret [2 x i32] [i32 1, i32 2]
345 declare void @smallstruct_callee([4 x i32])
346 define void @test_call_smallstruct() {
347 ; CHECK-LABEL: test_call_smallstruct:
348 ; CHECK: mov x0, #1
349 ; CHECK: movk x0, #2, lsl #32
350 ; CHECK: mov x1, #3
351 ; CHECK: movk x1, #4, lsl #32
352 ; CHECK: bl _smallstruct_callee
354   call void @smallstruct_callee([4 x i32] [i32 1, i32 2, i32 3, i32 4])
355   ret void
358 declare void @smallstruct_callee_stack([8 x i64], i32, [2 x i32])
359 define void @test_call_smallstruct_stack() {
360 ; CHECK-LABEL: test_call_smallstruct_stack:
361 ; CHECK: mov [[VAL:x[0-9]+]], #1
362 ; CHECK: movk [[VAL]], #2, lsl #32
363 ; CHECK: stur [[VAL]], [sp, #4]
365   call void @smallstruct_callee_stack([8 x i64] undef, i32 undef, [2 x i32] [i32 1, i32 2])
366   ret void
369 declare [3 x i32] @returns_smallstruct()
370 define i32 @test_use_smallstruct_low() {
371 ; CHECK-LABEL: test_use_smallstruct_low:
372 ; CHECK: bl _returns_smallstruct
373 ; CHECK: mov x0, x1
375   %struct = call [3 x i32] @returns_smallstruct()
376   %val = extractvalue [3 x i32] %struct, 2
377   ret i32 %val
380 define i32 @test_use_smallstruct_high() {
381 ; CHECK-LABEL: test_use_smallstruct_high:
382 ; CHECK: bl _returns_smallstruct
383 ; CHECK: lsr x0, x0, #32
385   %struct = call [3 x i32] @returns_smallstruct()
386   %val = extractvalue [3 x i32] %struct, 1
387   ret i32 %val
390 ; If a small struct can't be allocated to x0-x7, the remaining registers should
391 ; be marked as unavailable and subsequent GPR arguments should also be on the
392 ; stack. Obviously the struct itself should be passed entirely on the stack.
393 define i32 @test_smallstruct_padding([7 x i64], [4 x i32] %struct, i32 %in) {
394 ; CHECK-LABEL: test_smallstruct_padding:
395 ; CHECK-DAG: ldr [[IN:w[0-9]+]], [sp, #16]
396 ; CHECK-DAG: ldr [[LHS:w[0-9]+]], [sp]
397 ; CHECK: add w0, [[LHS]], [[IN]]
398   %lhs = extractvalue [4 x i32] %struct, 0
399   %sum = add i32 %lhs, %in
400   ret i32 %sum
403 declare void @take_small_smallstruct(i64, [1 x i32])
404 define void @test_small_smallstruct() {
405 ; CHECK-LABEL: test_small_smallstruct:
406 ; CHECK-DAG: mov w0, #1
407 ; CHECK-DAG: mov w1, #2
408 ; CHECK: bl _take_small_smallstruct
409   call void @take_small_smallstruct(i64 1, [1 x i32] [i32 2])
410   ret void
413 define void @test_bare_frameaddr(ptr %addr) {
414 ; CHECK-LABEL: test_bare_frameaddr:
415 ; CHECK: add x[[LOCAL:[0-9]+]], sp, #{{[0-9]+}}
416 ; CHECK: str w[[LOCAL]],
418   %ptr = alloca i8
419   store ptr %ptr, ptr %addr, align 4
420   ret void
423 define void @test_sret_use(ptr sret([8 x i64]) %out) {
424 ; CHECK-LABEL: test_sret_use:
425 ; CHECK: str xzr, [x8]
426   store i64 0, ptr %out
427   ret void
430 define i64 @test_sret_call() {
431 ; CHECK-LABEL: test_sret_call:
432 ; CHECK: mov x8, sp
433 ; CHECK: bl _test_sret_use
434   %arr = alloca [8 x i64]
435   call void @test_sret_use(ptr sret([8 x i64]) %arr)
437   %val = load i64, ptr %arr
438   ret i64 %val
441 define double @test_constpool() {
442 ; CHECK-LABEL: test_constpool:
443 ; CHECK: adrp x[[PAGE:[0-9]+]], [[POOL:lCPI[0-9]+_[0-9]+]]@PAGE
444 ; CHECK: ldr d0, [x[[PAGE]], [[POOL]]@PAGEOFF]
445   ret double 1.0e-6
448 define ptr @test_blockaddress() {
449 ; CHECK-LABEL: test_blockaddress:
450 ; CHECK: [[BLOCK:Ltmp[0-9]+]]:
451 ; CHECK: adrp x[[PAGE:[0-9]+]], lCPI{{[0-9]+_[0-9]+}}@PAGE
452 ; CHECK: ldr x0, [x[[PAGE]], lCPI{{[0-9]+_[0-9]+}}@PAGEOFF]
453   br label %dest
454 dest:
455   ret ptr blockaddress(@test_blockaddress, %dest)
458 define ptr @test_indirectbr(ptr %dest) {
459 ; CHECK-LABEL: test_indirectbr:
460 ; CHECK: br x0
461   indirectbr ptr %dest, [label %true, label %false]
463 true:
464   ret ptr blockaddress(@test_indirectbr, %true)
465 false:
466   ret ptr blockaddress(@test_indirectbr, %false)
469 ; ISelDAGToDAG tries to fold an offset FI load (in this case var+4) into the
470 ; actual load instruction. This needs to be done slightly carefully since we
471 ; claim the FI in the process -- it doesn't need extending.
472 define float @test_frameindex_offset_load() {
473 ; CHECK-LABEL: test_frameindex_offset_load:
474 ; CHECK: ldr s0, [sp, #4]
475   %arr = alloca float, i32 4, align 8
476   %addr = getelementptr inbounds float, ptr %arr, i32 1
478   %val = load float, ptr %addr, align 4
479   ret float %val
482 define void @test_unaligned_frameindex_offset_store() {
483 ; CHECK-LABEL: test_unaligned_frameindex_offset_store:
484 ; CHECK: mov x[[TMP:[0-9]+]], sp
485 ; CHECK: orr w[[ADDR:[0-9]+]], w[[TMP]], #0x2
486 ; CHECK: mov [[VAL:w[0-9]+]], #42
487 ; CHECK: str [[VAL]], [x[[ADDR]]]
488   %arr = alloca [4 x i32]
490   %addr.int = ptrtoint ptr %arr to i32
491   %addr.nextint = add nuw i32 %addr.int, 2
492   %addr.next = inttoptr i32 %addr.nextint to ptr
493   store i32 42, ptr %addr.next
494   ret void
498 define {i64, ptr} @test_pre_idx(ptr %addr) {
499 ; CHECK-LABEL: test_pre_idx:
501 ; CHECK: add w[[ADDR:[0-9]+]], w0, #8
502 ; CHECK: ldr x0, [x[[ADDR]]]
503   %addr.int = ptrtoint ptr %addr to i32
504   %addr.next.int = add nuw i32 %addr.int, 8
505   %addr.next = inttoptr i32 %addr.next.int to ptr
506   %val = load i64, ptr %addr.next
508   %tmp = insertvalue {i64, ptr} undef, i64 %val, 0
509   %res = insertvalue {i64, ptr} %tmp, ptr %addr.next, 1
511   ret {i64, ptr} %res
514 ; Forming a post-indexed load is invalid here since the GEP needs to work when
515 ; %addr wraps round to 0.
516 define {i64, ptr} @test_invalid_pre_idx(ptr %addr) {
517 ; CHECK-LABEL: test_invalid_pre_idx:
518 ; CHECK: add w1, w0, #8
519 ; CHECK: ldr x0, [x1]
520   %addr.next = getelementptr i64, ptr %addr, i32 1
521   %val = load i64, ptr %addr.next
523   %tmp = insertvalue {i64, ptr} undef, i64 %val, 0
524   %res = insertvalue {i64, ptr} %tmp, ptr %addr.next, 1
526   ret {i64, ptr} %res
529 declare void @callee(ptr)
530 define void @test_stack_guard() ssp {
531 ; CHECK-LABEL: test_stack_guard:
532 ; CHECK: adrp x[[GUARD_GOTPAGE:[0-9]+]], ___stack_chk_guard@GOTPAGE
533 ; CHECK: ldr w[[GUARD_ADDR:[0-9]+]], [x[[GUARD_GOTPAGE]], ___stack_chk_guard@GOTPAGEOFF]
534 ; CHECK: ldr [[GUARD_VAL:w[0-9]+]], [x[[GUARD_ADDR]]]
535 ; CHECK: stur [[GUARD_VAL]], [x29, #[[GUARD_OFFSET:-[0-9]+]]]
537 ; CHECK: add x0, sp, #{{[0-9]+}}
538 ; CHECK: bl _callee
540 ; CHECK-OPT: adrp x[[GUARD_GOTPAGE:[0-9]+]], ___stack_chk_guard@GOTPAGE
541 ; CHECK-OPT: ldr w[[GUARD_ADDR:[0-9]+]], [x[[GUARD_GOTPAGE]], ___stack_chk_guard@GOTPAGEOFF]
542 ; CHECK-OPT: ldr [[GUARD_VAL:w[0-9]+]], [x[[GUARD_ADDR]]]
543 ; CHECK-OPT: ldur [[NEW_VAL:w[0-9]+]], [x29, #[[GUARD_OFFSET]]]
544 ; CHECK-OPT: cmp [[GUARD_VAL]], [[NEW_VAL]]
545 ; CHECK-OPT: b.ne [[FAIL:LBB[0-9]+_[0-9]+]]
547 ; CHECK-OPT: [[FAIL]]:
548 ; CHECK-OPT-NEXT: bl ___stack_chk_fail
549   %arr = alloca [8 x i32]
550   call void @callee(ptr %arr)
551   ret void
554 declare i32 @__gxx_personality_v0(...)
555 declare void @eat_landingpad_args(i32, ptr, i32)
556 @_ZTI8Whatever = external global i8
557 define void @test_landingpad_marshalling() personality ptr @__gxx_personality_v0 {
558 ; CHECK-LABEL: test_landingpad_marshalling:
559 ; CHECK-OPT: mov x2, x1
560 ; CHECK-OPT: mov x1, x0
561 ; CHECK: bl _eat_landingpad_args
562   invoke void @callee(ptr undef) to label %done unwind label %lpad
564 lpad:                                             ; preds = %entry
565   %exc = landingpad { ptr, i32 }
566           catch ptr @_ZTI8Whatever
567   %pointer = extractvalue { ptr, i32 } %exc, 0
568   %selector = extractvalue { ptr, i32 } %exc, 1
569   call void @eat_landingpad_args(i32 undef, ptr %pointer, i32 %selector)
570   ret void
572 done:
573   ret void
576 define void @test_dynamic_stackalloc() {
577 ; CHECK-LABEL: test_dynamic_stackalloc:
578 ; CHECK: sub [[REG:x[0-9]+]], sp, #32
579 ; CHECK: mov sp, [[REG]]
580 ; CHECK-OPT-NOT: ubfx
581 ; CHECK: bl _callee
582   br label %next
584 next:
585   %val = alloca [8 x i32]
586   call void @callee(ptr %val)
587   ret void
590 define void @test_asm_memory(ptr %base.addr) {
591 ; CHECK-LABEL: test_asm_memory:
592 ; CHECK: add w[[ADDR:[0-9]+]], w0, #4
593 ; CHECK: str wzr, [x[[ADDR]]
594   %addr = getelementptr i32, ptr %base.addr, i32 1
595   call void asm sideeffect "str wzr, $0", "*m"(ptr elementtype(i32) %addr)
596   ret void
599 define void @test_unsafe_asm_memory(i64 %val) {
600 ; CHECK-LABEL: test_unsafe_asm_memory:
601 ; CHECK: mov w[[ADDR:[0-9]+]], w0
602 ; CHECK: str wzr, [x[[ADDR]]]
603   %addr_int = trunc i64 %val to i32
604   %addr = inttoptr i32 %addr_int to ptr
605   call void asm sideeffect "str wzr, $0", "*m"(ptr elementtype(i32) %addr)
606   ret void
609 define [9 x ptr] @test_demoted_return(ptr %in) {
610 ; CHECK-LABEL: test_demoted_return:
611 ; CHECK: str w0, [x8, #32]
612   %res = insertvalue [9 x ptr] undef, ptr %in, 8
613   ret [9 x ptr] %res
616 define ptr @test_inttoptr(i64 %in) {
617 ; CHECK-LABEL: test_inttoptr:
618 ; CHECK-OPT: mov w0, w0
619 ; CHECK-FAST: and x0, x0, #0xffffffff
620   %res = inttoptr i64 %in to ptr
621   ret ptr %res
624 declare i32 @llvm.get.dynamic.area.offset.i32()
625 define i32 @test_dynamic_area() {
626 ; CHECK-LABEL: test_dynamic_area:
627 ; CHECK: mov w0, wzr
628   %res = call i32 @llvm.get.dynamic.area.offset.i32()
629   ret i32 %res
632 define void @test_pointer_vec_store(ptr %addr) {
633 ; CHECK-LABEL: test_pointer_vec_store:
634 ; CHECK: str xzr, [x0]
635 ; CHECK-NOT: str
636 ; CHECK-NOT: stp
638   store <2 x ptr> zeroinitializer, ptr %addr, align 16
639   ret void
642 define <2 x ptr> @test_pointer_vec_load(ptr %addr) {
643 ; CHECK-LABEL: test_pointer_vec_load:
644 ; CHECK: ldr d[[TMP:[0-9]+]], [x0]
645 ; CHECK: ushll.2d v0, v[[TMP]], #0
646   %val = load <2 x ptr>, ptr %addr, align 16
647   ret <2 x ptr> %val
650 define void @test_inline_asm_mem_pointer(ptr %in) {
651 ; CHECK-LABEL: test_inline_asm_mem_pointer:
652 ; CHECK: str w0,
653   tail call void asm sideeffect "ldr x0, $0", "m"(ptr %in)
654   ret void
658 define void @test_struct_hi(i32 %hi) nounwind {
659 ; CHECK-LABEL: test_struct_hi:
660 ; CHECK: mov w[[IN:[0-9]+]], w0
661 ; CHECK: bl _get_int
662 ; CHECK-FAST-NEXT: mov w[[DST:[0-9]+]], w0
663 ; CHECK-FAST-NEXT: orr x0, x[[DST]], x[[IN]], lsl #32
664 ; CHECK-OPT-NEXT: bfi x0, x[[IN]], #32, #32
665 ; CHECK-NEXT: bl _take_pair
666   %val.64 = call i64 @get_int()
667   %val.32 = trunc i64 %val.64 to i32
669   %pair.0 = insertvalue [2 x i32] undef, i32 %val.32, 0
670   %pair.1 = insertvalue [2 x i32] %pair.0, i32 %hi, 1
671   call void @take_pair([2 x i32] %pair.1)
673   ret void
675 declare void @take_pair([2 x i32])
676 declare i64 @get_int()
678 define i1 @test_icmp_ptr(ptr %in) {
679 ; CHECK-LABEL: test_icmp_ptr
680 ; CHECK: lsr w0, w0, #31
681   %res = icmp slt ptr %in, null
682   ret i1 %res
685 define void @test_multiple_icmp_ptr(ptr %l, ptr %r) {
686 ; CHECK-LABEL: test_multiple_icmp_ptr:
687 ; CHECK: tbnz w0, #31, [[FALSEBB:LBB[0-9]+_[0-9]+]]
688 ; CHECK: tbnz w1, #31, [[FALSEBB]]
689   %tst1 = icmp sgt ptr %l, inttoptr (i32 -1 to ptr)
690   %tst2 = icmp sgt ptr %r, inttoptr (i32 -1 to ptr)
691   %tst = and i1 %tst1, %tst2
692   br i1 %tst, label %true, label %false
694 true:
695   call void(...) @bar()
696   ret void
698 false:
699   ret void
702 define void @test_multiple_icmp_ptr_select(ptr %l, ptr %r) {
703 ; CHECK-LABEL: test_multiple_icmp_ptr_select:
704 ; CHECK: tbnz w0, #31, [[FALSEBB:LBB[0-9]+_[0-9]+]]
705 ; CHECK: tbnz w1, #31, [[FALSEBB]]
706   %tst1 = icmp sgt ptr %l, inttoptr (i32 -1 to ptr)
707   %tst2 = icmp sgt ptr %r, inttoptr (i32 -1 to ptr)
708   %tst = select i1 %tst1, i1 %tst2, i1 false
709   br i1 %tst, label %true, label %false
711 true:
712   call void(...) @bar()
713   ret void
715 false:
716   ret void
719 define ptr @test_gep_nonpow2(ptr %a0, i32 %a1) {
720 ; CHECK-LABEL: test_gep_nonpow2:
721 ; CHECK-OPT:      mov w[[SIZE:[0-9]+]], #18
722 ; CHECK-OPT-NEXT: smaddl x0, w1, w[[SIZE]], x0
723 ; CHECK-OPT-NEXT: ret
725 ; CHECK-FAST:      mov w[[SIZE:[0-9]+]], #18
726 ; CHECK-FAST-NEXT: smaddl [[TMP:x[0-9]+]], w1, w[[SIZE]], x0
727 ; CHECK-FAST-NEXT: and x0, [[TMP]], #0xffffffff
728 ; CHECK-FAST-NEXT: ret
729   %tmp0 = getelementptr inbounds { [18 x i8] }, ptr %a0, i32 %a1
730   ret ptr %tmp0
733 define void @test_memset(i64 %in, i8 %value)  {
734 ; CHECK-LABEL: test_memset:
735 ; CHECK-DAG: lsr x2, x0, #32
736 ; CHECK-DAG: mov w0, w0
737 ; CHECK: b _memset
739   %ptr.i32 = trunc i64 %in to i32
740   %size.64 = lshr i64 %in, 32
741   %size = trunc i64 %size.64 to i32
742   %ptr = inttoptr i32 %ptr.i32 to ptr
743   tail call void @llvm.memset.p0.i32(ptr align 4 %ptr, i8 %value, i32 %size, i1 false)
744   ret void
747 define void @test_bzero(i64 %in)  {
748 ; CHECK-LABEL: test_bzero:
749 ; CHECK-DAG: lsr x1, x0, #32
750 ; CHECK-DAG: mov w0, w0
751 ; CHECK: b _bzero
753   %ptr.i32 = trunc i64 %in to i32
754   %size.64 = lshr i64 %in, 32
755   %size = trunc i64 %size.64 to i32
756   %ptr = inttoptr i32 %ptr.i32 to ptr
757   tail call void @llvm.memset.p0.i32(ptr align 4 %ptr, i8 0, i32 %size, i1 false)
758   ret void
761 declare void @llvm.memset.p0.i32(ptr nocapture writeonly, i8, i32, i1)
763 define i1 @test_stackguard(ptr %p1) {
764 ; CHECK-LABEL: test_stackguard:
765 ; CHECK: adrp x[[TMP:[0-9]+]], ___stack_chk_guard@GOTPAGE
766 ; CHECK: ldr [[GUARD:w[0-9]+]], [x[[TMP]], ___stack_chk_guard@GOTPAGEOFF]
767 ; CHECK: cmp [[GUARD]], w
769   %p2 = call ptr @llvm.stackguard()
770   %res = icmp ne ptr %p2, %p1
771   ret i1 %res
773 declare ptr @llvm.stackguard()
774 @__stack_chk_guard = external global i32
777 !llvm.module.flags = !{!0}
778 !0 = !{i32 7, !"PIC Level", i32 2}