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: %0:_(p0) = COPY $x0
104 ; CHECK: [[LD1:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.addr)
105 ; CHECK: [[CST1:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
106 ; CHECK: [[GEP1:%[0-9]+]]:_(p0) = G_GEP %0, [[CST1]](s64)
107 ; CHECK: [[LD2:%[0-9]+]]:_(s64) = G_LOAD [[GEP1]](p0) :: (load 8 from %ir.addr + 8)
108 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
109 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP %0, [[CST2]](s64)
110 ; CHECK: [[LD3:%[0-9]+]]:_(s64) = G_LOAD [[GEP2]](p0) :: (load 8 from %ir.addr + 16)
111 ; CHECK: [[CST3:%[0-9]+]]:_(s64) = G_CONSTANT i64 24
112 ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP %0, [[CST3]](s64)
113 ; CHECK: [[LD4:%[0-9]+]]:_(s64) = G_LOAD [[GEP3]](p0) :: (load 8 from %ir.addr + 24)
115 ; CHECK: $x0 = COPY [[LD1]](s64)
116 ; CHECK: $x1 = COPY [[LD2]](s64)
117 ; CHECK: $x2 = COPY [[LD3]](s64)
118 ; CHECK: $x3 = COPY [[LD4]](s64)
119 ; 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
120 ; CHECK: [[E0:%[0-9]+]]:_(s64) = COPY $x0
121 ; CHECK: [[E1:%[0-9]+]]:_(s64) = COPY $x1
122 ; CHECK: [[E2:%[0-9]+]]:_(s64) = COPY $x2
123 ; CHECK: [[E3:%[0-9]+]]:_(s64) = COPY $x3
124 ; CHECK: $x0 = COPY [[E1]]
125 declare [4 x i64] @arr_callee([4 x i64])
126 define i64 @test_arr_call([4 x i64]* %addr) {
127 %arg = load [4 x i64], [4 x i64]* %addr
128 %res = call [4 x i64] @arr_callee([4 x i64] %arg)
129 %val = extractvalue [4 x i64] %res, 1
134 ; CHECK-LABEL: name: test_abi_exts_call
135 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
136 ; CHECK: [[VAL_TMP:%[0-9]+]]:_(s32) = G_ANYEXT [[VAL]]
137 ; CHECK: $w0 = COPY [[VAL_TMP]]
138 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
139 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
140 ; CHECK: $w0 = COPY [[SVAL]](s32)
141 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
142 ; CHECK: [[ZVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
143 ; CHECK: $w0 = COPY [[ZVAL]](s32)
144 ; CHECK: BL @take_char, csr_aarch64_aapcs, implicit-def $lr, implicit $sp, implicit $w0
145 declare void @take_char(i8)
146 define void @test_abi_exts_call(i8* %addr) {
147 %val = load i8, i8* %addr
148 call void @take_char(i8 %val)
149 call void @take_char(i8 signext %val)
150 call void @take_char(i8 zeroext %val)
154 ; CHECK-LABEL: name: test_abi_sext_ret
155 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
156 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_SEXT [[VAL]](s8)
157 ; CHECK: $w0 = COPY [[SVAL]](s32)
158 ; CHECK: RET_ReallyLR implicit $w0
159 define signext i8 @test_abi_sext_ret(i8* %addr) {
160 %val = load i8, i8* %addr
164 ; CHECK-LABEL: name: test_abi_zext_ret
165 ; CHECK: [[VAL:%[0-9]+]]:_(s8) = G_LOAD
166 ; CHECK: [[SVAL:%[0-9]+]]:_(s32) = G_ZEXT [[VAL]](s8)
167 ; CHECK: $w0 = COPY [[SVAL]](s32)
168 ; CHECK: RET_ReallyLR implicit $w0
169 define zeroext i8 @test_abi_zext_ret(i8* %addr) {
170 %val = load i8, i8* %addr
174 ; CHECK-LABEL: name: test_stack_slots
176 ; CHECK-DAG: - { id: [[STACK0:[0-9]+]], type: default, offset: 0, size: 8,
177 ; CHECK-DAG: - { id: [[STACK8:[0-9]+]], type: default, offset: 8, size: 8,
178 ; CHECK-DAG: - { id: [[STACK16:[0-9]+]], type: default, offset: 16, size: 8,
179 ; CHECK: [[LHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK0]]
180 ; CHECK: [[LHS:%[0-9]+]]:_(s64) = G_LOAD [[LHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK0]], align 1)
181 ; CHECK: [[RHS_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK8]]
182 ; CHECK: [[RHS:%[0-9]+]]:_(s64) = G_LOAD [[RHS_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK8]], align 1)
183 ; CHECK: [[ADDR_ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[STACK16]]
184 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_LOAD [[ADDR_ADDR]](p0) :: (invariant load 8 from %fixed-stack.[[STACK16]], align 1)
185 ; CHECK: [[SUM:%[0-9]+]]:_(s64) = G_ADD [[LHS]], [[RHS]]
186 ; CHECK: G_STORE [[SUM]](s64), [[ADDR]](p0)
187 define void @test_stack_slots([8 x i64], i64 %lhs, i64 %rhs, i64* %addr) {
188 %sum = add i64 %lhs, %rhs
189 store i64 %sum, i64* %addr
193 ; CHECK-LABEL: name: test_call_stack
194 ; CHECK: [[C42:%[0-9]+]]:_(s64) = G_CONSTANT i64 42
195 ; CHECK: [[C12:%[0-9]+]]:_(s64) = G_CONSTANT i64 12
196 ; CHECK: [[ZERO:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
197 ; CHECK: [[PTR:%[0-9]+]]:_(p0) = G_INTTOPTR [[ZERO]]
198 ; CHECK: ADJCALLSTACKDOWN 24, 0, implicit-def $sp, implicit $sp
199 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
200 ; CHECK: [[C42_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
201 ; CHECK: [[C42_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C42_OFFS]](s64)
202 ; CHECK: G_STORE [[C42]](s64), [[C42_LOC]](p0) :: (store 8 into stack, align 1)
203 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
204 ; CHECK: [[C12_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
205 ; CHECK: [[C12_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[C12_OFFS]](s64)
206 ; CHECK: G_STORE [[C12]](s64), [[C12_LOC]](p0) :: (store 8 into stack + 8, align 1)
207 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
208 ; CHECK: [[PTR_OFFS:%[0-9]+]]:_(s64) = G_CONSTANT i64 16
209 ; CHECK: [[PTR_LOC:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[PTR_OFFS]](s64)
210 ; CHECK: G_STORE [[PTR]](p0), [[PTR_LOC]](p0) :: (store 8 into stack + 16, align 1)
211 ; CHECK: BL @test_stack_slots
212 ; CHECK: ADJCALLSTACKUP 24, 0, implicit-def $sp, implicit $sp
213 define void @test_call_stack() {
214 call void @test_stack_slots([8 x i64] undef, i64 42, i64 12, i64* null)
218 ; CHECK-LABEL: name: test_mem_i1
220 ; CHECK-NEXT: - { id: [[SLOT:[0-9]+]], type: default, offset: 0, size: 1, alignment: 16, stack-id: default,
221 ; CHECK-NEXT: isImmutable: true,
222 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[SLOT]]
223 ; CHECK: {{%[0-9]+}}:_(s1) = G_LOAD [[ADDR]](p0) :: (invariant load 1 from %fixed-stack.[[SLOT]])
224 define void @test_mem_i1([8 x i64], i1 %in) {
228 ; CHECK-LABEL: name: test_128bit_struct
232 ; CHECK: BL @take_128bit_struct
233 define void @test_128bit_struct([2 x i64]* %ptr) {
234 %struct = load [2 x i64], [2 x i64]* %ptr
235 call void @take_128bit_struct([2 x i64]* null, [2 x i64] %struct)
239 ; CHECK-LABEL: name: take_128bit_struct
240 ; CHECK: {{%.*}}:_(p0) = COPY $x0
241 ; CHECK: {{%.*}}:_(s64) = COPY $x1
242 ; CHECK: {{%.*}}:_(s64) = COPY $x2
243 define void @take_128bit_struct([2 x i64]* %ptr, [2 x i64] %in) {
244 store [2 x i64] %in, [2 x i64]* %ptr
248 ; CHECK-LABEL: name: test_split_struct
249 ; CHECK: [[ADDR:%[0-9]+]]:_(p0) = COPY $x0
250 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD %0(p0) :: (load 8 from %ir.ptr)
251 ; CHECK: [[CST:%[0-9]+]]:_(s64) = G_CONSTANT i64 8
252 ; CHECK: [[GEP:%[0-9]+]]:_(p0) = G_GEP [[ADDR]], [[CST]](s64)
253 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[GEP]](p0) :: (load 8 from %ir.ptr + 8)
255 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
256 ; CHECK: [[CST2:%[0-9]+]]:_(s64) = G_CONSTANT i64 0
257 ; CHECK: [[GEP2:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST2]](s64)
258 ; CHECK: G_STORE [[LO]](s64), [[GEP2]](p0) :: (store 8 into stack, align 1)
259 ; CHECK: [[SP:%[0-9]+]]:_(p0) = COPY $sp
260 ; CHECK: [[CST3:%[0-9]+]]:_(s64) = COPY [[CST]]
261 ; CHECK: [[GEP3:%[0-9]+]]:_(p0) = G_GEP [[SP]], [[CST3]](s64)
262 ; CHECK: G_STORE [[HI]](s64), [[GEP3]](p0) :: (store 8 into stack + 8, align 1)
263 define void @test_split_struct([2 x i64]* %ptr) {
264 %struct = load [2 x i64], [2 x i64]* %ptr
265 call void @take_split_struct([2 x i64]* null, i64 1, i64 2, i64 3,
271 ; CHECK-LABEL: name: take_split_struct
273 ; CHECK-DAG: - { id: [[LO_FRAME:[0-9]+]], type: default, offset: 0, size: 8
274 ; CHECK-DAG: - { id: [[HI_FRAME:[0-9]+]], type: default, offset: 8, size: 8
276 ; CHECK: [[LOPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[LO_FRAME]]
277 ; CHECK: [[LO:%[0-9]+]]:_(s64) = G_LOAD [[LOPTR]](p0) :: (invariant load 8 from %fixed-stack.[[LO_FRAME]], align 1)
279 ; CHECK: [[HIPTR:%[0-9]+]]:_(p0) = G_FRAME_INDEX %fixed-stack.[[HI_FRAME]]
280 ; CHECK: [[HI:%[0-9]+]]:_(s64) = G_LOAD [[HIPTR]](p0) :: (invariant load 8 from %fixed-stack.[[HI_FRAME]], align 1)
281 define void @take_split_struct([2 x i64]* %ptr, i64, i64, i64,
284 store [2 x i64] %in, [2 x i64]* %ptr