Skip to content

Commit d561d49

Browse files
danielframptonshravanrn
authored andcommitted
Backport fixes for aarch64-pc-windows-msvc (#46)
* [AArch64] Fix mismatch in prologue and epilogue for funclets on Windows The generated code for a funclet can have an add to sp in the epilogue for which there is no corresponding sub in the prologue. This patch removes the early return from emitPrologue that was preventing the sub to sp, and instead conditionalizes the appropriate parts of the rest of the function. Fixes https://bugs.llvm.org/show_bug.cgi?id=45345 Differential Revision: https://reviews.llvm.org/D77015 * [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 f56b974 commit d561d49

7 files changed

+212
-67
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

+58-43
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>();
@@ -997,10 +1015,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
9971015

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

10051020
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
10061021
// All of the remaining stack allocations are for locals.
@@ -1031,32 +1046,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
10311046
++MBBI;
10321047
}
10331048

1034-
// The code below is not applicable to funclets. We have emitted all the SEH
1035-
// opcodes that we needed to emit. The FP and BP belong to the containing
1036-
// function.
1037-
if (IsFunclet) {
1038-
if (NeedsWinCFI) {
1039-
HasWinCFI = true;
1040-
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
1041-
.setMIFlag(MachineInstr::FrameSetup);
1042-
}
1043-
1044-
// SEH funclets are passed the frame pointer in X1. If the parent
1045-
// function uses the base register, then the base register is used
1046-
// directly, and is not retrieved from X1.
1047-
if (F.hasPersonalityFn()) {
1048-
EHPersonality Per = classifyEHPersonality(F.getPersonalityFn());
1049-
if (isAsynchronousEHPersonality(Per)) {
1050-
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP)
1051-
.addReg(AArch64::X1).setMIFlag(MachineInstr::FrameSetup);
1052-
MBB.addLiveIn(AArch64::X1);
1053-
}
1054-
}
1055-
1056-
return;
1057-
}
1058-
1059-
if (HasFP) {
1049+
// For funclets the FP belongs to the containing function.
1050+
if (!IsFunclet && HasFP) {
10601051
// Only set up FP if we actually need to.
10611052
int64_t FPOffset = isTargetDarwin(MF) ? (AFI->getCalleeSavedStackSize() - 16) : 0;
10621053

@@ -1199,7 +1190,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
11991190

12001191
// Allocate space for the rest of the frame.
12011192
if (NumBytes) {
1202-
const bool NeedsRealignment = RegInfo->needsStackRealignment(MF);
1193+
// Alignment is required for the parent frame, not the funclet
1194+
const bool NeedsRealignment =
1195+
!IsFunclet && RegInfo->needsStackRealignment(MF);
12031196
unsigned scratchSPReg = AArch64::SP;
12041197

12051198
if (NeedsRealignment) {
@@ -1253,7 +1246,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
12531246
// FIXME: Clarify FrameSetup flags here.
12541247
// Note: Use emitFrameOffset() like above for FP if the FrameSetup flag is
12551248
// needed.
1256-
if (RegInfo->hasBasePointer(MF)) {
1249+
// For funclets the BP belongs to the containing function.
1250+
if (!IsFunclet && RegInfo->hasBasePointer(MF)) {
12571251
TII->copyPhysReg(MBB, MBBI, DL, RegInfo->getBaseRegister(), AArch64::SP,
12581252
false);
12591253
if (NeedsWinCFI) {
@@ -1270,6 +1264,19 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
12701264
.setMIFlag(MachineInstr::FrameSetup);
12711265
}
12721266

1267+
// SEH funclets are passed the frame pointer in X1. If the parent
1268+
// function uses the base register, then the base register is used
1269+
// directly, and is not retrieved from X1.
1270+
if (IsFunclet && F.hasPersonalityFn()) {
1271+
EHPersonality Per = classifyEHPersonality(F.getPersonalityFn());
1272+
if (isAsynchronousEHPersonality(Per)) {
1273+
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP)
1274+
.addReg(AArch64::X1)
1275+
.setMIFlag(MachineInstr::FrameSetup);
1276+
MBB.addLiveIn(AArch64::X1);
1277+
}
1278+
}
1279+
12731280
if (needsFrameMoves) {
12741281
const DataLayout &TD = MF.getDataLayout();
12751282
const int StackGrowth = isTargetDarwin(MF)
@@ -1488,10 +1495,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
14881495

14891496
bool IsWin64 =
14901497
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1491-
// Var args are accounted for in the containing function, so don't
1492-
// include them for funclets.
1493-
unsigned FixedObject =
1494-
(IsWin64 && !IsFunclet) ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1498+
unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
14951499

14961500
uint64_t AfterCSRPopSize = ArgumentPopSize;
14971501
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
@@ -1717,7 +1721,9 @@ static StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset)
17171721
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
17181722
bool IsWin64 =
17191723
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1720-
unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1724+
1725+
unsigned FixedObject =
1726+
getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false);
17211727
unsigned FPAdjust = isTargetDarwin(MF)
17221728
? 16 : AFI->getCalleeSavedStackSize(MF.getFrameInfo());
17231729
return {ObjectOffset + FixedObject + FPAdjust, MVT::i8};
@@ -2668,9 +2674,14 @@ void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
26682674
++MBBI;
26692675

26702676
// Create an UnwindHelp object.
2671-
int UnwindHelpFI =
2672-
MFI.CreateStackObject(/*size*/8, /*alignment*/16, false);
2677+
// The UnwindHelp object is allocated at the start of the fixed object area
2678+
int64_t FixedObject =
2679+
getFixedObjectSize(MF, AFI, /*IsWin64*/ true, /*IsFunclet*/ false);
2680+
int UnwindHelpFI = MFI.CreateFixedObject(/*Size*/ 8,
2681+
/*SPOffset*/ -FixedObject,
2682+
/*IsImmutable=*/false);
26732683
EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
2684+
26742685
// We need to store -2 into the UnwindHelp object at the start of the
26752686
// function.
26762687
DebugLoc DL;
@@ -3082,10 +3093,14 @@ int AArch64FrameLowering::getFrameIndexReferencePreferSP(
30823093
const MachineFunction &MF, int FI, unsigned &FrameReg,
30833094
bool IgnoreSPUpdates) const {
30843095
const MachineFrameInfo &MFI = MF.getFrameInfo();
3085-
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
3086-
<< MFI.getObjectOffset(FI) << "\n");
3087-
FrameReg = AArch64::SP;
3088-
return MFI.getObjectOffset(FI);
3096+
if (IgnoreSPUpdates) {
3097+
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
3098+
<< MFI.getObjectOffset(FI) << "\n");
3099+
FrameReg = AArch64::SP;
3100+
return MFI.getObjectOffset(FI);
3101+
}
3102+
3103+
return getFrameIndexReference(MF, FI, FrameReg);
30893104
}
30903105

30913106
/// The parent frame offset (aka dispFrame) is only used on X86_64 to retrieve
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
; RUN: llc -o - %s -mtriple=aarch64-windows | FileCheck %s
2+
; Check that the stack bump around a funclet is computed correctly in both the
3+
; prologue and epilogue in the case we have a MaxCallFrameSize > 0 and are doing alloca
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+
; // requires passing arguments on the stack
8+
; void test2(void*, int, int, int, int, int, int, int, int);
9+
;
10+
; // function with the funclet being checked
11+
; void test1(size_t bytes)
12+
; {
13+
; // alloca forces a separate callee save bump and stack bump
14+
; void *data = _alloca(bytes);
15+
; try {
16+
; test2(data, 0, 1, 2, 3, 4, 5, 6, 7);
17+
; } catch (...) {
18+
; // the funclet being checked
19+
; }
20+
; }
21+
22+
; CHECK-LABEL: ?catch$2@?0??test1@@YAX_K@Z@4HA
23+
; CHECK: sub sp, sp, #16
24+
; CHECK: add sp, sp, #16
25+
; Function Attrs: uwtable
26+
define dso_local void @"?test1@@YAX_K@Z"(i64 %0) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
27+
%2 = alloca i64, align 8
28+
%3 = alloca i8*, align 8
29+
store i64 %0, i64* %2, align 8
30+
%4 = load i64, i64* %2, align 8
31+
%5 = alloca i8, i64 %4, align 16
32+
store i8* %5, i8** %3, align 8
33+
%6 = load i8*, i8** %3, align 8
34+
invoke void @"?test2@@YAXPEAXHHHHHHHH@Z"(i8* %6, i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7)
35+
to label %13 unwind label %7
36+
37+
7: ; preds = %1
38+
%8 = catchswitch within none [label %9] unwind to caller
39+
40+
9: ; preds = %7
41+
%10 = catchpad within %8 [i8* null, i32 64, i8* null]
42+
catchret from %10 to label %11
43+
44+
11: ; preds = %9
45+
br label %12
46+
47+
12: ; preds = %11, %13
48+
ret void
49+
50+
13: ; preds = %1
51+
br label %12
52+
}
53+
54+
declare dso_local void @"?test2@@YAXPEAXHHHHHHHH@Z"(i8*, i32, i32, i32, i32, i32, i32, i32, i32) #1
55+
56+
declare dso_local i32 @__CxxFrameHandler3(...)
57+
58+
attributes #0 = { uwtable }
59+
60+
!llvm.module.flags = !{!0}
61+
62+
!0 = !{i32 1, !"wchar_size", i32 2}

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 [

0 commit comments

Comments
 (0)