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]]
74 ; CHECK: G_STORE [[ARG]](s192), [[ADDR]](p0)
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
84 ; CHECK: [[VAL:%[0-9]+]]:_(s192) = G_LOAD [[ADDR]](p0)
86 ; CHECK: [[DBL:%[0-9]+]]:_(s64) = G_EXTRACT [[VAL]](s192), 0
87 ; CHECK: [[I64:%[0-9]+]]:_(s64) = G_EXTRACT [[VAL]](s192), 64
88 ; CHECK: [[I32:%[0-9]+]]:_(s32) = G_EXTRACT [[VAL]](s192), 128
90 ; CHECK: %d0 = COPY [[DBL]](s64)
91 ; CHECK: %x0 = COPY [[I64]](s64)
92 ; CHECK: %w1 = COPY [[I32]](s32)
93 ; CHECK: RET_ReallyLR implicit %d0, implicit %x0, implicit %w1
94 define {double, i64, i32} @test_struct_return({double, i64, i32}* %addr) {
95 %val = load {double, i64, i32}, {double, i64, i32}* %addr
96 ret {double, i64, i32} %val
99 ; CHECK-LABEL: name: test_arr_call
100 ; CHECK: hasCalls: true
101 ; CHECK: [[ARG:%[0-9]+]]:_(s256) = G_LOAD
103 ; CHECK: [[E0:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 0
104 ; CHECK: [[E1:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 64
105 ; CHECK: [[E2:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 128
106 ; CHECK: [[E3:%[0-9]+]]:_(s64) = G_EXTRACT [[ARG]](s256), 192
108 ; CHECK: %x0 = COPY [[E0]](s64)
109 ; CHECK: %x1 = COPY [[E1]](s64)
110 ; CHECK: %x2 = COPY [[E2]](s64)
111 ; CHECK: %x3 = COPY [[E3]](s64)
112 ; 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
113 ; CHECK: [[E0:%[0-9]+]]:_(s64) = COPY %x0
114 ; CHECK: [[E1:%[0-9]+]]:_(s64) = COPY %x1
115 ; CHECK: [[E2:%[0-9]+]]:_(s64) = COPY %x2
116 ; CHECK: [[E3:%[0-9]+]]:_(s64) = COPY %x3
117 ; CHECK: [[RES:%[0-9]+]]:_(s256) = G_MERGE_VALUES [[E0]](s64), [[E1]](s64), [[E2]](s64), [[E3]](s64)
118 ; CHECK: G_EXTRACT [[RES]](s256), 64
119 declare [4 x i64] @arr_callee([4 x i64])
120 define i64 @test_arr_call([4 x i64]* %addr) {
121 %arg = load [4 x i64], [4 x i64]* %addr
122 %res = call [4 x i64] @arr_callee([4 x i64] %arg)
123 %val = extractvalue [4 x i64] %res, 1
128 ; CHECK-LABEL: name: test_abi_exts_call
129 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
130 ; CHECK: [[VAL_TMP:%[0-9]+]]:_(s32) = G_ANYEXT [[VAL]]
131 ; CHECK: %w0 = COPY [[VAL_TMP]]
132 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def %lr, implicit %sp, implicit %w0
133 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
134 ; CHECK: %w0 = COPY [[SVAL]](s32)
135 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def %lr, implicit %sp, implicit %w0
136 ; CHECK: [[ZVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
137 ; CHECK: %w0 = COPY [[ZVAL]](s32)
138 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def %lr, implicit %sp, implicit %w0
139 declare void @take_char(i8)
140 define void @test_abi_exts_call(i8* %addr) {
141 %val = load i8, i8* %addr
142 call void @take_char(i8 %val)
143 call void @take_char(i8 signext %val)
144 call void @take_char(i8 zeroext %val)
148 ; CHECK-LABEL: name: test_abi_sext_ret
149 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
150 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
151 ; CHECK: %w0 = COPY [[SVAL]](s32)
152 ; CHECK: RET_ReallyLR implicit %w0
153 define signext i8 @test_abi_sext_ret(i8* %addr) {
154 %val = load i8, i8* %addr
158 ; CHECK-LABEL: name: test_abi_zext_ret
159 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
160 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
161 ; CHECK: %w0 = COPY [[SVAL]](s32)
162 ; CHECK: RET_ReallyLR implicit %w0
163 define zeroext i8 @test_abi_zext_ret(i8* %addr) {
164 %val = load i8, i8* %addr
168 ; CHECK-LABEL: name: test_stack_slots
170 ; CHECK-DAG: - { id: [[STACK0:[0-9]+]], type: default, offset: 0, size: 8,
171 ; CHECK-DAG: - { id: [[STACK8:[0-9]+]], type: default, offset: 8, size: 8,
172 ; CHECK-DAG: - { id: [[STACK16:[0-9]+]], type: default, offset: 16, size: 8,
173 ; CHECK: [[LHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK0]]
174 ; CHECK: [[LHS:%[0-9]+]]:_(s64) = G_LOAD [[LHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK0]], align 0)
175 ; CHECK: [[RHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK8]]
176 ; CHECK: [[RHS:%[0-9]+]]:_(s64) = G_LOAD [[RHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK8]], align 0)
177 ; CHECK: [[ADDR_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK16]]
178 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_LOAD [[ADDR_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK16]], align 0)
179 ; CHECK: [[SUM:%[0-9]+]]:_(s64) = G_ADD [[LHS]], [[RHS]]
180 ; CHECK: G_STORE [[SUM]](s64), [[ADDR]](p0)
181 define void @test_stack_slots([8 x i64], i64 %lhs, i64 %rhs, i64* %addr) {
182 %sum = add i64 %lhs, %rhs
183 store i64 %sum, i64* %addr
187 ; CHECK-LABEL: name: test_call_stack
188 ; CHECK: [[C42:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
189 ; CHECK: [[C12:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
190 ; CHECK: [[PTR:%[0-9]+]]:_(p0) = G_CONSTANT i64 0
191 ; CHECK: ADJCALLSTACKDOWN 24, 0, implicit-def %sp, implicit %sp
192 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY %sp
193 ; CHECK: [[C42_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
194 ; CHECK: [[C42_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C42_OFFS]](s64)
195 ; CHECK: G_STORE [[C42]](s64), [[C42_LOC]](p0) :: (store 8 into stack, align 0)
196 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY %sp
197 ; CHECK: [[C12_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
198 ; CHECK: [[C12_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C12_OFFS]](s64)
199 ; CHECK: G_STORE [[C12]](s64), [[C12_LOC]](p0) :: (store 8 into stack + 8, align 0)
200 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY %sp
201 ; CHECK: [[PTR_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
202 ; CHECK: [[PTR_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[PTR_OFFS]](s64)
203 ; CHECK: G_STORE [[PTR]](p0), [[PTR_LOC]](p0) :: (store 8 into stack + 16, align 0)
204 ; CHECK: BL @test_stack_slots
205 ; CHECK: ADJCALLSTACKUP 24, 0, implicit-def %sp, implicit %sp
206 define void @test_call_stack() {
207 call void @test_stack_slots([8 x i64] undef, i64 42, i64 12, i64* null)
211 ; CHECK-LABEL: name: test_mem_i1
213 ; CHECK-NEXT: - { id: [[SLOT:[0-9]+]], type: default, offset: 0, size: 1, alignment: 16, stack-id: 0,
214 ; CHECK-NEXT: isImmutable: true,
215 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[SLOT]]
216 ; CHECK: {{%[0-9]+}}:_(s1) = G_LOAD [[ADDR]](p0) :: (invariant load 1 from %fixed-stack.[[SLOT]], align 0)
217 define void @test_mem_i1([8 x i64], i1 %in) {
221 ; CHECK-LABEL: name: test_128bit_struct
225 ; CHECK: BL @take_128bit_struct
226 define void @test_128bit_struct([2 x i64]* %ptr) {
227 %struct = load [2 x i64], [2 x i64]* %ptr
228 call void @take_128bit_struct([2 x i64]* null, [2 x i64] %struct)
232 ; CHECK-LABEL: name: take_128bit_struct
233 ; CHECK: {{%.*}}:_(p0) = COPY %x0
234 ; CHECK: {{%.*}}:_(s64) = COPY %x1
235 ; CHECK: {{%.*}}:_(s64) = COPY %x2
236 define void @take_128bit_struct([2 x i64]* %ptr, [2 x i64] %in) {
237 store [2 x i64] %in, [2 x i64]* %ptr
241 ; CHECK-LABEL: name: test_split_struct
242 ; CHECK: [[STRUCT:%[0-9]+]]:_(s128) = G_LOAD {{.*}}(p0)
243 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_EXTRACT [[STRUCT]](s128), 0
244 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_EXTRACT [[STRUCT]](s128), 64
246 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY %sp
247 ; CHECK: [[OFF:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
248 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[OFF]]
249 ; CHECK: G_STORE [[LO]](s64), [[ADDR]](p0) :: (store 8 into stack, align 0)
251 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY %sp
252 ; CHECK: [[OFF:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
253 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[OFF]]
254 ; CHECK: G_STORE [[HI]](s64), [[ADDR]](p0) :: (store 8 into stack + 8, align 0)
255 define void @test_split_struct([2 x i64]* %ptr) {
256 %struct = load [2 x i64], [2 x i64]* %ptr
257 call void @take_split_struct([2 x i64]* null, i64 1, i64 2, i64 3,
263 ; CHECK-LABEL: name: take_split_struct
265 ; CHECK-DAG: - { id: [[LO_FRAME:[0-9]+]], type: default, offset: 0, size: 8
266 ; CHECK-DAG: - { id: [[HI_FRAME:[0-9]+]], type: default, offset: 8, size: 8
268 ; CHECK: [[LOPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[LO_FRAME]]
269 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD [[LOPTR]](p0) :: (invariant load 8 from %fixed-stack.[[LO_FRAME]], align 0)
271 ; CHECK: [[HIPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[HI_FRAME]]
272 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[HIPTR]](p0) :: (invariant load 8 from %fixed-stack.[[HI_FRAME]], align 0)
273 define void @take_split_struct([2 x i64]* %ptr, i64, i64, i64,
276 store [2 x i64] %in, [2 x i64]* %ptr