diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index 32e712a48d76..1502e694bba5 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -3,20 +3,35 @@ The `-C linker-plugin-lto` flag allows for deferring the LTO optimization to the actual linking step, which in turn allows for performing interprocedural optimizations across programming language boundaries if -all the object files being linked were created by LLVM based toolchains. -The prime example here would be linking Rust code together with -Clang-compiled C/C++ code. +all the object files being linked were created by LLVM-based toolchains +using the **same** LTO mode: either thin LTO or fat LTO. +The examples would be linking Rust code together with +Clang-compiled C/C++ code and LLVM Flang-compiled Fortran code. ## Usage -There are two main cases how linker plugin based LTO can be used: +There are two main cases how linker-plugin-based LTO can be used: - compiling a Rust `staticlib` that is used as a C ABI dependency - compiling a Rust binary where `rustc` invokes the linker -In both cases the Rust code has to be compiled with `-C linker-plugin-lto` and -the C/C++ code with `-flto` or `-flto=thin` so that object files are emitted -as LLVM bitcode. +In both cases, the Rust code must be compiled with `-C linker-plugin-lto`. +By default, this enables thin LTO, so any interoperable language code must +also be compiled in thin LTO mode. To use fat LTO with linker-plugin-based LTO, +the `rustc` compiler requires the additional `-C lto=fat` flag, and the +interoperable language must likewise be compiled in fat LTO mode. Note that +interoperable language must be compiled using the LLVM infrastructure +(see more details in [toolchain compability](#toolchain-compatibility)). + +The following table summarizes how to enable thin LTO and fat LTO in +different compilers: + +| Compiler | Thin LTO | Fat LTO | +|:---------|-----------------:|---------------:| +| rustc | -Clto=thin | -Clto=fat | +| clang | -flto=thin | -flto=full | +| clang++ | -flto=thin | -flto=full | +| flang | -flto=thin (WIP) | -flto=full | ### Rust `staticlib` as dependency in C/C++ program @@ -54,7 +69,7 @@ that an appropriate linker is used. Using `rustc` directly: ```bash -# Compile C code with `-flto` +# Compile C code with `-flto=thin` clang ./clib.c -flto=thin -c -o ./clib.o -O2 # Create a static library from the C code ar crus ./libxyz.a ./clib.o @@ -66,7 +81,7 @@ rustc -Clinker-plugin-lto -L. -Copt-level=2 -Clinker=clang -Clink-arg=-fuse-ld=l Using `cargo` directly: ```bash -# Compile C code with `-flto` +# Compile C code with `-flto=thin` clang ./clib.c -flto=thin -c -o ./clib.o -O2 # Create a static library from the C code ar crus ./libxyz.a ./clib.o @@ -75,6 +90,41 @@ ar crus ./libxyz.a ./clib.o RUSTFLAGS="-Clinker-plugin-lto -Clinker=clang -Clink-arg=-fuse-ld=lld" cargo build --release ``` +### Fortran code as a dependency in Rust + +Rust code can also be linked together with Fortran code compiled by LLVM `flang`. +The following examples demonstrate fat LTO usage, as LLVM `flang` has WIP status for +thin LTO. The same approach can be applied to compile C and C++ code with fat LTO. + +Using `rustc` directly: + +```bash +# Compile Fortran code with `-flto=full` +flang ./ftnlib.f90 -flto=full -c -o ./ftnlib.f90.o -O3 +# Create a static library from the Fortran code +ar crus ./libftn.a ./ftnlib.f90.o + +# Invoke `rustc` with the additional arguments, `-Clto=fat` is mandatory +rustc -Clinker-plugin-lto -Clto=fat -Clink-arg=path/to/libftn.a -Copt-level=3 -Clinker=flang -C default-linker-libraries=yes -Clink-arg=-fuse-ld=lld ./main.rs +``` + +Using `cargo` directly: + +```bash +# Compile Fortran code with `-flto=full` +flang ./ftnlib.f90 -flto=full -c -o ./ftnlib.f90.o -O3 +# Create a static library from the Fortran code +ar crus ./libftn.a ./ftnlib.f90.o + +# Set the linking arguments via RUSTFLAGS, `-Clto=fat` is mandatory +RUSTFLAGS="-Clinker-plugin-lto -Clto=fat -Clink-arg=path/to/libftn.a -Clinker=flang -C default-linker-libraries=yes -Clink-arg=-fuse-ld=lld" cargo build --release +``` + +Note, LLVM `flang` can be used as a linker driver starting from flang 21.1.8. +The `-C default-linker-libraries=yes` option may be omitted if the Fortran +runtime is not required; however, most Fortran code depends on the runtime, +so enabling default linker libraries is usually necessary. + ### Explicitly specifying the linker plugin to be used by `rustc` If one wants to use a linker other than LLD, the LLVM linker plugin has to be @@ -179,11 +229,13 @@ for clang, rust in sorted(version_map.items()): --> In order for this kind of LTO to work, the LLVM linker plugin must be able to -handle the LLVM bitcode produced by both `rustc` and `clang`. +handle the LLVM bitcode produced by `rustc` and by compilers of all +interoperable languages. A good rule of thumb is to use an LLVM linker plugin +whose version is at least as new as the newest compiler involved. -Best results are achieved by using a `rustc` and `clang` that are based on the -exact same version of LLVM. One can use `rustc -vV` in order to view the LLVM -used by a given `rustc` version. Note that the version number given +Best results are achieved by using a `rustc` and LLVM compilers that are based +on the exact same version of LLVM. One can use `rustc -vV` in order to view +the LLVM used by a given `rustc` version. Note that the version number given here is only an approximation as Rust sometimes uses unstable revisions of LLVM. However, the approximation is usually reliable. @@ -204,6 +256,6 @@ The following table shows known good combinations of toolchain versions. | 1.78 - 1.81 | 18 | | 1.82 - 1.86 | 19 | | 1.87 - 1.90 | 20 | -| 1.91 - 1.92 | 21 | +| 1.91 - 1.93 | 21 | Note that the compatibility policy for this feature might change in the future.