1 ; RUN: llc -mtriple=aarch64-linux-gnu -O0 -stop-after=irtranslator -global-isel -verify-machineinstrs %s -o - 2>&1 | FileCheck %s
3 ; CHECK-LABEL: name: test_trivial_call
4 ; CHECK: ADJCALLSTACKDOWN 0, 0, implicit-def $sp, implicit $sp
5 ; CHECK: BL @trivial_callee, csr_aarch64_aapcs, implicit-def $lr
6 ; CHECK: ADJCALLSTACKUP 0, 0, implicit-def $sp, implicit $sp
7 declare void @trivial_callee()
8 define void @test_trivial_call() {
9 call void @trivial_callee()
13 ; CHECK-LABEL: name: test_simple_return
14 ; CHECK: BL @simple_return_callee, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit-def $x0
15 ; CHECK: [[RES:%[0-9]+]]:_(s64) = COPY $x0
16 ; CHECK: $x0 = COPY [[RES]]
17 ; CHECK: RET_ReallyLR implicit $x0
18 declare i64 @simple_return_callee()
19 define i64 @test_simple_return() {
20 %res = call i64 @simple_return_callee()
24 ; CHECK-LABEL: name: test_simple_arg
25 ; CHECK: [[IN:%[0-9]+]]:_(s32) = COPY $w0
26 ; CHECK: $w0 = COPY [[IN]]
27 ; CHECK: BL @simple_arg_callee, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
29 declare void @simple_arg_callee(i32 %in)
30 define void @test_simple_arg(i32 %in) {
31 call void @simple_arg_callee(i32 %in)
35 ; CHECK-LABEL: name: test_indirect_call
37 ; Make sure the register feeding the indirect call is properly constrained.
38 ; CHECK: - { id: [[FUNC:[0-9]+]], class: gpr64, preferred-register: '' }
39 ; CHECK: %[[FUNC]]:gpr64(p0) = COPY $x0
40 ; CHECK: BLR %[[FUNC]](p0), csr_aarch64_aapcs, implicit-def $lr, implicit $sp
42 define void @test_indirect_call(void()* %func) {
47 ; CHECK-LABEL: name: test_multiple_args
48 ; CHECK: [[IN:%[0-9]+]]:_(s64) = COPY $x0
49 ; CHECK: [[ANSWER:%[0-9]+]]:_(s32) = G_CONSTANT i32 42
50 ; CHECK: $w0 = COPY [[ANSWER]]
51 ; CHECK: $x1 = COPY [[IN]]
52 ; CHECK: BL @multiple_args_callee, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0, implicit $x1
54 declare void @multiple_args_callee(i32, i64)
55 define void @test_multiple_args(i64 %in) {
56 call void @multiple_args_callee(i32 42, i64 %in)
61 ; CHECK-LABEL: name: test_struct_formal
62 ; CHECK: [[DBL:%[0-9]+]]:_(s64) = COPY $d0
63 ; CHECK: [[I64:%[0-9]+]]:_(s64) = COPY $x0
64 ; CHECK: [[I8_C:%[0-9]+]]:_(s32) = COPY $w1
65 ; CHECK: [[I8:%[0-9]+]]:_(s8) = G_TRUNC [[I8_C]]
66 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x2
68 ; CHECK: G_STORE [[DBL]](s64), [[ADDR]](p0) :: (store 8 into %ir.addr)
69 ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
70 ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST1]](s64)
71 ; CHECK: G_STORE [[I64]](s64), [[GEP1]](p0) :: (store 8 into %ir.addr + 8)
72 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
73 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST2]](s64)
74 ; CHECK: G_STORE [[I8]](s8), [[GEP2]](p0) :: (store 1 into %ir.addr + 16, align 8)
76 define void @test_struct_formal({double, i64, i8} %in, {double, i64, i8}* %addr) {
77 store {double, i64, i8} %in, {double, i64, i8}* %addr
82 ; CHECK-LABEL: name: test_struct_return
83 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
85 ; CHECK: [[LD1:%[0-9]+]]:_(s64) = G_LOAD [[ADDR]](p0) :: (load 8 from %ir.addr)
86 ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
87 ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST1]](s64)
88 ; CHECK: [[LD2:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 8 from %ir.addr + 8)
89 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
90 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST2]](s64)
91 ; CHECK: [[LD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP2]](p0) :: (load 4 from %ir.addr + 16, align 8)
93 ; CHECK: $d0 = COPY [[LD1]](s64)
94 ; CHECK: $x0 = COPY [[LD2]](s64)
95 ; CHECK: $w1 = COPY [[LD3]](s32)
96 ; CHECK: RET_ReallyLR implicit $d0, implicit $x0, implicit $w1
97 define {double, i64, i32} @test_struct_return({double, i64, i32}* %addr) {
98 %val = load {double, i64, i32}, {double, i64, i32}* %addr
99 ret {double, i64, i32} %val
102 ; CHECK-LABEL: name: test_arr_call
103 ; CHECK: hasCalls: true
104 ; CHECK: %0:_(p0) = COPY $x0
105 ; CHECK: [[LD1:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.addr)
106 ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
107 ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP %0, [[CST1]](s64)
108 ; CHECK: [[LD2:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 8 from %ir.addr + 8)
109 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
110 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP %0, [[CST2]](s64)
111 ; CHECK: [[LD3:%[0-9]+]]:_(s64) = G_LOAD [[GEP2]](p0) :: (load 8 from %ir.addr + 16)
112 ; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 24
113 ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP %0, [[CST3]](s64)
114 ; CHECK: [[LD4:%[0-9]+]]:_(s64) = G_LOAD [[GEP3]](p0) :: (load 8 from %ir.addr + 24)
116 ; CHECK: $x0 = COPY [[LD1]](s64)
117 ; CHECK: $x1 = COPY [[LD2]](s64)
118 ; CHECK: $x2 = COPY [[LD3]](s64)
119 ; CHECK: $x3 = COPY [[LD4]](s64)
120 ; CHECK: BL @arr_callee, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $x0, implicit $x1, implicit $x2, implicit $x3, implicit-def $x0, implicit-def $x1, implicit-def $x2, implicit-def $x3
121 ; CHECK: [[E0:%[0-9]+]]:_(s64) = COPY $x0
122 ; CHECK: [[E1:%[0-9]+]]:_(s64) = COPY $x1
123 ; CHECK: [[E2:%[0-9]+]]:_(s64) = COPY $x2
124 ; CHECK: [[E3:%[0-9]+]]:_(s64) = COPY $x3
125 ; CHECK: $x0 = COPY [[E1]]
126 declare [4 x i64] @arr_callee([4 x i64])
127 define i64 @test_arr_call([4 x i64]* %addr) {
128 %arg = load [4 x i64], [4 x i64]* %addr
129 %res = call [4 x i64] @arr_callee([4 x i64] %arg)
130 %val = extractvalue [4 x i64] %res, 1
135 ; CHECK-LABEL: name: test_abi_exts_call
136 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
137 ; CHECK: [[VAL_TMP:%[0-9]+]]:_(s32) = G_ANYEXT [[VAL]]
138 ; CHECK: $w0 = COPY [[VAL_TMP]]
139 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
140 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
141 ; CHECK: $w0 = COPY [[SVAL]](s32)
142 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
143 ; CHECK: [[ZVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
144 ; CHECK: $w0 = COPY [[ZVAL]](s32)
145 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
146 declare void @take_char(i8)
147 define void @test_abi_exts_call(i8* %addr) {
148 %val = load i8, i8* %addr
149 call void @take_char(i8 %val)
150 call void @take_char(i8 signext %val)
151 call void @take_char(i8 zeroext %val)
155 ; CHECK-LABEL: name: test_abi_sext_ret
156 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
157 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
158 ; CHECK: $w0 = COPY [[SVAL]](s32)
159 ; CHECK: RET_ReallyLR implicit $w0
160 define signext i8 @test_abi_sext_ret(i8* %addr) {
161 %val = load i8, i8* %addr
165 ; CHECK-LABEL: name: test_abi_zext_ret
166 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
167 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
168 ; CHECK: $w0 = COPY [[SVAL]](s32)
169 ; CHECK: RET_ReallyLR implicit $w0
170 define zeroext i8 @test_abi_zext_ret(i8* %addr) {
171 %val = load i8, i8* %addr
175 ; CHECK-LABEL: name: test_stack_slots
177 ; CHECK-DAG: - { id: [[STACK0:[0-9]+]], type: default, offset: 0, size: 8,
178 ; CHECK-DAG: - { id: [[STACK8:[0-9]+]], type: default, offset: 8, size: 8,
179 ; CHECK-DAG: - { id: [[STACK16:[0-9]+]], type: default, offset: 16, size: 8,
180 ; CHECK: [[LHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK0]]
181 ; CHECK: [[LHS:%[0-9]+]]:_(s64) = G_LOAD [[LHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK0]], align 1)
182 ; CHECK: [[RHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK8]]
183 ; CHECK: [[RHS:%[0-9]+]]:_(s64) = G_LOAD [[RHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK8]], align 1)
184 ; CHECK: [[ADDR_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK16]]
185 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_LOAD [[ADDR_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK16]], align 1)
186 ; CHECK: [[SUM:%[0-9]+]]:_(s64) = G_ADD [[LHS]], [[RHS]]
187 ; CHECK: G_STORE [[SUM]](s64), [[ADDR]](p0)
188 define void @test_stack_slots([8 x i64], i64 %lhs, i64 %rhs, i64* %addr) {
189 %sum = add i64 %lhs, %rhs
190 store i64 %sum, i64* %addr
194 ; CHECK-LABEL: name: test_call_stack
195 ; CHECK: [[C42:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
196 ; CHECK: [[C12:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
197 ; CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
198 ; CHECK: [[PTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[ZERO]]
199 ; CHECK: ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
200 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
201 ; CHECK: [[C42_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
202 ; CHECK: [[C42_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C42_OFFS]](s64)
203 ; CHECK: G_STORE [[C42]](s64), [[C42_LOC]](p0) :: (store 8 into stack, align 1)
204 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
205 ; CHECK: [[C12_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
206 ; CHECK: [[C12_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C12_OFFS]](s64)
207 ; CHECK: G_STORE [[C12]](s64), [[C12_LOC]](p0) :: (store 8 into stack + 8, align 1)
208 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
209 ; CHECK: [[PTR_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
210 ; CHECK: [[PTR_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[PTR_OFFS]](s64)
211 ; CHECK: G_STORE [[PTR]](p0), [[PTR_LOC]](p0) :: (store 8 into stack + 16, align 1)
212 ; CHECK: BL @test_stack_slots
213 ; CHECK: ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
214 define void @test_call_stack() {
215 call void @test_stack_slots([8 x i64] undef, i64 42, i64 12, i64* null)
219 ; CHECK-LABEL: name: test_mem_i1
221 ; CHECK-NEXT: - { id: [[SLOT:[0-9]+]], type: default, offset: 0, size: 1, alignment: 16, stack-id: default,
222 ; CHECK-NEXT: isImmutable: true,
223 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[SLOT]]
224 ; CHECK: {{%[0-9]+}}:_(s1) = G_LOAD [[ADDR]](p0) :: (invariant load 1 from %fixed-stack.[[SLOT]])
225 define void @test_mem_i1([8 x i64], i1 %in) {
229 ; CHECK-LABEL: name: test_128bit_struct
233 ; CHECK: BL @take_128bit_struct
234 define void @test_128bit_struct([2 x i64]* %ptr) {
235 %struct = load [2 x i64], [2 x i64]* %ptr
236 call void @take_128bit_struct([2 x i64]* null, [2 x i64] %struct)
240 ; CHECK-LABEL: name: take_128bit_struct
241 ; CHECK: {{%.*}}:_(p0) = COPY $x0
242 ; CHECK: {{%.*}}:_(s64) = COPY $x1
243 ; CHECK: {{%.*}}:_(s64) = COPY $x2
244 define void @take_128bit_struct([2 x i64]* %ptr, [2 x i64] %in) {
245 store [2 x i64] %in, [2 x i64]* %ptr
249 ; CHECK-LABEL: name: test_split_struct
250 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
251 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr)
252 ; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
253 ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST]](s64)
254 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8 from %ir.ptr + 8)
256 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
257 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
258 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST2]](s64)
259 ; CHECK: G_STORE [[LO]](s64), [[GEP2]](p0) :: (store 8 into stack, align 1)
260 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
261 ; CHECK: [[CST3:%[0-9]+]]:_(s64) = COPY [[CST]]
262 ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST3]](s64)
263 ; CHECK: G_STORE [[HI]](s64), [[GEP3]](p0) :: (store 8 into stack + 8, align 1)
264 define void @test_split_struct([2 x i64]* %ptr) {
265 %struct = load [2 x i64], [2 x i64]* %ptr
266 call void @take_split_struct([2 x i64]* null, i64 1, i64 2, i64 3,
272 ; CHECK-LABEL: name: take_split_struct
274 ; CHECK-DAG: - { id: [[LO_FRAME:[0-9]+]], type: default, offset: 0, size: 8
275 ; CHECK-DAG: - { id: [[HI_FRAME:[0-9]+]], type: default, offset: 8, size: 8
277 ; CHECK: [[LOPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[LO_FRAME]]
278 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD [[LOPTR]](p0) :: (invariant load 8 from %fixed-stack.[[LO_FRAME]], align 1)
280 ; CHECK: [[HIPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[HI_FRAME]]
281 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[HIPTR]](p0) :: (invariant load 8 from %fixed-stack.[[HI_FRAME]], align 1)
282 define void @take_split_struct([2 x i64]* %ptr, i64, i64, i64,
285 store [2 x i64] %in, [2 x i64]* %ptr