Skip to content

Backport fixes for aarch64-pc-windows-msvc #45

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
[AArch64] Change AArch64 Windows EH UnwindHelp object to be a fixed o…
…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 committed Apr 2, 2020
commit cfc8124ce4ccadec2080e691978c59854f4aaa85
53 changes: 38 additions & 15 deletions llvm/lib/Target/AArch64/AArch64FrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,24 @@ static unsigned estimateRSStackSizeLimit(MachineFunction &MF) {
return DefaultSafeSPDisplacement;
}

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

bool AArch64FrameLowering::canUseRedZone(const MachineFunction &MF) const {
if (!EnableRedZone)
return false;
Expand Down Expand Up @@ -891,10 +909,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 @@ -1335,10 +1350,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 @@ -1508,7 +1520,8 @@ static int getFPOffset(const MachineFunction &MF, int 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);
return ObjectOffset + FixedObject + 16;
}

Expand Down Expand Up @@ -2188,9 +2201,15 @@ 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
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
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 All @@ -2212,10 +2231,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: add x29, sp, #16
; 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, #16]
; 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: add x29, sp, #16
; 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, #16]
; CHECK: .set .Lvla_and_realign$frame_escape_0, 32
; CHECK: stur w0, [x29, #-4]
; CHECK: ldur w8, [x29, #-4]
; CHECK: str w0, [x29, #28]
; CHECK: ldr w8, [x29, #28]
; CHECK: mov x9, sp
; CHECK: str x9, [x19, #24]
; CHECK: str x8, [x19, #16]
; CHECK: str x9, [x19, #56]
; 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: str x28, [sp, #-32]!
; CHECK-NEXT: str x19, [sp, #8]
; CHECK-NEXT: stp x29, x30, [sp, #16]
; 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
22 changes: 11 additions & 11 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: str x28, [sp, #-48]!
; CHECK str x28, [sp, #-64]!
; CHECK: str x21, [sp, #8]
; CHECK: stp x19, x20, [sp, #16]
; CHECK: stp x29, x30, [sp, #32]
; CHECK: add x29, sp, #32
; CHECK: sub sp, sp, #624
; CHECK: mov x19, sp
; CHECK: mov x0, #-2
; CHECK: stur x0, [x19]
; CHECK: stur x0, [x29, #16]

; 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,17 +81,17 @@
; 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 [
; UNWIND-NEXT: ; nop
; UNWIND-NEXT: ; sub sp, #624
; UNWIND-NEXT: ; add fp, sp, #32
; UNWIND-NEXT: ; stp x29, x30, [sp, #32]
; UNWIND-NEXT: ; stp x19, x20, [sp, #16]
; UNWIND-NEXT: ; str x21, [sp, #8]
; UNWIND-NEXT: ; str x28, [sp, #48]!
; UNWIND-NEXT: ; mov fp, sp
; 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, #-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, #16]
;
; // 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)
declare dso_local void @"??1A@@QEAA@XZ"(%struct.A*)
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
}