This is an archive of the discontinued LLVM Phabricator instance.

[FLANG] Fix MSVC + clang-cl build
ClosedPublic

Authored by omjavaid on Nov 15 2022, 3:31 AM.

Details

Summary

Flang build on windows with MSVC environment and clang-cl compiler
requires clang_rt.builtin.${target} library. This patch allows us to
locate and include this link library. This is mostly needed for flang
runtime and associated unittests as it requires the uint128 division
builtin function __udivti3.

Diff Detail

Event Timeline

omjavaid created this revision.Nov 15 2022, 3:31 AM
Herald added a project: Restricted Project. · View Herald TranscriptNov 15 2022, 3:31 AM
omjavaid requested review of this revision.Nov 15 2022, 3:31 AM

Flang build on windows with MSVC environment and clang-cl compiler requires clang_rt.builtin.${target} library.

Can you elaborate on which parts ends up requiring it? The main case I know of is for 128 bit integer support routines.

Clang implicitly uses this library while calling lld-link via clang driver

This doesn't match my experience - the builtin library isn't included automatically anywhere. If you do link with -rtlib=compiler-rt, then yes, it will try to link it in though.

Flang build on windows with MSVC environment and clang-cl compiler requires clang_rt.builtin.${target} library.

Can you elaborate on which parts ends up requiring it? The main case I know of is for 128 bit integer support routines.

Clang implicitly uses this library while calling lld-link via clang driver

This doesn't match my experience - the builtin library isn't included automatically anywhere. If you do link with -rtlib=compiler-rt, then yes, it will try to link it in though.

clang-cl implicitly uses clang_rt.builtins* but lld-link fails to include it. This fails a couple of flang unit tests and linking of bbc.exe with following error:

lld-link: error: undefined symbol: __udivti3

Building on Surface X Pro LLVM 15.0.1 release. Environtment set via "c:\Program Files\Microsoft Visual Studio\2022\Community\VC\Auxiliary\Build\vcvarsamd64_arm64.bat"

clang-cl implicitly uses clang_rt.builtins*

Can you give an example of a concrete, minimal, clang-cl command line, where you run it with the -v option, where you show where clang-cl actually implicitly links in clang_rt.builtins, as you claim it does in some cases? Because in my experience, it never does that implicitly.

(This is of course not entirely on point for the patch itself, but I would like that the patch background represents facts precisely.)

lld-link: error: undefined symbol: __udivti3

Right, that's the uint128 division function. It would be valuable to include this information in the commit description.

Note that there have been many discussions about how to fix this issue properly in one way or another - see most recently https://reviews.llvm.org/D134912#3828421. For now, the conclusion within e.g. libcxx is to just avoid int128 code until this is fixed properly in clang-cl.

How does flang work when built with MSVC proper, which doesn't have int128 as a built-in type at all?

flang/CMakeLists.txt
44

Won't this try to find and use the compiler-rt library even in a full pure-MSVC build (i.e. no clang-cl)?

clang-cl implicitly uses clang_rt.builtins*

Can you give an example of a concrete, minimal, clang-cl command line, where you run it with the -v option, where you show where clang-cl actually implicitly links in clang_rt.builtins, as you claim it does in some cases? Because in my experience, it never does that implicitly.

(This is of course not entirely on point for the patch itself, but I would like that the patch background represents facts precisely.)

So I went ahead and tried a simple int128 div and compiled it with clang-cl on Surface X. As you suggested clang does not implicitly link rt library. I actually just read docs that target specific rtlib is implicitly linked
https://github.com/llvm/llvm-project/blob/main/clang/docs/Toolchain.rst

lld-link: error: undefined symbol: __udivti3

Right, that's the uint128 division function. It would be valuable to include this information in the commit description.

Ack

Note that there have been many discussions about how to fix this issue properly in one way or another - see most recently https://reviews.llvm.org/D134912#3828421. For now, the conclusion within e.g. libcxx is to just avoid int128 code until this is fixed properly in clang-cl.

How does flang work when built with MSVC proper, which doesn't have int128 as a built-in type at all?

We have not been using cl as they are available as emulated tools on WoA while clang-cl is native and faster. Although I tried cl just today but was not able to get the build working facing errors which are unrelated to this particular issue.

So I went ahead and tried a simple int128 div and compiled it with clang-cl on Surface X. As you suggested clang does not implicitly link rt library. I actually just read docs that target specific rtlib is implicitly linked
https://github.com/llvm/llvm-project/blob/main/clang/docs/Toolchain.rst

Ok, I see! Yes, that document might not take all clang-cl considerations into account.

For most clang targets, you really do need the builtins (either in the form of libgcc, or compiler-rt builtins) everywhere. But for MSVC targets, it's usually not needed and thus not linked in implicitly, since everything you normally need is in the MSVC static libraries. But since MSVC doesn't support int128 (and Clang lowers it to a libgcc named helper function) they obviously don't provide that one. (There has been discussions about whether they could start including these helpe functions somewhere, to help Clang cases, but it hasn't materialized yet at least.)

Overall, this is a Clang-cl toolchain issue - known for some time already; since this is a builtin type, the helpers for it should really be handled automatically. But since most use in MSVC style settings invoke the linker directly instead of via the compiler driver, the fix isn't entirely trivial. https://reviews.llvm.org/D134912#3828421 is the latest word on what would be a good way forward to handle it (from the toolchain point of view).

Also from a toolchain point of view, this is a bit tricky, since you normally can cross compile with clang-cl for any supported architecture as long as you've got MSVC and WinSDK, but when clang starts requiring the builtins, they you also need to have those built and available, for all architectures that you want to compile for. MSVC itself actually does ship with these files for some architectures (x86 and x64), but not for arm64 (or arm). So I think we should request that MSVC should start bundling clang_rt.*.lib for arm64 too, at least as many parts of compiler-rt as works on arm64 (IIRC the sanitizers don't support it yet), so that Clang could start automatically linking against it when needed (without needing to ship it along with Clang specifically for arm64 only).

How does flang work when built with MSVC proper, which doesn't have int128 as a built-in type at all?

We have not been using cl as they are available as emulated tools on WoA while clang-cl is native and faster. Although I tried cl just today but was not able to get the build working facing errors which are unrelated to this particular issue.

Ok, I see. (BTW since some months, MSVC should be available as properly native arm64 apps now too. But I don't expect you to try to set it up right now, I'm sure there's lots of things one would run into trying to build flang with it.)

I wonder why this isn't an issue with clang-cl builds on x86_64 too - the same issue should appear there too, if it uses int128 in the same way.

If it is possible to just decide not to use int128 for this build configuration, that's clearly the simplest solution. But if that's not possible, I guess something like this has to be done.

flang/CMakeLists.txt
44

When reading the cmake code more, yes I think this should have an additional check like if (MSVC AND CMAKE_CXX_COMPILER_ID MATCHES Clang).

omjavaid updated this revision to Diff 476384.Nov 18 2022, 1:52 AM
omjavaid edited the summary of this revision. (Show Details)

Updated patch to include check for MSVC + Clang.
Also updated commit log description with information on uint128 division builtin function dependency.

Herald added a project: Restricted Project. · View Herald TranscriptNov 18 2022, 1:52 AM
Herald added a reviewer: Restricted Project. · View Herald Transcript

Updated patch to include check for MSVC + Clang.
Also updated commit log description with information on uint128 division builtin function dependency.

Thanks!

It seems like you got some unrelated lld changes included in the diff though...

I think this probably looks tolerable now, but it would be very interesting to know if the use of uint128 is isolated somehow, so that there's some conditional that can be set to opt out from it - I would expect this to exist somewhere, unless Flang doesn't support being built by pure MSVC at all?

So I went ahead and tried a simple int128 div and compiled it with clang-cl on Surface X. As you suggested clang does not implicitly link rt library. I actually just read docs that target specific rtlib is implicitly linked
https://github.com/llvm/llvm-project/blob/main/clang/docs/Toolchain.rst

Ok, I see! Yes, that document might not take all clang-cl considerations into account.

For most clang targets, you really do need the builtins (either in the form of libgcc, or compiler-rt builtins) everywhere. But for MSVC targets, it's usually not needed and thus not linked in implicitly, since everything you normally need is in the MSVC static libraries. But since MSVC doesn't support int128 (and Clang lowers it to a libgcc named helper function) they obviously don't provide that one. (There has been discussions about whether they could start including these helpe functions somewhere, to help Clang cases, but it hasn't materialized yet at least.)

Overall, this is a Clang-cl toolchain issue - known for some time already; since this is a builtin type, the helpers for it should really be handled automatically. But since most use in MSVC style settings invoke the linker directly instead of via the compiler driver, the fix isn't entirely trivial. https://reviews.llvm.org/D134912#3828421 is the latest word on what would be a good way forward to handle it (from the toolchain point of view).

Also from a toolchain point of view, this is a bit tricky, since you normally can cross compile with clang-cl for any supported architecture as long as you've got MSVC and WinSDK, but when clang starts requiring the builtins, they you also need to have those built and available, for all architectures that you want to compile for. MSVC itself actually does ship with these files for some architectures (x86 and x64), but not for arm64 (or arm). So I think we should request that MSVC should start bundling clang_rt.*.lib for arm64 too, at least as many parts of compiler-rt as works on arm64 (IIRC the sanitizers don't support it yet), so that Clang could start automatically linking against it when needed (without needing to ship it along with Clang specifically for arm64 only).

How does flang work when built with MSVC proper, which doesn't have int128 as a built-in type at all?

We have not been using cl as they are available as emulated tools on WoA while clang-cl is native and faster. Although I tried cl just today but was not able to get the build working facing errors which are unrelated to this particular issue.

Ok, I see. (BTW since some months, MSVC should be available as properly native arm64 apps now too. But I don't expect you to try to set it up right now, I'm sure there's lots of things one would run into trying to build flang with it.)

I wonder why this isn't an issue with clang-cl builds on x86_64 too - the same issue should appear there too, if it uses int128 in the same way.

This issue appear when compiling flang project and it also appears on x86_64 when a combination of MSVC + Clang-cl is used. I have not tried a MSVC + cl build.

If it is possible to just decide not to use int128 for this build configuration, that's clearly the simplest solution. But if that's not possible, I guess something like this has to be done.

I guess Fortran extensively uses 128bit types and 128 bit division may not be avoidable in this case.

omjavaid updated this revision to Diff 476394.Nov 18 2022, 2:34 AM

Corrects the diff error from last patch.

@mstorsjo Is it good to land?

No objections from me on this patch, but I’m not really authoritative to approve things under flang I think.

DavidTruby accepted this revision.Nov 22 2022, 6:38 AM

On MSVC flang uses a completely custom int128 implementation to get around it lacking int128 support, see: flang/include/flang/Common/uint128.h
I think with clang-cl on Windows we're better off using the builtins and using compiler-rt than using the custom implementation, so fixing this looks sensible.

LGTM

This revision is now accepted and ready to land.Nov 22 2022, 6:38 AM
This revision was automatically updated to reflect the committed changes.
Herald added a project: Restricted Project. · View Herald TranscriptNov 30 2022, 3:29 AM