Skip to content

Commit 027e428

Browse files
Backport fixes for aarch64-pc-windows-msvc (llvm#45)
* [CodeView] Add pragma push/pop_macro for ARM64_FPSR to enum header This fixes (one aspect of) compilation of LLDB with MSVC for ARM64. LLDB source files include intrin.h, and the MSVC intrin.h transitively includes arm64intr.h, which has an ARM64_FPSR define, which clashes with the enum declaration. Differential Revision: https://reviews.llvm.org/D67864 llvm-svn: 372481 * [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 Co-authored-by: Martin Storsjo <[email protected]>
1 parent 130721d commit 027e428

File tree

8 files changed

+222
-71
lines changed

8 files changed

+222
-71
lines changed

llvm/include/llvm/DebugInfo/CodeView/CodeViewRegisters.def

+7
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,11 @@ CV_REGISTER(AMD64_K7, 765)
368368

369369
#if defined(CV_REGISTERS_ALL) || defined(CV_REGISTERS_ARM64)
370370

371+
// arm64intr.h from MSVC defines ARM64_FPSR, which conflicts with
372+
// these declarations.
373+
#pragma push_macro("ARM64_FPSR")
374+
#undef ARM64_FPSR
375+
371376
// ARM64 registers
372377

373378
CV_REGISTER(ARM64_NOREG, 0)
@@ -556,4 +561,6 @@ CV_REGISTER(ARM64_Q31, 211)
556561

557562
CV_REGISTER(ARM64_FPSR, 220)
558563

564+
#pragma pop_macro("ARM64_FPSR")
565+
559566
#endif // defined(CV_REGISTERS_ALL) || defined(CV_REGISTERS_ARM64)

llvm/lib/Target/AArch64/AArch64FrameLowering.cpp

+57-43
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,24 @@ static unsigned estimateRSStackSizeLimit(MachineFunction &MF) {
183183
return DefaultSafeSPDisplacement;
184184
}
185185

186+
/// Returns the size of the fixed object area (allocated next to sp on entry)
187+
/// On Win64 this may include a var args area and an UnwindHelp object for EH.
188+
static unsigned getFixedObjectSize(const MachineFunction &MF,
189+
const AArch64FunctionInfo *AFI, bool IsWin64,
190+
bool IsFunclet) {
191+
if (!IsWin64 || IsFunclet) {
192+
// Only Win64 uses fixed objects, and then only for the function (not
193+
// funclets)
194+
return 0;
195+
} else {
196+
// Var args are stored here in the primary function.
197+
const unsigned VarArgsArea = AFI->getVarArgsGPRSize();
198+
// To support EH funclets we allocate an UnwindHelp object
199+
const unsigned UnwindHelpObject = (MF.hasEHFunclets() ? 8 : 0);
200+
return alignTo(VarArgsArea + UnwindHelpObject, 16);
201+
}
202+
}
203+
186204
bool AArch64FrameLowering::canUseRedZone(const MachineFunction &MF) const {
187205
if (!EnableRedZone)
188206
return false;
@@ -891,10 +909,7 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
891909

892910
bool IsWin64 =
893911
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
894-
// Var args are accounted for in the containing function, so don't
895-
// include them for funclets.
896-
unsigned FixedObject = (IsWin64 && !IsFunclet) ?
897-
alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
912+
unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
898913

899914
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
900915
// All of the remaining stack allocations are for locals.
@@ -922,32 +937,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
922937
++MBBI;
923938
}
924939

925-
// The code below is not applicable to funclets. We have emitted all the SEH
926-
// opcodes that we needed to emit. The FP and BP belong to the containing
927-
// function.
928-
if (IsFunclet) {
929-
if (NeedsWinCFI) {
930-
HasWinCFI = true;
931-
BuildMI(MBB, MBBI, DL, TII->get(AArch64::SEH_PrologEnd))
932-
.setMIFlag(MachineInstr::FrameSetup);
933-
}
934-
935-
// SEH funclets are passed the frame pointer in X1. If the parent
936-
// function uses the base register, then the base register is used
937-
// directly, and is not retrieved from X1.
938-
if (F.hasPersonalityFn()) {
939-
EHPersonality Per = classifyEHPersonality(F.getPersonalityFn());
940-
if (isAsynchronousEHPersonality(Per)) {
941-
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP)
942-
.addReg(AArch64::X1).setMIFlag(MachineInstr::FrameSetup);
943-
MBB.addLiveIn(AArch64::X1);
944-
}
945-
}
946-
947-
return;
948-
}
949-
950-
if (HasFP) {
940+
// For funclets the FP belongs to the containing function.
941+
if (!IsFunclet && HasFP) {
951942
// Only set up FP if we actually need to. Frame pointer is fp =
952943
// sp - fixedobject - 16.
953944
int FPOffset = AFI->getCalleeSavedStackSize() - 16;
@@ -1058,7 +1049,9 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
10581049

10591050
// Allocate space for the rest of the frame.
10601051
if (NumBytes) {
1061-
const bool NeedsRealignment = RegInfo->needsStackRealignment(MF);
1052+
// Alignment is required for the parent frame, not the funclet
1053+
const bool NeedsRealignment =
1054+
!IsFunclet && RegInfo->needsStackRealignment(MF);
10621055
unsigned scratchSPReg = AArch64::SP;
10631056

10641057
if (NeedsRealignment) {
@@ -1111,7 +1104,8 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
11111104
// FIXME: Clarify FrameSetup flags here.
11121105
// Note: Use emitFrameOffset() like above for FP if the FrameSetup flag is
11131106
// needed.
1114-
if (RegInfo->hasBasePointer(MF)) {
1107+
// For funclets the BP belongs to the containing function.
1108+
if (!IsFunclet && RegInfo->hasBasePointer(MF)) {
11151109
TII->copyPhysReg(MBB, MBBI, DL, RegInfo->getBaseRegister(), AArch64::SP,
11161110
false);
11171111
if (NeedsWinCFI) {
@@ -1128,6 +1122,18 @@ void AArch64FrameLowering::emitPrologue(MachineFunction &MF,
11281122
.setMIFlag(MachineInstr::FrameSetup);
11291123
}
11301124

1125+
// SEH funclets are passed the frame pointer in X1. If the parent
1126+
// function uses the base register, then the base register is used
1127+
// directly, and is not retrieved from X1.
1128+
if (IsFunclet && F.hasPersonalityFn()) {
1129+
EHPersonality Per = classifyEHPersonality(F.getPersonalityFn());
1130+
if (isAsynchronousEHPersonality(Per)) {
1131+
BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::COPY), AArch64::FP)
1132+
.addReg(AArch64::X1).setMIFlag(MachineInstr::FrameSetup);
1133+
MBB.addLiveIn(AArch64::X1);
1134+
}
1135+
}
1136+
11311137
if (needsFrameMoves) {
11321138
const DataLayout &TD = MF.getDataLayout();
11331139
const int StackGrowth = -TD.getPointerSize(0);
@@ -1344,10 +1350,7 @@ void AArch64FrameLowering::emitEpilogue(MachineFunction &MF,
13441350

13451351
bool IsWin64 =
13461352
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1347-
// Var args are accounted for in the containing function, so don't
1348-
// include them for funclets.
1349-
unsigned FixedObject =
1350-
(IsWin64 && !IsFunclet) ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1353+
unsigned FixedObject = getFixedObjectSize(MF, AFI, IsWin64, IsFunclet);
13511354

13521355
uint64_t AfterCSRPopSize = ArgumentPopSize;
13531356
auto PrologueSaveSize = AFI->getCalleeSavedStackSize() + FixedObject;
@@ -1517,7 +1520,8 @@ static int getFPOffset(const MachineFunction &MF, int ObjectOffset) {
15171520
const auto &Subtarget = MF.getSubtarget<AArch64Subtarget>();
15181521
bool IsWin64 =
15191522
Subtarget.isCallingConvWin64(MF.getFunction().getCallingConv());
1520-
unsigned FixedObject = IsWin64 ? alignTo(AFI->getVarArgsGPRSize(), 16) : 0;
1523+
unsigned FixedObject =
1524+
getFixedObjectSize(MF, AFI, IsWin64, /*IsFunclet=*/false);
15211525
return ObjectOffset + FixedObject + 16;
15221526
}
15231527

@@ -2197,9 +2201,15 @@ void AArch64FrameLowering::processFunctionBeforeFrameFinalized(
21972201
++MBBI;
21982202

21992203
// Create an UnwindHelp object.
2200-
int UnwindHelpFI =
2201-
MFI.CreateStackObject(/*size*/8, /*alignment*/16, false);
2204+
// The UnwindHelp object is allocated at the start of the fixed object area
2205+
const AArch64FunctionInfo *AFI = MF.getInfo<AArch64FunctionInfo>();
2206+
int64_t FixedObject =
2207+
getFixedObjectSize(MF, AFI, /*IsWin64*/ true, /*IsFunclet*/ false);
2208+
int UnwindHelpFI = MFI.CreateFixedObject(/*Size*/ 8,
2209+
/*SPOffset*/ -FixedObject,
2210+
/*IsImmutable=*/false);
22022211
EHInfo.UnwindHelpFrameIdx = UnwindHelpFI;
2212+
22032213
// We need to store -2 into the UnwindHelp object at the start of the
22042214
// function.
22052215
DebugLoc DL;
@@ -2221,10 +2231,14 @@ int AArch64FrameLowering::getFrameIndexReferencePreferSP(
22212231
const MachineFunction &MF, int FI, unsigned &FrameReg,
22222232
bool IgnoreSPUpdates) const {
22232233
const MachineFrameInfo &MFI = MF.getFrameInfo();
2224-
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
2225-
<< MFI.getObjectOffset(FI) << "\n");
2226-
FrameReg = AArch64::SP;
2227-
return MFI.getObjectOffset(FI);
2234+
if (IgnoreSPUpdates) {
2235+
LLVM_DEBUG(dbgs() << "Offset from the SP for " << FI << " is "
2236+
<< MFI.getObjectOffset(FI) << "\n");
2237+
FrameReg = AArch64::SP;
2238+
return MFI.getObjectOffset(FI);
2239+
}
2240+
2241+
return getFrameIndexReference(MF, FI, FrameReg);
22282242
}
22292243

22302244
/// 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 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: add x29, sp, #16
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, #16]
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: add x29, sp, #16
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, #16]
214214
; CHECK: .set .Lvla_and_realign$frame_escape_0, 32
215-
; CHECK: stur w0, [x29, #-4]
216-
; CHECK: ldur w8, [x29, #-4]
215+
; CHECK: str w0, [x29, #28]
216+
; CHECK: ldr w8, [x29, #28]
217217
; CHECK: mov x9, sp
218-
; CHECK: str x9, [x19, #24]
219-
; CHECK: str x8, [x19, #16]
218+
; CHECK: str x9, [x19, #56]
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: str x28, [sp, #-32]!
1313
; CHECK-NEXT: str x19, [sp, #8]
1414
; CHECK-NEXT: stp x29, x30, [sp, #16]
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

+11-11
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: str x28, [sp, #-48]!
18+
; CHECK str x28, [sp, #-64]!
1919
; CHECK: str x21, [sp, #8]
2020
; CHECK: stp x19, x20, [sp, #16]
2121
; CHECK: stp x29, x30, [sp, #32]
2222
; CHECK: add x29, sp, #32
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, #16]
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,17 +81,17 @@
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 [
8888
; UNWIND-NEXT: ; nop
8989
; UNWIND-NEXT: ; sub sp, #624
90-
; UNWIND-NEXT: ; add fp, sp, #32
91-
; UNWIND-NEXT: ; stp x29, x30, [sp, #32]
92-
; UNWIND-NEXT: ; stp x19, x20, [sp, #16]
93-
; UNWIND-NEXT: ; str x21, [sp, #8]
94-
; UNWIND-NEXT: ; str x28, [sp, #48]!
90+
; UNWIND-NEXT: ; mov fp, sp
91+
; UNWIND-NEXT: ; stp x19, x20, [sp, #32]
92+
; UNWIND-NEXT: ; str x21, [sp, #24]
93+
; UNWIND-NEXT: ; str x28, [sp, #16]
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)