Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit b485511

Browse files
danielframptonnikic
authored andcommittedMay 5, 2020
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

Lines changed: 58 additions & 43 deletions
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
Lines changed: 62 additions & 0 deletions
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

Lines changed: 12 additions & 12 deletions
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

Lines changed: 3 additions & 4 deletions
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

Lines changed: 1 addition & 1 deletion
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

Lines changed: 7 additions & 7 deletions
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 [
Lines changed: 69 additions & 0 deletions
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)
Please sign in to comment.