rustc: Fix some ThinLTO internalization
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
This commit is contained in:
parent
df095cefe2
commit
2e1c4cd0f5
8 changed files with 67 additions and 10 deletions
|
@ -130,6 +130,7 @@ pub fn run(cgcx: &CodegenContext,
|
||||||
.filter_map(symbol_filter)
|
.filter_map(symbol_filter)
|
||||||
.collect::<Vec<CString>>();
|
.collect::<Vec<CString>>();
|
||||||
timeline.record("whitelist");
|
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
|
// 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
|
// upstream dependencies, find the corresponding rlib and load the bitcode
|
||||||
|
@ -437,7 +438,24 @@ fn run_pass_manager(cgcx: &CodegenContext,
|
||||||
assert!(!pass.is_null());
|
assert!(!pass.is_null());
|
||||||
llvm::LLVMRustAddPass(pm, pass);
|
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 thin {
|
||||||
if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
|
if !llvm::LLVMRustPassManagerBuilderPopulateThinLTOPassManager(b, pm) {
|
||||||
panic!("this version of LLVM does not support ThinLTO");
|
panic!("this version of LLVM does not support ThinLTO");
|
||||||
|
|
|
@ -217,7 +217,7 @@ pub struct ModuleConfig {
|
||||||
passes: Vec<String>,
|
passes: Vec<String>,
|
||||||
/// Some(level) to optimize at a certain level, or None to run
|
/// Some(level) to optimize at a certain level, or None to run
|
||||||
/// absolutely no optimizations (used for the metadata module).
|
/// 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.
|
/// Some(level) to optimize binary size, or None to not affect program size.
|
||||||
opt_size: Option<llvm::CodeGenOptSize>,
|
opt_size: Option<llvm::CodeGenOptSize>,
|
||||||
|
@ -507,7 +507,8 @@ unsafe fn optimize(cgcx: &CodegenContext,
|
||||||
if !config.no_prepopulate_passes {
|
if !config.no_prepopulate_passes {
|
||||||
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
|
llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
|
||||||
llvm::LLVMRustAddAnalysisPasses(tm, mpm, 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::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
|
||||||
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
|
llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
|
||||||
})
|
})
|
||||||
|
@ -1842,16 +1843,17 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
|
||||||
|
|
||||||
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
|
pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
|
||||||
config: &ModuleConfig,
|
config: &ModuleConfig,
|
||||||
|
opt_level: llvm::CodeGenOptLevel,
|
||||||
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
|
f: &mut FnMut(llvm::PassManagerBuilderRef)) {
|
||||||
// Create the PassManagerBuilder for LLVM. We configure it with
|
// Create the PassManagerBuilder for LLVM. We configure it with
|
||||||
// reasonable defaults and prepare it to actually populate the pass
|
// reasonable defaults and prepare it to actually populate the pass
|
||||||
// manager.
|
// manager.
|
||||||
let builder = llvm::LLVMPassManagerBuilderCreate();
|
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 opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
|
||||||
let inline_threshold = config.inline_threshold;
|
let inline_threshold = config.inline_threshold;
|
||||||
|
|
||||||
llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level,
|
llvm::LLVMRustConfigurePassManagerBuilder(builder,
|
||||||
|
opt_level,
|
||||||
config.merge_functions,
|
config.merge_functions,
|
||||||
config.vectorize_slp,
|
config.vectorize_slp,
|
||||||
config.vectorize_loop);
|
config.vectorize_loop);
|
||||||
|
|
|
@ -901,9 +901,7 @@ addPreservedGUID(const ModuleSummaryIndex &Index,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
GlobalValueSummary *GVSummary = Summary.get();
|
if (auto *FS = dyn_cast<FunctionSummary>(Summary.get())) {
|
||||||
if (isa<FunctionSummary>(GVSummary)) {
|
|
||||||
FunctionSummary *FS = cast<FunctionSummary>(GVSummary);
|
|
||||||
for (auto &Call: FS->calls()) {
|
for (auto &Call: FS->calls()) {
|
||||||
if (Call.first.isGUID()) {
|
if (Call.first.isGUID()) {
|
||||||
addPreservedGUID(Index, Preserved, Call.first.getGUID());
|
addPreservedGUID(Index, Preserved, Call.first.getGUID());
|
||||||
|
@ -916,6 +914,10 @@ addPreservedGUID(const ModuleSummaryIndex &Index,
|
||||||
addPreservedGUID(Index, Preserved, GUID);
|
addPreservedGUID(Index, Preserved, GUID);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (auto *AS = dyn_cast<AliasSummary>(Summary.get())) {
|
||||||
|
auto GUID = AS->getAliasee().getOriginalName();
|
||||||
|
addPreservedGUID(Index, Preserved, GUID);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -963,12 +965,13 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules,
|
||||||
// combined index
|
// combined index
|
||||||
//
|
//
|
||||||
// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
|
// This is copied from `lib/LTO/ThinLTOCodeGenerator.cpp`
|
||||||
computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
|
auto DeadSymbols = computeDeadSymbols(Ret->Index, Ret->GUIDPreservedSymbols);
|
||||||
ComputeCrossModuleImport(
|
ComputeCrossModuleImport(
|
||||||
Ret->Index,
|
Ret->Index,
|
||||||
Ret->ModuleToDefinedGVSummaries,
|
Ret->ModuleToDefinedGVSummaries,
|
||||||
Ret->ImportLists,
|
Ret->ImportLists,
|
||||||
Ret->ExportLists
|
Ret->ExportLists,
|
||||||
|
&DeadSymbols
|
||||||
);
|
);
|
||||||
|
|
||||||
// Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
|
// Resolve LinkOnce/Weak symbols, this has to be computed early be cause it
|
||||||
|
|
16
src/test/run-pass/thinlto/auxiliary/dylib.rs
Normal file
16
src/test/run-pass/thinlto/auxiliary/dylib.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
// 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();
|
||||||
|
}
|
18
src/test/run-pass/thinlto/dylib-works.rs
Normal file
18
src/test/run-pass/thinlto/dylib-works.rs
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
// 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);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue