[RFC] Use LLVM_ENABLE_RUNTIMES for Flang's runtime

Currently, Flang compiles its runtime (libFortranRuntime.a) within the same CMake builddir as Flang itself. As a consequence, the runtime will only be built for the same target as flang-new is built for.
As a workaround, one can build Flang again for any intended target triple and use only the runtime library out of it. The Flang runtime can also be built as a standalone project so one would not need to build the entirety of LLVM+Flang again.

LLVM’s other runtime libraries use the LLVM_ENABLE_RUNTIMES and LLVM_RUNTIME_TARGETS CMake variables as a more straightforward solution. It also uses the frehsly built Clang itself to build the runtime libraries.
I would like to make FortranRuntime use the same mechanism.

Since #95388, FortranRuntime uses Flang itself to build some of its parts, making things a bit more complicated.
For instance, the standalone build of FortranRuntime does not have access to flang-new and will just leave that part of it out of the runtime (#99737 (comment)).
Also, when building Flang itself as a cross-compiler, the LLVM build system confuses the triples of host, target (of the host compiler), and the default target (of Clang/Flang).

There are some design decisions to make which this RFC is for.

  1. The name of the top-level directory.

    The straightforward name would be “FortranRuntime”, the current name of the library, but it stands out among the other projects due to the use of PascalCase where others use kebab-case.

  2. Subfolder structure

    Non-runtime projects are consistently using include// for public headers and lib/ for translation units, but there is much less agreement in runtime projects.

    • compiler-rt: include/<component> (no <projectname>) and lib/<component>
    • libc: src/<component> for headers and translation units, many more non-consistent subdirs
    • libcxx,libcxxabi: include/ for std:: headers, src/ for translation units, and lib/ for ABI export lists
    • libunwind: include/ for headers, src/ for translation units
    • offload: include/ for headers, src/ and plugins-nextgen/ for translation units, DeviceRTL/include and DeviceRTL/lib for offload-target code
    • openmp: runtime/src for translation units, runtime/src/include for headers
    • pstl: include/ for headers

    I propose to use lib/<component> (with <component> = Runtime, Common, and Decimal as currently structured) for translation units (C++ and Fortran), module/ for the module files (currently in flang/module), and potentially include/flang/ for header files shared with the Flang compiler (if needed, see below)

  3. Shared code

    The Flang compiler and the FortranRuntime library share some code, but the LLVM_ENABLE_RUNTIMES mechanism requires them in separate directories. This raises the question where these belong to. Generally, there are 4 options:
    Copy the files, FortranRuntime references then in the flang/ directory, Flang references them in the FortranRuntime/ directory, or they are moved to a common location such as LLVMFrontend. Unless there are only headers, one cannot reuse the Flang-compiler version for the FlangRuntime library since they may not even share the same target triple.

  1. libDecimal (library for converting between floats and strings)
  2. include/flang/Runtime/freestanding-tools.h, c-or-cpp.h (used by libDecimal, one FortranRuntime translation unit is C)
  3. include/flang/Runtime/magic-numbers.h (runtime-ABI definition)
  4. include/flang/Common/variant.h, optional.h, reference-wrapper.h (According to its comments, required for using the FortranRuntime within CUDA. optional.h was copied over from the standalone version from compiler-rt, reference-wrapper.h from libcudacxx)
  5. include/flang/Common/api-attrs.h (Introspection macros like LLVM's compiler.h for compiling the runtime for CUDA)
  6. include/flang/Common/bit-population-count.h, constexpr-bitset.h, leading-zero-bit-count.h, fast-int-set.h (bit-manipulation tools)
  7. include/flang/Common/enum-class.h, enum-set.h, idioms.h, restorer.h, visit.h (General-purpose code pattern utilities)
  8. include/flang/Common/real.h (Characteristics of floating-point formats, like number of bits in mantissa)
  9. include/flang/Common/uint128.h (Implements 128-bit integers for compilers that do not implement (u)int128_t natively)
  10. include/flang/Common/float128.h (Introspection header for quad-precision support)
  11. include/flang/Common/format.h (format-string validator)
  12. include/flang/Common/Fortran.h (Fortran language concepts, mostly enums)

Except libDecimal and Fortran.h, all sources are header-only. FortranRuntime doesn’t seem to use the functions from Fortran.h that require the translation unit.
Some like b. or e. are only really used by the runtime if it wasn’t for libDecimal which is used by both.

For Clang’s runtime libraries, I don’t think there is any shared code between compiler and runtime. For instance, libc has its own minimal version of C++ headers so it can make use of C++ idioms. OpenMP has its own definitions in the runtime and compiler.

In a first iteration, I would just copy the files in question, it may turn out that there may be even less overlap of actual definitions.

  1. LLVM_ENABLE_PROJECTS and standalone builds

    Currently, FlangRuntime can be built as standalone (using cmake -S llvm-project/flang/runtime), but AFAIK the LLVM_ENABLE_RUNTIMES projects generally do not support this (I think OpenMP does, if it did not fall out of maintanance). Is it worth supporting it? Similarly, openmp can be specified in LLVM_ENABLE_PROJECTS, which yields an in-tree build like FortranRuntime does now.

1 Like

Thank you for the thorough description!

I am not against supporting it with LLVM_ENABLE_RUNTIMES, but what are the benefits comparing to an out-of-tree build that can be done for any target right now, and it can also use the just built clang/flang?

Duplicating the header files does not seem right. I suppose the runtime files can use the header files installed with the just built Flang (given that all the required files are installed - not sure if it is true, and whether their installation can conflict with anything).

Is including the header files from the Flang tree an acceptable approach under LLVM_ENABLE_RUNTIMES mode? I am not sure about this.

Trying a tl;dr version of the OP:

  1. cmake -B builddir -DLLVM_ENABLE_RUNTIMES="FortranRuntime;libcxx;openmp;..." -DLLVM_RUNTIME_TARGETS="x86_64-unknown-linux-gnu;aarch64-none-elf" && cd builddir && ninja install

    is a more straightforward than

    $ cmake -B builddir ... && ninja
    $ cmake -B x86-builddir -DCMAKE_C_COMPILER=builddir/bin/clang -DCMAKE_CXX_COMPILER=... -DCMAKE_FORTRAN_COMPILER=... -DCMAKE_C_COMPILER_TARGET=x86_64-unknown-linux-gnu -DCMAKE_CXX_COMPILER_TARGET=...
    $ cmake -B aarch64-builddir -DCMAKE_C_COMPILER=builddir/bin/clang -DCMAKE_CXX_COMPILER=... -DCMAKE_FORTRAN_COMPILER=... -DCMAKE_C_COMPILER_TARGET=aarch64-none-elf -DCMAKE_CXX_COMPILER_TARGET=...
    $ cp x86-builddir/lib/libFortranRuntime.a builddir/lib/x86_64-linux-gnu/libFortranRuntime.a
    $ cp aarch64-builddir/lib/libFortranRuntime.a builddir/lib/aarch64-none-elf/libFortranRuntime.a
    repeat for every runtime library

    There is a reason someone invented LLVM_ENABLE_RUNTIMES.

  2. The FortranRuntime built as a standalone/out-of-source build is currently built without iso_fortran_env.f90, hence broken. See comment.

  3. As official LLVM project, Flang is expected to support LLVM facilities.

I mentioned this as the first iteration. I could not find a precedence where a runtime library project accesses source files of other projects, which does not automatically mean that it is unacceptable. But a decision would have to be made where those sources are at home. That’s what this RFC is for.

On the other side, it also feels weird that the flang compiler (indirectly) depends on files such as c-or-cpp.h (the only C translation unit is from FortranRuntime) and CUDA-compatibility headers.

Generally in favor, it’s always possible to make building possible in multiple configurations. I.e. projects builds work if you have a pre-built compatible clang, otherwise use runtimes.

I remember a long time ago there was a build of the Fortran runtime for the GPU (was it ⚙ D151173 [RFC][flang] Experimental device build of Flang runtime. ?). I think that this could also be pushed into LLVM_RUNTIME_TARGETS and RUNTIMES_<target>_LLVM_ENABLE_RUNTIMES=flang. This is how I handle, libc, libc++, libc++abi, and compiler-rt now and I think it’s more sound than using CUDA and hacking in non-standard compilations.

Thanks for the example #1, @Meinersbur! Yes, the LLVM_ENABLE_RUNTIMES build flow does look more convenient. Regarding the history, I do not know if LLVM_ENABLE_RUNTIMES was invented just for this convenience, but it might be just enough to try to adjust Fortran runtime to work in this mode.

Regarding #2, yes, I am aware of this problem - this is why I put that comment into Michael’s PR. While it is a problem, I do not think it justifies LLVM_ENABLE_RUNTIMES support. The suggested solution for this problem was to build the iso_fortran_env_impl.f90 module as part of the FortranRuntime target, and link/archive the resulting object file into FortranRuntime library. This would resolve the incompleteness of the out-of-tree build of FortranRuntime.

iso_fortran_env_impl.mod is a prerequisite of iso_fortran_env.mod, which is part of the “flang-new” build, so the source file iso_fortran_env_impl.f90 would have to be built and its artifacts would have to be reused for FortranRuntime in the in-tree build; in the out-of-tree build, the soruce file would have to be made available to FortranRuntime target to build it for the particular target. So it is yet another example of a file “shared” between the Fortran compiler and runtime projects. I suppose all the intrinsic Fortran modules can be made a part of FortranRuntime or isolated into their own “runtime” project. We will need to make sure that this works well with Flang LIT tests that require the modules to be built.

To summarize, this problem needs to be resolved, but it seems unrelated to LLVM_ENABLE_RUNTIMES topic.

Regarding #3, I am on board. At the same time, we should not complicate the development of Flang and the runtimes chaising this goal. Maybe I was confused by your comment in the initial message where you said In a first iteration, I would just copy the files in question. I thought that was the actual proposal. Sorry if I misunderstood it. Duplicating the files really does not sound right to me. It will be more error prone if we have to do synchronized changes here and there.

To me it would be best to leave the files where they are, and maybe try to “share” them between Flang and runtimes using CMake interface libraries. I cannot anticipate all the problems this may have, but it seems to be a working mechanism (e.g. FortranFloat128Math may be an interface library that provides the source files to FortranRuntime).

On the other side, it also feels weird that the flang compiler (indirectly) depends on files such as c-or-cpp.h (the only C translation unit is from FortranRuntime) and CUDA-compatibility headers.

I would like to keep the ability to build FortranRuntime using NVCC. This is just another target compiler, and it feels totally okay to me that FortranRuntime can be built for CUDA target. It does not prevent building FortranRuntime as OpenMP target library with any compiler that supports it.

One other thing about FortranDecimal: please note that this library is not only distributed as a target library, but it is also built and linked to Flang compiler itself, which uses it for the compilation time folding. This does not seem to play well with LLVM_ENABLE_RUNTIMES model, but I do not know for sure.

Most of the issues here look like the issues discussed in the previous thread ([RFC] Support CMake option to control link type built for Flang runtime libraries and ⚙ D154869 [Flang] [FlangRT] Introduce FlangRT project as solution to Flang's runtime LLVM integration); what’s new here?

1 Like

I don’t have any particular knowledge about this myself, just noting that the last time this topic came up (AFAICT) in the public flang meeting notes was last November[1]


  1. See Section “Technical Call 2023-11-27” ↩︎

I would support this change for a number of reasons, especially that it makes cross-compilation much easier.

For cross compilation, with LLVM_ENABLE_RUNTIMES you get a runtime built for each target you’ve asked for, meaning that you’d get a working flang cross-compiler without extra work. Flang works fine for cross compilation already in my experience but you have to build the flang runtimes for the extra targets manually rather than as an extra step.

One thing we should be aware of making this change though is that we aspire at some point to be able to build flang without also building clang. At the moment the flang-new driver is too intertwined with the clang code to be built separately but flang can be built without that driver with a cmake flag, and then does not require clang. If we only support building with LLVM_ENABLE_RUNTIMES then clang becomes a hard dependency for the flang runtimes which I think we should try and avoid. I.e. we should continue to support building the flang runtimes with the host compiler as well as with the just-built clang.

I would say that wrt sharing code, we should just have the new fortran_runtime project be a dependency for flang, and use the headers directly from fortran_runtime. I don’t see a reason we would need to duplicate things, and flang assumes you’re using its own runtime in a lot of places so I don’t see a need to avoid the dependency either. I might have missed something here though!

1 Like

Thanks for the feedback and pointers to past threads that I did not know about, including the previous approach ⚙ D154869 [Flang] [FlangRT] Introduce FlangRT project as solution to Flang's runtime LLVM integration. Since then, compiling FortranRuntime now also requires executing flang-newitself. Some additional questions were discussed there as well. Trying to summerize the current state:

  1. Top-Level name
    In addition to FortranRuntime, fortran_runtime and flang-rt came up. Drawing from similarities to compiler-rt, corresponding names could be flang-rt or fortran-rt. Drawing from similarities to libc, corresponding names could be libflang or libfortran. The currently library name is libFortranRuntime.a so I will work with “FortranRuntime”. Changing the names is straightforward and can be done later. If we go for a different name, we may also consider renaming the .a as well, see shared library question below.

  2. Subfolder structure
    No discussion taken place yet. Again, relatively straightforward to change.

  3. Shared code
    Code duplication seems rather disliked (even though optional.h already was copied from libc). My current intention is to put the shared code into a directory under FortranRuntime/{lib,include/FortranRuntime}/common which are referenced from flang as well.

  4. Build modes
    The different ways the FortranRuntime can be built.

    a. cmake -S llvm-project/llvm -DLLVM_ENABLE_RUNTIMES=FortranRuntime -DLLVM_RUNTIME_TARGETS=...
         Bootstrapping build that first compiles Clang and Flang, then uses them to build FortranRuntime for each target triple.

    b. cmake -S llvm-project/runtimes -DLLVM_ENABLE_RUNTIMES=FortranRuntime -DCMAKE_CXX_COMPILER=... -DCMAKE_Fortran_COMPILER=...
         Skip the bootstrap part and compiles the FortranRuntime using the selected compilers instead.

    c. cmake -S llvm-project/llvm -DLLVM_ENABLE_PROJECTS=FortranRuntime
         Use the same host C/C++ compiler to build Clang, Flang, and FortranRuntime. May use -DCMAKE_Fortran_COMPILER=... to build module files and iso_fortran_env_impl.f90 object. Alternatively, use just-built Flang instead as the current buildsystem does. Note that it is not possible to use CMake’s Fortran support in that case, e.g. for automatic dependency resolution.

    d. cmake -S llvm-project/FortranRuntime -DCMAKE_Fortran_COMPILER=... (“standalone build”)
         Independent CMakeLists.txt that needs to find_package its dependencies, as currently implemented in flang/runtime/CMakeLists.txt. In build mode b, this boilerplate is included in runtimes/CMakeLists.txt.

    e. cmake -S llvm-project/flang
         Building FortranRuntime implicitly when Flang is built, as the current buildsystem does.

    The more ways it is possible to build the FortranRuntime, the more complicated the CMake code becomes, the bigger the combinatorial build configuration explosion, the lower the fraction of configurations that are actually maintained and tested (e.g. with CI bots). That is, the number of build modes should stay as small as possible, unless it is really needed. I think libcxx only supports only a (“bootstrapping build”) and b (“default build”).

  5. CUDA/OpenMP build
    Unfortunately, the CUDA/OpenMP build of FortranRuntime does not fit well into the LLVM_ENABLE_RUNTIMES system. It is not equivalent to cmake -S llvm-project/runtimes -DLLVM_ENABLE_RUNTIMES=FortranRuntime -DCMAKE_CXX_COMPILER=nvcc -DLLVM_TARGET_TRIPLE=nvptx64-nvidia-cuda. That would not produce fat binaries. Instead, there is a host target (eg x86_64-unknown-linux-gnu) and one or more auxiliary targets (eg. nvptx64-nvidia-cuda for CUDA, additionally AMD for OpenMP).
    Until we can think of a general solution that also replaces liboffload auxiliary targets (-DLIBOMPTARGET_DEVICE_ARCHITECTURES=...), I would add an option that enables CUDA/OpenMP support when compiling in build mode b.

  6. Enabled by default with LLVM_ENABLE_RUNTIMES=all / LLVM_ENABLE_PROJECTS=all/flang
    I think this should be the case as soon as Flang is also built by default.

  7. Dependency on Clang
    Only applies to the bootstrapping build. Build mode b can specify any compatible C/C++ compiler and a pre-compiled Flang compiler.

  8. libFortranRuntime/libFortranDecimal separation
    Currently, these are two separate library names that are hardcoded in the flang-new driver. I don’t think this internal separation should be visible to the user, I would just link the object files of both into a single libFortranRuntime.a.

  9. Support shared library versions (libFortranRuntime.so)
    I don’t think this is supported with ⚙ D153426 Support LLVM_BUILD_USER_FORTRAN_LIBS=[shared|static|all] cmake option never committed, so I would consider it a separate issue that can be solved later on.
    Several issues would need to be solved, e.g. CMake not supporting building a static and shared library with the same name[1] (D153426 added a _static suffix because add_llvm_library does), potentially LD_LIBRARY_PATH/-rpath for finding the shared object at runtime, installation in ld default search path, and Windows that already has 5 different versions of FortranRuntime and the library selection working very differently. Should also be consistent with compiler-rt/libc.
    In any case, the CMakeLists.txt would handle this like for add_flang_library does for all Flang components, whereas FortranRuntime may get specially handling (like always building static and shared version). The Flang compiler and FortranRuntime will never use the same libraries or compiled object files since the compiler flags that LLVM_ENABLE_RUNTIMES adds are different from those from the bootstrap.

I intend to create a draft PR which then can be used to discuss more of the details.


  1. Because of Windows; there are workarounds to get the desired result on UNIX though. Flang on Windows already has a mechanism for selecting the static/shared FortranRuntime and there is no need to change it. ↩︎

Why do you need fat binaries? I find it much easier to just do add_library and then do -Xoffload-linker -lfortran. This should with all architectures so long as you emit LLVM-IR without -march set, and consequently any target specific intrinsic functions / macros.

The current compilation of FortranRuntime for CUDA only works with nvcc which does not have an Xoffload-linker option nor does it emit LLVM-IR.I currently do not intend to rewrite FortranRuntime’s CUDA support to use (bootstrapped) Clang instead. Users may also prefer nvcc for various reasons.

I see, I didn’t know that we had code in LLVM that only worked with nvcc. Realistically the way I’m proposing to build it is identical to libdevice.10.bc so NVIDIA should just re-use whatever they do there. Also, does this mean that it uses nvcc for the build itself? I’m not overly familiar with Fortran but it seems weird that LLVM mainline is carrying vendor specific library code that doesn’t even run w/ clang or flang.

Not in the default build. You have to enable FLANG_EXPERIMENTAL_CUDA_RUNTIME to do so.

Also a correction: Clang in CUDA mode is supported, in addition to nvcc. It uses CMake’s CUDA detection and sets all source files to be compiled as CUDA. Compilation with OpenMP requires Clang.

The draft PR is available here:
[Flang][DRAFT] LLVM_ENABLE_RUNTIMES=FortranRuntime #110217

Looking forward to your suggestions

1 Like

Can this be considered a successor (in spirit) of the reverted [Flang] [FlangRT] Introduce FlangRT project as solution to Flang's ru… · llvm/llvm-project@6403287 · GitHub?

Yes, goals are the same. In addition I am trying a cleaner separation between Flang (the compiler) and FortranRuntime/flang-rt (the runtime library), especially regarding the CMakeLists.txt. E.g. #110217 doesn’t move the lib/Runtime source files, but calls CMake add_subdirectory into the original location. I think also that the runtime should not reuse add_flang_library to compile the runtime. The build configuration of the compiler framework and of a runtime are not necessarily related.

1 Like

I am working on ensuring REAL(16) support. There are 4 configurations in runtime/Float128/CMakeLists.txt:

  1. Not supported
  2. Implemented by libquadmath (FLANG_RUNTIME_F128_MATH_LIB=“libquadmath”)
  3. Implemented by libc’s long double math function (HAVE_LDBL_MANT_DIG_113)
  4. Implemented by libc’s math function with f128 suffix (not yet working)

In configuration 3 and 4 the Float128 wrapper sources are directly added to libFortranRuntime.a. In config 2 however, an additional static library libFortranFloat128Math.a is created that required to be linked by the flang-new driver.

@szakharin I do not understand the motivation behind the additional library. libquadmath is also the only valid value for FLANG_RUNTIME_F128_MATH_LIB, mode 3 and 4 are autodetected by introspection, so could the presence of libquadmath.

The runtime implementation itself relies on native compiler and libc++ support for __float128 or 128-bit long double (HAS_FLOAT128 in float128.h). What is supposed to happen if __float128 is supported but which is not detected by config 3, or the other way around if e.g. runtime/numeric.cpp thinks 128-floats are not available, but runtime/Float128/CMakeLists.txt does due to config 2 or 4?

When cross-compiling, support for REAL(16) depends on the target, so I would try to avoid that building Flang needs to know anything about REAL(16) support of the host platform. First step would be folding libFortranFloat128Math.a into libFortranRuntime.a even for config 2.

The motivation for having FortranFloat128Math as a static library in the LLVM builds that implement the runtime via libquadmath is to avoid permanent dependency on libquadmath for programs that do not use REAL(16). In such a build the compiler driver will link libquadmath as needed, so the programs that do not use REAL(16) may be distributed without libquadmath dependency.

For this to work, the compiler driver and the FortranRuntime shared libraries have to be built “in sync”, i.e. FLANG_RUNTIME_F128_MATH_LIB=libquadmath is used to let the compiler driver know that FortranRuntimeFloat128Math static library should be linked, and libquadmath should be linked as needed.

mode 3 and 4 are autodetected by introspection, so could the presence of libquadmath.

I do not think the availability of libquadmath with the build compiler should necessarily trigger FortranFloat128Math implementation via libquadmath, hence there is an explicit control for this.

What is supposed to happen if __float128 is supported but which is not detected by config 3

If FLANG_RUNTIME_F128_MATH_LIB is not set, and if the compiler used to build the FortranRuntime supports __float128, but there is no library that provides the math functions implementations, then FortranRuntime will not provide the APIs for REAL(16) math. So compiling a program that relies on these APIs will result in a linking error.

if e.g. runtime/numeric.cpp thinks 128-floats are not available, but runtime/Float128/CMakeLists.txt does due to config 2 or 4?

runtime/numeric.cpp implements the exponentiation support via “basic” floating point operations and std templates. If the build compiler does not support 128-bit floats (neither via HAS_LDBL128 nor via HAS_FLOAT128), then those *Pow* APIs will not be defined by FortranRuntime. If the build compiler does not support 128-bit floats (neither via HAS_LDBL128 nor via HAS_FLOAT128), none of the FortranFloat128Math entries will be defined (since they are all guarded by #if HAS_LDBL128 || HAS_FLOAT128). I think in both cases there is not much we can do to provide 128-bit floating point math support. Let me know if I misunderstood your questions.

I don’t think this works. The flang-new driver will add --as-needed -lquadmath independently of whether REAL(16) is used or not. Even with --as-needed, the library must still exist:

$ clang hello.c -Wl,--as-needed -lxyzzy
/usr/bin/ld: cannot find -lxyzzy: No such file or directory
clang: error: linker command failed with exit code 1 (use -v to see invocation)       

In the long term, compiling runtime and compiler “in-sync” is not a viable mechanism for a cross-compiler. Think of I would like to cross-compile (--target flag) for a supercomputer which supports float128, but my local host machine does not. Flang on the local host machine would refuse to compile REAL(16).

The point of the question was that there are two independent mechanisms that detect float128 support: (1) float128.h and (2) runtime/Float128Math/CMakeLists.txt[1].

(1) detects the __float128 type and assumes overloads in std::, but (2) looks for sinf128 in libc.

(2) detects libquadmath but (1) doesn’t.

Reductions, runtime/numeric.cpp and other parts use the (1) mechanism. For instance, runtime/numeric.cpp implements REAL(16) pow. pow is also implemented in Float128Math/pow.cpp. AFAICS, the former implements pow for an integer exponent, the latter for REAL(16) exponent. Them using different detection mechanism may lead to the confusing situation that one is available, but not the other.


  1. Sources in Float128Math being guarded by #if HAS_LDBL128 || HAS_FLOAT128 is irrelevant because if runtime/Float128Math/CMakeLists.txt does not detect support, those sources will not even be compiled. ↩︎

I don’t think this works. The flang-new driver will add --as-needed -lquadmath independently of whether REAL(16) is used or not. Even with --as-needed , the library must still exist

This is correct, but I was referring to distributing the programs built using flang-new, not distributing the compiler itself. Flang compiler built with FLANG_RUNTIME_F128_MATH_LIB=libquadmath indeed has a requirement that libquadmath is present at the time of linking the program. After a program that does not use any REAL(16) math is built, it won’t have any dependency on libquadmath.

In the long term, compiling runtime and compiler “in-sync” is not a viable mechanism for a cross-compiler. Think of I would like to cross-compile (--target flag) for a supercomputer which supports float128, but my local host machine does not. Flang on the local host machine would refuse to compile REAL(16) .

A Flang cross-compiler compiling for a target that supports __float128 may provide the target-specific FortranRuntime, including the target-specific FortranFloat128Math as a separate library. The linking step in Flang driver for this target will be able to link FortranFloat128Math and the target-specific libquadmath to resolve the references to REAL(16) math APIs. So “in-sync”, in this case, would mean that the compiler driver for this particular target is aware of the requirement to link the target-specific libquadmath as-needed. Yes, it does not work like this right now. One way to make it work is to build the driver such that the FLANG_RUNTIME_F128_MATH_LIB handling is specified per target. There may be other ways to achieve the same.

The point of the question was that there are two independent mechanisms that detect float128 support: (1) float128.h and (2) runtime/Float128Math/CMakeLists.txt

These two mechanisms are checking different facts. One is checking that the build compiler supports __float128 data type and the basic operations/std support for this data type. When this check passes, there is not guarantee that, for example, the transcendental math functions are supported in any way by the target compiler toolchain. This check allows some limited support of REAL(16) math in the Flang runtime for this target, e.g. POW with an integer exponent is implemented via basic arithmetic operations on __float128 data.

The second mechanism is checking if there is __float128 math support in some library that can be used to implement Fortran REAL(16) math intrinsics. This check implies that the first check is also passing. When this check passes, the Flang compiler for this target can support REAL(16) math and it implies that the Flang driver needs to link this library.

So these two checks are not quite independent, but the basic support of __float128 does not automatically imply that the complete support for __float128 math is available.