Skip to content

Commit b485511

Browse files
danielframptonnikic
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 e0bac6a commit b485511

7 files changed

+212
-67
lines changed

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

+58-43
Original file line numberDiff line numberDiff line change
@@ -211,6 +211,24 @@ AArch64FrameLowering::getStackIDForScalableVectors() const {
211211
return TargetStackID::SVEVector;
212212
}
213213

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

960978
bool IsWin64 =
961979
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
962-
// Var args are accounted for in the containing function, so don't
963-
// include them for funclets.
964-
unsigned FixedObject = (IsWin64 && !IsFunclet) ?
965-
alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
980+
unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
966981

967982
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
968983
// All of the remaining stack allocations are for locals.
@@ -993,32 +1008,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
9931008
++MBBI;
9941009
}
9951010

996-
// The code below is not applicable to funclets. We have emitted all the SEH
997-
// opcodes that we needed to emit. The FP and BP belong to the containing
998-
// function.
999-
if (IsFunclet) {
1000-
if (NeedsWinCFI) {
1001-
HasWinCFI = true;
1002-
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
1003-
.setMIFlag(MachineInstr::FrameSetup);
1004-
}
1005-
1006-
// SEH funclets are passed the frame pointer in X1. If the parent
1007-
// function uses the base register, then the base register is used
1008-
// directly, and is not retrieved from X1.
1009-
if (F.hasPersonalityFn()) {
1010-
EHPersonality Per = classifyEHPersonality(F.getPersonalityFn());
1011-
if (isAsynchronousEHPersonality(Per)) {
1012-
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP)
1013-
.addReg(AArch64::X1).setMIFlag(MachineInstr::FrameSetup);
1014-
MBB.addLiveIn(AArch64::X1);
1015-
}
1016-
}
1017-
1018-
return;
1019-
}
1020-
1021-
if (HasFP) {
1011+
// For funclets the FP belongs to the containing function.
1012+
if (!IsFunclet && HasFP) {
10221013
// Only set up FP if we actually need to.
10231014
int64_t FPOffset = isTargetDarwin(MF) ? (AFI->getCalleeSavedStackSize() - 16) : 0;
10241015

@@ -1161,7 +1152,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
11611152

11621153
// Allocate space for the rest of the frame.
11631154
if (NumBytes) {
1164-
const bool NeedsRealignment = RegInfo->needsStackRealignment(MF);
1155+
// Alignment is required for the parent frame, not the funclet
1156+
const bool NeedsRealignment =
1157+
!IsFunclet && RegInfo->needsStackRealignment(MF);
11651158
unsigned scratchSPReg = AArch64::SP;
11661159

11671160
if (NeedsRealignment) {
@@ -1215,7 +1208,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
12151208
// FIXME: Clarify FrameSetup flags here.
12161209
// Note: Use emitFrameOffset() like above for FP if the FrameSetup flag is
12171210
// needed.
1218-
if (RegInfo->hasBasePointer(MF)) {
1211+
// For funclets the BP belongs to the containing function.
1212+
if (!IsFunclet && RegInfo->hasBasePointer(MF)) {
12191213
TII->copyPhysReg(MBB, MBBI, DL, RegInfo->getBaseRegister(), AArch64::SP,
12201214
false);
12211215
if (NeedsWinCFI) {
@@ -1232,6 +1226,19 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
12321226
.setMIFlag(MachineInstr::FrameSetup);
12331227
}
12341228

1229+
// SEH funclets are passed the frame pointer in X1. If the parent
1230+
// function uses the base register, then the base register is used
1231+
// directly, and is not retrieved from X1.
1232+
if (IsFunclet && F.hasPersonalityFn()) {
1233+
EHPersonality Per = classifyEHPersonality(F.getPersonalityFn());
1234+
if (isAsynchronousEHPersonality(Per)) {
1235+
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP)
1236+
.addReg(AArch64::X1)
1237+
.setMIFlag(MachineInstr::FrameSetup);
1238+
MBB.addLiveIn(AArch64::X1);
1239+
}
1240+
}
1241+
12351242
if (needsFrameMoves) {
12361243
const DataLayout &TD = MF.getDataLayout();
12371244
const int StackGrowth = isTargetDarwin(MF)
@@ -1450,10 +1457,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
14501457

14511458
bool IsWin64 =
14521459
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1453-
// Var args are accounted for in the containing function, so don't
1454-
// include them for funclets.
1455-
unsigned FixedObject =
1456-
(IsWin64 && !IsFunclet) ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1460+
unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
14571461

14581462
uint64_t AfterCSRPopSize = ArgumentPopSize;
14591463
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
@@ -1679,7 +1683,9 @@ static StackOffset getFPOffset(const MachineFunction &MF, int64_t ObjectOffset)
16791683
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
16801684
bool IsWin64 =
16811685
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1682-
unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1686+
1687+
unsigned FixedObject =
1688+
getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false);
16831689
unsigned FPAdjust = isTargetDarwin(MF)
16841690
? 16 : AFI->getCalleeSavedStackSize(MF.getFrameInfo());
16851691
return {ObjectOffset + FixedObject + FPAdjust, MVT::i8};
@@ -2632,9 +2638,14 @@ void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
26322638
++MBBI;
26332639

26342640
// Create an UnwindHelp object.
2635-
int UnwindHelpFI =
2636-
MFI.CreateStackObject(/*size*/8, /*alignment*/16, false);
2641+
// The UnwindHelp object is allocated at the start of the fixed object area
2642+
int64_t FixedObject =
2643+
getFixedObjectSize(MF, AFI, /*IsWin64*/ true, /*IsFunclet*/ false);
2644+
int UnwindHelpFI = MFI.CreateFixedObject(/*Size*/ 8,
2645+
/*SPOffset*/ -FixedObject,
2646+
/*IsImmutable=*/false);
26372647
EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
2648+
26382649
// We need to store -2 into the UnwindHelp object at the start of the
26392650
// function.
26402651
DebugLoc DL;
@@ -2656,10 +2667,14 @@ int AArch64FrameLowering::getFrameIndexReferencePreferSP(
26562667
const MachineFunction &MF, int FI, unsigned &FrameReg,
26572668
bool IgnoreSPUpdates) const {
26582669
const MachineFrameInfo &MFI = MF.getFrameInfo();
2659-
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
2660-
<< MFI.getObjectOffset(FI) << "\n");
2661-
FrameReg = AArch64::SP;
2662-
return MFI.getObjectOffset(FI);
2670+
if (IgnoreSPUpdates) {
2671+
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
2672+
<< MFI.getObjectOffset(FI) << "\n");
2673+
FrameReg = AArch64::SP;
2674+
return MFI.getObjectOffset(FI);
2675+
}
2676+
2677+
return getFrameIndexReference(MF, FI, FrameReg);
26632678
}
26642679

26652680
/// 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)