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 x29, x30, [sp, #-96] 107; CHECK: str x21, [sp, #16] 108; CHECK: stp x19, x20, [sp, #32] 109; CHECK: mov x29, sp 110; CHECK: add x8, x29, #56 111; CHECK: mov x19, x2 112; CHECK: mov x20, x1 113; CHECK: mov x21, x0 114; CHECK: stp x3, x4, [x29, #56] 115; CHECK: stp x5, x6, [x29, #72] 116; CHECK: str x7, [x29, #88] 117; CHECK: str x8, [x29, #24] 118; CHECK: bl __local_stdio_printf_options 119; CHECK: ldr x8, [x0] 120; CHECK: add x5, x29, #56 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 x19, x20, [sp, #32] 130; CHECK: ldr x21, [sp, #16] 131; CHECK: ldp x29, x30, [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 x29, x30, [sp, #-112]! 154; CHECK: str x23, [sp, #16] 155; CHECK: stp x21, x22, [sp, #32] 156; CHECK: stp x19, x20, [sp, #48] 157; CHECK: mov x29, sp 158; CHECK: add x8, x29, #64 159; CHECK: str x8, [x29, #24] 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, #64] 166; CHECK: stp x4, x5, [x29, #80] 167; CHECK: stp x6, x7, [x29, #96] 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, #24] 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: mov sp, x29 185; CHECK: ldp x19, x20, [sp, #48] 186; CHECK: ldp x21, x22, [sp, #32] 187; CHECK: ldr x23, [sp, #16] 188; CHECK: ldp x29, x30, [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: str x30, [sp, #16] 216; CHECK-DAG: str x21, [sp, #24] 217; CHECK-DAG: stp x19, x20, [sp, #32] 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, #16] 236; CHECK-DAG: ldr x21, [sp, #24] 237; CHECK-DAG: ldp x19, x20, [sp, #32] 238; CHECK-DAG: cmp w0, #0 239; CHECK-DAG: csinv w0, w0, wzr, ge 240; CHECK-DAG: add sp, sp, #96 241; CHECK-DAG: ret 242define 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 250 %9 = or i64 %8, 2 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 256 ret i32 %12 257} 258 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 263; CHECK: mov w2, w1 264; CHECK: fmov x1, d0 265; CHECK: fmov x3, d1 266; CHECK: fmov x5, d2 267; CHECK: fmov x7, d3 268; CHECK: str w4, [sp] 269; CHECK: mov w4, [[REG1]] 270; CHECK: str x30, [sp, #16] 271; CHECK: str d4, [sp, #8] 272; CHECK: bl varargs 273; CHECK: ldr x30, [sp, #16] 274; CHECK: add sp, sp, #32 275; CHECK: ret 276define 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) 278 ret void 279} 280 281declare void @varargs(i32, ...) local_unnamed_addr 282