diff --git a/src/tools/run-make-support/src/external_deps/clang.rs b/src/tools/run-make-support/src/external_deps/clang.rs index 2b0712541cd5f..2d110c6825e05 100644 --- a/src/tools/run-make-support/src/external_deps/clang.rs +++ b/src/tools/run-make-support/src/external_deps/clang.rs @@ -1,7 +1,7 @@ use std::path::Path; use crate::command::Command; -use crate::{bin_name, env_var}; +use crate::{bin_name, cwd, env_var}; /// Construct a new `clang` invocation. `clang` is not always available for all targets. #[track_caller] @@ -23,7 +23,8 @@ impl Clang { #[track_caller] pub fn new() -> Self { let clang = env_var("CLANG"); - let cmd = Command::new(clang); + let mut cmd = Command::new(clang); + cmd.arg("-L").arg(cwd()); Self { cmd } } diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 817259ee92166..6039f38123791 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,7 +1,6 @@ run-make/branch-protection-check-IBT/Makefile run-make/cat-and-grep-sanity-check/Makefile run-make/cdylib-dylib-linkage/Makefile -run-make/cross-lang-lto-pgo-smoketest/Makefile run-make/cross-lang-lto-upstream-rlibs/Makefile run-make/cross-lang-lto/Makefile run-make/dep-info-doesnt-run-much/Makefile diff --git a/tests/run-make/cross-lang-lto-clang/_Makefile b/tests/run-make/cross-lang-lto-clang/_Makefile new file mode 100644 index 0000000000000..b039328b0f9e8 --- /dev/null +++ b/tests/run-make/cross-lang-lto-clang/_Makefile @@ -0,0 +1,29 @@ +# FIXME(Oneirical): This is already implemented as an rmake.rs file, but due to #126180, +# the rmake.rs is not ran on CI. Once the rmake test has been proven to work, remove this +# Makefile. + +# needs-force-clang-based-tests + +# This test makes sure that cross-language inlining actually works by checking +# the generated machine code. + +include ../tools.mk + +all: cpp-executable rust-executable + +cpp-executable: + $(RUSTC) -Clinker-plugin-lto=on -o $(TMPDIR)/librustlib-xlto.a -Copt-level=2 -Ccodegen-units=1 ./rustlib.rs + $(CLANG) -flto=thin -fuse-ld=lld -L $(TMPDIR) -lrustlib-xlto -o $(TMPDIR)/cmain ./cmain.c -O3 + # Make sure we don't find a call instruction to the function we expect to + # always be inlined. + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -v -e "call.*rust_always_inlined" + # As a sanity check, make sure we do find a call instruction to a + # non-inlined function + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/cmain | $(CGREP) -e "call.*rust_never_inlined" + +rust-executable: + $(CLANG) ./clib.c -flto=thin -c -o $(TMPDIR)/clib.o -O2 + (cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o) + $(RUSTC) -Clinker-plugin-lto=on -L$(TMPDIR) -Copt-level=2 -Clinker=$(CLANG) -Clink-arg=-fuse-ld=lld ./main.rs -o $(TMPDIR)/rsmain + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -e "call.*c_never_inlined" + "$(LLVM_BIN_DIR)"/llvm-objdump -d $(TMPDIR)/rsmain | $(CGREP) -v -e "call.*c_always_inlined" diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile b/tests/run-make/cross-lang-lto-pgo-smoketest/_Makefile similarity index 94% rename from tests/run-make/cross-lang-lto-pgo-smoketest/Makefile rename to tests/run-make/cross-lang-lto-pgo-smoketest/_Makefile index 738e23f9c6614..737f066b4da03 100644 --- a/tests/run-make/cross-lang-lto-pgo-smoketest/Makefile +++ b/tests/run-make/cross-lang-lto-pgo-smoketest/_Makefile @@ -1,3 +1,7 @@ +# FIXME(Oneirical): This is already implemented as an rmake.rs file, but due to #126180, +# the rmake.rs is not ran on CI. Once the rmake test has been proven to work, remove this +# Makefile. + # needs-force-clang-based-tests # FIXME(#126180): This test doesn't actually run anywhere, because the only diff --git a/tests/run-make/cross-lang-lto-pgo-smoketest/rmake.rs b/tests/run-make/cross-lang-lto-pgo-smoketest/rmake.rs new file mode 100644 index 0000000000000..e4d8879607fd8 --- /dev/null +++ b/tests/run-make/cross-lang-lto-pgo-smoketest/rmake.rs @@ -0,0 +1,111 @@ +// This test makes sure that cross-language inlining can be used in conjunction +// with profile-guided optimization. The test only tests that the whole workflow +// can be executed without anything crashing. It does not test whether PGO or +// xLTO have any specific effect on the generated code. +// See https://github.com/rust-lang/rust/pull/61036 + +//@ needs-force-clang-based-tests +// FIXME(#126180): This test doesn't actually run anywhere, because the only +// CI job that sets RUSTBUILD_FORCE_CLANG_BASED_TESTS runs very few tests. + +//FIXME(Oneirical): There was a strange workaround for MSVC on this test +// which added -C panic=abort to every RUSTC call. It was justified as follows: +// LLVM doesn't support instrumenting binaries that use SEH: +// https://bugs.llvm.org/show_bug.cgi?id=41279 +// Things work fine with -Cpanic=abort though. + +use run_make_support::{ + clang, env_var, has_extension, has_prefix, llvm_ar, llvm_profdata, rfs, run, rustc, + shallow_find_files, static_lib_name, +}; + +fn main() { + rustc() + .linker_plugin_lto("on") + .output(static_lib_name("rustlib-xlto")) + .opt_level("3") + .codegen_units(1) + .input("rustlib.rs") + .arg("-Cprofile-generate=cpp-profdata") + .run(); + clang() + .lto("thin") + .arg("-fprofile-generate=cpp-profdata") + .use_ld("lld") + .arg("-lrustlib-xlto") + .out_exe("cmain") + .input("cmain.c") + .arg("-O3") + .run(); + run("cmain"); + // Postprocess the profiling data so it can be used by the compiler + let profraw_files = shallow_find_files("cpp-profdata", |path| { + has_prefix(path, "default") && has_extension(path, "profraw") + }); + let profraw_file = profraw_files.get(0).unwrap(); + llvm_profdata().merge().output("cpp-profdata/merged.profdata").input(profraw_file).run(); + rustc() + .linker_plugin_lto("on") + .profile_use("cpp-profdata/merged.profdata") + .output(static_lib_name("rustlib-xlto")) + .opt_level("3") + .codegen_units(1) + .input("rustlib.rs") + .run(); + clang() + .lto("thin") + .arg("-fprofile-use=cpp-profdata/merged.profdata") + .use_ld("lld") + .arg("-lrustlib-xlto") + .out_exe("cmain") + .input("cmain.c") + .arg("-O3") + .run(); + + clang() + .input("clib.c") + .arg("-fprofile-generate=rs-profdata") + .lto("thin") + .arg("-c") + .out_exe("clib.o") + .arg("-O3") + .run(); + llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run(); + rustc() + .linker_plugin_lto("on") + .opt_level("3") + .codegen_units(1) + .arg("-Cprofile-generate=rs-profdata") + .linker(&env_var("CLANG")) + .link_arg("-fuse-ld=lld") + .input("main.rs") + .output("rsmain") + .run(); + run("rsmain"); + // Postprocess the profiling data so it can be used by the compiler + let profraw_files = shallow_find_files("rs-profdata", |path| { + has_prefix(path, "default") && has_extension(path, "profraw") + }); + let profraw_file = profraw_files.get(0).unwrap(); + llvm_profdata().merge().output("rs-profdata/merged.profdata").input(profraw_file).run(); + clang() + .input("clib.c") + .arg("-fprofile-use=rs-profdata/merged.profdata") + .arg("-c") + .lto("thin") + .out_exe("clib.o") + .arg("-O3") + .run(); + rfs::remove_file(static_lib_name("xyz")); + llvm_ar().obj_to_ar().output_input(static_lib_name("xyz"), "clib.o").run(); + rustc() + .linker_plugin_lto("on") + .opt_level("3") + .codegen_units(1) + .arg("-Cprofile-use=rs-profdata/merged.profdata") + .linker(&env_var("CLANG")) + .link_arg("-fuse-ld=lld") + .input("main.rs") + .output("rsmain") + .run(); +}