llvm-project icon indicating copy to clipboard operation
llvm-project copied to clipboard

clang: Forward exception_model flag for bitcode inputs

Open arsenm opened this issue 6 months ago • 2 comments

This will enable removal of a hack from the wasm backend in a future change.

This feels unnecessarily clunky. I would assume something was automatically parsing this and propagating it in the C++ case, but I can't seem to find it. In particular it feels wrong that I need to parse out the individual values, given they are listed in the options.td file. We should also be parsing and forwarding every flag that corresponds to something else in TargetOptions, which requires auditing.

arsenm avatar Jun 30 '25 12:06 arsenm

This stack of pull requests is managed by Graphite. Learn more about stacking.

arsenm avatar Jun 30 '25 12:06 arsenm

@llvm/pr-subscribers-clang @llvm/pr-subscribers-backend-webassembly

@llvm/pr-subscribers-clang-driver

Author: Matt Arsenault (arsenm)

Changes

This will enable removal of a hack from the wasm backend in a future change.

This feels unnecessarily clunky. I would assume something was automatically parsing this and propagating it in the C++ case, but I can't seem to find it. In particular it feels wrong that I need to parse out the individual values, given they are listed in the options.td file. We should also be parsing and forwarding every flag that corresponds to something else in TargetOptions, which requires auditing.


Full diff: https://github.com/llvm/llvm-project/pull/146342.diff

4 Files Affected:

  • (modified) clang/lib/Frontend/CompilerInvocation.cpp (+38)
  • (added) clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll (+16)
  • (added) clang/test/CodeGen/WebAssembly/wasm-invalid-exception-kinds.ll (+8)
  • (added) clang/test/Driver/ir-exception-model.c (+14)
diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp
index f366e90945dac..d8916a6b15f58 100644
--- a/clang/lib/Frontend/CompilerInvocation.cpp
+++ b/clang/lib/Frontend/CompilerInvocation.cpp
@@ -3679,6 +3679,22 @@ static StringRef GetInputKindName(InputKind IK) {
   llvm_unreachable("unknown input language");
 }
 
+static StringRef getExceptionHandlingName(unsigned EHK) {
+  switch (static_cast<LangOptions::ExceptionHandlingKind>(EHK)) {
+  case LangOptions::ExceptionHandlingKind::None:
+  default:
+    return "none";
+  case LangOptions::ExceptionHandlingKind::SjLj:
+    return "sjlj";
+  case LangOptions::ExceptionHandlingKind::DwarfCFI:
+    return "dwarf";
+  case LangOptions::ExceptionHandlingKind::Wasm:
+    return "wasm";
+  }
+
+  llvm_unreachable("covered switch");
+}
+
 void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
                                               ArgumentConsumer Consumer,
                                               const llvm::Triple &T,
@@ -3694,6 +3710,10 @@ void CompilerInvocationBase::GenerateLangArgs(const LangOptions &Opts,
       GenerateArg(Consumer, OPT_pic_is_pie);
     for (StringRef Sanitizer : serializeSanitizerKinds(Opts.Sanitize))
       GenerateArg(Consumer, OPT_fsanitize_EQ, Sanitizer);
+    if (Opts.ExceptionHandling) {
+      GenerateArg(Consumer, OPT_exception_model,
+                  getExceptionHandlingName(Opts.ExceptionHandling));
+    }
 
     return;
   }
@@ -4002,6 +4022,24 @@ bool CompilerInvocation::ParseLangArgs(LangOptions &Opts, ArgList &Args,
     parseSanitizerKinds("-fsanitize=", Args.getAllArgValues(OPT_fsanitize_EQ),
                         Diags, Opts.Sanitize);
 
+    if (const Arg *A = Args.getLastArg(options::OPT_exception_model)) {
+      std::optional<LangOptions::ExceptionHandlingKind> EMValue =
+          llvm::StringSwitch<std::optional<LangOptions::ExceptionHandlingKind>>(
+              A->getValue())
+              .Case("dwarf", LangOptions::ExceptionHandlingKind::DwarfCFI)
+              .Case("sjlj", LangOptions::ExceptionHandlingKind::SjLj)
+              .Case("wineh", LangOptions::ExceptionHandlingKind::WinEH)
+              .Case("wasm", LangOptions::ExceptionHandlingKind::Wasm)
+              .Case("none", LangOptions::ExceptionHandlingKind::None)
+              .Default(std::nullopt);
+      if (EMValue) {
+        Opts.ExceptionHandling = static_cast<unsigned>(*EMValue);
+      } else {
+        Diags.Report(diag::err_drv_invalid_value)
+            << A->getAsString(Args) << A->getValue();
+      }
+    }
+
     return Diags.getNumErrors() == NumErrorsBefore;
   }
 
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
new file mode 100644
index 0000000000000..4a7eeece58717
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-exception-model-flag-parse-ir-input.ll
@@ -0,0 +1,16 @@
+; REQUIRES: webassembly-registered-target
+
+; Check all the options parse
+; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=none %s | FileCheck %s
+; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=wasm %s | FileCheck %s
+; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=dwarf %s | FileCheck %s
+; RUN: %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=sjlj %s | FileCheck %s
+
+; RUN: not %clang_cc1 -triple wasm32 -o - -emit-llvm -exception-model=invalid %s 2>&1 | FileCheck -check-prefix=ERR %s
+
+; CHECK-LABEL: define void @test(
+
+; ERR: error: invalid value 'invalid' in '-exception-model=invalid'
+define void @test() {
+  ret void
+}
diff --git a/clang/test/CodeGen/WebAssembly/wasm-invalid-exception-kinds.ll b/clang/test/CodeGen/WebAssembly/wasm-invalid-exception-kinds.ll
new file mode 100644
index 0000000000000..27fb696c92499
--- /dev/null
+++ b/clang/test/CodeGen/WebAssembly/wasm-invalid-exception-kinds.ll
@@ -0,0 +1,8 @@
+; RUN: not %clang_cc1 -triple wasm32 -exception-model=arst -S %s 2>&1 | FileCheck -check-prefix=INVALID-VALUE %s
+
+; Make sure invalid values are rejected for -exception-model when the
+; input is IR.
+
+; INVALID-VALUE: error: invalid value 'arst' in '-exception-model=arst'
+
+target triple = "wasm32"
diff --git a/clang/test/Driver/ir-exception-model.c b/clang/test/Driver/ir-exception-model.c
new file mode 100644
index 0000000000000..9e8f998de0d6b
--- /dev/null
+++ b/clang/test/Driver/ir-exception-model.c
@@ -0,0 +1,14 @@
+// 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-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
+// RUN: %clang -### -target wasm32-unknown-unknown -Xclang -exception-model=arst -c -S -o - %S/Inputs/file.ll 2>&1 | FileCheck -check-prefix=INVALID %s
+
+// Check that -fwasm-exceptions propagates -exception-model to cc1
+
+// CHECK: "-exception-model=wasm"
+// DWARF: "-exception-model=dwarf"
+// SJLJ: "-exception-model=sjlj"
+// WINEH: "-exception-model=wineh"
+// INVALID: "-exception-model=arst"

llvmbot avatar Jun 30 '25 12:06 llvmbot

(FWIW I have the alternative fix here: https://github.com/jansvoboda11/llvm-project/commit/45f21d8adec34fdc13e86d529a133189ec1b1d15; happy to create a PR after yours lands.)

jansvoboda11 avatar Jun 30 '25 16:06 jansvoboda11

Merge activity

  • Jul 2, 12:38 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Jul 2, 12:39 AM UTC: @arsenm merged this pull request with Graphite.

arsenm avatar Jul 02 '25 00:07 arsenm

LLVM Buildbot has detected a new failure on builder flang-arm64-windows-msvc running on linaro-armv8-windows-msvc-01 while building clang at step 7 "test-build-unified-tree-check-flang".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/207/builds/3225

Here is the relevant piece of the build log for the reference
Step 7 (test-build-unified-tree-check-flang) failure: test (failure)
******************** TEST 'Flang :: Parser/OpenMP/declare-reduction-operator.f90' FAILED ********************
Exit Code: 2

Command Output (stdout):
--
# RUN: at line 1
c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe -fc1 -fdebug-unparse -fopenmp C:\Users\tcwg\llvm-worker\flang-arm64-windows-msvc\llvm-project\flang\test\Parser\OpenMP\declare-reduction-operator.f90 | c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\filecheck.exe --ignore-case C:\Users\tcwg\llvm-worker\flang-arm64-windows-msvc\llvm-project\flang\test\Parser\OpenMP\declare-reduction-operator.f90
# executed command: 'c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe' -fc1 -fdebug-unparse -fopenmp 'C:\Users\tcwg\llvm-worker\flang-arm64-windows-msvc\llvm-project\flang\test\Parser\OpenMP\declare-reduction-operator.f90'
# .---command stderr------------
# | PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
# | Stack dump:
# | 0.	Program arguments: c:\\users\\tcwg\\llvm-worker\\flang-arm64-windows-msvc\\build\\bin\\flang.exe -fc1 -fdebug-unparse -fopenmp C:\\Users\\tcwg\\llvm-worker\\flang-arm64-windows-msvc\\llvm-project\\flang\\test\\Parser\\OpenMP\\declare-reduction-operator.f90
# | Exception Code: 0xC0000005
# |  #0 0x00007ff752361c64 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x1a91c64)
# |  #1 0x00007ff75235f94c (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x1a8f94c)
# |  #2 0x00007ff75235d7e0 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x1a8d7e0)
# |  #3 0x00007ff7523634f4 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x1a934f4)
# |  #4 0x00007ff75235d348 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x1a8d348)
# |  #5 0x00007ff75117c068 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x8ac068)
# |  #6 0x00007ff7511c54c8 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x8f54c8)
# |  #7 0x00007ff75126e1d0 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x99e1d0)
# |  #8 0x00007ff7511c4904 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x8f4904)
# |  #9 0x00007ff750968a94 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x98a94)
# | #10 0x00007ff75097ea5c (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0xaea5c)
# | #11 0x00007ff7508d34e8 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x34e8)
# | #12 0x00007ff7508d20a4 (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x20a4)
# | #13 0x00007ff7555885c8 mlir::detail::FallbackTypeIDResolver::registerImplicitTypeID(class llvm::StringRef) (c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\flang.exe+0x4cb85c8)
# | #14 0x5079fff755588664 
# `-----------------------------
# error: command failed with exit status: 0xc0000005
# executed command: 'c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\filecheck.exe' --ignore-case 'C:\Users\tcwg\llvm-worker\flang-arm64-windows-msvc\llvm-project\flang\test\Parser\OpenMP\declare-reduction-operator.f90'
# .---command stderr------------
# | FileCheck error: '<stdin>' is empty.
# | FileCheck command line:  c:\users\tcwg\llvm-worker\flang-arm64-windows-msvc\build\bin\filecheck.exe --ignore-case C:\Users\tcwg\llvm-worker\flang-arm64-windows-msvc\llvm-project\flang\test\Parser\OpenMP\declare-reduction-operator.f90
# `-----------------------------
# error: command failed with exit status: 2

--

********************


llvm-ci avatar Jul 02 '25 00:07 llvm-ci

LLVM Buildbot has detected a new failure on builder llvm-clang-x86_64-darwin running on doug-worker-3 while building clang at step 6 "test-build-unified-tree-check-all".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/23/builds/11788

Here is the relevant piece of the build log for the reference
Step 6 (test-build-unified-tree-check-all) failure: test (failure)
******************** TEST 'lit :: max-time.py' FAILED ********************
Exit Code: 1

Command Output (stdout):
--
# RUN: at line 5
env -u FILECHECK_OPTS "/Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/bin/python3.9" /Users/buildbot/buildbot-root/x86_64-darwin/llvm-project/llvm/utils/lit/lit.py -j1 --order=lexical Inputs/max-time --max-time=5 2>&1  |  FileCheck /Volumes/RAMDisk/buildbot-root/x86_64-darwin/build/utils/lit/tests/max-time.py
# executed command: env -u FILECHECK_OPTS /Library/Developer/CommandLineTools/Library/Frameworks/Python3.framework/Versions/3.9/bin/python3.9 /Users/buildbot/buildbot-root/x86_64-darwin/llvm-project/llvm/utils/lit/lit.py -j1 --order=lexical Inputs/max-time --max-time=5
# note: command had no output on stdout or stderr
# executed command: FileCheck /Volumes/RAMDisk/buildbot-root/x86_64-darwin/build/utils/lit/tests/max-time.py
# .---command stderr------------
# | /Volumes/RAMDisk/buildbot-root/x86_64-darwin/build/utils/lit/tests/max-time.py:8:10: error: CHECK: expected string not found in input
# | # CHECK: Skipped: 1
# |          ^
# | <stdin>:2:51: note: scanning from here
# | warning: reached timeout, skipping remaining tests
# |                                                   ^
# | <stdin>:7:2: note: possible intended match here
# |  Skipped: 2 (100.00%)
# |  ^
# | 
# | Input file: <stdin>
# | Check file: /Volumes/RAMDisk/buildbot-root/x86_64-darwin/build/utils/lit/tests/max-time.py
# | 
# | -dump-input=help explains the following input dump.
# | 
# | Input was:
# | <<<<<<
# |            1: -- Testing: 2 tests, 1 workers -- 
# |            2: warning: reached timeout, skipping remaining tests 
# | check:8'0                                                       X error: no match found
# |            3:  
# | check:8'0     ~
# |            4: Testing Time: 8.07s 
# | check:8'0     ~~~~~~~~~~~~~~~~~~~~
# |            5:  
# | check:8'0     ~
# |            6: Total Discovered Tests: 2 
# | check:8'0     ~~~~~~~~~~~~~~~~~~~~~~~~~~
# |            7:  Skipped: 2 (100.00%) 
# | check:8'0     ~~~~~~~~~~~~~~~~~~~~~~
# | check:8'1      ?                     possible intended match
# | >>>>>>
# `-----------------------------
# error: command failed with exit status: 1

--

********************


llvm-ci avatar Jul 02 '25 01:07 llvm-ci

This broke building C++ modules for mingw targets. Repro:

empty.cppm:

export module empty;
$ clang -target x86_64-windows-gnu -x c++-module empty.cppm -c -o empty.cppm.obj -std=gnu++23
error: invalid value 'seh' in '-exception-model=seh'

mstorsjo avatar Jul 02 '25 06:07 mstorsjo

This broke building C++ modules for mingw targets. Repro:

empty.cppm:

export module empty;
$ clang -target x86_64-windows-gnu -x c++-module empty.cppm -c -o empty.cppm.obj -std=gnu++23
error: invalid value 'seh' in '-exception-model=seh'

https://github.com/llvm/llvm-project/pull/146643

I for some reason have to repeat the reproducer exactly this way; if I just run cc1 with the same triple and flags it seems to work?

arsenm avatar Jul 02 '25 07:07 arsenm

This broke building C++ modules for mingw targets. Repro: empty.cppm:

export module empty;
$ clang -target x86_64-windows-gnu -x c++-module empty.cppm -c -o empty.cppm.obj -std=gnu++23
error: invalid value 'seh' in '-exception-model=seh'

#146643

I for some reason have to repeat the reproducer exactly this way; if I just run cc1 with the same triple and flags it seems to work?

Yeah, I have no idea what's being passed through at what level here, but the fix looks reasonable to me. Thanks!

mstorsjo avatar Jul 02 '25 09:07 mstorsjo