Revert 374373: [Codegen] Alter the default promotion for saturating adds and subs
[llvm-core.git] / test / CodeGen / AArch64 / arm64_32.ll
blob5fd619409a11d5c2dc6a72e061e8fc2c26802261
1 ; RUN: llc -mtriple=arm64_32-apple-ios7.0 %s -filetype=obj -o - -disable-post-ra -frame-pointer=all | \
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=all | 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=all | 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 i32* @test_global_addr() {
16 ; CHECK-LABEL: test_global_addr:
17 ; CHECK: adrp [[PAGE:x[0-9]+]], _var32@PAGE
18 ; CHECK: add x0, [[PAGE]], _var32@PAGEOFF
19   ret i32* @var32
22 ; ADRP is necessarily 64-bit. The important point to check is that, however that
23 ; gets truncated to 32-bits, it's free. No need to zero out higher bits of that
24 ; register.
25 define i64 @test_global_addr_extension() {
26 ; CHECK-LABEL: test_global_addr_extension:
27 ; CHECK: adrp [[PAGE:x[0-9]+]], _var32@PAGE
28 ; CHECK: add x0, [[PAGE]], _var32@PAGEOFF
29 ; CHECK-NOT: and
30 ; CHECK: ret
32   ret i64 ptrtoint(i32* @var32 to i64)
35 define i32 @test_global_value() {
36 ; CHECK-LABEL: test_global_value:
37 ; CHECK: adrp x[[PAGE:[0-9]+]], _var32@PAGE
38 ; CHECK: ldr w0, [x[[PAGE]], _var32@PAGEOFF]
39   %val = load i32, i32* @var32, align 4
40   ret i32 %val
43 ; Because the addition may wrap, it is not safe to use "ldr w0, [xN, #32]" here.
44 define i32 @test_unsafe_indexed_add() {
45 ; CHECK-LABEL: test_unsafe_indexed_add:
46 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
47 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32
48 ; CHECK: ldr w0, [x[[ADDR]]]
49   %addr_int = ptrtoint i32* @var32 to i32
50   %addr_plus_32 = add i32 %addr_int, 32
51   %addr = inttoptr i32 %addr_plus_32 to i32*
52   %val = load i32, i32* %addr, align 4
53   ret i32 %val
56 ; Since we've promised there is no unsigned overflow, @var32 must be at least
57 ; 32-bytes below 2^32, and we can use the load this time.
58 define i32 @test_safe_indexed_add() {
59 ; CHECK-LABEL: test_safe_indexed_add:
60 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
61 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32
62 ; CHECK: ldr w0, [x[[ADDR]]]
63   %addr_int = ptrtoint i32* @var32 to i64
64   %addr_plus_32 = add nuw i64 %addr_int, 32
65   %addr = inttoptr i64 %addr_plus_32 to i32*
66   %val = load i32, i32* %addr, align 4
67   ret i32 %val
70 define i32 @test_safe_indexed_or(i32 %in) {
71 ; CHECK-LABEL: test_safe_indexed_or:
72 ; CHECK: and [[TMP:w[0-9]+]], {{w[0-9]+}}, #0xfffffff0
73 ; CHECK: orr w[[ADDR:[0-9]+]], [[TMP]], #0x4
74 ; CHECK: ldr w0, [x[[ADDR]]]
75   %addr_int = and i32 %in, -16
76   %addr_plus_4 = or i32 %addr_int, 4
77   %addr = inttoptr i32 %addr_plus_4 to i32*
78   %val = load i32, i32* %addr, align 4
79   ret i32 %val
83 ; Promising nsw is not sufficient because the addressing mode basically
84 ; calculates "zext(base) + zext(offset)" and nsw only guarantees
85 ; "sext(base) + sext(offset) == base + offset".
86 define i32 @test_unsafe_nsw_indexed_add() {
87 ; CHECK-LABEL: test_unsafe_nsw_indexed_add:
88 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
89 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #32
90 ; CHECK-NOT: ubfx
91 ; CHECK: ldr w0, [x[[ADDR]]]
92   %addr_int = ptrtoint i32* @var32 to i32
93   %addr_plus_32 = add nsw i32 %addr_int, 32
94   %addr = inttoptr i32 %addr_plus_32 to i32*
95   %val = load i32, i32* %addr, align 4
96   ret i32 %val
99 ; Because the addition may wrap, it is not safe to use "ldr w0, [xN, #32]" here.
100 define i32 @test_unsafe_unscaled_add() {
101 ; CHECK-LABEL: test_unsafe_unscaled_add:
102 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
103 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3
104 ; CHECK: ldr w0, [x[[ADDR]]]
105   %addr_int = ptrtoint i32* @var32 to i32
106   %addr_plus_3 = add i32 %addr_int, 3
107   %addr = inttoptr i32 %addr_plus_3 to i32*
108   %val = load i32, i32* %addr, align 1
109   ret i32 %val
112 ; Since we've promised there is no unsigned overflow, @var32 must be at least
113 ; 32-bytes below 2^32, and we can use the load this time.
114 define i32 @test_safe_unscaled_add() {
115 ; CHECK-LABEL: test_safe_unscaled_add:
116 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
117 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3
118 ; CHECK: ldr w0, [x[[ADDR]]]
119   %addr_int = ptrtoint i32* @var32 to i32
120   %addr_plus_3 = add nuw i32 %addr_int, 3
121   %addr = inttoptr i32 %addr_plus_3 to i32*
122   %val = load i32, i32* %addr, align 1
123   ret i32 %val
126 ; Promising nsw is not sufficient because the addressing mode basically
127 ; calculates "zext(base) + zext(offset)" and nsw only guarantees
128 ; "sext(base) + sext(offset) == base + offset".
129 define i32 @test_unsafe_nsw_unscaled_add() {
130 ; CHECK-LABEL: test_unsafe_nsw_unscaled_add:
131 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
132 ; CHECK: add w[[ADDR:[0-9]+]], w[[VAR32]], #3
133 ; CHECK-NOT: ubfx
134 ; CHECK: ldr w0, [x[[ADDR]]]
135   %addr_int = ptrtoint i32* @var32 to i32
136   %addr_plus_3 = add nsw i32 %addr_int, 3
137   %addr = inttoptr i32 %addr_plus_3 to i32*
138   %val = load i32, i32* %addr, align 1
139   ret i32 %val
142 ; Because the addition may wrap, it is not safe to use "ldur w0, [xN, #-3]"
143 ; here.
144 define i32 @test_unsafe_negative_unscaled_add() {
145 ; CHECK-LABEL: test_unsafe_negative_unscaled_add:
146 ; CHECK: add x[[VAR32:[0-9]+]], {{x[0-9]+}}, _var32@PAGEOFF
147 ; CHECK: sub w[[ADDR:[0-9]+]], w[[VAR32]], #3
148 ; CHECK: ldr w0, [x[[ADDR]]]
149   %addr_int = ptrtoint i32* @var32 to i32
150   %addr_minus_3 = add i32 %addr_int, -3
151   %addr = inttoptr i32 %addr_minus_3 to i32*
152   %val = load i32, i32* %addr, align 1
153   ret i32 %val
156 define i8* @test_got_addr() {
157 ; CHECK-LABEL: test_got_addr:
158 ; CHECK: adrp x[[PAGE:[0-9]+]], _var_got@GOTPAGE
159 ; CHECK: ldr w0, [x[[PAGE]], _var_got@GOTPAGEOFF]
160   ret i8* @var_got
163 define float @test_va_arg_f32(i8** %list) {
164 ; CHECK-LABEL: test_va_arg_f32:
166 ; CHECK: ldr w[[START:[0-9]+]], [x0]
167 ; CHECK: add [[AFTER:w[0-9]+]], w[[START]], #8
168 ; CHECK: str [[AFTER]], [x0]
170   ; Floating point arguments get promoted to double as per C99.
171 ; CHECK: ldr [[DBL:d[0-9]+]], [x[[START]]]
172 ; CHECK: fcvt s0, [[DBL]]
173   %res = va_arg i8** %list, float
174   ret float %res
177 ; Interesting point is that the slot is 4 bytes.
178 define i8 @test_va_arg_i8(i8** %list) {
179 ; CHECK-LABEL: test_va_arg_i8:
181 ; CHECK: ldr w[[START:[0-9]+]], [x0]
182 ; CHECK: add [[AFTER:w[0-9]+]], w[[START]], #4
183 ; CHECK: str [[AFTER]], [x0]
185   ; i8 gets promoted to int (again, as per C99).
186 ; CHECK: ldr w0, [x[[START]]]
188   %res = va_arg i8** %list, i8
189   ret i8 %res
192 ; Interesting point is that the slot needs aligning (again, min size is 4
193 ; bytes).
194 define i64 @test_va_arg_i64(i64** %list) {
195 ; CHECK-LABEL: test_va_arg_i64:
197   ; Update the list for the next user (minimum slot size is 4, but the actual
198   ; argument is 8 which had better be reflected!)
199 ; CHECK: ldr w[[UNALIGNED_START:[0-9]+]], [x0]
200 ; CHECK: add [[ALIGN_TMP:x[0-9]+]], x[[UNALIGNED_START]], #7
201 ; CHECK: and x[[START:[0-9]+]], [[ALIGN_TMP]], #0x1fffffff8
202 ; CHECK: add w[[AFTER:[0-9]+]], w[[START]], #8
203 ; CHECK: str w[[AFTER]], [x0]
205 ; CHECK: ldr x0, [x[[START]]]
207   %res = va_arg i64** %list, i64
208   ret i64 %res
211 declare void @bar(...)
212 define void @test_va_call(i8 %l, i8 %r, float %in, i8* %ptr) {
213 ; CHECK-LABEL: test_va_call:
214 ; CHECK: add [[SUM:w[0-9]+]], {{w[0-9]+}}, w1
216 ; CHECK-DAG: str w2, [sp, #32]
217 ; CHECK-DAG: str xzr, [sp, #24]
218 ; CHECK-DAG: str s0, [sp, #16]
219 ; CHECK-DAG: str xzr, [sp, #8]
220 ; CHECK-DAG: str [[SUM]], [sp]
222   ; Add them to ensure real promotion occurs.
223   %sum = add i8 %l, %r
224   call void(...) @bar(i8 %sum, i64 0, float %in, double 0.0, i8* %ptr)
225   ret void
228 declare i8* @llvm.frameaddress(i32)
230 define i8* @test_frameaddr() {
231 ; CHECK-LABEL: test_frameaddr:
232 ; CHECK: ldr {{w0|x0}}, [x29]
233   %val = call i8* @llvm.frameaddress(i32 1)
234   ret i8* %val
237 declare i8* @llvm.returnaddress(i32)
239 define i8* @test_toplevel_returnaddr() {
240 ; CHECK-LABEL: test_toplevel_returnaddr:
241 ; CHECK: mov x0, x30
242   %val = call i8* @llvm.returnaddress(i32 0)
243   ret i8* %val
246 define i8* @test_deep_returnaddr() {
247 ; CHECK-LABEL: test_deep_returnaddr:
248 ; CHECK: ldr x[[FRAME_REC:[0-9]+]], [x29]
249 ; CHECK: ldr x0, [x[[FRAME_REC]], #8]
250   %val = call i8* @llvm.returnaddress(i32 1)
251   ret i8* %val
254 define void @test_indirect_call(void()* %func) {
255 ; CHECK-LABEL: test_indirect_call:
256 ; CHECK: blr x0
257   call void() %func()
258   ret void
261 ; Safe to use the unextended address here
262 define void @test_indirect_safe_call(i32* %weird_funcs) {
263 ; CHECK-LABEL: test_indirect_safe_call:
264 ; CHECK: add w[[ADDR32:[0-9]+]], w0, #4
265 ; CHECK-OPT-NOT: ubfx
266 ; CHECK: blr x[[ADDR32]]
267   %addr = getelementptr i32, i32* %weird_funcs, i32 1
268   %func = bitcast i32* %addr to void()*
269   call void() %func()
270   ret void
273 declare void @simple()
274 define void @test_simple_tail_call() {
275 ; CHECK-LABEL: test_simple_tail_call:
276 ; CHECK: b _simple
277   tail call void @simple()
278   ret void
281 define void @test_indirect_tail_call(void()* %func) {
282 ; CHECK-LABEL: test_indirect_tail_call:
283 ; CHECK: br x0
284   tail call void() %func()
285   ret void
288 ; Safe to use the unextended address here
289 define void @test_indirect_safe_tail_call(i32* %weird_funcs) {
290 ; CHECK-LABEL: test_indirect_safe_tail_call:
291 ; CHECK: add w[[ADDR32:[0-9]+]], w0, #4
292 ; CHECK-OPT-NOT: ubfx
293 ; CHECK-OPT: br x[[ADDR32]]
294   %addr = getelementptr i32, i32* %weird_funcs, i32 1
295   %func = bitcast i32* %addr to void()*
296   tail call void() %func()
297   ret void
300 ; For the "armv7k" slice, Clang will be emitting some small structs as [N x
301 ; i32]. For ABI compatibility with arm64_32 these need to be passed in *X*
302 ; registers (e.g. [2 x i32] would be packed into a single register).
304 define i32 @test_in_smallstruct_low([3 x i32] %in) {
305 ; CHECK-LABEL: test_in_smallstruct_low:
306 ; CHECK: mov x0, x1
307   %val = extractvalue [3 x i32] %in, 2
308   ret i32 %val
311 define i32 @test_in_smallstruct_high([3 x i32] %in) {
312 ; CHECK-LABEL: test_in_smallstruct_high:
313 ; CHECK: lsr x0, x0, #32
314   %val = extractvalue [3 x i32] %in, 1
315   ret i32 %val
318 ; The 64-bit DarwinPCS ABI has the quirk that structs on the stack are always
319 ; 64-bit aligned. This must not happen for arm64_32 since othwerwise va_arg will
320 ; be incompatible with the armv7k ABI.
321 define i32 @test_in_smallstruct_stack([8 x i64], i32, [3 x i32] %in) {
322 ; CHECK-LABEL: test_in_smallstruct_stack:
323 ; CHECK: ldr w0, [sp, #4]
324   %val = extractvalue [3 x i32] %in, 0
325   ret i32 %val
328 define [2 x i32] @test_ret_smallstruct([3 x i32] %in) {
329 ; CHECK-LABEL: test_ret_smallstruct:
330 ; CHECK: mov x0, #1
331 ; CHECK: movk x0, #2, lsl #32
333   ret [2 x i32] [i32 1, i32 2]
336 declare void @smallstruct_callee([4 x i32])
337 define void @test_call_smallstruct() {
338 ; CHECK-LABEL: test_call_smallstruct:
339 ; CHECK: mov x0, #1
340 ; CHECK: movk x0, #2, lsl #32
341 ; CHECK: mov x1, #3
342 ; CHECK: movk x1, #4, lsl #32
343 ; CHECK: bl _smallstruct_callee
345   call void @smallstruct_callee([4 x i32] [i32 1, i32 2, i32 3, i32 4])
346   ret void
349 declare void @smallstruct_callee_stack([8 x i64], i32, [2 x i32])
350 define void @test_call_smallstruct_stack() {
351 ; CHECK-LABEL: test_call_smallstruct_stack:
352 ; CHECK: mov [[VAL:x[0-9]+]], #1
353 ; CHECK: movk [[VAL]], #2, lsl #32
354 ; CHECK: stur [[VAL]], [sp, #4]
356   call void @smallstruct_callee_stack([8 x i64] undef, i32 undef, [2 x i32] [i32 1, i32 2])
357   ret void
360 declare [3 x i32] @returns_smallstruct()
361 define i32 @test_use_smallstruct_low() {
362 ; CHECK-LABEL: test_use_smallstruct_low:
363 ; CHECK: bl _returns_smallstruct
364 ; CHECK: mov x0, x1
366   %struct = call [3 x i32] @returns_smallstruct()
367   %val = extractvalue [3 x i32] %struct, 2
368   ret i32 %val
371 define i32 @test_use_smallstruct_high() {
372 ; CHECK-LABEL: test_use_smallstruct_high:
373 ; CHECK: bl _returns_smallstruct
374 ; CHECK: lsr x0, x0, #32
376   %struct = call [3 x i32] @returns_smallstruct()
377   %val = extractvalue [3 x i32] %struct, 1
378   ret i32 %val
381 ; If a small struct can't be allocated to x0-x7, the remaining registers should
382 ; be marked as unavailable and subsequent GPR arguments should also be on the
383 ; stack. Obviously the struct itself should be passed entirely on the stack.
384 define i32 @test_smallstruct_padding([7 x i64], [4 x i32] %struct, i32 %in) {
385 ; CHECK-LABEL: test_smallstruct_padding:
386 ; CHECK-DAG: ldr [[IN:w[0-9]+]], [sp, #16]
387 ; CHECK-DAG: ldr [[LHS:w[0-9]+]], [sp]
388 ; CHECK: add w0, [[LHS]], [[IN]]
389   %lhs = extractvalue [4 x i32] %struct, 0
390   %sum = add i32 %lhs, %in
391   ret i32 %sum
394 declare void @take_small_smallstruct(i64, [1 x i32])
395 define void @test_small_smallstruct() {
396 ; CHECK-LABEL: test_small_smallstruct:
397 ; CHECK-DAG: mov w0, #1
398 ; CHECK-DAG: mov w1, #2
399 ; CHECK: bl _take_small_smallstruct
400   call void @take_small_smallstruct(i64 1, [1 x i32] [i32 2])
401   ret void
404 define void @test_bare_frameaddr(i8** %addr) {
405 ; CHECK-LABEL: test_bare_frameaddr:
406 ; CHECK: add x[[LOCAL:[0-9]+]], sp, #{{[0-9]+}}
407 ; CHECK: str w[[LOCAL]],
409   %ptr = alloca i8
410   store i8* %ptr, i8** %addr, align 4
411   ret void
414 define void @test_sret_use([8 x i64]* sret %out) {
415 ; CHECK-LABEL: test_sret_use:
416 ; CHECK: str xzr, [x8]
417   %addr = getelementptr [8 x i64], [8 x i64]* %out, i32 0, i32 0
418   store i64 0, i64* %addr
419   ret void
422 define i64 @test_sret_call() {
423 ; CHECK-LABEL: test_sret_call:
424 ; CHECK: mov x8, sp
425 ; CHECK: bl _test_sret_use
426   %arr = alloca [8 x i64]
427   call void @test_sret_use([8 x i64]* sret %arr)
429   %addr = getelementptr [8 x i64], [8 x i64]* %arr, i32 0, i32 0
430   %val = load i64, i64* %addr
431   ret i64 %val
434 define double @test_constpool() {
435 ; CHECK-LABEL: test_constpool:
436 ; CHECK: adrp x[[PAGE:[0-9]+]], [[POOL:lCPI[0-9]+_[0-9]+]]@PAGE
437 ; CHECK: ldr d0, [x[[PAGE]], [[POOL]]@PAGEOFF]
438   ret double 1.0e-6
441 define i8* @test_blockaddress() {
442 ; CHECK-LABEL: test_blockaddress:
443 ; CHECK: [[BLOCK:Ltmp[0-9]+]]:
444 ; CHECK: adrp [[PAGE:x[0-9]+]], [[BLOCK]]@PAGE
445 ; CHECK: add x0, [[PAGE]], [[BLOCK]]@PAGEOFF
446   br label %dest
447 dest:
448   ret i8* blockaddress(@test_blockaddress, %dest)
451 define i8* @test_indirectbr(i8* %dest) {
452 ; CHECK-LABEL: test_indirectbr:
453 ; CHECK: br x0
454   indirectbr i8* %dest, [label %true, label %false]
456 true:
457   ret i8* blockaddress(@test_indirectbr, %true)
458 false:
459   ret i8* blockaddress(@test_indirectbr, %false)
462 ; ISelDAGToDAG tries to fold an offset FI load (in this case var+4) into the
463 ; actual load instruction. This needs to be done slightly carefully since we
464 ; claim the FI in the process -- it doesn't need extending.
465 define float @test_frameindex_offset_load() {
466 ; CHECK-LABEL: test_frameindex_offset_load:
467 ; CHECK: ldr s0, [sp, #4]
468   %arr = alloca float, i32 4, align 8
469   %addr = getelementptr inbounds float, float* %arr, i32 1
471   %val = load float, float* %addr, align 4
472   ret float %val
475 define void @test_unaligned_frameindex_offset_store() {
476 ; CHECK-LABEL: test_unaligned_frameindex_offset_store:
477 ; CHECK: mov x[[TMP:[0-9]+]], sp
478 ; CHECK: orr w[[ADDR:[0-9]+]], w[[TMP]], #0x2
479 ; CHECK: mov [[VAL:w[0-9]+]], #42
480 ; CHECK: str [[VAL]], [x[[ADDR]]]
481   %arr = alloca [4 x i32]
483   %addr.int = ptrtoint [4 x i32]* %arr to i32
484   %addr.nextint = add nuw i32 %addr.int, 2
485   %addr.next = inttoptr i32 %addr.nextint to i32*
486   store i32 42, i32* %addr.next
487   ret void
491 define {i64, i64*} @test_pre_idx(i64* %addr) {
492 ; CHECK-LABEL: test_pre_idx:
494 ; CHECK: add w[[ADDR:[0-9]+]], w0, #8
495 ; CHECK: ldr x0, [x[[ADDR]]]
496   %addr.int = ptrtoint i64* %addr to i32
497   %addr.next.int = add nuw i32 %addr.int, 8
498   %addr.next = inttoptr i32 %addr.next.int to i64*
499   %val = load i64, i64* %addr.next
501   %tmp = insertvalue {i64, i64*} undef, i64 %val, 0
502   %res = insertvalue {i64, i64*} %tmp, i64* %addr.next, 1
504   ret {i64, i64*} %res
507 ; Forming a post-indexed load is invalid here since the GEP needs to work when
508 ; %addr wraps round to 0.
509 define {i64, i64*} @test_invalid_pre_idx(i64* %addr) {
510 ; CHECK-LABEL: test_invalid_pre_idx:
511 ; CHECK: add w1, w0, #8
512 ; CHECK: ldr x0, [x1]
513   %addr.next = getelementptr i64, i64* %addr, i32 1
514   %val = load i64, i64* %addr.next
516   %tmp = insertvalue {i64, i64*} undef, i64 %val, 0
517   %res = insertvalue {i64, i64*} %tmp, i64* %addr.next, 1
519   ret {i64, i64*} %res
522 declare void @callee([8 x i32]*)
523 define void @test_stack_guard() ssp {
524 ; CHECK-LABEL: test_stack_guard:
525 ; CHECK: adrp x[[GUARD_GOTPAGE:[0-9]+]], ___stack_chk_guard@GOTPAGE
526 ; CHECK: ldr w[[GUARD_ADDR:[0-9]+]], [x[[GUARD_GOTPAGE]], ___stack_chk_guard@GOTPAGEOFF]
527 ; CHECK: ldr [[GUARD_VAL:w[0-9]+]], [x[[GUARD_ADDR]]]
528 ; CHECK: stur [[GUARD_VAL]], [x29, #[[GUARD_OFFSET:-[0-9]+]]]
530 ; CHECK: add x0, sp, #{{[0-9]+}}
531 ; CHECK: bl _callee
533 ; CHECK-OPT: adrp x[[GUARD_GOTPAGE:[0-9]+]], ___stack_chk_guard@GOTPAGE
534 ; CHECK-OPT: ldr w[[GUARD_ADDR:[0-9]+]], [x[[GUARD_GOTPAGE]], ___stack_chk_guard@GOTPAGEOFF]
535 ; CHECK-OPT: ldr [[GUARD_VAL:w[0-9]+]], [x[[GUARD_ADDR]]]
536 ; CHECK-OPT: ldur [[NEW_VAL:w[0-9]+]], [x29, #[[GUARD_OFFSET]]]
537 ; CHECK-OPT: cmp [[GUARD_VAL]], [[NEW_VAL]]
538 ; CHECK-OPT: b.ne [[FAIL:LBB[0-9]+_[0-9]+]]
540 ; CHECK-OPT: [[FAIL]]:
541 ; CHECK-OPT-NEXT: bl ___stack_chk_fail
542   %arr = alloca [8 x i32]
543   call void @callee([8 x i32]* %arr)
544   ret void
547 declare i32 @__gxx_personality_v0(...)
548 declare void @eat_landingpad_args(i32, i8*, i32)
549 @_ZTI8Whatever = external global i8
550 define void @test_landingpad_marshalling() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
551 ; CHECK-LABEL: test_landingpad_marshalling:
552 ; CHECK-OPT: mov x2, x1
553 ; CHECK-OPT: mov x1, x0
554 ; CHECK: bl _eat_landingpad_args
555   invoke void @callee([8 x i32]* undef) to label %done unwind label %lpad
557 lpad:                                             ; preds = %entry
558   %exc = landingpad { i8*, i32 }
559           catch i8* @_ZTI8Whatever
560   %pointer = extractvalue { i8*, i32 } %exc, 0
561   %selector = extractvalue { i8*, i32 } %exc, 1
562   call void @eat_landingpad_args(i32 undef, i8* %pointer, i32 %selector)
563   ret void
565 done:
566   ret void
569 define void @test_dynamic_stackalloc() {
570 ; CHECK-LABEL: test_dynamic_stackalloc:
571 ; CHECK: sub [[REG:x[0-9]+]], sp, #32
572 ; CHECK: mov sp, [[REG]]
573 ; CHECK-OPT-NOT: ubfx
574 ; CHECK: bl _callee
575   br label %next
577 next:
578   %val = alloca [8 x i32]
579   call void @callee([8 x i32]* %val)
580   ret void
583 define void @test_asm_memory(i32* %base.addr) {
584 ; CHECK-LABEL: test_asm_memory:
585 ; CHECK: add w[[ADDR:[0-9]+]], w0, #4
586 ; CHECK: str wzr, [x[[ADDR]]
587   %addr = getelementptr i32, i32* %base.addr, i32 1
588   call void asm sideeffect "str wzr, $0", "*m"(i32* %addr)
589   ret void
592 define void @test_unsafe_asm_memory(i64 %val) {
593 ; CHECK-LABEL: test_unsafe_asm_memory:
594 ; CHECK: and x[[ADDR:[0-9]+]], x0, #0xffffffff
595 ; CHECK: str wzr, [x[[ADDR]]]
596   %addr_int = trunc i64 %val to i32
597   %addr = inttoptr i32 %addr_int to i32*
598   call void asm sideeffect "str wzr, $0", "*m"(i32* %addr)
599   ret void
602 define [9 x i8*] @test_demoted_return(i8* %in) {
603 ; CHECK-LABEL: test_demoted_return:
604 ; CHECK: str w0, [x8, #32]
605   %res = insertvalue [9 x i8*] undef, i8* %in, 8
606   ret [9 x i8*] %res
609 define i8* @test_inttoptr(i64 %in) {
610 ; CHECK-LABEL: test_inttoptr:
611 ; CHECK: and x0, x0, #0xffffffff
612   %res = inttoptr i64 %in to i8*
613   ret i8* %res
616 declare i32 @llvm.get.dynamic.area.offset.i32()
617 define i32 @test_dynamic_area() {
618 ; CHECK-LABEL: test_dynamic_area:
619 ; CHECK: mov w0, wzr
620   %res = call i32 @llvm.get.dynamic.area.offset.i32()
621   ret i32 %res
624 define void @test_pointer_vec_store(<2 x i8*>* %addr) {
625 ; CHECK-LABEL: test_pointer_vec_store:
626 ; CHECK: str xzr, [x0]
627 ; CHECK-NOT: str
628 ; CHECK-NOT: stp
630   store <2 x i8*> zeroinitializer, <2 x i8*>* %addr, align 16
631   ret void
634 define <2 x i8*> @test_pointer_vec_load(<2 x i8*>* %addr) {
635 ; CHECK-LABEL: test_pointer_vec_load:
636 ; CHECK: ldr d[[TMP:[0-9]+]], [x0]
637 ; CHECK: ushll.2d v0, v[[TMP]], #0
638   %val = load <2 x i8*>, <2 x i8*>* %addr, align 16
639   ret <2 x i8*> %val
642 define void @test_inline_asm_mem_pointer(i32* %in) {
643 ; CHECK-LABEL: test_inline_asm_mem_pointer:
644 ; CHECK: str w0,
645   tail call void asm sideeffect "ldr x0, $0", "rm"(i32* %in)
646   ret void
650 define void @test_struct_hi(i32 %hi) nounwind {
651 ; CHECK-LABEL: test_struct_hi:
652 ; CHECK: mov w[[IN:[0-9]+]], w0
653 ; CHECK: bl _get_int
654 ; CHECK-NEXT: bfi x0, x[[IN]], #32, #32
655 ; CHECK-NEXT: bl _take_pair
656   %val.64 = call i64 @get_int()
657   %val.32 = trunc i64 %val.64 to i32
659   %pair.0 = insertvalue [2 x i32] undef, i32 %val.32, 0
660   %pair.1 = insertvalue [2 x i32] %pair.0, i32 %hi, 1
661   call void @take_pair([2 x i32] %pair.1)
663   ret void
665 declare void @take_pair([2 x i32])
666 declare i64 @get_int()
668 define i1 @test_icmp_ptr(i8* %in) {
669 ; CHECK-LABEL: test_icmp_ptr
670 ; CHECK: ubfx x0, x0, #31, #1
671   %res = icmp slt i8* %in, null
672   ret i1 %res
675 define void @test_multiple_icmp_ptr(i8* %l, i8* %r) {
676 ; CHECK-LABEL: test_multiple_icmp_ptr:
677 ; CHECK: tbnz w0, #31, [[FALSEBB:LBB[0-9]+_[0-9]+]]
678 ; CHECK: tbnz w1, #31, [[FALSEBB]]
679   %tst1 = icmp sgt i8* %l, inttoptr (i32 -1 to i8*)
680   %tst2 = icmp sgt i8* %r, inttoptr (i32 -1 to i8*)
681   %tst = and i1 %tst1, %tst2
682   br i1 %tst, label %true, label %false
684 true:
685   call void(...) @bar()
686   ret void
688 false:
689   ret void
692 define { [18 x i8] }* @test_gep_nonpow2({ [18 x i8] }* %a0, i32 %a1) {
693 ; CHECK-LABEL: test_gep_nonpow2:
694 ; CHECK:      mov w[[SIZE:[0-9]+]], #18
695 ; CHECK-NEXT: smaddl x0, w1, w[[SIZE]], x0
696 ; CHECK-NEXT: ret
697   %tmp0 = getelementptr inbounds { [18 x i8] }, { [18 x i8] }* %a0, i32 %a1
698   ret { [18 x i8] }* %tmp0
701 define void @test_bzero(i64 %in)  {
702 ; CHECK-LABEL: test_bzero:
703 ; CHECK-DAG: lsr x1, x0, #32
704 ; CHECK-DAG: and x0, x0, #0xffffffff
705 ; CHECK: bl _bzero
707   %ptr.i32 = trunc i64 %in to i32
708   %size.64 = lshr i64 %in, 32
709   %size = trunc i64 %size.64 to i32
710   %ptr = inttoptr i32 %ptr.i32 to i8*
711   tail call void @llvm.memset.p0i8.i32(i8* align 4 %ptr, i8 0, i32 %size, i1 false)
712   ret void
715 declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1)