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: [[UNDEF:%[0-9]+]]:_(s192) = G_IMPLICIT_DEF
69 ; CHECK: [[ARG0:%[0-9]+]]:_(s192) = G_INSERT [[UNDEF]], [[DBL]](s64), 0
70 ; CHECK: [[ARG1:%[0-9]+]]:_(s192) = G_INSERT [[ARG0]], [[I64]](s64), 64
71 ; CHECK: [[ARG2:%[0-9]+]]:_(s192) = G_INSERT [[ARG1]], [[I8]](s8), 128
72 ; CHECK: [[ARG:%[0-9]+]]:_(s192) = COPY [[ARG2]]
73 ; CHECK: [[EXTA0:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s192), 0
74 ; CHECK: [[EXTA1:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s192), 64
75 ; CHECK: [[EXTA2:%[0-9]+]]:_(s8) = G_EXTRACT [[ARG]](s192), 128
76 ; CHECK: G_STORE [[EXTA0]](s64), [[ADDR]](p0) :: (store 8 into %ir.addr)
77 ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
78 ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST1]](s64)
79 ; CHECK: G_STORE [[EXTA1]](s64), [[GEP1]](p0) :: (store 8 into %ir.addr + 8)
80 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
81 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST2]](s64)
82 ; CHECK: G_STORE [[EXTA2]](s8), [[GEP2]](p0) :: (store 1 into %ir.addr + 16, align 8)
84 define void @test_struct_formal({double, i64, i8} %in, {double, i64, i8}* %addr) {
85 store {double, i64, i8} %in, {double, i64, i8}* %addr
90 ; CHECK-LABEL: name: test_struct_return
91 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
93 ; CHECK: [[LD1:%[0-9]+]]:_(s64) = G_LOAD [[ADDR]](p0) :: (load 8 from %ir.addr)
94 ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
95 ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST1]](s64)
96 ; CHECK: [[LD2:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 8 from %ir.addr + 8)
97 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
98 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST2]](s64)
99 ; CHECK: [[LD3:%[0-9]+]]:_(s32) = G_LOAD [[GEP2]](p0) :: (load 4 from %ir.addr + 16, align 8)
101 ; CHECK: $d0 = COPY [[LD1]](s64)
102 ; CHECK: $x0 = COPY [[LD2]](s64)
103 ; CHECK: $w1 = COPY [[LD3]](s32)
104 ; CHECK: RET_ReallyLR implicit $d0, implicit $x0, implicit $w1
105 define {double, i64, i32} @test_struct_return({double, i64, i32}* %addr) {
106 %val = load {double, i64, i32}, {double, i64, i32}* %addr
107 ret {double, i64, i32} %val
110 ; CHECK-LABEL: name: test_arr_call
111 ; CHECK: hasCalls: true
112 ; CHECK: %0:_(p0) = COPY $x0
113 ; CHECK: [[LD1:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.addr)
114 ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
115 ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP %0, [[CST1]](s64)
116 ; CHECK: [[LD2:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 8 from %ir.addr + 8)
117 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
118 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP %0, [[CST2]](s64)
119 ; CHECK: [[LD3:%[0-9]+]]:_(s64) = G_LOAD [[GEP2]](p0) :: (load 8 from %ir.addr + 16)
120 ; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 24
121 ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP %0, [[CST3]](s64)
122 ; CHECK: [[LD4:%[0-9]+]]:_(s64) = G_LOAD [[GEP3]](p0) :: (load 8 from %ir.addr + 24)
123 ; CHECK: [[IMPDEF:%[0-9]+]]:_(s256) = G_IMPLICIT_DEF
124 ; CHECK: [[INS1:%[0-9]+]]:_(s256) = G_INSERT [[IMPDEF]], [[LD1]](s64), 0
125 ; CHECK: [[INS2:%[0-9]+]]:_(s256) = G_INSERT [[INS1]], [[LD2]](s64), 64
126 ; CHECK: [[INS3:%[0-9]+]]:_(s256) = G_INSERT [[INS2]], [[LD3]](s64), 128
127 ; CHECK: [[ARG:%[0-9]+]]:_(s256) = G_INSERT [[INS3]], [[LD4]](s64), 192
128 ; CHECK: [[E0:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 0
129 ; CHECK: [[E1:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 64
130 ; CHECK: [[E2:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 128
131 ; CHECK: [[E3:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 192
133 ; CHECK: $x0 = COPY [[E0]](s64)
134 ; CHECK: $x1 = COPY [[E1]](s64)
135 ; CHECK: $x2 = COPY [[E2]](s64)
136 ; CHECK: $x3 = COPY [[E3]](s64)
137 ; 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
138 ; CHECK: [[E0:%[0-9]+]]:_(s64) = COPY $x0
139 ; CHECK: [[E1:%[0-9]+]]:_(s64) = COPY $x1
140 ; CHECK: [[E2:%[0-9]+]]:_(s64) = COPY $x2
141 ; CHECK: [[E3:%[0-9]+]]:_(s64) = COPY $x3
142 ; CHECK: [[RES:%[0-9]+]]:_(s256) = G_MERGE_VALUES [[E0]](s64), [[E1]](s64), [[E2]](s64), [[E3]](s64)
143 ; CHECK: G_EXTRACT [[RES]](s256), 64
144 declare [4 x i64] @arr_callee([4 x i64])
145 define i64 @test_arr_call([4 x i64]* %addr) {
146 %arg = load [4 x i64], [4 x i64]* %addr
147 %res = call [4 x i64] @arr_callee([4 x i64] %arg)
148 %val = extractvalue [4 x i64] %res, 1
153 ; CHECK-LABEL: name: test_abi_exts_call
154 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
155 ; CHECK: [[VAL_TMP:%[0-9]+]]:_(s32) = G_ANYEXT [[VAL]]
156 ; CHECK: $w0 = COPY [[VAL_TMP]]
157 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
158 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
159 ; CHECK: $w0 = COPY [[SVAL]](s32)
160 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
161 ; CHECK: [[ZVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
162 ; CHECK: $w0 = COPY [[ZVAL]](s32)
163 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
164 declare void @take_char(i8)
165 define void @test_abi_exts_call(i8* %addr) {
166 %val = load i8, i8* %addr
167 call void @take_char(i8 %val)
168 call void @take_char(i8 signext %val)
169 call void @take_char(i8 zeroext %val)
173 ; CHECK-LABEL: name: test_abi_sext_ret
174 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
175 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
176 ; CHECK: $w0 = COPY [[SVAL]](s32)
177 ; CHECK: RET_ReallyLR implicit $w0
178 define signext i8 @test_abi_sext_ret(i8* %addr) {
179 %val = load i8, i8* %addr
183 ; CHECK-LABEL: name: test_abi_zext_ret
184 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
185 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
186 ; CHECK: $w0 = COPY [[SVAL]](s32)
187 ; CHECK: RET_ReallyLR implicit $w0
188 define zeroext i8 @test_abi_zext_ret(i8* %addr) {
189 %val = load i8, i8* %addr
193 ; CHECK-LABEL: name: test_stack_slots
195 ; CHECK-DAG: - { id: [[STACK0:[0-9]+]], type: default, offset: 0, size: 8,
196 ; CHECK-DAG: - { id: [[STACK8:[0-9]+]], type: default, offset: 8, size: 8,
197 ; CHECK-DAG: - { id: [[STACK16:[0-9]+]], type: default, offset: 16, size: 8,
198 ; CHECK: [[LHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK0]]
199 ; CHECK: [[LHS:%[0-9]+]]:_(s64) = G_LOAD [[LHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK0]], align 1)
200 ; CHECK: [[RHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK8]]
201 ; CHECK: [[RHS:%[0-9]+]]:_(s64) = G_LOAD [[RHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK8]], align 1)
202 ; CHECK: [[ADDR_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK16]]
203 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_LOAD [[ADDR_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK16]], align 1)
204 ; CHECK: [[SUM:%[0-9]+]]:_(s64) = G_ADD [[LHS]], [[RHS]]
205 ; CHECK: G_STORE [[SUM]](s64), [[ADDR]](p0)
206 define void @test_stack_slots([8 x i64], i64 %lhs, i64 %rhs, i64* %addr) {
207 %sum = add i64 %lhs, %rhs
208 store i64 %sum, i64* %addr
212 ; CHECK-LABEL: name: test_call_stack
213 ; CHECK: [[C42:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
214 ; CHECK: [[C12:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
215 ; CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
216 ; CHECK: [[PTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[ZERO]]
217 ; CHECK: ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
218 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
219 ; CHECK: [[C42_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
220 ; CHECK: [[C42_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C42_OFFS]](s64)
221 ; CHECK: G_STORE [[C42]](s64), [[C42_LOC]](p0) :: (store 8 into stack, align 1)
222 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
223 ; CHECK: [[C12_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
224 ; CHECK: [[C12_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C12_OFFS]](s64)
225 ; CHECK: G_STORE [[C12]](s64), [[C12_LOC]](p0) :: (store 8 into stack + 8, align 1)
226 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
227 ; CHECK: [[PTR_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
228 ; CHECK: [[PTR_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[PTR_OFFS]](s64)
229 ; CHECK: G_STORE [[PTR]](p0), [[PTR_LOC]](p0) :: (store 8 into stack + 16, align 1)
230 ; CHECK: BL @test_stack_slots
231 ; CHECK: ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
232 define void @test_call_stack() {
233 call void @test_stack_slots([8 x i64] undef, i64 42, i64 12, i64* null)
237 ; CHECK-LABEL: name: test_mem_i1
239 ; CHECK-NEXT: - { id: [[SLOT:[0-9]+]], type: default, offset: 0, size: 1, alignment: 16, stack-id: 0,
240 ; CHECK-NEXT: isImmutable: true,
241 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[SLOT]]
242 ; CHECK: {{%[0-9]+}}:_(s1) = G_LOAD [[ADDR]](p0) :: (invariant load 1 from %fixed-stack.[[SLOT]])
243 define void @test_mem_i1([8 x i64], i1 %in) {
247 ; CHECK-LABEL: name: test_128bit_struct
251 ; CHECK: BL @take_128bit_struct
252 define void @test_128bit_struct([2 x i64]* %ptr) {
253 %struct = load [2 x i64], [2 x i64]* %ptr
254 call void @take_128bit_struct([2 x i64]* null, [2 x i64] %struct)
258 ; CHECK-LABEL: name: take_128bit_struct
259 ; CHECK: {{%.*}}:_(p0) = COPY $x0
260 ; CHECK: {{%.*}}:_(s64) = COPY $x1
261 ; CHECK: {{%.*}}:_(s64) = COPY $x2
262 define void @take_128bit_struct([2 x i64]* %ptr, [2 x i64] %in) {
263 store [2 x i64] %in, [2 x i64]* %ptr
267 ; CHECK-LABEL: name: test_split_struct
268 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
269 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr)
270 ; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
271 ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST]](s64)
272 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8 from %ir.ptr + 8)
274 ; CHECK: [[IMPDEF:%[0-9]+]]:_(s128) = G_IMPLICIT_DEF
275 ; CHECK: [[INS1:%[0-9]+]]:_(s128) = G_INSERT [[IMPDEF]], [[LO]](s64), 0
276 ; CHECK: [[INS2:%[0-9]+]]:_(s128) = G_INSERT [[INS1]], [[HI]](s64), 64
277 ; CHECK: [[EXTLO:%[0-9]+]]:_(s64) = G_EXTRACT [[INS2]](s128), 0
278 ; CHECK: [[EXTHI:%[0-9]+]]:_(s64) = G_EXTRACT [[INS2]](s128), 64
280 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
281 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
282 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST2]](s64)
283 ; CHECK: G_STORE [[EXTLO]](s64), [[GEP2]](p0) :: (store 8 into stack, align 1)
284 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
285 ; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
286 ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST3]](s64)
287 ; CHECK: G_STORE [[EXTHI]](s64), [[GEP3]](p0) :: (store 8 into stack + 8, align 1)
288 define void @test_split_struct([2 x i64]* %ptr) {
289 %struct = load [2 x i64], [2 x i64]* %ptr
290 call void @take_split_struct([2 x i64]* null, i64 1, i64 2, i64 3,
296 ; CHECK-LABEL: name: take_split_struct
298 ; CHECK-DAG: - { id: [[LO_FRAME:[0-9]+]], type: default, offset: 0, size: 8
299 ; CHECK-DAG: - { id: [[HI_FRAME:[0-9]+]], type: default, offset: 8, size: 8
301 ; CHECK: [[LOPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[LO_FRAME]]
302 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD [[LOPTR]](p0) :: (invariant load 8 from %fixed-stack.[[LO_FRAME]], align 1)
304 ; CHECK: [[HIPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[HI_FRAME]]
305 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[HIPTR]](p0) :: (invariant load 8 from %fixed-stack.[[HI_FRAME]], align 1)
306 define void @take_split_struct([2 x i64]* %ptr, i64, i64, i64,
309 store [2 x i64] %in, [2 x i64]* %ptr