1; RUN: llc < %s -mtriple=aarch64-pc-win32 | FileCheck %s 2 3define void @pass_va(i32 %count, ...) nounwind { 4entry: 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 15; CHECK: ret 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) 21 ret void 22} 23 24declare void @other_func(i8*) local_unnamed_addr 25 26declare void @llvm.va_start(i8*) nounwind 27declare void @llvm.va_copy(i8*, i8*) nounwind 28 29; CHECK-LABEL: f9: 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 35; CHECK: ret 36define i8* @f9(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, i64 %a8, ...) nounwind { 37entry: 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 42 ret i8* %ap2 43} 44 45; CHECK-LABEL: f8: 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 51; CHECK: ret 52define i8* @f8(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, i64 %a7, ...) nounwind { 53entry: 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 58 ret i8* %ap2 59} 60 61; CHECK-LABEL: f7: 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 68; CHECK: ret 69define i8* @f7(i64 %a0, i64 %a1, i64 %a2, i64 %a3, i64 %a4, i64 %a5, i64 %a6, ...) nounwind { 70entry: 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 75 ret i8* %ap2 76} 77 78; CHECK-LABEL: copy1: 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 86; CHECK: ret 87define void @copy1(i64 %a0, ...) nounwind { 88entry: 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) 95 ret void 96} 97 98declare void @llvm.va_end(i8*) 99declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) #1 100declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) #1 101 102declare i32 @__stdio_common_vsprintf(i64, i8*, i64, i8*, i8*, i8*) local_unnamed_addr #3 103declare i64* @__local_stdio_printf_options() local_unnamed_addr #4 104 105; CHECK-LABEL: fp 106; CHECK: stp x19, x20, [sp, #-96] 107; CHECK: str x21, [sp, #16] 108; CHECK: stp x29, x30, [sp, #24] 109; CHECK: add x29, sp, #24 110; CHECK: add x8, x29, #32 111; CHECK: mov x19, x2 112; CHECK: mov x20, x1 113; CHECK: mov x21, x0 114; CHECK: stp x3, x4, [x29, #32] 115; CHECK: stp x5, x6, [x29, #48] 116; CHECK: str x7, [x29, #64] 117; CHECK: str x8, [x29, #16] 118; CHECK: bl __local_stdio_printf_options 119; CHECK: ldr x8, [x0] 120; CHECK: add x5, x29, #32 121; CHECK: mov x1, x21 122; CHECK: mov x2, x20 123; CHECK: orr x0, x8, #0x2 124; CHECK: mov x3, x19 125; CHECK: mov x4, xzr 126; CHECK: bl __stdio_common_vsprintf 127; CHECK: cmp w0, #0 128; CHECK: csinv w0, w0, wzr, ge 129; CHECK: ldp x29, x30, [sp, #24] 130; CHECK: ldr x21, [sp, #16] 131; CHECK: ldp x19, x20, [sp], #96 132; CHECK: ret 133define 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 141 %9 = or i64 %8, 2 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 147 ret i32 %12 148} 149 150attributes #6 = { "frame-pointer"="all" } 151 152; CHECK-LABEL: vla 153; CHECK: stp x19, x20, [sp, #-112]! 154; CHECK: stp x21, x22, [sp, #16] 155; CHECK: str x23, [sp, #32] 156; CHECK: stp x29, x30, [sp, #40] 157; CHECK: add x29, sp, #40 158; CHECK: add x8, x29, #24 159; CHECK: str x8, [x29, #16] 160; CHECK: mov w8, w0 161; CHECK: add x8, x8, #15 162; CHECK: lsr x15, x8, #4 163; CHECK: mov x19, x1 164; CHECK: mov [[REG2:x[0-9]+]], sp 165; CHECK: stp x2, x3, [x29, #24] 166; CHECK: stp x4, x5, [x29, #40] 167; CHECK: stp x6, x7, [x29, #56] 168; CHECK: bl __chkstk 169; CHECK: mov x8, sp 170; CHECK: sub [[REG:x[0-9]+]], x8, x15, lsl #4 171; CHECK: mov sp, [[REG]] 172; CHECK: ldr [[REG3:x[0-9]+]], [x29, #16] 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]] 178; CHECK: mov x3, x19 179; CHECK: orr x0, x8, #0x2 180; CHECK: mov x4, xzr 181; CHECK: mov x5, [[REG3]] 182; CHECK: bl __stdio_common_vsprintf 183; CHECK: mov sp, [[REG2]] 184; CHECK: sub sp, x29, #40 185; CHECK: ldp x29, x30, [sp, #40] 186; CHECK: ldr x23, [sp, #32] 187; CHECK: ldp x21, x22, [sp, #16] 188; CHECK: ldp x19, x20, [sp], #112 189; CHECK: ret 190define 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 202 %12 = or i64 %11, 2 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 207 ret void 208} 209 210declare i8* @llvm.stacksave() 211declare void @llvm.stackrestore(i8*) 212 213; CHECK-LABEL: snprintf 214; CHECK-DAG: sub sp, sp, #96 215; CHECK-DAG: stp x19, x20, [sp, #16] 216; CHECK-DAG: stp x21, x30, [sp, #32] 217; CHECK-DAG: add x8, sp, #56 218; CHECK-DAG: mov x19, x2 219; CHECK-DAG: mov x20, x1 220; CHECK-DAG: mov x21, x0 221; CHECK-DAG: stp x3, x4, [sp, #56] 222; CHECK-DAG: stp x5, x6, [sp, #72] 223; CHECK-DAG: str x7, [sp, #88] 224; CHECK-DAG: str x8, [sp, #8] 225; CHECK-DAG: bl __local_stdio_printf_options 226; CHECK-DAG: ldr x8, [x0] 227; CHECK-DAG: add x5, sp, #56 228; CHECK-DAG: mov x1, x21 229; CHECK-DAG: mov x2, x20 230; CHECK-DAG: orr x0, x8, #0x2 231; CHECK-DAG: mov x3, x19 232; CHECK-DAG: mov x4, xzr 233; CHECK-DAG: bl __stdio_common_vsprintf 234; CHECK-DAG: ldp x21, x30, [sp, #32] 235; CHECK-DAG: ldp x19, x20, [sp, #16] 236; CHECK-DAG: cmp w0, #0 237; CHECK-DAG: csinv w0, w0, wzr, ge 238; CHECK-DAG: add sp, sp, #96 239; CHECK-DAG: ret 240define i32 @snprintf(i8*, i64, i8*, ...) local_unnamed_addr #5 { 241 %4 = alloca i8*, align 8 242 %5 = bitcast i8** %4 to i8* 243 call void @llvm.lifetime.start.p0i8(i64 8, i8* nonnull %5) #2 244 call void @llvm.va_start(i8* nonnull %5) 245 %6 = load i8*, i8** %4, align 8 246 %7 = call i64* @__local_stdio_printf_options() #2 247 %8 = load i64, i64* %7, align 8 248 %9 = or i64 %8, 2 249 %10 = call i32 @__stdio_common_vsprintf(i64 %9, i8* %0, i64 %1, i8* %2, i8* null, i8* %6) #2 250 %11 = icmp sgt i32 %10, -1 251 %12 = select i1 %11, i32 %10, i32 -1 252 call void @llvm.va_end(i8* nonnull %5) 253 call void @llvm.lifetime.end.p0i8(i64 8, i8* nonnull %5) #2 254 ret i32 %12 255} 256 257; CHECK-LABEL: fixed_params 258; CHECK: sub sp, sp, #32 259; CHECK-DAG: mov w6, w3 260; CHECK-DAG: mov [[REG1:w[0-9]+]], w2 261; CHECK: mov w2, w1 262; CHECK: fmov x1, d0 263; CHECK: fmov x3, d1 264; CHECK: fmov x5, d2 265; CHECK: fmov x7, d3 266; CHECK: str w4, [sp] 267; CHECK: mov w4, [[REG1]] 268; CHECK: str x30, [sp, #16] 269; CHECK: str d4, [sp, #8] 270; CHECK: bl varargs 271; CHECK: ldr x30, [sp, #16] 272; CHECK: add sp, sp, #32 273; CHECK: ret 274define void @fixed_params(i32, double, i32, double, i32, double, i32, double, i32, double) nounwind { 275 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) 276 ret void 277} 278 279declare void @varargs(i32, ...) local_unnamed_addr 280