LLVM doesn’t use exceptions by our coding standard, and on Unix systems, we build LLVM and clang with
-fno-exceptions. But on windows, we pass the flags
/EHs-c-, which enables some exceptions.
I did some local tests and removed the
EH flags from the windows build when building with
clang-cl. We save around 11% of the binary size (clang-cl) and around 2% in performance compiling
Is there a reason that the default setting would be
/EHs-c- that I am missing?
There are also no ways to disable these flags without editing the CMake source, at minimum I think we should include a flag to disable this: llvm-project/AddLLVM.cmake at 2a16e1ff7d2735001dbe40e607823857f4bedd0e · llvm/llvm-project · GitHub
Any ideas @mstorsjo @hansw2000 @zero9178 ?
I believe the intention when passing
/EHs-c- was to disable exceptions. Looks like it was added in a679f43f4e330ac313cb1d1b5dee4c98f94da822.
I do think we use SEH in the CrashRecoveryContext on Windows (and maybe elsewhere too).
I’m surprised removing that flag reduces code size so much though. Maybe clang-cl is doing something strange? Do you see the same size reduction when building with MSVC.
Huh, that’s funny - I tried the flags with MSVC 2022, and the results were a bit surprising: the binary ended up being the same size with and without the flag.
But they are much bigger than the clang-produced binary (almost 40% bigger), so maybe whatever clang-cl is doing is already baked in?
When you say we use SEH in the
CrashRecoverContext, do you mean that we will not get correct crash reporting if SEH is disabled?
Btw - I get the same size-reduction if I pass
-fnew-infallible this is how my investigation started, I wanted to see if it made any difference, and it reduced the binary size by 11%, when my coworker said that
/EHs-c- is still generating exception data, our production game-engine omit the
/EH flags entirely.
IIRC there’s two different concepts involved here - whether SEH unwind info is generated for all code (which is more or less mandatory), and whether code is generated for catching/handling C++ exceptions. AFAIK these options disable the C++ bits, but SEH unwind info still is generated, and I would expect that to be enough for the crash reporting.
clang, it’s possible to disable the generation of the unwind info with
-fno-unwind-tables -fno-asynchronous-unwind-tables (and that saves a fair bit of file size too), but that breaks backtraces in lots of places, and probably breaks the crash reports.
Reading Microsoft’s documentation:
The compiler always generates code that supports asynchronous structured exception handling (SEH). By default (that is, if no /EHsc, /EHs, or /EHa option is specified.
So it seems the correct behavior is not to pass any of the
/EH flags when building LLVM with clang-cl.
I looked at Chromium, which also doesn’t use exceptions, and it seems we also don’t pass any ‘/EH’ flag. So maybe that’s the right thing.
But I’m still confused about what’s going on here. It seems not passing
/EHs-c-'to clang-cl made a difference in your builds, whereas
parseClangCLEHFlags() says “The default is /EHs-c-”.
And it sounds like MSVC does something slightly different?
I just looked at
parseClangCLEHFlags() and it will set
/Ehs-c- if you also pass
/GX otherwise both are set to false.
if (EHArgs.empty() &&
The comment should probably reflect this.
It looks to me like it will set
/EHsc if you pass
Ah, you are right. My bad.
Then I agree - it’s a little of a mystery here.
I checked the driver invocation with
/clang:-v and can’t see any difference in the invocation between no
I’ll dig further.