1 ; RUN: llc < %s -mtriple=aarch64-pc-win32 | FileCheck %s
3 define void @pass_va(i32 %count, ...) nounwind {
5 ; CHECK: str x30, [sp, #-80]!
6 ; CHECK: add x8, sp, #24
7 ; CHECK: add x0, sp, #24
8 ; CHECK: stp x1, x2, [sp, #24]
9 ; CHECK: stp x3, x4, [sp, #40]
10 ; CHECK: stp x5, x6, [sp, #56]
11 ; CHECK: str x7, [sp, #72]
12 ; CHECK: str x8, [sp, #8]
13 ; CHECK: bl other_func
14 ; CHECK: ldr x30, [sp], #80
16 %ap = alloca i8*, align 8
17 %ap1 = bitcast i8** %ap to i8*
18 call void @llvm.va_start(i8* %ap1)
19 %ap2 = load i8*, i8** %ap, align 8
20 call void @other_func(i8* %ap2)
24 declare void @other_func(i8*) local_unnamed_addr
26 declare void @llvm.va_start(i8*) nounwind
27 declare void @llvm.va_copy(i8*, i8*) nounwind
30 ; CHECK: sub sp, sp, #16
31 ; CHECK: add x8, sp, #24
32 ; CHECK: add x0, sp, #24
33 ; CHECK: str x8, [sp, #8]
34 ; CHECK: add sp, sp, #16
36 define i8* @f9(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, ...) nounwind {
38 %ap = alloca i8*, align 8
39 %ap1 = bitcast i8** %ap to i8*
40 call void @llvm.va_start(i8* %ap1)
41 %ap2 = load i8*, i8** %ap, align 8
46 ; CHECK: sub sp, sp, #16
47 ; CHECK: add x8, sp, #16
48 ; CHECK: add x0, sp, #16
49 ; CHECK: str x8, [sp, #8]
50 ; CHECK: add sp, sp, #16
52 define i8* @f8(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, ...) nounwind {
54 %ap = alloca i8*, align 8
55 %ap1 = bitcast i8** %ap to i8*
56 call void @llvm.va_start(i8* %ap1)
57 %ap2 = load i8*, i8** %ap, align 8
62 ; CHECK: sub sp, sp, #32
63 ; CHECK: add x8, sp, #24
64 ; CHECK: str x7, [sp, #24]
65 ; CHECK: add x0, sp, #24
66 ; CHECK: str x8, [sp, #8]
67 ; CHECK: add sp, sp, #32
69 define i8* @f7(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, ...) nounwind {
71 %ap = alloca i8*, align 8
72 %ap1 = bitcast i8** %ap to i8*
73 call void @llvm.va_start(i8* %ap1)
74 %ap2 = load i8*, i8** %ap, align 8
79 ; CHECK: sub sp, sp, #80
80 ; CHECK: add x8, sp, #24
81 ; CHECK: stp x1, x2, [sp, #24]
82 ; CHECK: stp x3, x4, [sp, #40]
83 ; CHECK: stp x5, x6, [sp, #56]
84 ; CHECK: str x7, [sp, #72]
85 ; CHECK: stp x8, x8, [sp], #80
87 define void @copy1(i64 %a0, ...) nounwind {
89 %ap = alloca i8*, align 8
90 %cp = alloca i8*, align 8
91 %ap1 = bitcast i8** %ap to i8*
92 %cp1 = bitcast i8** %cp to i8*
93 call void @llvm.va_start(i8* %ap1)
94 call void @llvm.va_copy(i8* %cp1, i8* %ap1)
98 declare void @llvm.va_end(i8*)
99 declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1
100 declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1
102 declare i32 @__stdio_common_vsprintf(i64, i8*, i64, i8*, i8*, i8*) local_unnamed_addr #3
103 declare i64* @__local_stdio_printf_options() local_unnamed_addr #4
106 ; CHECK: str x21, [sp, #-96]!
107 ; CHECK: stp x19, x20, [sp, #16]
108 ; CHECK: stp x29, x30, [sp, #32]
109 ; CHECK: add x29, sp, #32
110 ; CHECK: add x8, x29, #24
114 ; CHECK: stp x3, x4, [x29, #24]
115 ; CHECK: stp x5, x6, [x29, #40]
116 ; CHECK: str x7, [x29, #56]
117 ; CHECK: str x8, [sp, #8]
118 ; CHECK: bl __local_stdio_printf_options
119 ; CHECK: ldr x8, [x0]
120 ; CHECK: add x5, x29, #24
123 ; CHECK: orr x0, x8, #0x2
126 ; CHECK: bl __stdio_common_vsprintf
128 ; CHECK: csinv w0, w0, wzr, ge
129 ; CHECK: ldp x29, x30, [sp, #32]
130 ; CHECK: ldp x19, x20, [sp, #16]
131 ; CHECK: ldr x21, [sp], #96
133 define i32 @fp(i8*, i64, i8*, ...) local_unnamed_addr #6 {
134 %4 = alloca i8*, align 8
135 %5 = bitcast i8** %4 to i8*
136 call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %5) #2
137 call void @llvm.va_start(i8* nonnull %5)
138 %6 = load i8*, i8** %4, align 8
139 %7 = call i64* @__local_stdio_printf_options() #2
140 %8 = load i64, i64* %7, align 8
142 %10 = call i32 @__stdio_common_vsprintf(i64 %9, i8* %0, i64 %1, i8* %2, i8* null, i8* %6) #2
143 %11 = icmp sgt i32 %10, -1
144 %12 = select i1 %11, i32 %10, i32 -1
145 call void @llvm.va_end(i8* nonnull %5)
146 call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %5) #2
150 attributes #6 = { "no-frame-pointer-elim"="true" }
153 ; CHECK: str x23, [sp, #-112]!
154 ; CHECK: stp x21, x22, [sp, #16]
155 ; CHECK: stp x19, x20, [sp, #32]
156 ; CHECK: stp x29, x30, [sp, #48]
157 ; CHECK: add x29, sp, #48
158 ; CHECK: add x8, x29, #16
159 ; CHECK: stur x8, [x29, #-40]
161 ; CHECK: add x8, x8, #15
162 ; CHECK: lsr x15, x8, #4
164 ; CHECK: mov [[REG2:x[0-9]+]], sp
165 ; CHECK: stp x2, x3, [x29, #16]
166 ; CHECK: stp x4, x5, [x29, #32]
167 ; CHECK: stp x6, x7, [x29, #48]
170 ; CHECK: sub [[REG:x[0-9]+]], x8, x15, lsl #4
171 ; CHECK: mov sp, [[REG]]
172 ; CHECK: ldur [[REG3:x[0-9]+]], [x29, #-40]
173 ; CHECK: sxtw [[REG4:x[0-9]+]], w0
174 ; CHECK: bl __local_stdio_printf_options
175 ; CHECK: ldr x8, [x0]
176 ; CHECK: mov x1, [[REG]]
177 ; CHECK: mov x2, [[REG4]]
179 ; CHECK: orr x0, x8, #0x2
181 ; CHECK: mov x5, [[REG3]]
182 ; CHECK: bl __stdio_common_vsprintf
183 ; CHECK: mov sp, [[REG2]]
184 ; CHECK: sub sp, x29, #48
185 ; CHECK: ldp x29, x30, [sp, #48]
186 ; CHECK: ldp x19, x20, [sp, #32]
187 ; CHECK: ldp x21, x22, [sp, #16]
188 ; CHECK: ldr x23, [sp], #112
190 define void @vla(i32, i8*, ...) local_unnamed_addr {
191 %3 = alloca i8*, align 8
192 %4 = bitcast i8** %3 to i8*
193 call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %4) #5
194 call void @llvm.va_start(i8* nonnull %4)
195 %5 = zext i32 %0 to i64
196 %6 = call i8* @llvm.stacksave()
197 %7 = alloca i8, i64 %5, align 1
198 %8 = load i8*, i8** %3, align 8
199 %9 = sext i32 %0 to i64
200 %10 = call i64* @__local_stdio_printf_options()
201 %11 = load i64, i64* %10, align 8
203 %13 = call i32 @__stdio_common_vsprintf(i64 %12, i8* nonnull %7, i64 %9, i8* %1, i8* null, i8* %8)
204 call void @llvm.va_end(i8* nonnull %4)
205 call void @llvm.stackrestore(i8* %6)
206 call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %4) #5
210 declare i8* @llvm.stacksave()
211 declare void @llvm.stackrestore(i8*)
213 ; CHECK-LABEL: snprintf
214 ; CHECK-DAG: sub sp, sp, #96
215 ; CHECK-DAG: str x21, [sp, #16]
216 ; CHECK-DAG: stp x19, x20, [sp, #24]
217 ; CHECK-DAG: str x30, [sp, #40]
218 ; CHECK-DAG: add x8, sp, #56
219 ; CHECK-DAG: mov x19, x2
220 ; CHECK-DAG: mov x20, x1
221 ; CHECK-DAG: mov x21, x0
222 ; CHECK-DAG: stp x3, x4, [sp, #56]
223 ; CHECK-DAG: stp x5, x6, [sp, #72]
224 ; CHECK-DAG: str x7, [sp, #88]
225 ; CHECK-DAG: str x8, [sp, #8]
226 ; CHECK-DAG: bl __local_stdio_printf_options
227 ; CHECK-DAG: ldr x8, [x0]
228 ; CHECK-DAG: add x5, sp, #56
229 ; CHECK-DAG: mov x1, x21
230 ; CHECK-DAG: mov x2, x20
231 ; CHECK-DAG: orr x0, x8, #0x2
232 ; CHECK-DAG: mov x3, x19
233 ; CHECK-DAG: mov x4, xzr
234 ; CHECK-DAG: bl __stdio_common_vsprintf
235 ; CHECK-DAG: ldr x30, [sp, #40]
236 ; CHECK-DAG: ldp x19, x20, [sp, #24]
237 ; CHECK-DAG: ldr x21, [sp, #16]
238 ; CHECK-DAG: cmp w0, #0
239 ; CHECK-DAG: csinv w0, w0, wzr, ge
240 ; CHECK-DAG: add sp, sp, #96
242 define i32 @snprintf(i8*, i64, i8*, ...) local_unnamed_addr #5 {
243 %4 = alloca i8*, align 8
244 %5 = bitcast i8** %4 to i8*
245 call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %5) #2
246 call void @llvm.va_start(i8* nonnull %5)
247 %6 = load i8*, i8** %4, align 8
248 %7 = call i64* @__local_stdio_printf_options() #2
249 %8 = load i64, i64* %7, align 8
251 %10 = call i32 @__stdio_common_vsprintf(i64 %9, i8* %0, i64 %1, i8* %2, i8* null, i8* %6) #2
252 %11 = icmp sgt i32 %10, -1
253 %12 = select i1 %11, i32 %10, i32 -1
254 call void @llvm.va_end(i8* nonnull %5)
255 call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %5) #2
259 ; CHECK-LABEL: fixed_params
260 ; CHECK: sub sp, sp, #32
261 ; CHECK-DAG: mov w6, w3
262 ; CHECK-DAG: mov [[REG1:w[0-9]+]], w2
264 ; CHECK: str w4, [sp]
269 ; CHECK: mov w4, [[REG1]]
270 ; CHECK: str x30, [sp, #16]
271 ; CHECK: str d4, [sp, #8]
273 ; CHECK: ldr x30, [sp, #16]
274 ; CHECK: add sp, sp, #32
276 define void @fixed_params(i32, double, i32, double, i32, double, i32, double, i32, double) nounwind {
277 tail call void (i32, ...) @varargs(i32 %0, double %1, i32 %2, double %3, i32 %4, double %5, i32 %6, double %7, i32 %8, double %9)
281 declare void @varargs(i32, ...) local_unnamed_addr