mirror-llvm-project/flang-rt/lib/runtime/iso_c_binding.f90
Michael Kruse bafde6fbb8
[Flang] Move builtin .mod generation into runtimes (Reapply #137828) (#171515)
Reapplication of #137828 and #169638

Move building the .mod files from openmp/flang to openmp/flang-rt using
a shared mechanism. Motivations to do so are:

1. Most modules are target-dependent and need to be re-compiled for each
target separately, which is something the LLVM_ENABLE_RUNTIMES system
already does. Prime example is `iso_c_binding.mod` which encodes the
target's ABI. Constants such as `c_long_double` also have different
values).
Most other modules have `#ifdef`-enclosed code as well. For instance
this caused offload targets nvptx64-nvidia-cuda/amdgpu-amd-amdhsa to use
the modules files compiled for the host which may contrain uses of the
types REAL(10) or REAL(16) not available for nvptx/amdgpu.

2. CMake has support for Fortran that we should use. Among other things,
it automatically determines module dependencies so there is no need to
hardcode them in the CMakeLists.txt.

Currently the dependencies between builtin modules and `omp_lib.mod`
seem to be incorrect:
https://github.com/llvm/llvm-project/pull/174474#issuecomment-3880189581

3. It allows using Fortran itself to implement Flang-RT. Currently, only
`iso_fortran_env_impl.f90` emits object files that are needed by Fortran
applications (#89403). The workaround of #95388 could be reverted (PR
#169525).


If using Flang for cross-compilation or target-offloading, flang-rt must
now be compiled for each target not only for the library, but also to
get the target-specific module files. For instance in a bootstrapping
runtime build, this can be done by adding:
`-DLLVM_RUNTIME_TARGETS=default;nvptx64-nvidia-cuda;amdgpu-amd-amdhsa`.


Some new dependencies come into play:
* openmp depends on flang-rt for building `lib_omp.mod` and
`lib_omp_kinds.mod`. Currently, if flang-rt is not found then the
modules are not built.
* check-flang depends on flang-rt: If not found, the majority of tests
are disabled. If not building in a bootstrpping build, the location of
the module files can be pointed to using
`-DFLANG_INTRINSIC_MODULES_DIR=<path>`, e.g. in a flang-standalone
build. Alternatively, the test needing any of the intrinsic modules
could be marked with `REQUIRES: flangrt-modules`.
* check-flang depends on openmp: Not a change; tests requiring
`lib_omp.mod` and `lib_omp_kinds.mod` those are already marked with
`openmp_runtime`.

As intrinsic are now specific to the target, their location is moved
from `include/flang` to `<resource-dir>/finclude/flang/<triple>`. The
mechnism to compute the location have been moved from flang-rt
(previously used to compute the location of `libflang_rt.*.a`) to common
locations in `cmake/GetToolchainDirs.cmake` and
`runtimes/CMakeLists.txt` so they can be used by both, openmp and
flang-rt. Potentially the mechnism could also be shared by other
libraries such as compiler-rt.

`finclude` was chosen because `gfortran` uses it as well and avoids
misuse such as `#include <flang/iso_c_binding.mod>`. The search location
is now determined by `ToolChain` in the driver, instead of by the
frontend. Another subdirectory `flang` avoids accidental inclusion of
gfortran-modules which due to compression would result in
user-unfriendly errors. Now the driver adds `-fintrinsic-module-path`
for that location to the frontend call (Just like gfortran does).
Since the driver determines the location,
tests invoking `flang -fc1` and `bbc` must also be passed the location
by llvm-lit. This works like llvm-lit does for finding the include dirs
for Clang using `-print-file-name=...`.
2026-05-29 10:50:52 +02:00

160 lines
4.9 KiB
Fortran

!===-- module/iso_c_binding.f90 --------------------------------------------===!
!
! Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
! See https://llvm.org/LICENSE.txt for license information.
! SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
!
!===------------------------------------------------------------------------===!
! See Fortran 2018, clause 18.2
module iso_c_binding
use __fortran_builtins, only: &
c_associated => __builtin_c_associated, &
c_funloc => __builtin_c_funloc, &
c_funptr => __builtin_c_funptr, &
c_f_pointer => __builtin_c_f_pointer, &
c_f_strpointer => __builtin_c_f_strpointer, &
c_loc => __builtin_c_loc, &
c_null_funptr => __builtin_c_null_funptr, &
c_null_ptr => __builtin_c_null_ptr, &
c_ptr => __builtin_c_ptr, &
c_sizeof => sizeof, &
f_c_string => __builtin_f_c_string, &
operator(==), operator(/=)
implicit none
! Set PRIVATE by default to explicitly only export what is meant
! to be exported by this MODULE.
private
public :: c_associated, c_funloc, c_funptr, c_f_pointer, c_f_strpointer, &
c_loc, c_null_funptr, c_null_ptr, c_ptr, c_sizeof, f_c_string, &
operator(==), operator(/=)
! Table 18.2 (in clause 18.3.1)
! TODO: Specialize (via macros?) for alternative targets
integer, parameter, public :: &
c_int8_t = 1, &
c_int16_t = 2, &
c_int32_t = 4, &
c_int64_t = 8, &
c_int128_t = 16 ! anticipating future addition
integer, parameter, public :: &
c_int = c_int32_t, &
c_short = c_int16_t, &
#if defined(_WIN32)
c_long = c_int32_t, &
#else
c_long = c_int64_t, &
#endif
c_long_long = c_int64_t, &
c_signed_char = c_int8_t, &
c_size_t = kind(c_sizeof(1)), &
! Currently both gcc and clang define intmax_t to be 64 bit.
c_intmax_t = c_int64_t, &
c_intptr_t = c_size_t, &
c_ptrdiff_t = c_size_t
integer, parameter, public :: &
c_int_least8_t = c_int8_t, &
c_int_fast8_t = c_int8_t, &
c_int_least16_t = c_int16_t, &
#if defined(__linux__) && defined(__powerpc__)
c_int_fast16_t = c_long, &
#else
c_int_fast16_t = c_int16_t, &
#endif
c_int_least32_t = c_int32_t, &
#if defined(__linux__) && defined(__powerpc__)
c_int_fast32_t = c_long, &
#else
c_int_fast32_t = c_int32_t, &
#endif
c_int_least64_t = c_int64_t, &
c_int_fast64_t = c_int64_t, &
c_int_least128_t = c_int128_t, &
c_int_fast128_t = c_int128_t
integer, parameter, public :: &
c_float = 4, &
c_double = 8, &
#if defined(__x86_64__)
c_long_double = 10
#elif defined(_WIN32) && defined(__aarch64__)
c_long_double = 8
#else
c_long_double = 16
#endif
integer, parameter, public :: &
c_float_complex = c_float, &
c_double_complex = c_double, &
c_long_double_complex = c_long_double
integer, parameter, public :: c_bool = 1
integer, parameter, public :: c_char = 1
! C characters with special semantics
character(kind=c_char, len=1), parameter, public :: c_null_char = achar(0)
character(kind=c_char, len=1), parameter, public :: c_alert = achar(7)
character(kind=c_char, len=1), parameter, public :: c_backspace = achar(8)
character(kind=c_char, len=1), parameter, public :: c_form_feed = achar(12)
character(kind=c_char, len=1), parameter, public :: c_new_line = achar(10)
character(kind=c_char, len=1), parameter, public :: c_carriage_return = achar(13)
character(kind=c_char, len=1), parameter, public :: c_horizontal_tab = achar(9)
character(kind=c_char, len=1), parameter, public :: c_vertical_tab = achar(11)
interface c_f_procpointer
module procedure c_f_procpointer
end interface
public :: c_f_procpointer
! gfortran extensions
integer, parameter, public :: &
c_float128 = 16, &
c_float128_complex = c_float128
integer, parameter, public :: &
c_uint8_t = 1, &
c_uint16_t = 2, &
c_uint32_t = 4, &
c_uint64_t = 8, &
c_uint128_t = 16
integer, parameter, public :: &
c_unsigned_char = c_uint8_t, &
c_unsigned_short = c_uint16_t, &
c_unsigned = c_uint32_t, &
#if defined(_WIN32)
c_unsigned_long = c_uint32_t, &
#else
c_unsigned_long = c_uint64_t, &
#endif
c_unsigned_long_long = c_uint64_t, &
#if defined(__powerpc__) || defined(_WIN32)
c_uintmax_t = c_uint64_t
#else
c_uintmax_t = c_uint128_t
#endif
integer, parameter, public :: &
c_uint_fast8_t = c_uint8_t, &
c_uint_fast16_t = c_uint16_t, &
c_uint_fast32_t = c_uint32_t, &
c_uint_fast64_t = c_uint64_t, &
c_uint_fast128_t = c_uint128_t
integer, parameter, public :: &
c_uint_least8_t = c_uint8_t, &
c_uint_least16_t = c_uint16_t, &
c_uint_least32_t = c_uint32_t, &
c_uint_least64_t = c_uint64_t, &
c_uint_least128_t = c_uint128_t
contains
subroutine c_f_procpointer(cptr, fptr)
type(c_funptr), intent(in) :: cptr
procedure(), pointer, intent(out) :: fptr
! TODO: implement
end subroutine c_f_procpointer
end module iso_c_binding