mirror of
https://github.com/rust-lang/rust.git
synced 2025-11-25 08:57:39 +00:00
When rust provides LLVM bitcode files to lld and the bitcode contains function summaries as used for thin lto, lld defaults to using thin lto. This prevents some optimizations that are only applied for fat lto. We solve this by not creating function summaries when fat lto is enabled. The bitcode for the module is just directly written out. An alternative solution would be to set the `ThinLTO=0` module flag to signal lld to do fat lto. The code in clang that sets this flag is here:560149b5e3/clang/lib/CodeGen/BackendUtil.cpp (L1150)The code in LLVM that queries the flag and defaults to thin lto if not set is here:e258bca950/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp (L4441-L4446)
96 lines
3.6 KiB
Rust
96 lines
3.6 KiB
Rust
// This test checks that cross-language inlining actually works by checking
|
|
// the generated machine code.
|
|
// See https://github.com/rust-lang/rust/pull/57514
|
|
|
|
//@ needs-force-clang-based-tests
|
|
// NOTE(#126180): This test only runs on `x86_64-gnu-debug`, because that CI job sets
|
|
// RUSTBUILD_FORCE_CLANG_BASED_TESTS and only runs tests which contain "clang" in their
|
|
// name.
|
|
|
|
use run_make_support::{clang, env_var, llvm_ar, llvm_objdump, rustc, static_lib_name};
|
|
|
|
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
|
static RUST_ALWAYS_INLINED_PATTERN: &'static str = "bl.*<rust_always_inlined>";
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
static RUST_ALWAYS_INLINED_PATTERN: &'static str = "call.*rust_always_inlined";
|
|
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
|
static C_ALWAYS_INLINED_PATTERN: &'static str = "bl.*<c_always_inlined>";
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
static C_ALWAYS_INLINED_PATTERN: &'static str = "call.*c_always_inlined";
|
|
|
|
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
|
static RUST_NEVER_INLINED_PATTERN: &'static str = "bl.*<rust_never_inlined>";
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
static RUST_NEVER_INLINED_PATTERN: &'static str = "call.*rust_never_inlined";
|
|
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
|
static C_NEVER_INLINED_PATTERN: &'static str = "bl.*<c_never_inlined>";
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
static C_NEVER_INLINED_PATTERN: &'static str = "call.*c_never_inlined";
|
|
|
|
fn main() {
|
|
test_lto(false);
|
|
test_lto(true);
|
|
}
|
|
|
|
fn test_lto(fat_lto: bool) {
|
|
let lto = if fat_lto { "fat" } else { "thin" };
|
|
let clang_lto = if fat_lto { "full" } else { "thin" };
|
|
println!("Running {lto} lto");
|
|
|
|
rustc()
|
|
.lto(lto)
|
|
.linker_plugin_lto("on")
|
|
.output(static_lib_name("rustlib-xlto"))
|
|
.opt_level("2")
|
|
.codegen_units(1)
|
|
.input("rustlib.rs")
|
|
.run();
|
|
clang()
|
|
.lto(clang_lto)
|
|
.use_ld("lld")
|
|
.arg("-lrustlib-xlto")
|
|
.out_exe("cmain")
|
|
.input("cmain.c")
|
|
.arg("-O3")
|
|
.run();
|
|
|
|
let dump = llvm_objdump().disassemble().input("cmain").run();
|
|
// Make sure we don't find a call instruction to the function we expect to
|
|
// always be inlined.
|
|
dump.assert_stdout_not_contains_regex(RUST_ALWAYS_INLINED_PATTERN);
|
|
// As a sanity check, make sure we do find a call instruction to a
|
|
// non-inlined function
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
|
dump.assert_stdout_contains_regex(RUST_NEVER_INLINED_PATTERN);
|
|
#[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
|
|
{
|
|
if fat_lto {
|
|
// fat lto inlines this anyway
|
|
dump.assert_stdout_not_contains_regex(RUST_NEVER_INLINED_PATTERN);
|
|
} else {
|
|
dump.assert_stdout_contains_regex(RUST_NEVER_INLINED_PATTERN);
|
|
}
|
|
}
|
|
|
|
clang().input("clib.c").lto(clang_lto).arg("-c").out_exe("clib.o").arg("-O2").run();
|
|
llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run();
|
|
rustc()
|
|
.lto(lto)
|
|
.linker_plugin_lto("on")
|
|
.opt_level("2")
|
|
.linker(&env_var("CLANG"))
|
|
.link_arg("-fuse-ld=lld")
|
|
.input("main.rs")
|
|
.output("rsmain")
|
|
.run();
|
|
|
|
let dump = llvm_objdump().disassemble().input("rsmain").run();
|
|
dump.assert_stdout_not_contains_regex(C_ALWAYS_INLINED_PATTERN);
|
|
if fat_lto {
|
|
// fat lto inlines this anyway
|
|
dump.assert_stdout_not_contains_regex(C_NEVER_INLINED_PATTERN);
|
|
} else {
|
|
dump.assert_stdout_contains_regex(C_NEVER_INLINED_PATTERN);
|
|
}
|
|
}
|