https://github.com/arsenm updated https://github.com/llvm/llvm-project/pull/221443
>From 89e13008600307db52c421ab59c0e98ea2508518 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Sat, 5 Sep 2026 12:19:03 +0200 Subject: [PATCH 1/2] clang/WebAssembly: Add -femscripten-exceptions driver flag Add a proper -femscripten-exceptions driver flag for Emscripten exception handling, parallel to -fwasm-exceptions. Previously the only way to select Emscripten EH was to pass the backend implementation detail -mllvm -enable-emscripten-cxx-exceptions. This drives the existing cl::opt mechanism, but in the future this will change the emitted exception model module flag. Co-authored-by: Claude (Claude-Opus-4.8) <[email protected]> --- clang/include/clang/Options/Options.td | 3 +++ clang/lib/Driver/ToolChains/WebAssembly.cpp | 18 +++++++++++++++--- clang/test/Driver/wasm-toolchain.c | 21 ++++++++++++++++++++- 3 files changed, 38 insertions(+), 4 deletions(-) diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 37e5c3199a003..2f2ab2f2ba6d8 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2454,6 +2454,9 @@ def fseh_exceptions : Flag<["-"], "fseh-exceptions">, Group<f_Group>, HelpText<"Use SEH style exceptions">; def fwasm_exceptions : Flag<["-"], "fwasm-exceptions">, Group<f_Group>, HelpText<"Use WebAssembly style exceptions">; +def femscripten_exceptions : Flag<["-"], "femscripten-exceptions">, + Group<f_Group>, + HelpText<"Use Emscripten JavaScript-based C++ exceptions">; def exception_model : Separate<["-"], "exception-model">, Visibility<[CC1Option]>, HelpText<"The exception model">, Values<"dwarf,sjlj,seh,wasm,none">, diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 7d5d406df2399..0d3271d31a0b7 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -423,6 +423,10 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, getDriver().Diag(diag::err_drv_argument_not_allowed_with) << CurOption << "-mno-reference-types"; + if (DriverArgs.hasArg(options::OPT_femscripten_exceptions)) + getDriver().Diag(diag::err_drv_argument_not_allowed_with) + << CurOption << "-femscripten-exceptions"; + for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { for (const auto *Option : {"-enable-emscripten-cxx-exceptions", "-enable-emscripten-sjlj", @@ -458,12 +462,20 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-wasm-enable-eh"); } + if (DriverArgs.getLastArg(options::OPT_femscripten_exceptions)) { + // Backend needs -enable-emscripten-cxx-exceptions to enable Emscripten EH + CC1Args.push_back("-mllvm"); + CC1Args.push_back("-enable-emscripten-cxx-exceptions"); + } + for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { StringRef Opt = A->getValue(0); if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) { // '-mllvm -emscripten-cxx-exceptions-allowed' should be used with - // '-mllvm -enable-emscripten-cxx-exceptions' - bool EmEHArgExists = false; + // '-femscripten-exceptions' (or the underlying + // '-mllvm -enable-emscripten-cxx-exceptions'). + bool EmEHArgExists = + DriverArgs.hasArg(options::OPT_femscripten_exceptions); for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { if (StringRef(A->getValue(0)) == "-enable-emscripten-cxx-exceptions") { EmEHArgExists = true; @@ -473,7 +485,7 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, if (!EmEHArgExists) getDriver().Diag(diag::err_drv_argument_only_allowed_with) << "-mllvm -emscripten-cxx-exceptions-allowed" - << "-mllvm -enable-emscripten-cxx-exceptions"; + << "-femscripten-exceptions"; // Prevent functions specified in -emscripten-cxx-exceptions-allowed list // from being inlined before reaching the wasm backend. diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 467d79e57aff1..083773e8e8197 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -133,7 +133,26 @@ // RUN: not %clang -### --target=wasm32-unknown-unknown \ // RUN: --sysroot=/foo %s -mllvm -emscripten-cxx-exceptions-allowed 2>&1 \ // RUN: | FileCheck -check-prefix=EMSCRIPTEN_EH_ALLOWED_WO_ENABLE %s -// EMSCRIPTEN_EH_ALLOWED_WO_ENABLE: invalid argument '-mllvm -emscripten-cxx-exceptions-allowed' only allowed with '-mllvm -enable-emscripten-cxx-exceptions' +// EMSCRIPTEN_EH_ALLOWED_WO_ENABLE: invalid argument '-mllvm -emscripten-cxx-exceptions-allowed' only allowed with '-femscripten-exceptions' + +// '-femscripten-exceptions' sets '-mllvm -enable-emscripten-cxx-exceptions' +// RUN: %clang -### --target=wasm32-unknown-unknown \ +// RUN: --sysroot=/foo %s -femscripten-exceptions 2>&1 \ +// RUN: | FileCheck -check-prefix=EMSCRIPTEN_EXCEPTIONS %s +// EMSCRIPTEN_EXCEPTIONS: "-cc1" {{.*}} "-mllvm" "-enable-emscripten-cxx-exceptions" + +// '-femscripten-exceptions' satisfies the '-emscripten-cxx-exceptions-allowed' +// companion requirement. +// RUN: %clang -### --target=wasm32-unknown-unknown \ +// RUN: --sysroot=/foo %s -femscripten-exceptions \ +// RUN: -mllvm -emscripten-cxx-exceptions-allowed=foo,bar 2>&1 \ +// RUN: | FileCheck -check-prefix=EMSCRIPTEN_EH_ALLOWED_NOINLINE %s + +// '-fwasm-exceptions' not allowed with '-femscripten-exceptions' +// RUN: not %clang -### --target=wasm32-unknown-unknown \ +// RUN: --sysroot=/foo %s -fwasm-exceptions -femscripten-exceptions 2>&1 \ +// RUN: | FileCheck -check-prefix=WASM_EXCEPTIONS_FEMSCRIPTEN_EH %s +// WASM_EXCEPTIONS_FEMSCRIPTEN_EH: invalid argument '-fwasm-exceptions' not allowed with '-femscripten-exceptions' // '-fwasm-exceptions' sets +exception-handling, -multivalue, -reference-types, // "-exception-model=wasm", and '-mllvm -wasm-enable-eh' >From 6143832401f0f3afa86b8f82748867178bf02129 Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> Date: Sat, 5 Sep 2026 15:24:05 +0200 Subject: [PATCH 2/2] WebAssembly: Introduce ExceptionHandling::EmscriptenEH model Add a dedicated EmscriptenEH exception model so the control uses the standard exception model control, instead of relying on a backend specific cl::opt. This will later migrate to a module flag and remove -enable-emscripten-cxx-exceptions Co-authored-by: Claude (Claude-Opus-4.8) <[email protected]> --- clang/include/clang/Basic/CodeGenOptions.h | 13 +++++++- .../clang/Basic/DiagnosticFrontendKinds.td | 2 +- clang/include/clang/Options/Options.td | 4 +-- clang/lib/CodeGen/BackendUtil.cpp | 2 ++ clang/lib/Driver/ToolChains/Clang.cpp | 5 ++- clang/lib/Driver/ToolChains/WebAssembly.cpp | 6 ---- ...asm-exception-model-flag-parse-ir-input.ll | 2 +- clang/test/Driver/ir-exception-model.c | 2 ++ clang/test/Driver/wasm-toolchain.c | 6 ++-- llvm/include/llvm/Support/CodeGen.h | 15 +++++---- llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp | 2 ++ llvm/lib/CodeGen/CommandFlags.cpp | 4 ++- llvm/lib/CodeGen/TargetPassConfig.cpp | 3 ++ llvm/lib/Passes/CodeGenPassBuilder.cpp | 3 ++ llvm/lib/Target/WebAssembly/WebAssembly.h | 6 +++- .../WebAssembly/WebAssemblyAsmPrinter.cpp | 1 + .../WebAssemblyCodeGenPassBuilder.cpp | 9 ++++-- .../WebAssemblyLowerEmscriptenEHSjLj.cpp | 17 ++++++---- .../WebAssembly/WebAssemblyTargetMachine.cpp | 32 ++++++++++++------- .../CodeGen/WebAssembly/eh-option-errors.ll | 13 +++----- 20 files changed, 94 insertions(+), 53 deletions(-) diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 17f367bc02607..8b65a5bc920a5 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -199,7 +199,14 @@ class CodeGenOptions : public CodeGenOptionsBase { } /// Possible exception handling behavior. - enum class ExceptionHandlingKind { None, SjLj, WinEH, DwarfCFI, Wasm }; + enum class ExceptionHandlingKind { + None, + SjLj, + WinEH, + DwarfCFI, + Wasm, + EmscriptenEH + }; enum class SwiftAsyncFramePointerKind { Auto, // Choose Swift async extended frame info based on deployment target. @@ -634,6 +641,10 @@ class CodeGenOptions : public CodeGenOptionsBase { return getExceptionHandling() == ExceptionHandlingKind::Wasm; } + bool hasEmscriptenExceptions() const { + return getExceptionHandling() == ExceptionHandlingKind::EmscriptenEH; + } + /// Check if Clang profile instrumenation is on. bool hasProfileClangInstr() const { return getProfileInstr() == diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td index a10f10502a702..de38915bd8985 100644 --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -151,7 +151,7 @@ def err_fe_invalid_multiple_actions : Error< def err_fe_invalid_alignment : Error< "invalid value '%1' in '%0'; alignment must be a power of 2">; def err_fe_invalid_exception_model - : Error<"invalid exception model '%select{none|sjlj|seh|dwarf|wasm}0' for target '%1'">; + : Error<"invalid exception model '%select{none|sjlj|seh|dwarf|wasm|emscripten}0' for target '%1'">; def err_fe_invalid_source_date_epoch : Error< "environment variable 'SOURCE_DATE_EPOCH' ('%0') must be a non-negative decimal integer <= %1">; diff --git a/clang/include/clang/Options/Options.td b/clang/include/clang/Options/Options.td index 2f2ab2f2ba6d8..60d511c5a71e5 100644 --- a/clang/include/clang/Options/Options.td +++ b/clang/include/clang/Options/Options.td @@ -2459,9 +2459,9 @@ def femscripten_exceptions : Flag<["-"], "femscripten-exceptions">, HelpText<"Use Emscripten JavaScript-based C++ exceptions">; def exception_model : Separate<["-"], "exception-model">, Visibility<[CC1Option]>, HelpText<"The exception model">, - Values<"dwarf,sjlj,seh,wasm,none">, + Values<"dwarf,sjlj,seh,wasm,emscripten,none">, NormalizedValuesScope<"CodeGenOptions::ExceptionHandlingKind">, - NormalizedValues<["DwarfCFI", "SjLj", "WinEH", "Wasm", "None"]>, + NormalizedValues<["DwarfCFI", "SjLj", "WinEH", "Wasm", "EmscriptenEH", "None"]>, MarshallingInfoEnum<CodeGenOpts<"ExceptionHandling">, "None">; def exception_model_EQ : Joined<["-"], "exception-model=">, Visibility<[CC1Option]>, Alias<exception_model>; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp index ed369d360c48b..d73d1fb497d07 100644 --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -419,6 +419,8 @@ static bool initTargetOptions(const CompilerInstance &CI, Options.ExceptionModel = llvm::ExceptionHandling::DwarfCFI; if (CodeGenOpts.hasWasmExceptions()) Options.ExceptionModel = llvm::ExceptionHandling::Wasm; + if (CodeGenOpts.hasEmscriptenExceptions()) + Options.ExceptionModel = llvm::ExceptionHandling::EmscriptenEH; Options.NoZerosInBSS = CodeGenOpts.NoZeroInitializedInBSS; diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp index ab852bf0e0043..9f426a0f17fcc 100644 --- a/clang/lib/Driver/ToolChains/Clang.cpp +++ b/clang/lib/Driver/ToolChains/Clang.cpp @@ -7891,7 +7891,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, // Handle exception personalities Arg *A = Args.getLastArg( options::OPT_fsjlj_exceptions, options::OPT_fseh_exceptions, - options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions); + options::OPT_fdwarf_exceptions, options::OPT_fwasm_exceptions, + options::OPT_femscripten_exceptions); if (A) { const Option &Opt = A->getOption(); if (Opt.matches(options::OPT_fsjlj_exceptions)) @@ -7902,6 +7903,8 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA, CmdArgs.push_back("-exception-model=dwarf"); if (Opt.matches(options::OPT_fwasm_exceptions)) CmdArgs.push_back("-exception-model=wasm"); + if (Opt.matches(options::OPT_femscripten_exceptions)) + CmdArgs.push_back("-exception-model=emscripten"); } else { switch (TC.GetExceptionModel(Args)) { default: diff --git a/clang/lib/Driver/ToolChains/WebAssembly.cpp b/clang/lib/Driver/ToolChains/WebAssembly.cpp index 0d3271d31a0b7..2880f03057ba6 100644 --- a/clang/lib/Driver/ToolChains/WebAssembly.cpp +++ b/clang/lib/Driver/ToolChains/WebAssembly.cpp @@ -462,12 +462,6 @@ void WebAssembly::addClangTargetOptions(const ArgList &DriverArgs, CC1Args.push_back("-wasm-enable-eh"); } - if (DriverArgs.getLastArg(options::OPT_femscripten_exceptions)) { - // Backend needs -enable-emscripten-cxx-exceptions to enable Emscripten EH - CC1Args.push_back("-mllvm"); - CC1Args.push_back("-enable-emscripten-cxx-exceptions"); - } - for (const Arg *A : DriverArgs.filtered(options::OPT_mllvm)) { StringRef Opt = A->getValue(0); if (Opt.starts_with("-emscripten-cxx-exceptions-allowed")) { diff --git a/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll b/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll index 85bfc7f74daed..8263c98670aab 100644 --- a/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll +++ b/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll @@ -11,7 +11,7 @@ ; CHECK-LABEL: define void @test( ; ERR: error: invalid value 'invalid' in '-exception-model=invalid' -; ERR-BE: fatal error: error in backend: -exception-model should be either 'none' or 'wasm' +; ERR-BE: fatal error: error in backend: -exception-model should be either 'none', 'wasm', or 'emscripten' define void @test() { ret void } diff --git a/clang/test/Driver/ir-exception-model.c b/clang/test/Driver/ir-exception-model.c index 9e8f998de0d6b..b5d68c644e1b7 100644 --- a/clang/test/Driver/ir-exception-model.c +++ b/clang/test/Driver/ir-exception-model.c @@ -1,5 +1,6 @@ // RUN: %clang -### -target wasm32-unknown-unknown -fwasm-exceptions -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck %s // RUN: %clang -### -target wasm32-unknown-unknown -Xclang -exception-model=wasm -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck %s +// RUN: %clang -### -target wasm32-unknown-emscripten -femscripten-exceptions -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck -check-prefix=EMSCRIPTEN %s // RUN: %clang -### -target wasm32-unknown-unknown -Xclang -exception-model=dwarf -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck -check-prefix=DWARF %s // RUN: %clang -### -target wasm32-unknown-unknown -Xclang -exception-model=sjlj -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck -check-prefix=SJLJ %s // RUN: %clang -### -target wasm32-unknown-unknown -Xclang -exception-model=wineh -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck -check-prefix=WINEH %s @@ -8,6 +9,7 @@ // Check that -fwasm-exceptions propagates -exception-model to cc1 // CHECK: "-exception-model=wasm" +// EMSCRIPTEN: "-exception-model=emscripten" // DWARF: "-exception-model=dwarf" // SJLJ: "-exception-model=sjlj" // WINEH: "-exception-model=wineh" diff --git a/clang/test/Driver/wasm-toolchain.c b/clang/test/Driver/wasm-toolchain.c index 083773e8e8197..665cf4d1a667b 100644 --- a/clang/test/Driver/wasm-toolchain.c +++ b/clang/test/Driver/wasm-toolchain.c @@ -123,7 +123,7 @@ // '-mllvm -emscripten-cxx-exceptions-allowed=foo,bar' sets // '-mllvm --force-attribute=foo:noinline -mllvm --force-attribute=bar:noinline' // RUN: %clang -### --target=wasm32-unknown-unknown \ -// RUN: --sysroot=/foo %s -mllvm -enable-emscripten-cxx-exceptions \ +// RUN: --sysroot=/foo %s -femscripten-exceptions \ // RUN: -mllvm -emscripten-cxx-exceptions-allowed=foo,bar 2>&1 \ // RUN: | FileCheck -check-prefix=EMSCRIPTEN_EH_ALLOWED_NOINLINE %s // EMSCRIPTEN_EH_ALLOWED_NOINLINE: "-cc1" {{.*}} "-mllvm" "--force-attribute=foo:noinline" "-mllvm" "--force-attribute=bar:noinline" @@ -135,11 +135,11 @@ // RUN: | FileCheck -check-prefix=EMSCRIPTEN_EH_ALLOWED_WO_ENABLE %s // EMSCRIPTEN_EH_ALLOWED_WO_ENABLE: invalid argument '-mllvm -emscripten-cxx-exceptions-allowed' only allowed with '-femscripten-exceptions' -// '-femscripten-exceptions' sets '-mllvm -enable-emscripten-cxx-exceptions' +// '-femscripten-exceptions' sets '-exception-model=emscripten' // RUN: %clang -### --target=wasm32-unknown-unknown \ // RUN: --sysroot=/foo %s -femscripten-exceptions 2>&1 \ // RUN: | FileCheck -check-prefix=EMSCRIPTEN_EXCEPTIONS %s -// EMSCRIPTEN_EXCEPTIONS: "-cc1" {{.*}} "-mllvm" "-enable-emscripten-cxx-exceptions" +// EMSCRIPTEN_EXCEPTIONS: "-cc1" {{.*}} "-exception-model=emscripten" // '-femscripten-exceptions' satisfies the '-emscripten-cxx-exceptions-allowed' // companion requirement. diff --git a/llvm/include/llvm/Support/CodeGen.h b/llvm/include/llvm/Support/CodeGen.h index e61a36ed42d96..6b1929ebb5c71 100644 --- a/llvm/include/llvm/Support/CodeGen.h +++ b/llvm/include/llvm/Support/CodeGen.h @@ -52,13 +52,14 @@ namespace llvm { } enum class ExceptionHandling : int { - None, ///< No exception support - DwarfCFI, ///< DWARF-like instruction based exceptions - SjLj, ///< setjmp/longjmp based exceptions - ARM, ///< ARM EHABI - WinEH, ///< Windows Exception Handling - Wasm, ///< WebAssembly Exception Handling - AIX, ///< AIX Exception Handling + None, ///< No exception support + DwarfCFI, ///< DWARF-like instruction based exceptions + SjLj, ///< setjmp/longjmp based exceptions + ARM, ///< ARM EHABI + WinEH, ///< Windows Exception Handling + Wasm, ///< WebAssembly Exception Handling + EmscriptenEH, ///< Emscripten JavaScript-based C++ exception handling + AIX, ///< AIX Exception Handling ZOS, ///< z/OS MVS Exception Handling. Very similar to DwarfCFI, but the ///< PPA1 is used instead of an .eh_frame section. }; diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 3d06677d1706b..a535d4bb473cc 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -669,6 +669,8 @@ bool AsmPrinter::doInitialization(Module &M) { EHStreamer *ES = nullptr; switch (MAI.getExceptionHandlingType()) { case ExceptionHandling::None: + case ExceptionHandling::EmscriptenEH: + // Emscripten EH is handled in JS glue code and emits no EH tables here. if (!usesCFIWithoutEH()) break; [[fallthrough]]; diff --git a/llvm/lib/CodeGen/CommandFlags.cpp b/llvm/lib/CodeGen/CommandFlags.cpp index db149dd938203..6de05e3469cca 100644 --- a/llvm/lib/CodeGen/CommandFlags.cpp +++ b/llvm/lib/CodeGen/CommandFlags.cpp @@ -198,7 +198,9 @@ codegen::RegisterCodeGenFlags::RegisterCodeGenFlags() { clEnumValN(ExceptionHandling::WinEH, "wineh", "Windows exception model"), clEnumValN(ExceptionHandling::Wasm, "wasm", - "WebAssembly exception handling"))); + "WebAssembly exception handling"), + clEnumValN(ExceptionHandling::EmscriptenEH, "emscripten", + "Emscripten JavaScript-based C++ exception handling"))); CGBINDOPT(ExceptionModel); static cl::opt<CodeGenFileType> FileType( diff --git a/llvm/lib/CodeGen/TargetPassConfig.cpp b/llvm/lib/CodeGen/TargetPassConfig.cpp index e390db16aa63d..3d8883a8a2049 100644 --- a/llvm/lib/CodeGen/TargetPassConfig.cpp +++ b/llvm/lib/CodeGen/TargetPassConfig.cpp @@ -961,6 +961,9 @@ void TargetPassConfig::addPassesToHandleExceptions() { addPass(createWasmEHPass()); break; case ExceptionHandling::None: + case ExceptionHandling::EmscriptenEH: + // Emscripten EH is lowered earlier by WebAssemblyLowerEmscriptenEHSjLj, so + // by this point it needs no generic EH preparation, like the None case. addPass(createLowerInvokePass()); // The lower invoke pass may create unreachable code. Remove it. diff --git a/llvm/lib/Passes/CodeGenPassBuilder.cpp b/llvm/lib/Passes/CodeGenPassBuilder.cpp index 63e161965820e..57d4b74c4e24c 100644 --- a/llvm/lib/Passes/CodeGenPassBuilder.cpp +++ b/llvm/lib/Passes/CodeGenPassBuilder.cpp @@ -473,6 +473,9 @@ void CodeGenPassBuilder::addPassesToHandleExceptions(PassManagerWrapper &PMW) { addFunctionPass(WasmEHPreparePass(), PMW); break; case ExceptionHandling::None: + case ExceptionHandling::EmscriptenEH: + // Emscripten EH is lowered earlier by WebAssemblyLowerEmscriptenEHSjLj, so + // by this point it needs no generic EH preparation, like the None case. addFunctionPass(LowerInvokePass(), PMW); // The lower invoke pass may create unreachable code. Remove it. diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h index 94628d0944f8d..e6aefc2ba43e9 100644 --- a/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -35,11 +35,15 @@ 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(); +ModulePass *createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(bool EnableEmEH); class WebAssemblyAddMissingPrototypesPass : public RequiredPassInfoMixin<WebAssemblyAddMissingPrototypesPass> { diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 69a0f97253f3e..d64f03c24b11c 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp @@ -166,6 +166,7 @@ MCSymbolWasm *WebAssemblyAsmPrinter::getMCSymbolForFunction( MCSymbolWasm *WasmSym = nullptr; const bool EnableEmEH = + TM.Options.ExceptionModel == ExceptionHandling::EmscriptenEH || WebAssembly::WasmEnableEmEH || WebAssembly::WasmEnableEmSjLj; if (EnableEmEH && isEmscriptenInvokeName(F->getName())) { assert(Sig); diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp index 7fecb163625cf..653080fd81582 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyCodeGenPassBuilder.cpp @@ -127,7 +127,10 @@ 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. - if (!WasmEnableEmEH && !WasmEnableEH) { + bool EnableEmEH = + TM.Options.ExceptionModel == ExceptionHandling::EmscriptenEH || + WasmEnableEmEH; + if (!EnableEmEH && !WasmEnableEH) { addFunctionPass(LowerInvokePass(), PMW); // The lower invoke pass may create unreachable code. Remove it in order not // to process dead blocks in setjmp/longjmp handling. @@ -138,9 +141,9 @@ void WebAssemblyCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) { // 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 (WasmEnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj) { + if (EnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj) { flushFPMsToMPM(PMW); - addModulePass(WebAssemblyLowerEmscriptenEHSjLjPass(), PMW); + addModulePass(WebAssemblyLowerEmscriptenEHSjLjPass(EnableEmEH), PMW); } // Expand indirectbr instructions to switches. diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index cd1ce993a16ed..5894e9b09ffdc 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -359,8 +359,9 @@ class WebAssemblyLowerEmscriptenEHSjLjImpl { public: WebAssemblyLowerEmscriptenEHSjLjImpl( + bool EnableEmEH, std::function<DominatorTree &(Function &F)> GetDominatorTree) - : EnableEmEH(WebAssembly::WasmEnableEmEH), + : EnableEmEH(EnableEmEH || WebAssembly::WasmEnableEmEH), EnableEmSjLj(WebAssembly::WasmEnableEmSjLj), EnableWasmSjLj(WebAssembly::WasmEnableSjLj), GetDominatorTree(GetDominatorTree) { @@ -375,6 +376,8 @@ class WebAssemblyLowerEmscriptenEHSjLjImpl { }; class WebAssemblyLowerEmscriptenEHSjLjLegacy final : public ModulePass { + bool EnableEmEH; + StringRef getPassName() const override { return "WebAssembly Lower Emscripten Exceptions"; } @@ -382,7 +385,8 @@ class WebAssemblyLowerEmscriptenEHSjLjLegacy final : public ModulePass { public: static char ID; - WebAssemblyLowerEmscriptenEHSjLjLegacy() : ModulePass(ID) {} + WebAssemblyLowerEmscriptenEHSjLjLegacy(bool EnableEmEH = false) + : ModulePass(ID), EnableEmEH(EnableEmEH) {} bool runOnModule(Module &M) override; void getAnalysisUsage(AnalysisUsage &AU) const override { @@ -396,8 +400,9 @@ INITIALIZE_PASS(WebAssemblyLowerEmscriptenEHSjLjLegacy, DEBUG_TYPE, "WebAssembly Lower Emscripten Exceptions / Setjmp / Longjmp", false, false) -ModulePass *llvm::createWebAssemblyLowerEmscriptenEHSjLjLegacyPass() { - return new WebAssemblyLowerEmscriptenEHSjLjLegacy(); +ModulePass * +llvm::createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(bool EnableEmEH) { + return new WebAssemblyLowerEmscriptenEHSjLjLegacy(EnableEmEH); } static bool canThrow(const Value *V) { @@ -1871,7 +1876,7 @@ void WebAssemblyLowerEmscriptenEHSjLjImpl::handleLongjmpableCallsForWasmSjLj( bool WebAssemblyLowerEmscriptenEHSjLjLegacy::runOnModule(Module &M) { WebAssemblyLowerEmscriptenEHSjLjImpl Impl( - [&](Function &F) -> DominatorTree & { + EnableEmEH, [&](Function &F) -> DominatorTree & { return getAnalysis<DominatorTreeWrapperPass>(F).getDomTree(); }); return Impl.runOnModule(M); @@ -1881,7 +1886,7 @@ PreservedAnalyses WebAssemblyLowerEmscriptenEHSjLjPass::run(Module &M, ModuleAnalysisManager &MAM) { WebAssemblyLowerEmscriptenEHSjLjImpl Impl( - [&](Function &F) -> DominatorTree & { + EnableEmEH, [&](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 964b67edde3e0..a9a905b6698c0 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -141,18 +141,24 @@ using WebAssembly::WasmEnableSjLj; static void basicCheckForEHAndSjLj(TargetMachine *TM) { + // Emscripten EH is selected by the exception model. WasmEnableEmEH is a + // deprecated cl::opt alias, OR-ed in here until it is removed. + bool EnableEmEH = + TM->Options.ExceptionModel == ExceptionHandling::EmscriptenEH || + WasmEnableEmEH; + // You can't enable two modes of EH at the same time - if (WasmEnableEmEH && WasmEnableEH) + if (EnableEmEH && WasmEnableEH) report_fatal_error( - "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-eh"); + "-exception-model=emscripten not allowed with -wasm-enable-eh"); // You can't enable two modes of SjLj at the same time if (WasmEnableEmSjLj && WasmEnableSjLj) report_fatal_error( "-enable-emscripten-sjlj not allowed with -wasm-enable-sjlj"); // You can't mix Emscripten EH with Wasm SjLj. - if (WasmEnableEmEH && WasmEnableSjLj) + if (EnableEmEH && WasmEnableSjLj) report_fatal_error( - "-enable-emscripten-cxx-exceptions not allowed with -wasm-enable-sjlj"); + "-exception-model=emscripten not allowed with -wasm-enable-sjlj"); if (TM->Options.ExceptionModel == ExceptionHandling::None) { // FIXME: These flags should be removed in favor of directly using the @@ -163,11 +169,10 @@ static void basicCheckForEHAndSjLj(TargetMachine *TM) { // Basic Correctness checking related to -exception-model if (TM->Options.ExceptionModel != ExceptionHandling::None && - TM->Options.ExceptionModel != ExceptionHandling::Wasm) - report_fatal_error("-exception-model should be either 'none' or 'wasm'"); - if (WasmEnableEmEH && TM->Options.ExceptionModel == ExceptionHandling::Wasm) - report_fatal_error("-exception-model=wasm not allowed with " - "-enable-emscripten-cxx-exceptions"); + TM->Options.ExceptionModel != ExceptionHandling::Wasm && + TM->Options.ExceptionModel != ExceptionHandling::EmscriptenEH) + report_fatal_error( + "-exception-model should be either 'none', 'wasm', or 'emscripten'"); if (WasmEnableEH && TM->Options.ExceptionModel != ExceptionHandling::Wasm) report_fatal_error( "-wasm-enable-eh only allowed with -exception-model=wasm"); @@ -337,7 +342,10 @@ void WebAssemblyPassConfig::addIRPasses() { // TargetPassConfig::addPassesToHandleExceptions, but that runs after these IR // passes and Emscripten SjLj handling expects all invokes to be lowered // before. - if (!WasmEnableEmEH && !WasmEnableEH) { + bool EnableEmEH = + TM->Options.ExceptionModel == ExceptionHandling::EmscriptenEH || + WasmEnableEmEH; + if (!EnableEmEH && !WasmEnableEH) { addPass(createLowerInvokePass()); // The lower invoke pass may create unreachable code. Remove it in order not // to process dead blocks in setjmp/longjmp handling. @@ -348,8 +356,8 @@ void WebAssemblyPassConfig::addIRPasses() { // 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 (WasmEnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj) - addPass(createWebAssemblyLowerEmscriptenEHSjLjLegacyPass()); + if (EnableEmEH || WasmEnableEmSjLj || WasmEnableSjLj) + addPass(createWebAssemblyLowerEmscriptenEHSjLjLegacyPass(EnableEmEH)); // Expand indirectbr instructions to switches. addPass(createIndirectBrExpandPass()); diff --git a/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll b/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll index 74d02ddc405d3..010c06a2283d5 100644 --- a/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll +++ b/llvm/test/CodeGen/WebAssembly/eh-option-errors.ll @@ -1,19 +1,16 @@ target triple = "wasm32-unknown-unknown" -; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions -wasm-enable-eh 2>&1 | FileCheck %s --check-prefix=EM_EH_W_WASM_EH -; EM_EH_W_WASM_EH: LLVM ERROR: -enable-emscripten-cxx-exceptions not allowed with -wasm-enable-eh +; RUN: not --crash llc < %s -exception-model=emscripten -wasm-enable-eh 2>&1 | FileCheck %s --check-prefix=EM_EH_W_WASM_EH +; EM_EH_W_WASM_EH: LLVM ERROR: -exception-model=emscripten not allowed with -wasm-enable-eh ; RUN: not --crash llc < %s -enable-emscripten-sjlj -wasm-enable-sjlj 2>&1 | FileCheck %s --check-prefix=EM_SJLJ_W_WASM_SJLJ ; EM_SJLJ_W_WASM_SJLJ: LLVM ERROR: -enable-emscripten-sjlj not allowed with -wasm-enable-sjlj -; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions -wasm-enable-sjlj 2>&1 | FileCheck %s --check-prefix=EM_EH_W_WASM_SJLJ -; EM_EH_W_WASM_SJLJ: LLVM ERROR: -enable-emscripten-cxx-exceptions not allowed with -wasm-enable-sjlj +; RUN: not --crash llc < %s -exception-model=emscripten -wasm-enable-sjlj 2>&1 | FileCheck %s --check-prefix=EM_EH_W_WASM_SJLJ +; EM_EH_W_WASM_SJLJ: LLVM ERROR: -exception-model=emscripten not allowed with -wasm-enable-sjlj ; RUN: not --crash llc < %s -wasm-enable-eh -exception-model=dwarf 2>&1 | FileCheck %s --check-prefix=EH_MODEL_DWARF -; EH_MODEL_DWARF: LLVM ERROR: -exception-model should be either 'none' or 'wasm' - -; RUN: not --crash llc < %s -enable-emscripten-cxx-exceptions -exception-model=wasm 2>&1 | FileCheck %s --check-prefix=EM_EH_W_MODEL_WASM -; EM_EH_W_MODEL_WASM: LLVM ERROR: -exception-model=wasm not allowed with -enable-emscripten-cxx-exceptions +; EH_MODEL_DWARF: LLVM ERROR: -exception-model should be either 'none', 'wasm', or 'emscripten' ; RUN: not --crash llc < %s -exception-model=wasm 2>&1 | FileCheck %s --check-prefix=MODEL_WASM_WO_WASM_EH_SJLJ ; MODEL_WASM_WO_WASM_EH_SJLJ: LLVM ERROR: -exception-model=wasm only allowed with at least one of -wasm-enable-eh or -wasm-enable-sjlj _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
