First the `addPreservedGUID` function forgot to take care of "alias" summaries.
I'm not 100% sure what this is but the current code now matches upstream. Next
the `computeDeadSymbols` return value wasn't actually being used, but it needed
to be used! Together these should...
Closes #45195
.filter_map(symbol_filter)
.collect::<Vec<CString>>();
timeline.record("whitelist");
+ info!("{} symbols to preserve in this crate", symbol_white_list.len());
// If we're performing LTO for the entire crate graph, then for each of our
// upstream dependencies, find the corresponding rlib and load the bitcode
assert!(!pass.is_null());
llvm::LLVMRustAddPass(pm, pass);
- with_llvm_pmb(llmod, config, &mut |b| {
+ // When optimizing for LTO we don't actually pass in `-O0`, but we force
+ // it to always happen at least with `-O1`.
+ //
+ // With ThinLTO we mess around a lot with symbol visibility in a way
+ // that will actually cause linking failures if we optimize at O0 which
+ // notable is lacking in dead code elimination. To ensure we at least
+ // get some optimizations and correctly link we forcibly switch to `-O1`
+ // to get dead code elimination.
+ //
+ // Note that in general this shouldn't matter too much as you typically
+ // only turn on ThinLTO when you're compiling with optimizations
+ // otherwise.
+ let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
+ let opt_level = match opt_level {
+ llvm::CodeGenOptLevel::None => llvm::CodeGenOptLevel::Less,
+ level => level,
+ };
+ with_llvm_pmb(llmod, config, opt_level, &mut |b| {
if thin {
if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
panic!("this version of LLVM does not support ThinLTO");
passes: Vec<String>,
/// Some(level) to optimize at a certain level, or None to run
/// absolutely no optimizations (used for the metadata module).
- opt_level: Option<llvm::CodeGenOptLevel>,
+ pub opt_level: Option<llvm::CodeGenOptLevel>,
/// Some(level) to optimize binary size, or None to not affect program size.
opt_size: Option<llvm::CodeGenOptSize>,
if !config.no_prepopulate_passes {
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
- with_llvm_pmb(llmod, &config, &mut |b| {
+ let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
+ with_llvm_pmb(llmod, &config, opt_level, &mut |b| {
llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
})
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
config: &ModuleConfig,
+ opt_level: llvm::CodeGenOptLevel,
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
// Create the PassManagerBuilder for LLVM. We configure it with
// reasonable defaults and prepare it to actually populate the pass
// manager.
let builder = llvm::LLVMPassManagerBuilderCreate();
- let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
let inline_threshold = config.inline_threshold;
- llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level,
+ llvm::LLVMRustConfigurePassManagerBuilder(builder,
+ opt_level,
config.merge_functions,
config.vectorize_slp,
config.vectorize_loop);
}
}
- GlobalValueSummary *GVSummary = Summary.get();
- if (isa<FunctionSummary>(GVSummary)) {
- FunctionSummary *FS = cast<FunctionSummary>(GVSummary);
+ if (auto *FS = dyn_cast<FunctionSummary>(Summary.get())) {
for (auto &Call: FS->calls()) {
if (Call.first.isGUID()) {
addPreservedGUID(Index, Preserved, Call.first.getGUID());
addPreservedGUID(Index, Preserved, GUID);
}
}
+ if (auto *AS = dyn_cast<AliasSummary>(Summary.get())) {
+ auto GUID = AS->getAliasee().getOriginalName();
+ addPreservedGUID(Index, Preserved, GUID);
+ }
}
}
// combined index
//
// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
- computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
+ auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
ComputeCrossModuleImport(
Ret->Index,
Ret->ModuleToDefinedGVSummaries,
Ret->ImportLists,
- Ret->ExportLists
+ Ret->ExportLists,
+ &DeadSymbols
);
// Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// no-prefer-dynamic
-
-#![crate_type = "rlib"]
-
-pub fn bar() -> u32 {
- 3
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z thinlto -C codegen-units=8 -O
-// min-llvm-version 4.0
-// ignore-emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-mod bar {
- pub fn bar() -> u32 {
- 3
- }
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
+++ /dev/null
-// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
-// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
-// aux-build:thin-lto-inlines-aux.rs
-// min-llvm-version 4.0
-// no-prefer-dynamic
-// ignore-emscripten
-
-// We want to assert here that ThinLTO will inline across codegen units. There's
-// not really a great way to do that in general so we sort of hack around it by
-// praying two functions go into separate codegen units and then assuming that
-// if inlining *doesn't* happen the first byte of the functions will differ.
-
-extern crate thin_lto_inlines_aux as bar;
-
-pub fn foo() -> u32 {
- bar::bar()
-}
-
-fn main() {
- println!("{} {}", foo(), bar::bar());
-
- unsafe {
- let foo = foo as usize as *const u8;
- let bar = bar::bar as usize as *const u8;
-
- assert_eq!(*foo, *bar);
- }
-}
-
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=8
+
+#[inline]
+pub fn foo(b: u8) {
+ b.to_string();
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// no-prefer-dynamic
+
+#![crate_type = "rlib"]
+
+pub fn bar() -> u32 {
+ 3
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// aux-build:dylib.rs
+// min-llvm-version 4.0
+
+extern crate dylib;
+
+fn main() {
+ dylib::foo(1);
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O
+// min-llvm-version 4.0
+// ignore-emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+mod bar {
+ pub fn bar() -> u32 {
+ 3
+ }
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
--- /dev/null
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
+// aux-build:thin-lto-inlines-aux.rs
+// min-llvm-version 4.0
+// no-prefer-dynamic
+// ignore-emscripten
+
+// We want to assert here that ThinLTO will inline across codegen units. There's
+// not really a great way to do that in general so we sort of hack around it by
+// praying two functions go into separate codegen units and then assuming that
+// if inlining *doesn't* happen the first byte of the functions will differ.
+
+extern crate thin_lto_inlines_aux as bar;
+
+pub fn foo() -> u32 {
+ bar::bar()
+}
+
+fn main() {
+ println!("{} {}", foo(), bar::bar());
+
+ unsafe {
+ let foo = foo as usize as *const u8;
+ let bar = bar::bar as usize as *const u8;
+
+ assert_eq!(*foo, *bar);
+ }
+}
+