diff --git a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp --- a/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64CallLowering.cpp @@ -564,6 +564,11 @@ if (IsWin64CC) { GPRIdx = MFI.CreateFixedObject(GPRSaveSize, -static_cast(GPRSaveSize), false); + if (GPRSaveSize & 15) + // The extra size here, if triggered, will always be 8. + MFI.CreateFixedObject(16 - (GPRSaveSize & 15), + -static_cast(alignTo(GPRSaveSize, 16)), + false); } else GPRIdx = MFI.CreateStackObject(GPRSaveSize, Align(8), false); diff --git a/llvm/test/CodeGen/AArch64/win64_vararg2.ll b/llvm/test/CodeGen/AArch64/win64_vararg2.ll new file mode 100644 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/win64_vararg2.ll @@ -0,0 +1,82 @@ +; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py +; RUN: llc < %s -mtriple=aarch64-pc-win32 | FileCheck %s +; RUN: llc < %s -global-isel -mtriple=aarch64-pc-win32 | FileCheck %s --check-prefix=GISEL + +; Function Attrs: mustprogress noinline nounwind optnone uwtable +define i1 @va_func(i32 %a, i8 %b, i8 %c, ...) { +; CHECK-LABEL: va_func: +; CHECK: .seh_proc va_func +; CHECK-NEXT: // %bb.0: +; CHECK-NEXT: sub sp, sp, #80 +; CHECK-NEXT: .seh_stackalloc 80 +; CHECK-NEXT: str x19, [sp, #16] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x19, 16 +; CHECK-NEXT: str x30, [sp, #24] // 8-byte Folded Spill +; CHECK-NEXT: .seh_save_reg x30, 24 +; CHECK-NEXT: .seh_endprologue +; CHECK-NEXT: mov w19, w0 +; CHECK-NEXT: stp x3, x4, [sp, #40] +; CHECK-NEXT: stp x5, x6, [sp, #56] +; CHECK-NEXT: str x7, [sp, #72] +; CHECK-NEXT: str w0, [sp, #12] +; CHECK-NEXT: strb w1, [sp, #11] +; CHECK-NEXT: strb w2, [sp, #10] +; CHECK-NEXT: bl other +; CHECK-NEXT: cmp w19, w0 +; CHECK-NEXT: cset w0, ls +; CHECK-NEXT: .seh_startepilogue +; CHECK-NEXT: ldr x30, [sp, #24] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x30, 24 +; CHECK-NEXT: ldr x19, [sp, #16] // 8-byte Folded Reload +; CHECK-NEXT: .seh_save_reg x19, 16 +; CHECK-NEXT: add sp, sp, #80 +; CHECK-NEXT: .seh_stackalloc 80 +; CHECK-NEXT: .seh_endepilogue +; CHECK-NEXT: ret +; CHECK-NEXT: .seh_endfunclet +; CHECK-NEXT: .seh_endproc +; +; GISEL-LABEL: va_func: +; GISEL: .seh_proc va_func +; GISEL-NEXT: // %bb.0: +; GISEL-NEXT: sub sp, sp, #80 +; GISEL-NEXT: .seh_stackalloc 80 +; GISEL-NEXT: str x19, [sp, #16] // 8-byte Folded Spill +; GISEL-NEXT: .seh_save_reg x19, 16 +; GISEL-NEXT: str x30, [sp, #24] // 8-byte Folded Spill +; GISEL-NEXT: .seh_save_reg x30, 24 +; GISEL-NEXT: .seh_endprologue +; GISEL-NEXT: stp x3, x4, [sp, #40] +; GISEL-NEXT: mov w19, w0 +; GISEL-NEXT: stp x5, x6, [sp, #56] +; GISEL-NEXT: str w0, [sp, #12] +; GISEL-NEXT: str x7, [sp, #72] +; GISEL-NEXT: strb w1, [sp, #11] +; GISEL-NEXT: strb w2, [sp, #10] +; GISEL-NEXT: bl other +; GISEL-NEXT: cmp w19, w0 +; GISEL-NEXT: cset w0, ls +; GISEL-NEXT: .seh_startepilogue +; GISEL-NEXT: ldr x30, [sp, #24] // 8-byte Folded Reload +; GISEL-NEXT: .seh_save_reg x30, 24 +; GISEL-NEXT: ldr x19, [sp, #16] // 8-byte Folded Reload +; GISEL-NEXT: .seh_save_reg x19, 16 +; GISEL-NEXT: add sp, sp, #80 +; GISEL-NEXT: .seh_stackalloc 80 +; GISEL-NEXT: .seh_endepilogue +; GISEL-NEXT: ret +; GISEL-NEXT: .seh_endfunclet +; GISEL-NEXT: .seh_endproc + %a_alloc = alloca i32, align 4 + %b_alloc = alloca i8, align 1 + %c_alloc = alloca i8, align 1 + store i32 %a, ptr %a_alloc, align 4 + store i8 %b, ptr %b_alloc, align 1 + store i8 %c, ptr %c_alloc, align 1 + %a_load = load i32, ptr %a_alloc, align 4 + %ret = call noundef i32 @other() + %cmp = icmp ule i32 %a_load, %ret + ret i1 %cmp +} + +declare i32 @other()