-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[WebAssembly] Make llvm.wasm.throw invokable #128104
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
`llvm.wasm.throw` intrinsic can throw but it was not invokable. Not sure what the rationale was when it was first written that way, but I think at least in Emscripten's C++ exception support with the Wasm port of libunwind, `__builtin_wasm_throw`, which is lowered down to `llvm.wasm.rethrow`, is used only within `_Unwind_RaiseException`, which is a one-liner and thus does not need an `invoke`: https://github.com/emscripten-core/emscripten/blob/720e97f76d6f19e0c6a2d6988988cfe23f0517fb/system/lib/libunwind/src/Unwind-wasm.c#L69 (`_Unwind_RaiseException` is called by `__cxa_throw`, which is generated by the `throw` C++ keyword) But this does not address other direct uses of the builtin in C++, whose use I'm not sure about but is not prohibited. Also other language frontends may need to use the builtin in different functions, which has `try`-`catch`es or destructors. This makes `llvm.wasm.throw` invokable in the backend. To do that, this adds a custom lowering routine to `SelectionDAGBuilder::visitInvoke`, like we did for `llvm.wasm.rethrow`. This does not generate `invoke`s for `__builtin_wasm_throw` yet, which will be done by a follow-up PR. Addresses llvm#124710.
@llvm/pr-subscribers-backend-webassembly Author: Heejin Ahn (aheejin) Changes
But this does not address other direct uses of the builtin in C++, whose use I'm not sure about but is not prohibited. Also other language frontends may need to use the builtin in different functions, which has This makes This does not generate Addresses #124710. Full diff: https://github.com/llvm/llvm-project/pull/128104.diff 4 Files Affected:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 1c58a7f05446c..2b333bd81a570 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3360,10 +3360,23 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
case Intrinsic::experimental_gc_statepoint:
LowerStatepoint(cast<GCStatepointInst>(I), EHPadBB);
break;
+ // wasm_throw, wasm_rethrow: This is usually done in visitTargetIntrinsic,
+ // but this intrinsic is special because it can be invoked, so we manually
+ // lower it to a DAG node here.
+ case Intrinsic::wasm_throw: {
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(getControlRoot()); // inchain for the terminator node
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ Ops.push_back(
+ DAG.getTargetConstant(Intrinsic::wasm_throw, getCurSDLoc(),
+ TLI.getPointerTy(DAG.getDataLayout())));
+ Ops.push_back(getValue(I.getArgOperand(0))); // tag
+ Ops.push_back(getValue(I.getArgOperand(1))); // thrown value
+ SDVTList VTs = DAG.getVTList(ArrayRef<EVT>({MVT::Other})); // outchain
+ DAG.setRoot(DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops));
+ break;
+ }
case Intrinsic::wasm_rethrow: {
- // This is usually done in visitTargetIntrinsic, but this intrinsic is
- // special because it can be invoked, so we manually lower it to a DAG
- // node here.
SmallVector<SDValue, 8> Ops;
Ops.push_back(getControlRoot()); // inchain for the terminator node
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp
index d18196b2217f5..fc98f594660bb 100644
--- a/llvm/lib/CodeGen/WasmEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp
@@ -201,10 +201,8 @@ bool WasmEHPrepareImpl::prepareThrows(Function &F) {
// delete all following instructions within the BB, and delete all the dead
// children of the BB as well.
for (User *U : ThrowF->users()) {
- // A call to @llvm.wasm.throw() is only generated from __cxa_throw()
- // builtin call within libcxxabi, and cannot be an InvokeInst.
- auto *ThrowI = cast<CallInst>(U);
- if (ThrowI->getFunction() != &F)
+ auto *ThrowI = dyn_cast<CallInst>(U);
+ if (!ThrowI || ThrowI->getFunction() != &F)
continue;
Changed = true;
auto *BB = ThrowI->getParent();
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 8432779c107de..0ef4438450ea2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5203,10 +5203,12 @@ void Verifier::visitInstruction(Instruction &I) {
F->getIntrinsicID() == Intrinsic::experimental_patchpoint ||
F->getIntrinsicID() == Intrinsic::fake_use ||
F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint ||
+ F->getIntrinsicID() == Intrinsic::wasm_throw ||
F->getIntrinsicID() == Intrinsic::wasm_rethrow ||
IsAttachedCallOperand(F, CBI, i),
"Cannot invoke an intrinsic other than donothing, patchpoint, "
- "statepoint, coro_resume, coro_destroy or clang.arc.attachedcall",
+ "statepoint, coro_resume, coro_destroy, clang.arc.attachedcall or "
+ "wasm.(re)throw",
&I);
Check(F->getParent() == &M, "Referencing function in another module!", &I,
&M, F, F->getParent());
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index febab822a6a9e..57d1f37c0039f 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -566,6 +566,32 @@ unreachable: ; preds = %entry
unreachable
}
+; This tests whether llvm.wasm.throw intrinsic can invoked and iseled correctly.
+
+; CHECK-LABEL: invoke_throw:
+; CHECK: try_table (catch __cpp_exception 0)
+; CHECK: local.get 0
+; CHECK: throw __cpp_exception
+; CHECK: end_try_table
+define void @invoke_throw(ptr %p) personality ptr @__gxx_wasm_personality_v0 {
+entry:
+ invoke void @llvm.wasm.throw(i32 0, ptr %p)
+ to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %0 = catchswitch within none [label %catch.start] unwind to caller
+
+catch.start: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [ptr null]
+ %2 = call ptr @llvm.wasm.get.exception(token %1)
+ %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+ %4 = call ptr @__cxa_begin_catch(ptr %2) #4 [ "funclet"(token %1) ]
+ call void @__cxa_end_catch() [ "funclet"(token %1) ]
+ catchret from %1 to label %try.cont
+
+try.cont: ; preds = %catch, %entry
+ ret void
+}
declare void @foo()
declare void @bar(ptr)
|
@llvm/pr-subscribers-llvm-ir Author: Heejin Ahn (aheejin) Changes
But this does not address other direct uses of the builtin in C++, whose use I'm not sure about but is not prohibited. Also other language frontends may need to use the builtin in different functions, which has This makes This does not generate Addresses #124710. Full diff: https://github.com/llvm/llvm-project/pull/128104.diff 4 Files Affected:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 1c58a7f05446c..2b333bd81a570 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3360,10 +3360,23 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
case Intrinsic::experimental_gc_statepoint:
LowerStatepoint(cast<GCStatepointInst>(I), EHPadBB);
break;
+ // wasm_throw, wasm_rethrow: This is usually done in visitTargetIntrinsic,
+ // but this intrinsic is special because it can be invoked, so we manually
+ // lower it to a DAG node here.
+ case Intrinsic::wasm_throw: {
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(getControlRoot()); // inchain for the terminator node
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ Ops.push_back(
+ DAG.getTargetConstant(Intrinsic::wasm_throw, getCurSDLoc(),
+ TLI.getPointerTy(DAG.getDataLayout())));
+ Ops.push_back(getValue(I.getArgOperand(0))); // tag
+ Ops.push_back(getValue(I.getArgOperand(1))); // thrown value
+ SDVTList VTs = DAG.getVTList(ArrayRef<EVT>({MVT::Other})); // outchain
+ DAG.setRoot(DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops));
+ break;
+ }
case Intrinsic::wasm_rethrow: {
- // This is usually done in visitTargetIntrinsic, but this intrinsic is
- // special because it can be invoked, so we manually lower it to a DAG
- // node here.
SmallVector<SDValue, 8> Ops;
Ops.push_back(getControlRoot()); // inchain for the terminator node
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp
index d18196b2217f5..fc98f594660bb 100644
--- a/llvm/lib/CodeGen/WasmEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp
@@ -201,10 +201,8 @@ bool WasmEHPrepareImpl::prepareThrows(Function &F) {
// delete all following instructions within the BB, and delete all the dead
// children of the BB as well.
for (User *U : ThrowF->users()) {
- // A call to @llvm.wasm.throw() is only generated from __cxa_throw()
- // builtin call within libcxxabi, and cannot be an InvokeInst.
- auto *ThrowI = cast<CallInst>(U);
- if (ThrowI->getFunction() != &F)
+ auto *ThrowI = dyn_cast<CallInst>(U);
+ if (!ThrowI || ThrowI->getFunction() != &F)
continue;
Changed = true;
auto *BB = ThrowI->getParent();
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 8432779c107de..0ef4438450ea2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5203,10 +5203,12 @@ void Verifier::visitInstruction(Instruction &I) {
F->getIntrinsicID() == Intrinsic::experimental_patchpoint ||
F->getIntrinsicID() == Intrinsic::fake_use ||
F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint ||
+ F->getIntrinsicID() == Intrinsic::wasm_throw ||
F->getIntrinsicID() == Intrinsic::wasm_rethrow ||
IsAttachedCallOperand(F, CBI, i),
"Cannot invoke an intrinsic other than donothing, patchpoint, "
- "statepoint, coro_resume, coro_destroy or clang.arc.attachedcall",
+ "statepoint, coro_resume, coro_destroy, clang.arc.attachedcall or "
+ "wasm.(re)throw",
&I);
Check(F->getParent() == &M, "Referencing function in another module!", &I,
&M, F, F->getParent());
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index febab822a6a9e..57d1f37c0039f 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -566,6 +566,32 @@ unreachable: ; preds = %entry
unreachable
}
+; This tests whether llvm.wasm.throw intrinsic can invoked and iseled correctly.
+
+; CHECK-LABEL: invoke_throw:
+; CHECK: try_table (catch __cpp_exception 0)
+; CHECK: local.get 0
+; CHECK: throw __cpp_exception
+; CHECK: end_try_table
+define void @invoke_throw(ptr %p) personality ptr @__gxx_wasm_personality_v0 {
+entry:
+ invoke void @llvm.wasm.throw(i32 0, ptr %p)
+ to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %0 = catchswitch within none [label %catch.start] unwind to caller
+
+catch.start: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [ptr null]
+ %2 = call ptr @llvm.wasm.get.exception(token %1)
+ %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+ %4 = call ptr @__cxa_begin_catch(ptr %2) #4 [ "funclet"(token %1) ]
+ call void @__cxa_end_catch() [ "funclet"(token %1) ]
+ catchret from %1 to label %try.cont
+
+try.cont: ; preds = %catch, %entry
+ ret void
+}
declare void @foo()
declare void @bar(ptr)
|
@llvm/pr-subscribers-llvm-selectiondag Author: Heejin Ahn (aheejin) Changes
But this does not address other direct uses of the builtin in C++, whose use I'm not sure about but is not prohibited. Also other language frontends may need to use the builtin in different functions, which has This makes This does not generate Addresses #124710. Full diff: https://github.com/llvm/llvm-project/pull/128104.diff 4 Files Affected:
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 1c58a7f05446c..2b333bd81a570 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3360,10 +3360,23 @@ void SelectionDAGBuilder::visitInvoke(const InvokeInst &I) {
case Intrinsic::experimental_gc_statepoint:
LowerStatepoint(cast<GCStatepointInst>(I), EHPadBB);
break;
+ // wasm_throw, wasm_rethrow: This is usually done in visitTargetIntrinsic,
+ // but this intrinsic is special because it can be invoked, so we manually
+ // lower it to a DAG node here.
+ case Intrinsic::wasm_throw: {
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(getControlRoot()); // inchain for the terminator node
+ const TargetLowering &TLI = DAG.getTargetLoweringInfo();
+ Ops.push_back(
+ DAG.getTargetConstant(Intrinsic::wasm_throw, getCurSDLoc(),
+ TLI.getPointerTy(DAG.getDataLayout())));
+ Ops.push_back(getValue(I.getArgOperand(0))); // tag
+ Ops.push_back(getValue(I.getArgOperand(1))); // thrown value
+ SDVTList VTs = DAG.getVTList(ArrayRef<EVT>({MVT::Other})); // outchain
+ DAG.setRoot(DAG.getNode(ISD::INTRINSIC_VOID, getCurSDLoc(), VTs, Ops));
+ break;
+ }
case Intrinsic::wasm_rethrow: {
- // This is usually done in visitTargetIntrinsic, but this intrinsic is
- // special because it can be invoked, so we manually lower it to a DAG
- // node here.
SmallVector<SDValue, 8> Ops;
Ops.push_back(getControlRoot()); // inchain for the terminator node
const TargetLowering &TLI = DAG.getTargetLoweringInfo();
diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp
index d18196b2217f5..fc98f594660bb 100644
--- a/llvm/lib/CodeGen/WasmEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp
@@ -201,10 +201,8 @@ bool WasmEHPrepareImpl::prepareThrows(Function &F) {
// delete all following instructions within the BB, and delete all the dead
// children of the BB as well.
for (User *U : ThrowF->users()) {
- // A call to @llvm.wasm.throw() is only generated from __cxa_throw()
- // builtin call within libcxxabi, and cannot be an InvokeInst.
- auto *ThrowI = cast<CallInst>(U);
- if (ThrowI->getFunction() != &F)
+ auto *ThrowI = dyn_cast<CallInst>(U);
+ if (!ThrowI || ThrowI->getFunction() != &F)
continue;
Changed = true;
auto *BB = ThrowI->getParent();
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 8432779c107de..0ef4438450ea2 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -5203,10 +5203,12 @@ void Verifier::visitInstruction(Instruction &I) {
F->getIntrinsicID() == Intrinsic::experimental_patchpoint ||
F->getIntrinsicID() == Intrinsic::fake_use ||
F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint ||
+ F->getIntrinsicID() == Intrinsic::wasm_throw ||
F->getIntrinsicID() == Intrinsic::wasm_rethrow ||
IsAttachedCallOperand(F, CBI, i),
"Cannot invoke an intrinsic other than donothing, patchpoint, "
- "statepoint, coro_resume, coro_destroy or clang.arc.attachedcall",
+ "statepoint, coro_resume, coro_destroy, clang.arc.attachedcall or "
+ "wasm.(re)throw",
&I);
Check(F->getParent() == &M, "Referencing function in another module!", &I,
&M, F, F->getParent());
diff --git a/llvm/test/CodeGen/WebAssembly/exception.ll b/llvm/test/CodeGen/WebAssembly/exception.ll
index febab822a6a9e..57d1f37c0039f 100644
--- a/llvm/test/CodeGen/WebAssembly/exception.ll
+++ b/llvm/test/CodeGen/WebAssembly/exception.ll
@@ -566,6 +566,32 @@ unreachable: ; preds = %entry
unreachable
}
+; This tests whether llvm.wasm.throw intrinsic can invoked and iseled correctly.
+
+; CHECK-LABEL: invoke_throw:
+; CHECK: try_table (catch __cpp_exception 0)
+; CHECK: local.get 0
+; CHECK: throw __cpp_exception
+; CHECK: end_try_table
+define void @invoke_throw(ptr %p) personality ptr @__gxx_wasm_personality_v0 {
+entry:
+ invoke void @llvm.wasm.throw(i32 0, ptr %p)
+ to label %try.cont unwind label %catch.dispatch
+
+catch.dispatch: ; preds = %entry
+ %0 = catchswitch within none [label %catch.start] unwind to caller
+
+catch.start: ; preds = %catch.dispatch
+ %1 = catchpad within %0 [ptr null]
+ %2 = call ptr @llvm.wasm.get.exception(token %1)
+ %3 = call i32 @llvm.wasm.get.ehselector(token %1)
+ %4 = call ptr @__cxa_begin_catch(ptr %2) #4 [ "funclet"(token %1) ]
+ call void @__cxa_end_catch() [ "funclet"(token %1) ]
+ catchret from %1 to label %try.cont
+
+try.cont: ; preds = %catch, %entry
+ ret void
+}
declare void @foo()
declare void @bar(ptr)
|
Even though `__builtin_wasm_throw`, which is lowered down to `llvm.wasm.throw`, throws, ```cpp try { __builtin_wasm_throw(0, obj); } catch (...) { } ``` does not generate `invoke`. This is because we have assumed the intrinsic cannot be invoked, which doesn't make much sense. (See llvm#128104 for the historical context) llvm#128104 made `llvm.wasm.throw` intrinsic invokable in the backend. This actually generates `invoke`s in Clang for `__builtin_wasm_throw`. While we're at it, this also generates `invoke`s for `__builtin_wasm_rethrow`, which is actually not used anywhere in C++ support. I haven't deleted it just in case in may have uses later. (For example, to support rethrow functionality that carries stack trace with exnref) Depends on llvm#128104 for the CI to pass. Fixes llvm#124710.
✅ With the latest revision this PR passed the C/C++ code formatter. |
SmallVector<SDValue, 8> Ops; | ||
Ops.push_back(getControlRoot()); // inchain for the terminator node | ||
const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | ||
Ops.push_back( | ||
DAG.getTargetConstant(Intrinsic::wasm_throw, getCurSDLoc(), | ||
TLI.getPointerTy(DAG.getDataLayout()))); | ||
Ops.push_back(getValue(I.getArgOperand(0))); // tag | ||
Ops.push_back(getValue(I.getArgOperand(1))); // thrown value |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can replace opts with a static sized, initialized array
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: aa5fafd
const TargetLowering &TLI = DAG.getTargetLoweringInfo(); | ||
Ops.push_back( | ||
SmallVector<SDValue, 8> Ops = { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
std::array
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done: aa7b0f6
std::array<SDValue, 2> Ops = { | ||
getControlRoot(), // inchain for the terminator node | ||
DAG.getTargetConstant(Intrinsic::wasm_rethrow, getCurSDLoc(), | ||
TLI.getPointerTy(DAG.getDataLayout()))); | ||
TLI.getPointerTy(DAG.getDataLayout()))}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This just makes the existing wasm_rethrow
use std::array
and NFC
Even though `__builtin_wasm_throw`, which is lowered down to `llvm.wasm.throw`, throws, ```cpp try { __builtin_wasm_throw(0, obj); } catch (...) { } ``` does not generate `invoke`. This is because we have assumed the intrinsic cannot be invoked, which doesn't make much sense. (See #128104 for the historical context) #128104 made `llvm.wasm.throw` intrinsic invokable in the backend. This actually generates `invoke`s in Clang for `__builtin_wasm_throw`. While we're at it, this also generates `invoke`s for `__builtin_wasm_rethrow`, which is actually not used anywhere in C++ support. I haven't deleted it just in case in may have uses later. (For example, to support rethrow functionality that carries stack trace with exnref) Depends on #128104 for the CI to pass. Fixes #124710.
llvm.wasm.throw
intrinsic can throw but it was not invokable. Not sure what the rationale was when it was first written that way, but I think at least in Emscripten's C++ exception support with the Wasm port of libunwind,__builtin_wasm_throw
, which is lowered down tollvm.wasm.rethrow
, is used only within_Unwind_RaiseException
, which is an one-liner and thus does not need aninvoke
: https://github.com/emscripten-core/emscripten/blob/720e97f76d6f19e0c6a2d6988988cfe23f0517fb/system/lib/libunwind/src/Unwind-wasm.c#L69 (_Unwind_RaiseException
is called by__cxa_throw
, which is generated by thethrow
C++ keyword)But this does not address other direct uses of the builtin in C++, whose use I'm not sure about but is not prohibited. Also other language frontends may need to use the builtin in different functions, which has
try
-catch
es or destructors.This makes
llvm.wasm.throw
invokable in the backend. To do that, this adds a custom lowering routine toSelectionDAGBuilder::visitInvoke
, like we did forllvm.wasm.rethrow
.This does not generate
invoke
s for__builtin_wasm_throw
yet, which will be done by a follow-up PR.Addresses #124710.