Skip to content

Commit aadaa00

Browse files
aheejintru
authored andcommitted
[WebAssembly] Fix rethrow's index calculation (#114693)
So far we have assumed that we only rethrow the exception caught in the innermost EH pad. This is true in code we directly generate, but after inlining this may not be the case. For example, consider this code: ```ll ehcleanup: %0 = cleanuppad ... call @Destructor cleanupret from %0 unwind label %catch.dispatch ``` If `destructor` gets inlined into this function, the code can be like ```ll ehcleanup: %0 = cleanuppad ... invoke @throwing_func to label %unreachale unwind label %catch.dispatch.i catch.dispatch.i: catchswitch ... [ label %catch.start.i ] catch.start.i: %1 = catchpad ... invoke @some_function to label %invoke.cont.i unwind label %terminate.i invoke.cont.i: catchret from %1 to label %destructor.exit destructor.exit: cleanupret from %0 unwind label %catch.dispatch ``` We lower a `cleanupret` into `rethrow`, which assumes it rethrows the exception caught by the nearest dominating EH pad. But after the inlining, the nearest dominating EH pad is not `ehcleanup` but `catch.start.i`. The problem exists in the same manner in the new (exnref) EH, because it assumes the exception comes from the nearest EH pad and saves an exnref from that EH pad and rethrows it (using `throw_ref`). This problem can be fixed easily if `cleanupret` has the basic block where its matching `cleanuppad` is. The bitcode instruction `cleanupret` kind of has that info (it has a token from the `cleanuppad`), but that info is lost when when we enter ISel, because `TargetSelectionDAG.td`'s `cleanupret` node does not have any arguments: https://github.com/llvm/llvm-project/blob/5091a359d9807db8f7d62375696f93fc34226969/llvm/include/llvm/Target/TargetSelectionDAG.td#L700 Note that `catchret` already has two basic block arguments, even though neither of them means `catchpad`'s BB. This PR adds the `cleanuppad`'s BB as an argument to `cleanupret` node in ISel and uses it in the Wasm backend. Because this node is also used in X86 backend we need to note its argument there too but nothing more needs to change there as long as X86 doesn't need it. --- - Details about changes in the Wasm backend: After this PR, our pseudo `RETHROW` instruction takes a BB, which means the EH pad whose exception it needs to rethrow. There are currently two ways to generate a `RETHROW`: one is from `llvm.wasm.rethrow` intrinsic and the other is from `CLEANUPRET` we discussed above. In case of `llvm.wasm.rethrow`, we add a '0' as a placeholder argument when it is lowered to a `RETHROW`, and change it to a BB in LateEHPrepare. As written in the comments, this PR doesn't change how this BB is computed. The BB argument will be converted to an immediate argument as with other control flow instructions in CFGStackify. In case of `CLEANUPRET`, it already has a BB argument pointing to an EH pad, so it is just converted to a `RETHROW` with the same BB argument in LateEHPrepare. This will also be lowered to an immediate in CFGStackify with other control flow instructions. --- Fixes #114600.
1 parent 6925f3c commit aadaa00

11 files changed

+181
-63
lines changed

llvm/include/llvm/Target/TargetSelectionDAG.td

+5-1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,10 @@ def SDTCatchret : SDTypeProfile<0, 2, [ // catchret
231231
SDTCisVT<0, OtherVT>, SDTCisVT<1, OtherVT>
232232
]>;
233233

234+
def SDTCleanupret : SDTypeProfile<0, 1, [ // cleanupret
235+
SDTCisVT<0, OtherVT>
236+
]>;
237+
234238
def SDTNone : SDTypeProfile<0, 0, []>; // ret, trap
235239

236240
def SDTUBSANTrap : SDTypeProfile<0, 1, []>; // ubsantrap
@@ -680,7 +684,7 @@ def brind : SDNode<"ISD::BRIND" , SDTBrind, [SDNPHasChain]>;
680684
def br : SDNode<"ISD::BR" , SDTBr, [SDNPHasChain]>;
681685
def catchret : SDNode<"ISD::CATCHRET" , SDTCatchret,
682686
[SDNPHasChain, SDNPSideEffect]>;
683-
def cleanupret : SDNode<"ISD::CLEANUPRET" , SDTNone, [SDNPHasChain]>;
687+
def cleanupret : SDNode<"ISD::CLEANUPRET" , SDTCleanupret, [SDNPHasChain]>;
684688

685689
def trap : SDNode<"ISD::TRAP" , SDTNone,
686690
[SDNPHasChain, SDNPSideEffect]>;

llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp

+4-2
Original file line numberDiff line numberDiff line change
@@ -2155,8 +2155,10 @@ void SelectionDAGBuilder::visitCleanupRet(const CleanupReturnInst &I) {
21552155
FuncInfo.MBB->normalizeSuccProbs();
21562156

21572157
// Create the terminator node.
2158-
SDValue Ret =
2159-
DAG.getNode(ISD::CLEANUPRET, getCurSDLoc(), MVT::Other, getControlRoot());
2158+
MachineBasicBlock *CleanupPadMBB =
2159+
FuncInfo.MBBMap[I.getCleanupPad()->getParent()];
2160+
SDValue Ret = DAG.getNode(ISD::CLEANUPRET, getCurSDLoc(), MVT::Other,
2161+
getControlRoot(), DAG.getBasicBlock(CleanupPadMBB));
21602162
DAG.setRoot(Ret);
21612163
}
21622164

llvm/lib/Target/AArch64/AArch64InstrInfo.td

+1-1
Original file line numberDiff line numberDiff line change
@@ -5159,7 +5159,7 @@ let isPseudo = 1 in {
51595159
//===----------------------------------------------------------------------===//
51605160
let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
51615161
isCodeGenOnly = 1, isReturn = 1, isEHScopeReturn = 1, isPseudo = 1 in {
5162-
def CLEANUPRET : Pseudo<(outs), (ins), [(cleanupret)]>, Sched<[]>;
5162+
def CLEANUPRET : Pseudo<(outs), (ins), [(cleanupret bb)]>, Sched<[]>;
51635163
let usesCustomInserter = 1 in
51645164
def CATCHRET : Pseudo<(outs), (ins am_brcond:$dst, am_brcond:$src), [(catchret bb:$dst, bb:$src)]>,
51655165
Sched<[]>;

llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp

+8-45
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,8 @@ class WebAssemblyCFGStackify final : public MachineFunctionPass {
8787
const MachineBasicBlock *MBB);
8888
unsigned getDelegateDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,
8989
const MachineBasicBlock *MBB);
90-
unsigned
91-
getRethrowDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,
92-
const SmallVectorImpl<const MachineBasicBlock *> &EHPadStack);
90+
unsigned getRethrowDepth(const SmallVectorImpl<EndMarkerInfo> &Stack,
91+
const MachineBasicBlock *EHPadToRethrow);
9392
void rewriteDepthImmediates(MachineFunction &MF);
9493
void fixEndsAtEndOfFunction(MachineFunction &MF);
9594
void cleanupFunctionData(MachineFunction &MF);
@@ -1612,34 +1611,13 @@ unsigned WebAssemblyCFGStackify::getDelegateDepth(
16121611

16131612
unsigned WebAssemblyCFGStackify::getRethrowDepth(
16141613
const SmallVectorImpl<EndMarkerInfo> &Stack,
1615-
const SmallVectorImpl<const MachineBasicBlock *> &EHPadStack) {
1614+
const MachineBasicBlock *EHPadToRethrow) {
16161615
unsigned Depth = 0;
1617-
// In our current implementation, rethrows always rethrow the exception caught
1618-
// by the innermost enclosing catch. This means while traversing Stack in the
1619-
// reverse direction, when we encounter END_TRY, we should check if the
1620-
// END_TRY corresponds to the current innermost EH pad. For example:
1621-
// try
1622-
// ...
1623-
// catch ;; (a)
1624-
// try
1625-
// rethrow 1 ;; (b)
1626-
// catch ;; (c)
1627-
// rethrow 0 ;; (d)
1628-
// end ;; (e)
1629-
// end ;; (f)
1630-
//
1631-
// When we are at 'rethrow' (d), while reversely traversing Stack the first
1632-
// 'end' we encounter is the 'end' (e), which corresponds to the 'catch' (c).
1633-
// And 'rethrow' (d) rethrows the exception caught by 'catch' (c), so we stop
1634-
// there and the depth should be 0. But when we are at 'rethrow' (b), it
1635-
// rethrows the exception caught by 'catch' (a), so when traversing Stack
1636-
// reversely, we should skip the 'end' (e) and choose 'end' (f), which
1637-
// corresponds to 'catch' (a).
16381616
for (auto X : reverse(Stack)) {
16391617
const MachineInstr *End = X.second;
16401618
if (End->getOpcode() == WebAssembly::END_TRY) {
16411619
auto *EHPad = TryToEHPad[EndToBegin[End]];
1642-
if (EHPadStack.back() == EHPad)
1620+
if (EHPadToRethrow == EHPad)
16431621
break;
16441622
}
16451623
++Depth;
@@ -1651,7 +1629,6 @@ unsigned WebAssemblyCFGStackify::getRethrowDepth(
16511629
void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
16521630
// Now rewrite references to basic blocks to be depth immediates.
16531631
SmallVector<EndMarkerInfo, 8> Stack;
1654-
SmallVector<const MachineBasicBlock *, 8> EHPadStack;
16551632
for (auto &MBB : reverse(MF)) {
16561633
for (MachineInstr &MI : llvm::reverse(MBB)) {
16571634
switch (MI.getOpcode()) {
@@ -1669,31 +1646,14 @@ void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
16691646
break;
16701647

16711648
case WebAssembly::END_BLOCK:
1649+
case WebAssembly::END_TRY:
16721650
Stack.push_back(std::make_pair(&MBB, &MI));
16731651
break;
16741652

1675-
case WebAssembly::END_TRY: {
1676-
// We handle DELEGATE in the default level, because DELEGATE has
1677-
// immediate operands to rewrite.
1678-
Stack.push_back(std::make_pair(&MBB, &MI));
1679-
auto *EHPad = TryToEHPad[EndToBegin[&MI]];
1680-
EHPadStack.push_back(EHPad);
1681-
break;
1682-
}
1683-
16841653
case WebAssembly::END_LOOP:
16851654
Stack.push_back(std::make_pair(EndToBegin[&MI]->getParent(), &MI));
16861655
break;
16871656

1688-
case WebAssembly::CATCH:
1689-
case WebAssembly::CATCH_ALL:
1690-
EHPadStack.pop_back();
1691-
break;
1692-
1693-
case WebAssembly::RETHROW:
1694-
MI.getOperand(0).setImm(getRethrowDepth(Stack, EHPadStack));
1695-
break;
1696-
16971657
default:
16981658
if (MI.isTerminator()) {
16991659
// Rewrite MBB operands to be depth immediates.
@@ -1705,6 +1665,9 @@ void WebAssemblyCFGStackify::rewriteDepthImmediates(MachineFunction &MF) {
17051665
if (MI.getOpcode() == WebAssembly::DELEGATE)
17061666
MO = MachineOperand::CreateImm(
17071667
getDelegateDepth(Stack, MO.getMBB()));
1668+
else if (MI.getOpcode() == WebAssembly::RETHROW)
1669+
MO = MachineOperand::CreateImm(
1670+
getRethrowDepth(Stack, MO.getMBB()));
17081671
else
17091672
MO = MachineOperand::CreateImm(
17101673
getBranchDepth(Stack, MO.getMBB()));

llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp

+13
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,19 @@ void WebAssemblyDAGToDAGISel::Select(SDNode *Node) {
245245
ReplaceNode(Node, Throw);
246246
return;
247247
}
248+
case Intrinsic::wasm_rethrow: {
249+
// RETHROW's BB argument will be populated in LateEHPrepare. Just use a
250+
// '0' as a placeholder for now.
251+
MachineSDNode *Rethrow = CurDAG->getMachineNode(
252+
WebAssembly::RETHROW, DL,
253+
MVT::Other, // outchain type
254+
{
255+
CurDAG->getConstant(0, DL, MVT::i32), // placeholder
256+
Node->getOperand(0) // inchain
257+
});
258+
ReplaceNode(Node, Rethrow);
259+
return;
260+
}
248261
}
249262
break;
250263
}

llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td

+4-5
Original file line numberDiff line numberDiff line change
@@ -132,11 +132,9 @@ let isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 in {
132132
defm THROW : I<(outs), (ins tag_op:$tag, variable_ops),
133133
(outs), (ins tag_op:$tag), [],
134134
"throw \t$tag", "throw \t$tag", 0x08>;
135-
defm RETHROW : NRI<(outs), (ins i32imm:$depth), [], "rethrow \t$depth", 0x09>;
135+
// $ehpad is the EH pad where the exception to rethrow has been caught.
136+
defm RETHROW : NRI<(outs), (ins bb_op:$ehpad), [], "rethrow \t$ehpad", 0x09>;
136137
} // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1
137-
// The depth argument will be computed in CFGStackify. We set it to 0 here for
138-
// now.
139-
def : Pat<(int_wasm_rethrow), (RETHROW 0)>;
140138

141139
// Region within which an exception is caught: try / end_try
142140
let Uses = [VALUE_STACK], Defs = [VALUE_STACK] in {
@@ -160,7 +158,8 @@ defm DELEGATE : NRI<(outs), (ins bb_op:$dst), [], "delegate \t $dst", 0x18>;
160158
// Pseudo instructions: cleanupret / catchret
161159
let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
162160
isPseudo = 1, isEHScopeReturn = 1 in {
163-
defm CLEANUPRET : NRI<(outs), (ins), [(cleanupret)], "cleanupret", 0>;
161+
defm CLEANUPRET : NRI<(outs), (ins bb_op:$ehpad), [(cleanupret bb:$ehpad)],
162+
"cleanupret", 0>;
164163
defm CATCHRET : NRI<(outs), (ins bb_op:$dst, bb_op:$from),
165164
[(catchret bb:$dst, bb:$from)], "catchret", 0>;
166165
} // isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,

llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp

+31-3
Original file line numberDiff line numberDiff line change
@@ -245,11 +245,39 @@ bool WebAssemblyLateEHPrepare::replaceFuncletReturns(MachineFunction &MF) {
245245
Changed = true;
246246
break;
247247
}
248+
case WebAssembly::RETHROW:
249+
// These RETHROWs here were lowered from llvm.wasm.rethrow() intrinsics,
250+
// generated in Clang for when an exception is not caught by the given
251+
// type (e.g. catch (int)).
252+
//
253+
// RETHROW's BB argument is the EH pad where the exception to rethrow has
254+
// been caught. (Until this point, RETHROW has just a '0' as a placeholder
255+
// argument.) For these llvm.wasm.rethrow()s, we can safely assume the
256+
// exception comes from the nearest dominating EH pad, because catch.start
257+
// EH pad is structured like this:
258+
//
259+
// catch.start:
260+
// catchpad ...
261+
// %matches = compare ehselector with typeid
262+
// br i1 %matches, label %catch, label %rethrow
263+
//
264+
// rethrow:
265+
// ;; rethrows the exception caught in 'catch.start'
266+
// call @llvm.wasm.rethrow()
267+
TI->removeOperand(0);
268+
TI->addOperand(MachineOperand::CreateMBB(getMatchingEHPad(TI)));
269+
Changed = true;
270+
break;
248271
case WebAssembly::CLEANUPRET: {
249-
// Replace a cleanupret with a rethrow. For C++ support, currently
250-
// rethrow's immediate argument is always 0 (= the latest exception).
272+
// CLEANUPRETs have the EH pad BB the exception to rethrow has been caught
273+
// as an argument. Use it and change the instruction opcode to 'RETHROW'
274+
// to make rethrowing instructions consistent.
275+
//
276+
// This is because we cannot safely assume that it is always the nearest
277+
// dominating EH pad, in case there are code transformations such as
278+
// inlining.
251279
BuildMI(MBB, TI, TI->getDebugLoc(), TII.get(WebAssembly::RETHROW))
252-
.addImm(0);
280+
.addMBB(TI->getOperand(0).getMBB());
253281
TI->eraseFromParent();
254282
Changed = true;
255283
break;

llvm/lib/Target/X86/X86InstrCompiler.td

+2-1
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,8 @@ def EH_RETURN64 : I<0xC3, RawFrm, (outs), (ins GR64:$addr),
195195

196196
let isTerminator = 1, hasSideEffects = 1, isBarrier = 1, hasCtrlDep = 1,
197197
isCodeGenOnly = 1, isReturn = 1, isEHScopeReturn = 1 in {
198-
def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET", [(cleanupret)]>;
198+
def CLEANUPRET : I<0, Pseudo, (outs), (ins), "# CLEANUPRET",
199+
[(cleanupret bb)]>;
199200

200201
// CATCHRET needs a custom inserter for SEH.
201202
let usesCustomInserter = 1 in

llvm/test/CodeGen/WebAssembly/cfg-stackify-eh.mir

+7-4
Original file line numberDiff line numberDiff line change
@@ -39,15 +39,16 @@ body: |
3939
; CHECK: RETHROW 1
4040
EH_LABEL <mcsymbol .Ltmp2>
4141
%0:i32 = CATCH &__cpp_exception, implicit-def dead $arguments
42-
RETHROW 0, implicit-def dead $arguments
42+
RETHROW %bb.1, implicit-def dead $arguments
4343
4444
bb.2 (landing-pad):
45+
successors: %bb.3
4546
; CHECK: bb.2 (landing-pad):
4647
; CHECK: CATCH
4748
; CHECK: RETHROW 0
4849
EH_LABEL <mcsymbol .Ltmp3>
4950
%1:i32 = CATCH &__cpp_exception, implicit-def dead $arguments
50-
RETHROW 0, implicit-def dead $arguments
51+
RETHROW %bb.2, implicit-def dead $arguments
5152
5253
bb.3:
5354
; CHECK: bb.3:
@@ -104,12 +105,14 @@ body: |
104105
RETURN %0:i32, implicit-def dead $arguments
105106
106107
bb.3 (landing-pad):
108+
successors:
107109
EH_LABEL <mcsymbol .Ltmp4>
108110
%0:i32 = CATCH &__cpp_exception, implicit-def dead $arguments
109-
RETHROW 0, implicit-def dead $arguments
111+
RETHROW %bb.3, implicit-def dead $arguments
110112
111113
bb.4 (landing-pad):
114+
successors:
112115
EH_LABEL <mcsymbol .Ltmp5>
113116
%1:i32 = CATCH &__cpp_exception, implicit-def dead $arguments
114-
RETHROW 0, implicit-def dead $arguments
117+
RETHROW %bb.4, implicit-def dead $arguments
115118
...

llvm/test/CodeGen/WebAssembly/exception-legacy.ll

+105
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,107 @@ unreachable: ; preds = %rethrow
400400
unreachable
401401
}
402402

403+
; The bitcode below is generated when the code below is compiled and
404+
; Temp::~Temp() is inlined into inlined_cleanupret():
405+
;
406+
; void inlined_cleanupret() {
407+
; try {
408+
; Temp t;
409+
; throw 2;
410+
; } catch (...)
411+
; }
412+
;
413+
; Temp::~Temp() {
414+
; try {
415+
; throw 1;
416+
; } catch (...) {
417+
; }
418+
; }
419+
;
420+
; ~Temp() generates cleanupret, which is lowered to a 'rethrow' later. That
421+
; rethrow's immediate argument should correctly target the top-level cleanuppad
422+
; (catch_all). This is a regression test for the bug where we did not compute
423+
; rethrow's argument correctly.
424+
425+
; CHECK-LABEL: inlined_cleanupret:
426+
; CHECK: try
427+
; CHECK: call __cxa_throw
428+
; CHECK: catch_all
429+
; CHECK: try
430+
; CHECK: try
431+
; CHECK: call __cxa_throw
432+
; CHECK: catch
433+
; CHECK: call __cxa_end_catch
434+
; CHECK: try
435+
; CHECK: try
436+
; Note that this rethrow targets the top-level catch_all
437+
; CHECK: rethrow 4
438+
; CHECK: catch
439+
; CHECK: try
440+
; CHECK: call __cxa_end_catch
441+
; CHECK: delegate 5
442+
; CHECK: return
443+
; CHECK: end_try
444+
; CHECK: delegate 3
445+
; CHECK: end_try
446+
; CHECK: catch_all
447+
; CHECK: call _ZSt9terminatev
448+
; CHECK: end_try
449+
; CHECK: end_try
450+
define void @inlined_cleanupret() personality ptr @__gxx_wasm_personality_v0 {
451+
entry:
452+
%exception = tail call ptr @__cxa_allocate_exception(i32 4)
453+
store i32 2, ptr %exception, align 16
454+
invoke void @__cxa_throw(ptr nonnull %exception, ptr nonnull @_ZTIi, ptr null)
455+
to label %unreachable unwind label %ehcleanup
456+
457+
ehcleanup: ; preds = %entry
458+
%0 = cleanuppad within none []
459+
%exception.i = call ptr @__cxa_allocate_exception(i32 4) [ "funclet"(token %0) ]
460+
store i32 1, ptr %exception.i, align 16
461+
invoke void @__cxa_throw(ptr nonnull %exception.i, ptr nonnull @_ZTIi, ptr null) [ "funclet"(token %0) ]
462+
to label %unreachable unwind label %catch.dispatch.i
463+
464+
catch.dispatch.i: ; preds = %ehcleanup
465+
%1 = catchswitch within %0 [label %catch.start.i] unwind label %terminate.i
466+
467+
catch.start.i: ; preds = %catch.dispatch.i
468+
%2 = catchpad within %1 [ptr null]
469+
%3 = tail call ptr @llvm.wasm.get.exception(token %2)
470+
%4 = tail call i32 @llvm.wasm.get.ehselector(token %2)
471+
%5 = call ptr @__cxa_begin_catch(ptr %3) [ "funclet"(token %2) ]
472+
invoke void @__cxa_end_catch() [ "funclet"(token %2) ]
473+
to label %invoke.cont.i unwind label %terminate.i
474+
475+
invoke.cont.i: ; preds = %catch.start.i
476+
catchret from %2 to label %_ZN4TempD2Ev.exit
477+
478+
terminate.i: ; preds = %catch.start.i, %catch.dispatch.i
479+
%6 = cleanuppad within %0 []
480+
call void @_ZSt9terminatev() [ "funclet"(token %6) ]
481+
unreachable
482+
483+
_ZN4TempD2Ev.exit: ; preds = %invoke.cont.i
484+
cleanupret from %0 unwind label %catch.dispatch
485+
486+
catch.dispatch: ; preds = %_ZN4TempD2Ev.exit
487+
%7 = catchswitch within none [label %catch.start] unwind to caller
488+
489+
catch.start: ; preds = %catch.dispatch
490+
%8 = catchpad within %7 [ptr null]
491+
%9 = tail call ptr @llvm.wasm.get.exception(token %8)
492+
%10 = tail call i32 @llvm.wasm.get.ehselector(token %8)
493+
%11 = call ptr @__cxa_begin_catch(ptr %9) #8 [ "funclet"(token %8) ]
494+
call void @__cxa_end_catch() [ "funclet"(token %8) ]
495+
catchret from %8 to label %try.cont
496+
497+
try.cont: ; preds = %catch.start
498+
ret void
499+
500+
unreachable: ; preds = %entry
501+
unreachable
502+
}
503+
403504

404505
declare void @foo()
405506
declare void @bar(ptr)
@@ -415,8 +516,12 @@ declare i32 @llvm.wasm.get.ehselector(token) #0
415516
declare void @llvm.wasm.rethrow() #1
416517
; Function Attrs: nounwind
417518
declare i32 @llvm.eh.typeid.for(ptr) #0
519+
; Function Attrs: nounwind
520+
declare ptr @__cxa_allocate_exception(i32) #0
418521
declare ptr @__cxa_begin_catch(ptr)
419522
declare void @__cxa_end_catch()
523+
; Function Attrs: noreturn
524+
declare void @__cxa_throw(ptr, ptr, ptr) #1
420525
declare void @_ZSt9terminatev()
421526
declare ptr @_ZN4TempD2Ev(ptr returned)
422527

0 commit comments

Comments
 (0)