[llvm] WebAssembly: Take the exception model from the module flag (PR #227583)
via llvm-commits
llvm-commits at lists.llvm.org
Wed Sep 30 00:07:17 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-webassembly
Author: Matt Arsenault (arsenm)
<details>
<summary>Changes</summary>
The WebAssembly EH passes chose whether and how to run from
MCAsmInfo::getExceptionHandlingType() and TargetOptions::ExceptionModel,
A module that asked for Wasm EH through the module flag alone would have
its invokes rewritten by LowerInvoke before WasmEHPrepare ran.
Schedule the passes unconditionally and read the module flag inside the
passes instead. Passes for other models can noop on the models they are
not intended for.
Co-authored-by: Claude Opus 5 <noreply@<!-- -->anthropic.com>
---
Patch is 28.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/227583.diff
14 Files Affected:
- (modified) llvm/lib/CodeGen/WasmEHPrepare.cpp (+3)
- (modified) llvm/lib/Target/WebAssembly/WebAssembly.h (+1-5)
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp (+10-10)
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp (+8-20)
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp (+4-5)
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp (+4-4)
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp (+2-3)
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp (+10-18)
- (modified) llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (+7-14)
- (modified) llvm/lib/Transforms/Utils/LowerInvoke.cpp (+7)
- (added) llvm/test/CodeGen/WebAssembly/exception-model.ll (+93)
- (added) llvm/test/CodeGen/WebAssembly/wasm-eh-prepare-exception-model.ll (+60)
- (modified) llvm/test/CodeGen/WebAssembly/wasm-eh-prepare.ll (+3)
- (added) llvm/test/Transforms/LowerInvoke/respect-exception-model-flag.ll (+133)
``````````diff
diff --git a/llvm/lib/CodeGen/WasmEHPrepare.cpp b/llvm/lib/CodeGen/WasmEHPrepare.cpp
index 37cd2048dfc85..4a47ace295018 100644
--- a/llvm/lib/CodeGen/WasmEHPrepare.cpp
+++ b/llvm/lib/CodeGen/WasmEHPrepare.cpp
@@ -168,6 +168,9 @@ static void eraseDeadBBsAndChildren(const Container &BBs) {
}
bool WasmEHPrepareImpl::runOnFunction(Function &F) {
+ if (F.getParent()->getExceptionModel() != ExceptionHandling::Wasm)
+ return false;
+
bool Changed = false;
Changed |= prepareThrows(F);
Changed |= prepareEHPads(F);
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index e6aefc2ba43e9..94628d0944f8d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -35,15 +35,11 @@ class FunctionPass;
// LLVM IR passes.
class WebAssemblyLowerEmscriptenEHSjLjPass
: public RequiredPassInfoMixin<WebAssemblyLowerEmscriptenEHSjLjPass> {
- bool EnableEmEH;
-
public:
- WebAssemblyLowerEmscriptenEHSjLjPass(bool EnableEmEH = false)
- : EnableEmEH(EnableEmEH) {}
PreservedAnalyses run(Module &M, ModuleAnalysisManager &MAM);
};
-ModulePass *createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(bool EnableEmEH);
+ModulePass *createWebAssemblyLowerEmscriptenEHSjLjLegacyPass();
class WebAssemblyAddMissingPrototypesPass
: public RequiredPassInfoMixin<WebAssemblyAddMissingPrototypesPass> {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 385aaf0c068ce..3e7e0fa6b175c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -39,8 +39,7 @@
#include "llvm/CodeGen/MachineLoopInfo.h"
#include "llvm/CodeGen/MachinePassManager.h"
#include "llvm/IR/Analysis.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/Target/TargetMachine.h"
+#include "llvm/IR/Module.h"
using namespace llvm;
using WebAssembly::SortRegionInfo;
@@ -55,6 +54,8 @@ class WebAssemblyCFGStackifyImpl {
MachineLoopInfo &MLI;
WebAssemblyExceptionInfo &WEI;
+ bool UsesWasmEH = false;
+
// For each block whose label represents the end of a scope, record the block
// which holds the beginning of the scope. This will allow us to quickly skip
// over scoped regions when walking blocks.
@@ -2494,12 +2495,10 @@ void WebAssemblyCFGStackifyImpl::placeMarkers(MachineFunction &MF) {
for (auto &MBB : MF)
placeLoopMarker(MBB);
- const MCAsmInfo &MCAI = MF.getTarget().getMCAsmInfo();
for (auto &MBB : MF) {
if (MBB.isEHPad()) {
// Place the TRY/TRY_TABLE for MBB if MBB is the EH pad of an exception.
- if (MCAI.getExceptionHandlingType() == ExceptionHandling::Wasm &&
- MF.getFunction().hasPersonalityFn()) {
+ if (UsesWasmEH) {
if (WebAssembly::WasmUseLegacyEH)
placeTryMarker(MBB);
else
@@ -2511,8 +2510,7 @@ void WebAssemblyCFGStackifyImpl::placeMarkers(MachineFunction &MF) {
}
}
- if (MCAI.getExceptionHandlingType() == ExceptionHandling::Wasm &&
- MF.getFunction().hasPersonalityFn()) {
+ if (UsesWasmEH) {
const auto &TII = *MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo();
// Add an 'unreachable' after 'end_try_table's.
addUnreachableAfterTryTables(MF, TII);
@@ -2673,7 +2671,10 @@ bool WebAssemblyCFGStackifyImpl::runOnMachineFunction(MachineFunction &MF) {
LLVM_DEBUG(dbgs() << "********** CFG Stackifying **********\n"
"********** Function: "
<< MF.getName() << '\n');
- const MCAsmInfo &MCAI = MF.getTarget().getMCAsmInfo();
+
+ UsesWasmEH = MF.getFunction().hasPersonalityFn() &&
+ MF.getFunction().getParent()->getExceptionModel() ==
+ ExceptionHandling::Wasm;
// Liveness is not tracked for VALUE_STACK physreg.
MF.getRegInfo().invalidateLiveness();
@@ -2683,8 +2684,7 @@ bool WebAssemblyCFGStackifyImpl::runOnMachineFunction(MachineFunction &MF) {
placeMarkers(MF);
// Remove unnecessary instructions possibly introduced by try/end_trys.
- if (MCAI.getExceptionHandlingType() == ExceptionHandling::Wasm &&
- MF.getFunction().hasPersonalityFn() && WebAssembly::WasmUseLegacyEH)
+ if (UsesWasmEH && WebAssembly::WasmUseLegacyEH)
removeUnnecessaryInstrs(MF);
// Convert MBB operands in terminators to relative depth immediates.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
index d10770787433b..6b450e7320e72 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp
@@ -42,13 +42,9 @@ using namespace llvm;
namespace WebAssembly {
extern cl::opt<bool> WasmDisableExplicitLocals;
-extern cl::opt<bool> WasmEnableEmSjLj;
-extern cl::opt<bool> WasmEnableSjLj;
} // namespace WebAssembly
using llvm::WebAssembly::WasmDisableExplicitLocals;
-using llvm::WebAssembly::WasmEnableEmSjLj;
-using llvm::WebAssembly::WasmEnableSjLj;
namespace {
@@ -124,23 +120,17 @@ void WebAssemblyCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) {
// TargetPassConfig::addPassesToHandleExceptions, but that runs after these IR
// passes and Emscripten SjLj handling expects all invokes to be lowered
// before.
- bool EnableEmEH = TM.Options.ExceptionModel == ExceptionHandling::Emscripten;
- bool EnableWasmEH = TM.Options.ExceptionModel == ExceptionHandling::Wasm;
- if (!EnableEmEH && !EnableWasmEH) {
- addFunctionPass(LowerInvokePass(), PMW);
- // The lower invoke pass may create unreachable code. Remove it in order not
- // to process dead blocks in setjmp/longjmp handling.
- addFunctionPass(UnreachableBlockElimPass(), PMW);
- }
+ addFunctionPass(LowerInvokePass(), PMW);
+ // The lower invoke pass may create unreachable code. Remove it in order not
+ // to process dead blocks in setjmp/longjmp handling.
+ addFunctionPass(UnreachableBlockElimPass(), PMW);
// Handle exceptions and setjmp/longjmp if enabled. Unlike Wasm EH preparation
// done in WasmEHPrepare pass, Wasm SjLj preparation shares libraries and
// transformation algorithms with Emscripten SjLj, so we run
// LowerEmscriptenEHSjLj pass also when Wasm SjLj is enabled.
- if (EnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj) {
- flushFPMsToMPM(PMW);
- addModulePass(WebAssemblyLowerEmscriptenEHSjLjPass(EnableEmEH), PMW);
- }
+ flushFPMsToMPM(PMW);
+ addModulePass(WebAssemblyLowerEmscriptenEHSjLjPass(), PMW);
// Expand indirectbr instructions to switches.
addFunctionPass(IndirectBrExpandPass(TM), PMW);
@@ -152,8 +142,7 @@ void WebAssemblyCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) {
}
void WebAssemblyCodeGenPassBuilder::addISelPrepare(PassManagerWrapper &PMW) {
- if (TM.Options.ExceptionModel == ExceptionHandling::Wasm)
- addFunctionPass(WasmEHPreparePass(), PMW);
+ addFunctionPass(WasmEHPreparePass(), PMW);
// We need to move reference type allocas to WASM_ADDRESS_SPACE_VAR so that
// loads and stores are promoted to local.gets/local.sets.
@@ -259,8 +248,7 @@ void WebAssemblyCodeGenPassBuilder::addPreEmitPass(PassManagerWrapper &PMW) {
// Do various transformations for exception handling.
// Every CFG-changing optimizations should come before this.
- if (TM.Options.ExceptionModel == ExceptionHandling::Wasm)
- addMachineFunctionPass(WebAssemblyLateEHPreparePass(), PMW);
+ addMachineFunctionPass(WebAssemblyLateEHPreparePass(), PMW);
// Now that we have a prologue and epilogue and all frame indices are
// rewritten, eliminate SP and FP. This allows them to be stackified,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
index fc3689fbd6ec4..2945a0f48d26c 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyExceptionInfo.cpp
@@ -20,9 +20,8 @@
#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
#include "llvm/IR/Analysis.h"
#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
-#include "llvm/MC/MCAsmInfo.h"
-#include "llvm/Target/TargetMachine.h"
using namespace llvm;
@@ -43,9 +42,9 @@ static void computeWEI(WebAssemblyExceptionInfo &WEI, MachineFunction &MF,
LLVM_DEBUG(dbgs() << "********** Exception Info Calculation **********\n"
"********** Function: "
<< MF.getName() << '\n');
- if (MF.getTarget().getMCAsmInfo().getExceptionHandlingType() !=
- ExceptionHandling::Wasm ||
- !MF.getFunction().hasPersonalityFn())
+ if (!MF.getFunction().hasPersonalityFn() ||
+ MF.getFunction().getParent()->getExceptionModel() !=
+ ExceptionHandling::Wasm)
return;
MachineDominatorTree &MDT = GetMDT();
MachineDominanceFrontier &MDF = GetMDF();
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
index 7331db70fca72..50f3142037e7b 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
@@ -31,7 +31,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/Instructions.h"
-#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/IR/Module.h"
using namespace llvm;
#define DEBUG_TYPE "wasm-frame-info"
@@ -150,9 +150,9 @@ bool WebAssemblyFrameLowering::needsSPForLocalFrame(
// restoring the stack pointer after an exception is caught.
bool WebAssemblyFrameLowering::needsPrologForEH(
const MachineFunction &MF) const {
- auto EHType = MF.getTarget().getMCAsmInfo().getExceptionHandlingType();
- return EHType == ExceptionHandling::Wasm &&
- MF.getFunction().hasPersonalityFn() && MF.getFrameInfo().hasCalls();
+ return MF.getFunction().hasPersonalityFn() && MF.getFrameInfo().hasCalls() &&
+ MF.getFunction().getParent()->getExceptionModel() ==
+ ExceptionHandling::Wasm;
}
/// Returns true if this function needs a local user-space stack pointer.
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
index 01f9975225aa2..db13379f17d21 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp
@@ -22,9 +22,8 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachinePassManager.h"
#include "llvm/IR/Analysis.h"
-#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/IR/Module.h"
#include "llvm/Support/Debug.h"
-#include "llvm/Target/TargetMachine.h"
using namespace llvm;
#define DEBUG_TYPE "wasm-late-eh-prepare"
@@ -126,7 +125,7 @@ bool WebAssemblyLateEHPrepareImpl::runOnMachineFunction(MachineFunction &MF) {
"********** Function: "
<< MF.getName() << '\n');
- if (MF.getTarget().getMCAsmInfo().getExceptionHandlingType() !=
+ if (MF.getFunction().getParent()->getExceptionModel() !=
ExceptionHandling::Wasm)
return false;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
index 0ee7731f8e4f5..7273418143c55 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp
@@ -295,7 +295,7 @@ static cl::list<std::string>
namespace {
class WebAssemblyLowerEmscriptenEHSjLjImpl {
- bool EnableEmEH; // Enable Emscripten exception handling
+ bool EnableEmEH = false; // Enable Emscripten exception handling
bool EnableEmSjLj; // Enable Emscripten setjmp/longjmp handling
bool EnableWasmSjLj; // Enable Wasm setjmp/longjmp handling
bool DoSjLj; // Whether we actually perform setjmp/longjmp handling
@@ -359,15 +359,12 @@ class WebAssemblyLowerEmscriptenEHSjLjImpl {
public:
WebAssemblyLowerEmscriptenEHSjLjImpl(
- bool EnableEmEH,
std::function<DominatorTree &(Function &F)> GetDominatorTree)
- : EnableEmEH(EnableEmEH), EnableEmSjLj(WebAssembly::WasmEnableEmSjLj),
+ : EnableEmSjLj(WebAssembly::WasmEnableEmSjLj),
EnableWasmSjLj(WebAssembly::WasmEnableSjLj),
GetDominatorTree(GetDominatorTree) {
assert(!(EnableEmSjLj && EnableWasmSjLj) &&
"Two SjLj modes cannot be turned on at the same time");
- assert(!(EnableEmEH && EnableWasmSjLj) &&
- "Wasm SjLj should be only used with Wasm EH");
EHAllowlistSet.insert(EHAllowlist.begin(), EHAllowlist.end());
}
@@ -375,8 +372,6 @@ class WebAssemblyLowerEmscriptenEHSjLjImpl {
};
class WebAssemblyLowerEmscriptenEHSjLjLegacy final : public ModulePass {
- bool EnableEmEH;
-
StringRef getPassName() const override {
return "WebAssembly Lower Emscripten Exceptions";
}
@@ -384,8 +379,7 @@ class WebAssemblyLowerEmscriptenEHSjLjLegacy final : public ModulePass {
public:
static char ID;
- WebAssemblyLowerEmscriptenEHSjLjLegacy(bool EnableEmEH = false)
- : ModulePass(ID), EnableEmEH(EnableEmEH) {}
+ WebAssemblyLowerEmscriptenEHSjLjLegacy() : ModulePass(ID) {}
bool runOnModule(Module &M) override;
void getAnalysisUsage(AnalysisUsage &AU) const override {
@@ -399,9 +393,8 @@ INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLjLegacy, DEBUG_TYPE,
"WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp",
false, false)
-ModulePass *
-llvm::createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(bool EnableEmEH) {
- return new WebAssemblyLowerEmscriptenEHSjLjLegacy(EnableEmEH);
+ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLjLegacyPass() {
+ return new WebAssemblyLowerEmscriptenEHSjLjLegacy();
}
static bool canThrow(const Value *V) {
@@ -927,10 +920,9 @@ static void nullifySetjmp(Function *F) {
bool WebAssemblyLowerEmscriptenEHSjLjImpl::runOnModule(Module &M) {
LLVM_DEBUG(dbgs() << "********** Lower Emscripten EH & SjLj **********\n");
- // The Emscripten EH model may come from the "exception-model" module flag
- // (e.g. when this pass is run standalone via opt) in addition to being
- // threaded in from the TargetMachine.
- EnableEmEH |= M.getExceptionModel() == ExceptionHandling::Emscripten;
+ EnableEmEH = M.getExceptionModel() == ExceptionHandling::Emscripten;
+ assert((!EnableEmEH || !EnableWasmSjLj) &&
+ "Wasm SjLj should be only used with Wasm EH");
LLVMContext &C = M.getContext();
IRBuilder<> IRB(C);
@@ -1877,7 +1869,7 @@ void WebAssemblyLowerEmscriptenEHSjLjImpl::handleLongjmpableCallsForWasmSjLj(
bool WebAssemblyLowerEmscriptenEHSjLjLegacy::runOnModule(Module &M) {
WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
- EnableEmEH, [&](Function &F) -> DominatorTree & {
+ [&](Function &F) -> DominatorTree & {
return getAnalysis<DominatorTreeWrapperPass>(F).getDomTree();
});
return Impl.runOnModule(M);
@@ -1887,7 +1879,7 @@ PreservedAnalyses
WebAssemblyLowerEmscriptenEHSjLjPass::run(Module &M,
ModuleAnalysisManager &MAM) {
WebAssemblyLowerEmscriptenEHSjLjImpl Impl(
- EnableEmEH, [&](Function &F) -> DominatorTree & {
+ [&](Function &F) -> DominatorTree & {
return MAM.getResult<FunctionAnalysisManagerModuleProxy>(M)
.getManager()
.getResult<DominatorTreeAnalysis>(F);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 8363d9c0a53cd..c74dc04e6a472 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -309,21 +309,16 @@ void WebAssemblyPassConfig::addIRPasses() {
// TargetPassConfig::addPassesToHandleExceptions, but that runs after these IR
// passes and Emscripten SjLj handling expects all invokes to be lowered
// before.
- bool EnableEmEH = TM->Options.ExceptionModel == ExceptionHandling::Emscripten;
- bool EnableWasmEH = TM->Options.ExceptionModel == ExceptionHandling::Wasm;
- if (!EnableEmEH && !EnableWasmEH) {
- addPass(createLowerInvokePass());
- // The lower invoke pass may create unreachable code. Remove it in order not
- // to process dead blocks in setjmp/longjmp handling.
- addPass(createUnreachableBlockEliminationPass());
- }
+ addPass(createLowerInvokePass());
+ // The lower invoke pass may create unreachable code. Remove it in order not
+ // to process dead blocks in setjmp/longjmp handling.
+ addPass(createUnreachableBlockEliminationPass());
// Handle exceptions and setjmp/longjmp if enabled. Unlike Wasm EH preparation
// done in WasmEHPrepare pass, Wasm SjLj preparation shares libraries and
// transformation algorithms with Emscripten SjLj, so we run
// LowerEmscriptenEHSjLj pass also when Wasm SjLj is enabled.
- if (EnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj)
- addPass(createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(EnableEmEH));
+ addPass(createWebAssemblyLowerEmscriptenEHSjLjLegacyPass());
// Expand indirectbr instructions to switches.
addPass(createIndirectBrExpandPass());
@@ -336,8 +331,7 @@ void WebAssemblyPassConfig::addIRPasses() {
}
void WebAssemblyPassConfig::addISelPrepare() {
- if (TM->Options.ExceptionModel == ExceptionHandling::Wasm)
- addPass(createWasmEHPass());
+ addPass(createWasmEHPass());
// We need to move reference type allocas to WASM_ADDRESS_SPACE_VAR so that
// loads and stores are promoted to local.gets/local.sets.
@@ -426,8 +420,7 @@ void WebAssemblyPassConfig::addPreEmitPass() {
// Do various transformations for exception handling.
// Every CFG-changing optimizations should come before this.
- if (TM->Options.ExceptionModel == ExceptionHandling::Wasm)
- addPass(createWebAssemblyLateEHPrepareLegacyPass());
+ addPass(createWebAssemblyLateEHPrepareLegacyPass());
// Now that we have a prologue and epilogue and all frame indices are
// rewritten, eliminate SP and FP. This allows them to be stackified,
diff --git a/llvm/lib/Transforms/Utils/LowerInvoke.cpp b/llvm/lib/Transforms/Utils/LowerInvoke.cpp
index 9a476e7a48f91..cc38b3574b72a 100644
--- a/llvm/lib/Transforms/Utils/LowerInvoke.cpp
+++ b/llvm/lib/Transforms/Utils/LowerInvoke.cpp
@@ -16,6 +16,7 @@
#include "llvm/Transforms/Utils/LowerInvoke.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Instructions.h"
+#include "llvm/IR/Module.h"
#include "llvm/InitializePasses.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Utils.h"
@@ -43,6 +44,12 @@ INITIALIZE_PASS(LowerInvokeLegacyPass, "lowerinvoke",
false, false)
static bool runImpl(Function &F) {
+ // The WebAssembly models keep invokes through isel, so lowering them here
+ // would destroy the exception handling the module asked for.
+ ExceptionHandling EH = F.getParent()->getExceptionModel();
+ if (EH == ExceptionHandling::Wasm || EH == ExceptionHandling::Emscripten)
+ return false;
+
bool Changed = false;
for (BasicBlock &BB : F)
if (InvokeInst *II = dyn_cast<InvokeInst>(BB.getTerminator())) {
diff --git a/llvm/test/CodeGen/WebAssembly/exception-model.ll b/llvm/test/CodeGen/WebAssembly/exception-model.ll
new file mode 100644
index 0000000000000..564459dcc3a91
--- /dev/null
+++ b/llvm/test/CodeGen/WebAssembly/exception-model.ll
@@ -0,0 +1,93 @@
+; The "exception-model" module flag selects the EH model with no
+; -exception-model on the command line. Wasm triples default to no exception
+; handling, so a module without the flag keeps neither lowering.
+
+; RUN: split-file %s %t
+
+; RUN: llc -wasm-use-legacy-eh=false -mattr=+exception-handling %t/wasm.ll -o - | FileCheck %s --check-prefix=WASM
+; RUN: llc %t/emscripten.ll -o - | FileCheck %s --check-prefix=EM
+; RUN: llc -wasm-use-legacy-eh=false -mattr=+exception-handling %t/noflag.ll -o - | FileCheck %s --check-prefix=NOFLAG
+
+; WASM: .tagtype __cpp_exception i32
+; WASM: try_table (catch __cpp_exception 0)
+
+; EM: .functype invoke_v (i32) -> ()
+; EM: call invoke_v
+; EM: call __cxa_find_matching_catch_3
+
+; NOFLAG: call g
+; NOFLAG-NOT: try_table
+; NOFLAG-NOT: invoke_v
+
+;--- wasm.ll
+target triple = "wasm32-unk...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/227583
More information about the llvm-commits
mailing list