Skip to content

Commit b0d3198

Browse files
authored
Rollup merge of rust-lang#61036 - michaelwoerister:pgo-xlto-test, r=alexcrichton
PGO - Add a smoketest for combining PGO with cross-language LTO. This PR - Adds a test making sure that PGO can be combined with cross-language LTO. - Does a little cleanup on how the `pgo-use` flag is handled internally. - Makes the compiler error if the `pgo-use` file given to `rustc` doesn't actually exist. LLVM only gives a warning and then just doesn't do PGO. Clang, on the other hand, does give an error in this case. - Makes the build system also build `compiler-rt` when building LLDB. This way the Clang compiler that we get from building LLDB can perform PGO, which is something that the new test case wants to do. CI compile times shouldn't be affected too much.
2 parents 9f210e4 + b3c5cdd commit b0d3198

File tree

10 files changed

+149
-11
lines changed

10 files changed

+149
-11
lines changed

src/bootstrap/native.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,7 @@ impl Step for Llvm {
204204
}
205205

206206
if want_lldb {
207-
cfg.define("LLVM_ENABLE_PROJECTS", "clang;lldb");
207+
cfg.define("LLVM_ENABLE_PROJECTS", "clang;lldb;compiler-rt");
208208
// For the time being, disable code signing.
209209
cfg.define("LLDB_CODESIGN_IDENTITY", "");
210210
cfg.define("LLDB_NO_DEBUGSERVER", "ON");

src/librustc/session/config.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1381,7 +1381,7 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
13811381
"insert profiling code"),
13821382
pgo_gen: PgoGenerate = (PgoGenerate::Disabled, parse_pgo_generate, [TRACKED],
13831383
"Generate PGO profile data, to a given file, or to the default location if it's empty."),
1384-
pgo_use: String = (String::new(), parse_string, [TRACKED],
1384+
pgo_use: Option<PathBuf> = (None, parse_opt_pathbuf, [TRACKED],
13851385
"Use PGO profile data from the given profile file."),
13861386
disable_instrumentation_preinliner: bool = (false, parse_bool, [TRACKED],
13871387
"Disable the instrumentation pre-inliner, useful for profiling / PGO."),
@@ -2021,7 +2021,7 @@ pub fn build_session_options_and_crate_config(
20212021
}
20222022
}
20232023

2024-
if debugging_opts.pgo_gen.enabled() && !debugging_opts.pgo_use.is_empty() {
2024+
if debugging_opts.pgo_gen.enabled() && debugging_opts.pgo_use.is_some() {
20252025
early_error(
20262026
error_format,
20272027
"options `-Z pgo-gen` and `-Z pgo-use` are exclusive",
@@ -3212,7 +3212,7 @@ mod tests {
32123212
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
32133213

32143214
opts = reference.clone();
3215-
opts.debugging_opts.pgo_use = String::from("abc");
3215+
opts.debugging_opts.pgo_use = Some(PathBuf::from("abc"));
32163216
assert_ne!(reference.dep_tracking_hash(), opts.dep_tracking_hash());
32173217

32183218
opts = reference.clone();

src/librustc/session/mod.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1272,6 +1272,15 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
12721272
sess.err("Linker plugin based LTO is not supported together with \
12731273
`-C prefer-dynamic` when targeting MSVC");
12741274
}
1275+
1276+
// Make sure that any given profiling data actually exists so LLVM can't
1277+
// decide to silently skip PGO.
1278+
if let Some(ref path) = sess.opts.debugging_opts.pgo_use {
1279+
if !path.exists() {
1280+
sess.err(&format!("File `{}` passed to `-Zpgo-use` does not exist.",
1281+
path.display()));
1282+
}
1283+
}
12751284
}
12761285

12771286
/// Hash value constructed out of all the `-C metadata` arguments passed to the

src/librustc_codegen_llvm/back/write.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -721,11 +721,9 @@ pub unsafe fn with_llvm_pmb(llmod: &llvm::Module,
721721
}
722722
};
723723

724-
let pgo_use_path = if config.pgo_use.is_empty() {
725-
None
726-
} else {
727-
Some(CString::new(config.pgo_use.as_bytes()).unwrap())
728-
};
724+
let pgo_use_path = config.pgo_use.as_ref().map(|path_buf| {
725+
CString::new(path_buf.to_string_lossy().as_bytes()).unwrap()
726+
});
729727

730728
llvm::LLVMRustConfigurePassManagerBuilder(
731729
builder,

src/librustc_codegen_ssa/back/write.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ pub struct ModuleConfig {
5757
pub opt_size: Option<config::OptLevel>,
5858

5959
pub pgo_gen: PgoGenerate,
60-
pub pgo_use: String,
60+
pub pgo_use: Option<PathBuf>,
6161

6262
// Flags indicating which outputs to produce.
6363
pub emit_pre_lto_bc: bool,
@@ -95,7 +95,7 @@ impl ModuleConfig {
9595
opt_size: None,
9696

9797
pgo_gen: PgoGenerate::Disabled,
98-
pgo_use: String::new(),
98+
pgo_use: None,
9999

100100
emit_no_opt_bc: false,
101101
emit_pre_lto_bc: false,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
# needs-matching-clang
2+
3+
# This test makes sure that cross-language inlining can be used in conjunction
4+
# with profile-guided optimization. The test only tests that the whole workflow
5+
# can be executed without anything crashing. It does not test whether PGO or
6+
# xLTO have any specific effect on the generated code.
7+
8+
-include ../tools.mk
9+
10+
COMMON_FLAGS=-Copt-level=3 -Ccodegen-units=1
11+
12+
# LLVM doesn't support instrumenting binaries that use SEH:
13+
# https://bugs.llvm.org/show_bug.cgi?id=41279
14+
#
15+
# Things work fine with -Cpanic=abort though.
16+
ifdef IS_MSVC
17+
COMMON_FLAGS+= -Cpanic=abort
18+
endif
19+
20+
all: cpp-executable rust-executable
21+
22+
cpp-executable:
23+
$(RUSTC) -Clinker-plugin-lto=on \
24+
-Zpgo-gen="$(TMPDIR)"/cpp-profdata \
25+
-o "$(TMPDIR)"/librustlib-xlto.a \
26+
$(COMMON_FLAGS) \
27+
./rustlib.rs
28+
$(CLANG) -flto=thin \
29+
-fprofile-generate="$(TMPDIR)"/cpp-profdata \
30+
-fuse-ld=lld \
31+
-L "$(TMPDIR)" \
32+
-lrustlib-xlto \
33+
-o "$(TMPDIR)"/cmain \
34+
-O3 \
35+
./cmain.c
36+
$(TMPDIR)/cmain
37+
# Postprocess the profiling data so it can be used by the compiler
38+
"$(LLVM_BIN_DIR)"/llvm-profdata merge \
39+
-o "$(TMPDIR)"/cpp-profdata/merged.profdata \
40+
"$(TMPDIR)"/cpp-profdata/default_*.profraw
41+
$(RUSTC) -Clinker-plugin-lto=on \
42+
-Zpgo-use="$(TMPDIR)"/cpp-profdata/merged.profdata \
43+
-o "$(TMPDIR)"/librustlib-xlto.a \
44+
$(COMMON_FLAGS) \
45+
./rustlib.rs
46+
$(CLANG) -flto=thin \
47+
-fprofile-use="$(TMPDIR)"/cpp-profdata/merged.profdata \
48+
-fuse-ld=lld \
49+
-L "$(TMPDIR)" \
50+
-lrustlib-xlto \
51+
-o "$(TMPDIR)"/cmain \
52+
-O3 \
53+
./cmain.c
54+
55+
rust-executable:
56+
exit
57+
$(CLANG) ./clib.c -fprofile-generate="$(TMPDIR)"/rs-profdata -flto=thin -c -o $(TMPDIR)/clib.o -O3
58+
(cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
59+
$(RUSTC) -Clinker-plugin-lto=on \
60+
-Zpgo-gen="$(TMPDIR)"/rs-profdata \
61+
-L$(TMPDIR) \
62+
$(COMMON_FLAGS) \
63+
-Clinker=$(CLANG) \
64+
-Clink-arg=-fuse-ld=lld \
65+
-o $(TMPDIR)/rsmain \
66+
./main.rs
67+
$(TMPDIR)/rsmain
68+
# Postprocess the profiling data so it can be used by the compiler
69+
"$(LLVM_BIN_DIR)"/llvm-profdata merge \
70+
-o "$(TMPDIR)"/rs-profdata/merged.profdata \
71+
"$(TMPDIR)"/rs-profdata/default_*.profraw
72+
$(CLANG) ./clib.c \
73+
-fprofile-use="$(TMPDIR)"/rs-profdata/merged.profdata \
74+
-flto=thin \
75+
-c \
76+
-o $(TMPDIR)/clib.o \
77+
-O3
78+
rm "$(TMPDIR)"/libxyz.a
79+
(cd $(TMPDIR); $(AR) crus ./libxyz.a ./clib.o)
80+
$(RUSTC) -Clinker-plugin-lto=on \
81+
-Zpgo-use="$(TMPDIR)"/rs-profdata/merged.profdata \
82+
-L$(TMPDIR) \
83+
$(COMMON_FLAGS) \
84+
-Clinker=$(CLANG) \
85+
-Clink-arg=-fuse-ld=lld \
86+
-o $(TMPDIR)/rsmain \
87+
./main.rs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
#include <stdint.h>
2+
3+
uint32_t c_always_inlined() {
4+
return 1234;
5+
}
6+
7+
__attribute__((noinline)) uint32_t c_never_inlined() {
8+
return 12345;
9+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#include <stdint.h>
2+
3+
// A trivial function defined in Rust, returning a constant value. This should
4+
// always be inlined.
5+
uint32_t rust_always_inlined();
6+
7+
8+
uint32_t rust_never_inlined();
9+
10+
int main(int argc, char** argv) {
11+
return (rust_never_inlined() + rust_always_inlined()) * 0;
12+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#[link(name = "xyz")]
2+
extern "C" {
3+
fn c_always_inlined() -> u32;
4+
fn c_never_inlined() -> u32;
5+
}
6+
7+
fn main() {
8+
unsafe {
9+
println!("blub: {}", c_always_inlined() + c_never_inlined());
10+
}
11+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
#![crate_type="staticlib"]
2+
3+
#[no_mangle]
4+
pub extern "C" fn rust_always_inlined() -> u32 {
5+
42
6+
}
7+
8+
#[no_mangle]
9+
#[inline(never)]
10+
pub extern "C" fn rust_never_inlined() -> u32 {
11+
421
12+
}

0 commit comments

Comments
 (0)