Skip to content

Commit

Permalink
[AArch64] Change AArch64 Windows EH UnwindHelp object to be a fixed o…
Browse files Browse the repository at this point in the history
…bject

The UnwindHelp object is used during exception handling by runtime
code. It must be findable from a fixed offset from FP.

This change allocates the UnwindHelp object as a fixed object (as is
done for x86_64) to ensure that both the generated code and runtime
agree on the location of the object.

Fixes https://bugs.llvm.org/show_bug.cgi?id=45346

Differential Revision: https://reviews.llvm.org/D77016
  • Loading branch information
danielframpton authored and efriedma-quic committed Mar 31, 2020
1 parent 522b4c4 commit 494abe1
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 39 deletions.
53 changes: 38 additions & 15 deletions llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,24 @@ AArch64FrameLowering::getStackIDForScalableVectors() const {
return TargetStackID::SVEVector;
}

/// Returns the size of the fixed object area (allocated next to sp on entry)
/// On Win64 this may include a var args area and an UnwindHelp object for EH.
static unsigned getFixedObjectSize(const MachineFunction &MF,
const AArch64FunctionInfo *AFI, bool IsWin64,
bool IsFunclet) {
if (!IsWin64 || IsFunclet) {
// Only Win64 uses fixed objects, and then only for the function (not
// funclets)
return 0;
} else {
// Var args are stored here in the primary function.
const unsigned VarArgsArea = AFI->getVarArgsGPRSize();
// To support EH funclets we allocate an UnwindHelp object
const unsigned UnwindHelpObject = (MF.hasEHFunclets() ? 8 : 0);
return alignTo(VarArgsArea + UnwindHelpObject, 16);
}
}

/// Returns the size of the entire SVE stackframe (calleesaves + spills).
static StackOffset getSVEStackSize(const MachineFunction &MF) {
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
Expand Down Expand Up @@ -995,10 +1013,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,

bool IsWin64 =
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.
Expand Down Expand Up @@ -1477,10 +1492,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,

bool IsWin64 =
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;
Expand Down Expand Up @@ -1706,7 +1718,9 @@ static StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset)
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
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};
Expand Down Expand Up @@ -2659,9 +2673,14 @@ void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
++MBBI;

// Create an UnwindHelp object.
int UnwindHelpFI =
MFI.CreateStackObject(/*size*/8, /*alignment*/16, false);
// The UnwindHelp object is allocated at the start of the fixed object area
int64_t FixedObject =
getFixedObjectSize(MF, AFI, /*IsWin64*/ true, /*IsFunclet*/ false);
int UnwindHelpFI = MFI.CreateFixedObject(/*Size*/ 8,
/*SPOffset*/ -FixedObject,
/*IsImmutable=*/false);
EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;

// We need to store -2 into the UnwindHelp object at the start of the
// function.
DebugLoc DL;
Expand Down Expand Up @@ -3073,10 +3092,14 @@ int AArch64FrameLowering::getFrameIndexReferencePreferSP(
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
Expand Down
24 changes: 12 additions & 12 deletions llvm/test/CodeGen/AArch64/seh-finally.ll
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ entry:
; 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
Expand Down Expand Up @@ -87,13 +87,13 @@ define void @stack_realign() #0 personality i8* bitcast (i32 (...)* @__C_specifi
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
Expand Down Expand Up @@ -142,7 +142,7 @@ entry:
; 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]
Expand Down Expand Up @@ -206,17 +206,17 @@ define void @vla_and_realign(i32 %n) #0 personality i8* bitcast (i32 (...)* @__C
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

Expand Down
7 changes: 3 additions & 4 deletions llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
2 changes: 1 addition & 1 deletion llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
14 changes: 7 additions & 7 deletions llvm/test/CodeGen/AArch64/wineh-try-catch.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,19 @@
; 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]
; CHECK: mov x29, sp
; 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.
Expand Down Expand Up @@ -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
Expand All @@ -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 [
Expand All @@ -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 [
Expand Down
69 changes: 69 additions & 0 deletions llvm/test/CodeGen/AArch64/wineh-unwindhelp-via-fp.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
; 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(...) {}
; }

%struct.A = type { [4 x i32], [16 x i8] }
declare dso_local %struct.A* @"??0A@@QEAA@XZ"(%struct.A* returned %0)
declare dso_local void @"??1A@@QEAA@XZ"(%struct.A* %0)
declare dso_local i32 @__CxxFrameHandler3(...)
declare dso_local void @"?func3@@YAXXZ"()

; 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
}

0 comments on commit 494abe1

Please sign in to comment.