Index: llvm/lib/Target/AArch64/AArch64FrameLowering.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64FrameLowering.cpp +++ llvm/lib/Target/AArch64/AArch64FrameLowering.cpp @@ -216,6 +216,19 @@ return TargetStackID::SVEVector; } +/// Returns the size of fixed object (to determine the prologue size). +static unsigned getFixedObjectSize(const MachineFunction &MF, + const AArch64FunctionInfo *AFI, bool IsWin64, + bool IsFunclet) { + if (!IsWin64 || IsFunclet) { + return 0; + } else { + const unsigned VarArgsArea = alignTo(AFI->getVarArgsGPRSize(), 16); + const unsigned UnwindHelpObject = (MF.hasEHFunclets() ? 16 : 0); + return VarArgsArea + UnwindHelpObject; + } +} + /// Returns the size of the entire SVE stackframe (calleesaves + spills). static StackOffset getSVEStackSize(const MachineFunction &MF) { const AArch64FunctionInfo *AFI = MF.getInfo(); @@ -997,8 +1010,7 @@ Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); // Var args are accounted for in the containing function, so don't // include them for funclets. - unsigned FixedObject = (IsWin64 && !IsFunclet) ? - alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet); auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject; // All of the remaining stack allocations are for locals. @@ -1487,8 +1499,7 @@ Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); // Var args are accounted for in the containing function, so don't // include them for funclets. - unsigned FixedObject = - (IsWin64 && !IsFunclet) ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet); uint64_t AfterCSRPopSize = ArgumentPopSize; auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject; @@ -1714,7 +1725,9 @@ const auto &Subtarget = MF.getSubtarget(); bool IsWin64 = Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv()); - unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0; + + unsigned FixedObject = + getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false); unsigned FPAdjust = isTargetDarwin(MF) ? 16 : AFI->getCalleeSavedStackSize(MF.getFrameInfo()); return {ObjectOffset + FixedObject + FPAdjust, MVT::i8}; @@ -2664,10 +2677,23 @@ while (MBBI != MBB.end() && MBBI->getFlag(MachineInstr::FrameSetup)) ++MBBI; + // Find the minimum fixed object offset already allocated. + int64_t MinFixedObjOffset = -getOffsetOfLocalArea(); + for (int I = MFI.getObjectIndexBegin(); I < 0; ++I) + MinFixedObjOffset = std::min(MinFixedObjOffset, MFI.getObjectOffset(I)); + + // Allocate space for the UnwindHelp object + assert(MinFixedObjOffset <= 0 && "Unexpected MinFixedObjOffset"); + int64_t UnwindHelpOffset = MinFixedObjOffset -= 8; + + // Ensure alignment. + UnwindHelpOffset = -alignTo(-UnwindHelpOffset, 16); + // Create an UnwindHelp object. - int UnwindHelpFI = - MFI.CreateStackObject(/*size*/8, /*alignment*/16, false); + int UnwindHelpFI = MFI.CreateFixedObject(/*size*/ 8, UnwindHelpOffset, + /*IsImmutable=*/false); EHInfo.UnwindHelpFrameIdx = UnwindHelpFI; + // We need to store -2 into the UnwindHelp object at the start of the // function. DebugLoc DL; @@ -3079,10 +3105,14 @@ const MachineFunction &MF, int FI, unsigned &FrameReg, bool IgnoreSPUpdates) const { const MachineFrameInfo &MFI = MF.getFrameInfo(); - LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is " - << MFI.getObjectOffset(FI) << "\n"); - FrameReg = AArch64::SP; - return MFI.getObjectOffset(FI); + if (IgnoreSPUpdates) { + LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is " + << MFI.getObjectOffset(FI) << "\n"); + FrameReg = AArch64::SP; + return MFI.getObjectOffset(FI); + } + + return getFrameIndexReference(MF, FI, FrameReg); } /// The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve Index: llvm/test/CodeGen/AArch64/seh-finally.ll =================================================================== --- llvm/test/CodeGen/AArch64/seh-finally.ll +++ llvm/test/CodeGen/AArch64/seh-finally.ll @@ -37,7 +37,7 @@ ; CHECK-LABEL: simple_seh ; CHECK: add x29, sp, #16 ; CHECK: mov x0, #-2 -; CHECK: stur x0, [x29, #-16] +; CHECK: stur x0, [x29, #16] ; CHECK: .set .Lsimple_seh$frame_escape_0, -8 ; CHECK: ldur w0, [x29, #-8] ; CHECK: bl foo @@ -87,13 +87,13 @@ entry: ; CHECK-LABEL: stack_realign ; CHECK: mov x29, sp -; CHECK: sub x9, sp, #64 +; CHECK: sub x9, sp, #16 ; CHECK: and sp, x9, #0xffffffffffffffe0 ; CHECK: mov x19, sp ; CHECK: mov x0, #-2 -; CHECK: stur x0, [x19, #16] -; CHECK: .set .Lstack_realign$frame_escape_0, 32 -; CHECK: ldr w0, [x19, #32] +; CHECK: stur x0, [x29, #32] +; CHECK: .set .Lstack_realign$frame_escape_0, 0 +; CHECK: ldr w0, [x19] ; CHECK: bl foo %o = alloca %struct.S, align 32 @@ -142,7 +142,7 @@ ; CHECK-LABEL: vla_present ; CHECK: add x29, sp, #32 ; CHECK: mov x1, #-2 -; CHECK: stur x1, [x29, #-32] +; CHECK: stur x1, [x29, #16] ; CHECK: .set .Lvla_present$frame_escape_0, -4 ; CHECK: stur w0, [x29, #-4] ; CHECK: ldur w8, [x29, #-4] @@ -206,17 +206,17 @@ entry: ; CHECK-LABEL: vla_and_realign ; CHECK: mov x29, sp -; CHECK: sub x9, sp, #64 +; CHECK: sub x9, sp, #48 ; CHECK: and sp, x9, #0xffffffffffffffe0 ; CHECK: mov x19, sp ; CHECK: mov x1, #-2 -; CHECK: stur x1, [x19] +; CHECK: stur x1, [x29, #32] ; CHECK: .set .Lvla_and_realign$frame_escape_0, 32 -; CHECK: str w0, [x29, #28] -; CHECK: ldr w8, [x29, #28] +; CHECK: str w0, [x29, #44] +; CHECK: ldr w8, [x29, #44] ; CHECK: mov x9, sp -; CHECK: str x9, [x19, #24] -; CHECK: str x8, [x19, #16] +; CHECK: str x9, [x29, #24] +; CHECK: str x8, [x19, #24] ; CHECK: ldr w0, [x19, #32] ; CHECK: bl foo Index: llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll =================================================================== --- llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll +++ llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll @@ -4,11 +4,10 @@ ; but the original issue only reproduced if the cbz was immediately ; after the frame setup.) -; CHECK: sub sp, sp, #32 -; CHECK-NEXT: stp x29, x30, [sp, #16] -; CHECK-NEXT: add x29, sp, #16 +; CHECK: stp x29, x30, [sp, #-32]! +; CHECK-NEXT: mov x29, sp ; CHECK-NEXT: mov x1, #-2 -; CHECK-NEXT: stur x1, [x29, #-16] +; CHECK-NEXT: stur x1, [x29, #16] ; CHECK-NEXT: cbz w0, .LBB0_2 target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" Index: llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll =================================================================== --- llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll +++ llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll @@ -12,7 +12,7 @@ ; CHECK: stp x29, x30, [sp, #-32]! ; CHECK-NEXT: str x28, [sp, #16] ; CHECK-NEXT: str x19, [sp, #24] -; CHECK-NEXT: add x0, x19, #64 +; CHECK-NEXT: add x0, x19, #0 ; CHECK-NEXT: mov w1, wzr ; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z" ; CHECK-NEXT: adrp x0, .LBB0_1 Index: llvm/test/CodeGen/AArch64/wineh-try-catch.ll =================================================================== --- llvm/test/CodeGen/AArch64/wineh-try-catch.ll +++ llvm/test/CodeGen/AArch64/wineh-try-catch.ll @@ -11,11 +11,11 @@ ; and the parent function. ; The following checks that the unwind help object has -2 stored into it at -; fp - 400 - 256 = fp - 656, which is on-entry sp - 48 + 32 - 656 = -; on-entry sp - 672. We check this offset in the table later on. +; fp + 16, which is on-entry sp - 16. +; We check this offset in the table later on. ; CHECK-LABEL: "?func@@YAHXZ": -; CHECK: stp x29, x30, [sp, #-48]! +; CHECK: stp x29, x30, [sp, #-64]! ; CHECK: str x28, [sp, #16] ; CHECK: str x21, [sp, #24] ; CHECK: stp x19, x20, [sp, #32] @@ -23,7 +23,7 @@ ; CHECK: sub sp, sp, #624 ; CHECK: mov x19, sp ; CHECK: mov x0, #-2 -; CHECK: stur x0, [x19] +; CHECK: stur x0, [x29, #48] ; Now check that x is stored at fp - 20. We check that this is the same ; location accessed from the funclet to retrieve x. @@ -72,7 +72,7 @@ ; Now check that the offset of the unwind help object from the stack pointer on ; entry to func is encoded in cppxdata that is passed to __CxxFrameHandler3. As -; computed above, this comes to -672. +; computed above, this comes to -16. ; CHECK-LABEL: "$cppxdata$?func@@YAHXZ": ; CHECK-NEXT: .word 429065506 ; MagicNumber ; CHECK-NEXT: .word 2 ; MaxState @@ -81,7 +81,7 @@ ; CHECK-NEXT: .word ("$tryMap$?func@@YAHXZ")@IMGREL ; TryBlockMap ; CHECK-NEXT: .word 4 ; IPMapEntries ; CHECK-NEXT: .word ("$ip2state$?func@@YAHXZ")@IMGREL ; IPToStateXData -; CHECK-NEXT: .word -672 ; UnwindHelp +; CHECK-NEXT: .word -16 ; UnwindHelp ; UNWIND: Function: ?func@@YAHXZ (0x0) ; UNWIND: Prologue [ @@ -91,7 +91,7 @@ ; UNWIND-NEXT: ; stp x19, x20, [sp, #32] ; UNWIND-NEXT: ; str x21, [sp, #24] ; UNWIND-NEXT: ; str x28, [sp, #16] -; UNWIND-NEXT: ; stp x29, x30, [sp, #-48]! +; UNWIND-NEXT: ; stp x29, x30, [sp, #-64]! ; UNWIND-NEXT: ; end ; UNWIND: Function: ?catch$2@?0??func@@YAHXZ@4HA ; UNWIND: Prologue [ Index: llvm/test/CodeGen/AArch64/wineh-unwindhelp-via-fp.ll =================================================================== --- /dev/null +++ llvm/test/CodeGen/AArch64/wineh-unwindhelp-via-fp.ll @@ -0,0 +1,166 @@ +; RUN: llc -o - %s -mtriple=aarch64-windows | FileCheck %s +; Check that we allocate the unwind help stack object in a fixed location from fp +; so that the runtime can find it when handling an exception +target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128" +target triple = "aarch64-pc-windows-msvc19.25.28611" + +; Check that the store to the unwind help object for func2 is via FP +; CHECK-LABEL: ?func2@@YAXXZ +; CHECK: mov x[[#SCRATCH_REG:]], #-2 +; CHECK: stur x[[#SCRATCH_REG:]], [x29, #[[#]]] +; +; // struct that requires greater than stack alignment +; struct alignas(32) A +; { +; // data that would be invalid for unwind help (> 0) +; int _x[4]{42, 42, 42, 42}; +; ~A() {} +; }; +; +; // cause us to run the funclet in func2 +; void func3() +; { +; throw 1; +; } +; +; // the funclet that ensures we have the unwind help correct +; void func2() +; { +; A a; +; func3(); +; } +; +; // function to ensure we are misaligned in func2 +; void func1() +; { +; func2(); +; } +; +; // set things up and ensure alignment for func1 +; void test() +; { +; try { +; A a; +; func1(); +; } catch(...) {} +; } + +%rtti.TypeDescriptor2 = type { i8**, i8*, [3 x i8] } +%eh.CatchableType = type { i32, i32, i32, i32, i32, i32, i32 } +%eh.CatchableTypeArray.1 = type { i32, [1 x i32] } +%eh.ThrowInfo = type { i32, i32, i32, i32 } +%struct.A = type { [4 x i32], [16 x i8] } + +$"??0A@@QEAA@XZ" = comdat any + +$"??1A@@QEAA@XZ" = comdat any + +$"??_R0H@8" = comdat any + +$"_CT??_R0H@84" = comdat any + +$_CTA1H = comdat any + +$_TI1H = comdat any + +@"??_7type_info@@6B@" = external constant i8* +@"??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { i8** @"??_7type_info@@6B@", i8* null, [3 x i8] c".H\00" }, comdat +@__ImageBase = external dso_local constant i8 +@"_CT??_R0H@84" = linkonce_odr unnamed_addr constant %eh.CatchableType { i32 1, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%rtti.TypeDescriptor2* @"??_R0H@8" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32), i32 0, i32 -1, i32 0, i32 4, i32 0 }, section ".xdata", comdat +@_CTA1H = linkonce_odr unnamed_addr constant %eh.CatchableTypeArray.1 { i32 1, [1 x i32] [i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableType* @"_CT??_R0H@84" to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32)] }, section ".xdata", comdat +@_TI1H = linkonce_odr unnamed_addr constant %eh.ThrowInfo { i32 0, i32 0, i32 0, i32 trunc (i64 sub nuw nsw (i64 ptrtoint (%eh.CatchableTypeArray.1* @_CTA1H to i64), i64 ptrtoint (i8* @__ImageBase to i64)) to i32) }, section ".xdata", comdat + +; Function Attrs: noinline optnone uwtable +define dso_local void @"?func3@@YAXXZ"() #0 { + %1 = alloca i32, align 4 + store i32 1, i32* %1, align 4 + %2 = bitcast i32* %1 to i8* + call void @_CxxThrowException(i8* %2, %eh.ThrowInfo* @_TI1H) #2 + unreachable +} + +declare dso_local void @_CxxThrowException(i8*, %eh.ThrowInfo*) + +; Function Attrs: noinline optnone uwtable +define dso_local void @"?func2@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { + %1 = alloca %struct.A, align 32 + %2 = call %struct.A* @"??0A@@QEAA@XZ"(%struct.A* %1) #3 + invoke void @"?func3@@YAXXZ"() + to label %3 unwind label %4 + +3: ; preds = %0 + call void @"??1A@@QEAA@XZ"(%struct.A* %1) #3 + ret void + +4: ; preds = %0 + %5 = cleanuppad within none [] + call void @"??1A@@QEAA@XZ"(%struct.A* %1) #3 [ "funclet"(token %5) ] + cleanupret from %5 unwind to caller +} + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr dso_local %struct.A* @"??0A@@QEAA@XZ"(%struct.A* returned %0) unnamed_addr #1 comdat align 2 { + %2 = alloca %struct.A*, align 8 + store %struct.A* %0, %struct.A** %2, align 8 + %3 = load %struct.A*, %struct.A** %2, align 8 + %4 = getelementptr inbounds %struct.A, %struct.A* %3, i32 0, i32 0 + %5 = getelementptr inbounds [4 x i32], [4 x i32]* %4, i64 0, i64 0 + store i32 42, i32* %5, align 4 + %6 = getelementptr inbounds i32, i32* %5, i64 1 + store i32 42, i32* %6, align 4 + %7 = getelementptr inbounds i32, i32* %6, i64 1 + store i32 42, i32* %7, align 4 + %8 = getelementptr inbounds i32, i32* %7, i64 1 + store i32 42, i32* %8, align 4 + ret %struct.A* %3 +} + +declare dso_local i32 @__CxxFrameHandler3(...) + +; Function Attrs: noinline nounwind optnone uwtable +define linkonce_odr dso_local void @"??1A@@QEAA@XZ"(%struct.A* %0) unnamed_addr #1 comdat align 2 { + %2 = alloca %struct.A*, align 8 + store %struct.A* %0, %struct.A** %2, align 8 + %3 = load %struct.A*, %struct.A** %2, align 8 + ret void +} + +; Function Attrs: noinline optnone uwtable +define dso_local void @"?func1@@YAXXZ"() #0 { + call void @"?func2@@YAXXZ"() + ret void +} + +; Function Attrs: noinline optnone uwtable +define dso_local void @"?test@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { + %1 = alloca %struct.A, align 32 + %2 = call %struct.A* @"??0A@@QEAA@XZ"(%struct.A* %1) #3 + invoke void @"?func1@@YAXXZ"() + to label %3 unwind label %4 + +3: ; preds = %0 + call void @"??1A@@QEAA@XZ"(%struct.A* %1) #3 + br label %11 + +4: ; preds = %0 + %5 = cleanuppad within none [] + call void @"??1A@@QEAA@XZ"(%struct.A* %1) #3 [ "funclet"(token %5) ] + cleanupret from %5 unwind label %6 + +6: ; preds = %4 + %7 = catchswitch within none [label %8] unwind to caller + +8: ; preds = %6 + %9 = catchpad within %7 [i8* null, i32 64, i8* null] + catchret from %9 to label %10 + +10: ; preds = %8 + br label %11 + +11: ; preds = %10, %3 + ret void +} + +!llvm.module.flags = !{!0} + +!0 = !{i32 1, !"wchar_size", i32 2}