diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index 8f75b891a302c..01d3d656dfe19 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -130,6 +130,7 @@ pub fn run(cgcx: &CodegenContext, .filter_map(symbol_filter) .collect::>(); 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 @@ -437,7 +438,24 @@ fn run_pass_manager(cgcx: &CodegenContext, 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"); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 9d914243ec6e2..f7e0ad029afaf 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -217,7 +217,7 @@ pub struct ModuleConfig { passes: Vec, /// Some(level) to optimize at a certain level, or None to run /// absolutely no optimizations (used for the metadata module). - opt_level: Option, + pub opt_level: Option, /// Some(level) to optimize binary size, or None to not affect program size. opt_size: Option, @@ -507,7 +507,8 @@ unsafe fn optimize(cgcx: &CodegenContext, 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); }) @@ -1842,16 +1843,17 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) { 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); diff --git a/src/rustllvm/PassWrapper.cpp b/src/rustllvm/PassWrapper.cpp index e37f048dd4757..1287b94159a57 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/src/rustllvm/PassWrapper.cpp @@ -901,9 +901,7 @@ addPreservedGUID(const ModuleSummaryIndex &Index, } } - GlobalValueSummary *GVSummary = Summary.get(); - if (isa(GVSummary)) { - FunctionSummary *FS = cast(GVSummary); + if (auto *FS = dyn_cast(Summary.get())) { for (auto &Call: FS->calls()) { if (Call.first.isGUID()) { addPreservedGUID(Index, Preserved, Call.first.getGUID()); @@ -916,6 +914,10 @@ addPreservedGUID(const ModuleSummaryIndex &Index, addPreservedGUID(Index, Preserved, GUID); } } + if (auto *AS = dyn_cast(Summary.get())) { + auto GUID = AS->getAliasee().getOriginalName(); + addPreservedGUID(Index, Preserved, GUID); + } } } @@ -963,12 +965,13 @@ LLVMRustCreateThinLTOData(LLVMRustThinLTOModule *modules, // 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 diff --git a/src/test/run-pass/thinlto/auxiliary/dylib.rs b/src/test/run-pass/thinlto/auxiliary/dylib.rs new file mode 100644 index 0000000000000..cdb3f49cae88b --- /dev/null +++ b/src/test/run-pass/thinlto/auxiliary/dylib.rs @@ -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 or the MIT license +// , 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(); +} diff --git a/src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs b/src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs similarity index 100% rename from src/test/run-pass/auxiliary/thin-lto-inlines-aux.rs rename to src/test/run-pass/thinlto/auxiliary/thin-lto-inlines-aux.rs diff --git a/src/test/run-pass/thinlto/dylib-works.rs b/src/test/run-pass/thinlto/dylib-works.rs new file mode 100644 index 0000000000000..3f54519d0d8ce --- /dev/null +++ b/src/test/run-pass/thinlto/dylib-works.rs @@ -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 or the MIT license +// , 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); +} diff --git a/src/test/run-pass/thin-lto-inlines.rs b/src/test/run-pass/thinlto/thin-lto-inlines.rs similarity index 100% rename from src/test/run-pass/thin-lto-inlines.rs rename to src/test/run-pass/thinlto/thin-lto-inlines.rs diff --git a/src/test/run-pass/thin-lto-inlines2.rs b/src/test/run-pass/thinlto/thin-lto-inlines2.rs similarity index 100% rename from src/test/run-pass/thin-lto-inlines2.rs rename to src/test/run-pass/thinlto/thin-lto-inlines2.rs