Skip to content

Commit 494abe1

Browse files
danielframptonefriedma-quic
authored andcommitted
[AArch64] Change AArch64 Windows EH UnwindHelp object to be a fixed object
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
1 parent 522b4c4 commit 494abe1

6 files changed

+130
-39
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

+38-15
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,24 @@ AArch64FrameLowering::getStackIDForScalableVectors() const {
216216
return TargetStackID::SVEVector;
217217
}
218218

219+
/// Returns the size of the fixed object area (allocated next to sp on entry)
220+
/// On Win64 this may include a var args area and an UnwindHelp object for EH.
221+
static unsigned getFixedObjectSize(const MachineFunction &MF,
222+
const AArch64FunctionInfo *AFI, bool IsWin64,
223+
bool IsFunclet) {
224+
if (!IsWin64 || IsFunclet) {
225+
// Only Win64 uses fixed objects, and then only for the function (not
226+
// funclets)
227+
return 0;
228+
} else {
229+
// Var args are stored here in the primary function.
230+
const unsigned VarArgsArea = AFI->getVarArgsGPRSize();
231+
// To support EH funclets we allocate an UnwindHelp object
232+
const unsigned UnwindHelpObject = (MF.hasEHFunclets() ? 8 : 0);
233+
return alignTo(VarArgsArea + UnwindHelpObject, 16);
234+
}
235+
}
236+
219237
/// Returns the size of the entire SVE stackframe (calleesaves + spills).
220238
static StackOffset getSVEStackSize(const MachineFunction &MF) {
221239
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
@@ -995,10 +1013,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
9951013

9961014
bool IsWin64 =
9971015
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
998-
// Var args are accounted for in the containing function, so don't
999-
// include them for funclets.
1000-
unsigned FixedObject = (IsWin64 && !IsFunclet) ?
1001-
alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1016+
unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
10021017

10031018
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
10041019
// All of the remaining stack allocations are for locals.
@@ -1477,10 +1492,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
14771492

14781493
bool IsWin64 =
14791494
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1480-
// Var args are accounted for in the containing function, so don't
1481-
// include them for funclets.
1482-
unsigned FixedObject =
1483-
(IsWin64 && !IsFunclet) ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1495+
unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
14841496

14851497
uint64_t AfterCSRPopSize = ArgumentPopSize;
14861498
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
@@ -1706,7 +1718,9 @@ static StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset)
17061718
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
17071719
bool IsWin64 =
17081720
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1709-
unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1721+
1722+
unsigned FixedObject =
1723+
getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false);
17101724
unsigned FPAdjust = isTargetDarwin(MF)
17111725
? 16 : AFI->getCalleeSavedStackSize(MF.getFrameInfo());
17121726
return {ObjectOffset + FixedObject + FPAdjust, MVT::i8};
@@ -2659,9 +2673,14 @@ void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
26592673
++MBBI;
26602674

26612675
// Create an UnwindHelp object.
2662-
int UnwindHelpFI =
2663-
MFI.CreateStackObject(/*size*/8, /*alignment*/16, false);
2676+
// The UnwindHelp object is allocated at the start of the fixed object area
2677+
int64_t FixedObject =
2678+
getFixedObjectSize(MF, AFI, /*IsWin64*/ true, /*IsFunclet*/ false);
2679+
int UnwindHelpFI = MFI.CreateFixedObject(/*Size*/ 8,
2680+
/*SPOffset*/ -FixedObject,
2681+
/*IsImmutable=*/false);
26642682
EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
2683+
26652684
// We need to store -2 into the UnwindHelp object at the start of the
26662685
// function.
26672686
DebugLoc DL;
@@ -3073,10 +3092,14 @@ int AArch64FrameLowering::getFrameIndexReferencePreferSP(
30733092
const MachineFunction &MF, int FI, unsigned &FrameReg,
30743093
bool IgnoreSPUpdates) const {
30753094
const MachineFrameInfo &MFI = MF.getFrameInfo();
3076-
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
3077-
<< MFI.getObjectOffset(FI) << "\n");
3078-
FrameReg = AArch64::SP;
3079-
return MFI.getObjectOffset(FI);
3095+
if (IgnoreSPUpdates) {
3096+
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
3097+
<< MFI.getObjectOffset(FI) << "\n");
3098+
FrameReg = AArch64::SP;
3099+
return MFI.getObjectOffset(FI);
3100+
}
3101+
3102+
return getFrameIndexReference(MF, FI, FrameReg);
30803103
}
30813104

30823105
/// The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve

llvm/test/CodeGen/AArch64/seh-finally.ll

+12-12
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ entry:
3737
; CHECK-LABEL: simple_seh
3838
; CHECK: add x29, sp, #16
3939
; CHECK: mov x0, #-2
40-
; CHECK: stur x0, [x29, #-16]
40+
; CHECK: stur x0, [x29, #16]
4141
; CHECK: .set .Lsimple_seh$frame_escape_0, -8
4242
; CHECK: ldur w0, [x29, #-8]
4343
; CHECK: bl foo
@@ -87,13 +87,13 @@ define void @stack_realign() #0 personality i8* bitcast (i32 (...)* @__C_specifi
8787
entry:
8888
; CHECK-LABEL: stack_realign
8989
; CHECK: mov x29, sp
90-
; CHECK: sub x9, sp, #64
90+
; CHECK: sub x9, sp, #16
9191
; CHECK: and sp, x9, #0xffffffffffffffe0
9292
; CHECK: mov x19, sp
9393
; CHECK: mov x0, #-2
94-
; CHECK: stur x0, [x19, #16]
95-
; CHECK: .set .Lstack_realign$frame_escape_0, 32
96-
; CHECK: ldr w0, [x19, #32]
94+
; CHECK: stur x0, [x29, #32]
95+
; CHECK: .set .Lstack_realign$frame_escape_0, 0
96+
; CHECK: ldr w0, [x19]
9797
; CHECK: bl foo
9898

9999
%o = alloca %struct.S, align 32
@@ -142,7 +142,7 @@ entry:
142142
; CHECK-LABEL: vla_present
143143
; CHECK: add x29, sp, #32
144144
; CHECK: mov x1, #-2
145-
; CHECK: stur x1, [x29, #-32]
145+
; CHECK: stur x1, [x29, #16]
146146
; CHECK: .set .Lvla_present$frame_escape_0, -4
147147
; CHECK: stur w0, [x29, #-4]
148148
; CHECK: ldur w8, [x29, #-4]
@@ -206,17 +206,17 @@ define void @vla_and_realign(i32 %n) #0 personality i8* bitcast (i32 (...)* @__C
206206
entry:
207207
; CHECK-LABEL: vla_and_realign
208208
; CHECK: mov x29, sp
209-
; CHECK: sub x9, sp, #64
209+
; CHECK: sub x9, sp, #48
210210
; CHECK: and sp, x9, #0xffffffffffffffe0
211211
; CHECK: mov x19, sp
212212
; CHECK: mov x1, #-2
213-
; CHECK: stur x1, [x19]
213+
; CHECK: stur x1, [x29, #32]
214214
; CHECK: .set .Lvla_and_realign$frame_escape_0, 32
215-
; CHECK: str w0, [x29, #28]
216-
; CHECK: ldr w8, [x29, #28]
215+
; CHECK: str w0, [x29, #44]
216+
; CHECK: ldr w8, [x29, #44]
217217
; CHECK: mov x9, sp
218-
; CHECK: str x9, [x19, #24]
219-
; CHECK: str x8, [x19, #16]
218+
; CHECK: str x9, [x29, #24]
219+
; CHECK: str x8, [x19, #24]
220220
; CHECK: ldr w0, [x19, #32]
221221
; CHECK: bl foo
222222

llvm/test/CodeGen/AArch64/wineh-try-catch-cbz.ll

+3-4
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,10 @@
44
; but the original issue only reproduced if the cbz was immediately
55
; after the frame setup.)
66

7-
; CHECK: sub sp, sp, #32
8-
; CHECK-NEXT: stp x29, x30, [sp, #16]
9-
; CHECK-NEXT: add x29, sp, #16
7+
; CHECK: stp x29, x30, [sp, #-32]!
8+
; CHECK-NEXT: mov x29, sp
109
; CHECK-NEXT: mov x1, #-2
11-
; CHECK-NEXT: stur x1, [x29, #-16]
10+
; CHECK-NEXT: stur x1, [x29, #16]
1211
; CHECK-NEXT: cbz w0, .LBB0_2
1312

1413
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"

llvm/test/CodeGen/AArch64/wineh-try-catch-realign.ll

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
; CHECK: stp x29, x30, [sp, #-32]!
1313
; CHECK-NEXT: str x28, [sp, #16]
1414
; CHECK-NEXT: str x19, [sp, #24]
15-
; CHECK-NEXT: add x0, x19, #64
15+
; CHECK-NEXT: add x0, x19, #0
1616
; CHECK-NEXT: mov w1, wzr
1717
; CHECK-NEXT: bl "?bb@@YAXPEAHH@Z"
1818
; CHECK-NEXT: adrp x0, .LBB0_1

llvm/test/CodeGen/AArch64/wineh-try-catch.ll

+7-7
Original file line numberDiff line numberDiff line change
@@ -11,19 +11,19 @@
1111
; and the parent function.
1212

1313
; The following checks that the unwind help object has -2 stored into it at
14-
; fp - 400 - 256 = fp - 656, which is on-entry sp - 48 + 32 - 656 =
15-
; on-entry sp - 672. We check this offset in the table later on.
14+
; fp + 16, which is on-entry sp - 16.
15+
; We check this offset in the table later on.
1616

1717
; CHECK-LABEL: "?func@@YAHXZ":
18-
; CHECK: stp x29, x30, [sp, #-48]!
18+
; CHECK: stp x29, x30, [sp, #-64]!
1919
; CHECK: str x28, [sp, #16]
2020
; CHECK: str x21, [sp, #24]
2121
; CHECK: stp x19, x20, [sp, #32]
2222
; CHECK: mov x29, sp
2323
; CHECK: sub sp, sp, #624
2424
; CHECK: mov x19, sp
2525
; CHECK: mov x0, #-2
26-
; CHECK: stur x0, [x19]
26+
; CHECK: stur x0, [x29, #48]
2727

2828
; Now check that x is stored at fp - 20. We check that this is the same
2929
; location accessed from the funclet to retrieve x.
@@ -72,7 +72,7 @@
7272

7373
; Now check that the offset of the unwind help object from the stack pointer on
7474
; entry to func is encoded in cppxdata that is passed to __CxxFrameHandler3. As
75-
; computed above, this comes to -672.
75+
; computed above, this comes to -16.
7676
; CHECK-LABEL: "$cppxdata$?func@@YAHXZ":
7777
; CHECK-NEXT: .word 429065506 ; MagicNumber
7878
; CHECK-NEXT: .word 2 ; MaxState
@@ -81,7 +81,7 @@
8181
; CHECK-NEXT: .word ("$tryMap$?func@@YAHXZ")@IMGREL ; TryBlockMap
8282
; CHECK-NEXT: .word 4 ; IPMapEntries
8383
; CHECK-NEXT: .word ("$ip2state$?func@@YAHXZ")@IMGREL ; IPToStateXData
84-
; CHECK-NEXT: .word -672 ; UnwindHelp
84+
; CHECK-NEXT: .word -16 ; UnwindHelp
8585

8686
; UNWIND: Function: ?func@@YAHXZ (0x0)
8787
; UNWIND: Prologue [
@@ -91,7 +91,7 @@
9191
; UNWIND-NEXT: ; stp x19, x20, [sp, #32]
9292
; UNWIND-NEXT: ; str x21, [sp, #24]
9393
; UNWIND-NEXT: ; str x28, [sp, #16]
94-
; UNWIND-NEXT: ; stp x29, x30, [sp, #-48]!
94+
; UNWIND-NEXT: ; stp x29, x30, [sp, #-64]!
9595
; UNWIND-NEXT: ; end
9696
; UNWIND: Function: ?catch$2@?0??func@@YAHXZ@4HA
9797
; UNWIND: Prologue [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
; RUN: llc -o - %s -mtriple=aarch64-windows | FileCheck %s
2+
; Check that we allocate the unwind help stack object in a fixed location from fp
3+
; so that the runtime can find it when handling an exception
4+
target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128"
5+
target triple = "aarch64-pc-windows-msvc19.25.28611"
6+
7+
; Check that the store to the unwind help object for func2 is via FP
8+
; CHECK-LABEL: ?func2@@YAXXZ
9+
; CHECK: mov x[[#SCRATCH_REG:]], #-2
10+
; CHECK: stur x[[#SCRATCH_REG:]], [x29, #[[#]]]
11+
;
12+
; // struct that requires greater than stack alignment
13+
; struct alignas(32) A
14+
; {
15+
; // data that would be invalid for unwind help (> 0)
16+
; int _x[4]{42, 42, 42, 42};
17+
; ~A() {}
18+
; };
19+
;
20+
; // cause us to run the funclet in func2
21+
; void func3()
22+
; {
23+
; throw 1;
24+
; }
25+
;
26+
; // the funclet that ensures we have the unwind help correct
27+
; void func2()
28+
; {
29+
; A a;
30+
; func3();
31+
; }
32+
;
33+
; // function to ensure we are misaligned in func2
34+
; void func1()
35+
; {
36+
; func2();
37+
; }
38+
;
39+
; // set things up and ensure alignment for func1
40+
; void test()
41+
; {
42+
; try {
43+
; A a;
44+
; func1();
45+
; } catch(...) {}
46+
; }
47+
48+
%struct.A = type { [4 x i32], [16 x i8] }
49+
declare dso_local %struct.A* @"??0A@@QEAA@XZ"(%struct.A* returned %0)
50+
declare dso_local void @"??1A@@QEAA@XZ"(%struct.A* %0)
51+
declare dso_local i32 @__CxxFrameHandler3(...)
52+
declare dso_local void @"?func3@@YAXXZ"()
53+
54+
; Function Attrs: noinline optnone uwtable
55+
define dso_local void @"?func2@@YAXXZ"() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
56+
%1 = alloca %struct.A, align 32
57+
%2 = call %struct.A* @"??0A@@QEAA@XZ"(%struct.A* %1) #3
58+
invoke void @"?func3@@YAXXZ"()
59+
to label %3 unwind label %4
60+
61+
3: ; preds = %0
62+
call void @"??1A@@QEAA@XZ"(%struct.A* %1) #3
63+
ret void
64+
65+
4: ; preds = %0
66+
%5 = cleanuppad within none []
67+
call void @"??1A@@QEAA@XZ"(%struct.A* %1) #3 [ "funclet"(token %5) ]
68+
cleanupret from %5 unwind to caller
69+
}

0 commit comments

Comments
 (0)