mirror of
https://github.com/rust-lang/rust.git
synced 2025-01-10 23:06:23 +00:00
Merge branch 'configure-lto' of https://github.com/alexcrichton/rust into rollup
This commit is contained in:
commit
e61c609320
@ -72,6 +72,26 @@ pub enum OptLevel {
|
|||||||
SizeMin, // -Oz
|
SizeMin, // -Oz
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, PartialEq, Hash)]
|
||||||
|
pub enum Lto {
|
||||||
|
/// Don't do any LTO whatsoever
|
||||||
|
No,
|
||||||
|
|
||||||
|
/// Do a full crate graph LTO. The flavor is determined by the compiler
|
||||||
|
/// (currently the default is "fat").
|
||||||
|
Yes,
|
||||||
|
|
||||||
|
/// Do a full crate graph LTO with ThinLTO
|
||||||
|
Thin,
|
||||||
|
|
||||||
|
/// Do a local graph LTO with ThinLTO (only relevant for multiple codegen
|
||||||
|
/// units).
|
||||||
|
ThinLocal,
|
||||||
|
|
||||||
|
/// Do a full crate graph LTO with "fat" LTO
|
||||||
|
Fat,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Hash)]
|
#[derive(Clone, Copy, PartialEq, Hash)]
|
||||||
pub enum DebugInfoLevel {
|
pub enum DebugInfoLevel {
|
||||||
NoDebugInfo,
|
NoDebugInfo,
|
||||||
@ -389,7 +409,7 @@ top_level_options!(
|
|||||||
// commands like `--emit llvm-ir` which they're often incompatible with
|
// commands like `--emit llvm-ir` which they're often incompatible with
|
||||||
// if we otherwise use the defaults of rustc.
|
// if we otherwise use the defaults of rustc.
|
||||||
cli_forced_codegen_units: Option<usize> [UNTRACKED],
|
cli_forced_codegen_units: Option<usize> [UNTRACKED],
|
||||||
cli_forced_thinlto: Option<bool> [UNTRACKED],
|
cli_forced_thinlto_off: bool [UNTRACKED],
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -590,7 +610,7 @@ pub fn basic_options() -> Options {
|
|||||||
debug_assertions: true,
|
debug_assertions: true,
|
||||||
actually_rustdoc: false,
|
actually_rustdoc: false,
|
||||||
cli_forced_codegen_units: None,
|
cli_forced_codegen_units: None,
|
||||||
cli_forced_thinlto: None,
|
cli_forced_thinlto_off: false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -780,11 +800,13 @@ macro_rules! options {
|
|||||||
Some("crate=integer");
|
Some("crate=integer");
|
||||||
pub const parse_unpretty: Option<&'static str> =
|
pub const parse_unpretty: Option<&'static str> =
|
||||||
Some("`string` or `string=string`");
|
Some("`string` or `string=string`");
|
||||||
|
pub const parse_lto: Option<&'static str> =
|
||||||
|
Some("one of `thin`, `fat`, or omitted");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
mod $mod_set {
|
mod $mod_set {
|
||||||
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer};
|
use super::{$struct_name, Passes, SomePasses, AllPasses, Sanitizer, Lto};
|
||||||
use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel};
|
use rustc_back::{LinkerFlavor, PanicStrategy, RelroLevel};
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
|
||||||
@ -978,6 +1000,16 @@ macro_rules! options {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn parse_lto(slot: &mut Lto, v: Option<&str>) -> bool {
|
||||||
|
*slot = match v {
|
||||||
|
None => Lto::Yes,
|
||||||
|
Some("thin") => Lto::Thin,
|
||||||
|
Some("fat") => Lto::Fat,
|
||||||
|
Some(_) => return false,
|
||||||
|
};
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
) }
|
) }
|
||||||
|
|
||||||
@ -994,7 +1026,7 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options,
|
|||||||
"extra arguments to append to the linker invocation (space separated)"),
|
"extra arguments to append to the linker invocation (space separated)"),
|
||||||
link_dead_code: bool = (false, parse_bool, [UNTRACKED],
|
link_dead_code: bool = (false, parse_bool, [UNTRACKED],
|
||||||
"don't let linker strip dead code (turning it on can be used for code coverage)"),
|
"don't let linker strip dead code (turning it on can be used for code coverage)"),
|
||||||
lto: bool = (false, parse_bool, [TRACKED],
|
lto: Lto = (Lto::No, parse_lto, [TRACKED],
|
||||||
"perform LLVM link-time optimizations"),
|
"perform LLVM link-time optimizations"),
|
||||||
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
|
||||||
"select target processor (rustc --print target-cpus for details)"),
|
"select target processor (rustc --print target-cpus for details)"),
|
||||||
@ -1677,7 +1709,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
|
|||||||
|
|
||||||
let mut cg = build_codegen_options(matches, error_format);
|
let mut cg = build_codegen_options(matches, error_format);
|
||||||
let mut codegen_units = cg.codegen_units;
|
let mut codegen_units = cg.codegen_units;
|
||||||
let mut thinlto = None;
|
let mut disable_thinlto = false;
|
||||||
|
|
||||||
// Issue #30063: if user requests llvm-related output to one
|
// Issue #30063: if user requests llvm-related output to one
|
||||||
// particular path, disable codegen-units.
|
// particular path, disable codegen-units.
|
||||||
@ -1699,12 +1731,12 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
|
|||||||
}
|
}
|
||||||
early_warn(error_format, "resetting to default -C codegen-units=1");
|
early_warn(error_format, "resetting to default -C codegen-units=1");
|
||||||
codegen_units = Some(1);
|
codegen_units = Some(1);
|
||||||
thinlto = Some(false);
|
disable_thinlto = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
codegen_units = Some(1);
|
codegen_units = Some(1);
|
||||||
thinlto = Some(false);
|
disable_thinlto = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1734,7 +1766,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
|
|||||||
(&None, &None) => None,
|
(&None, &None) => None,
|
||||||
}.map(|m| PathBuf::from(m));
|
}.map(|m| PathBuf::from(m));
|
||||||
|
|
||||||
if cg.lto && incremental.is_some() {
|
if cg.lto != Lto::No && incremental.is_some() {
|
||||||
early_error(error_format, "can't perform LTO when compiling incrementally");
|
early_error(error_format, "can't perform LTO when compiling incrementally");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1934,7 +1966,7 @@ pub fn build_session_options_and_crate_config(matches: &getopts::Matches)
|
|||||||
debug_assertions,
|
debug_assertions,
|
||||||
actually_rustdoc: false,
|
actually_rustdoc: false,
|
||||||
cli_forced_codegen_units: codegen_units,
|
cli_forced_codegen_units: codegen_units,
|
||||||
cli_forced_thinlto: thinlto,
|
cli_forced_thinlto_off: disable_thinlto,
|
||||||
},
|
},
|
||||||
cfg)
|
cfg)
|
||||||
}
|
}
|
||||||
@ -2052,7 +2084,7 @@ mod dep_tracking {
|
|||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::collections::hash_map::DefaultHasher;
|
use std::collections::hash_map::DefaultHasher;
|
||||||
use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
|
use super::{Passes, CrateType, OptLevel, DebugInfoLevel, Lto,
|
||||||
OutputTypes, Externs, ErrorOutputType, Sanitizer};
|
OutputTypes, Externs, ErrorOutputType, Sanitizer};
|
||||||
use syntax::feature_gate::UnstableFeatures;
|
use syntax::feature_gate::UnstableFeatures;
|
||||||
use rustc_back::{PanicStrategy, RelroLevel};
|
use rustc_back::{PanicStrategy, RelroLevel};
|
||||||
@ -2107,6 +2139,7 @@ mod dep_tracking {
|
|||||||
impl_dep_tracking_hash_via_hash!(RelroLevel);
|
impl_dep_tracking_hash_via_hash!(RelroLevel);
|
||||||
impl_dep_tracking_hash_via_hash!(Passes);
|
impl_dep_tracking_hash_via_hash!(Passes);
|
||||||
impl_dep_tracking_hash_via_hash!(OptLevel);
|
impl_dep_tracking_hash_via_hash!(OptLevel);
|
||||||
|
impl_dep_tracking_hash_via_hash!(Lto);
|
||||||
impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
|
impl_dep_tracking_hash_via_hash!(DebugInfoLevel);
|
||||||
impl_dep_tracking_hash_via_hash!(UnstableFeatures);
|
impl_dep_tracking_hash_via_hash!(UnstableFeatures);
|
||||||
impl_dep_tracking_hash_via_hash!(Externs);
|
impl_dep_tracking_hash_via_hash!(Externs);
|
||||||
@ -2180,6 +2213,7 @@ mod tests {
|
|||||||
use lint;
|
use lint;
|
||||||
use middle::cstore;
|
use middle::cstore;
|
||||||
use session::config::{build_configuration, build_session_options_and_crate_config};
|
use session::config::{build_configuration, build_session_options_and_crate_config};
|
||||||
|
use session::config::Lto;
|
||||||
use session::build_session;
|
use session::build_session;
|
||||||
use std::collections::{BTreeMap, BTreeSet};
|
use std::collections::{BTreeMap, BTreeSet};
|
||||||
use std::iter::FromIterator;
|
use std::iter::FromIterator;
|
||||||
@ -2656,7 +2690,7 @@ mod tests {
|
|||||||
|
|
||||||
// Make sure changing a [TRACKED] option changes the hash
|
// Make sure changing a [TRACKED] option changes the hash
|
||||||
opts = reference.clone();
|
opts = reference.clone();
|
||||||
opts.cg.lto = true;
|
opts.cg.lto = Lto::Fat;
|
||||||
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
|
||||||
|
|
||||||
opts = reference.clone();
|
opts = reference.clone();
|
||||||
|
@ -498,9 +498,65 @@ impl Session {
|
|||||||
self.use_mir()
|
self.use_mir()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn lto(&self) -> bool {
|
/// Calculates the flavor of LTO to use for this compilation.
|
||||||
self.opts.cg.lto || self.target.target.options.requires_lto
|
pub fn lto(&self) -> config::Lto {
|
||||||
|
// If our target has codegen requirements ignore the command line
|
||||||
|
if self.target.target.options.requires_lto {
|
||||||
|
return config::Lto::Fat
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the user specified something, return that. If they only said `-C
|
||||||
|
// lto` and we've for whatever reason forced off ThinLTO via the CLI,
|
||||||
|
// then ensure we can't use a ThinLTO.
|
||||||
|
match self.opts.cg.lto {
|
||||||
|
config::Lto::No => {}
|
||||||
|
config::Lto::Yes if self.opts.cli_forced_thinlto_off => {
|
||||||
|
return config::Lto::Fat
|
||||||
|
}
|
||||||
|
other => return other,
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ok at this point the target doesn't require anything and the user
|
||||||
|
// hasn't asked for anything. Our next decision is whether or not
|
||||||
|
// we enable "auto" ThinLTO where we use multiple codegen units and
|
||||||
|
// then do ThinLTO over those codegen units. The logic below will
|
||||||
|
// either return `No` or `ThinLocal`.
|
||||||
|
|
||||||
|
// If processing command line options determined that we're incompatible
|
||||||
|
// with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option.
|
||||||
|
if self.opts.cli_forced_thinlto_off {
|
||||||
|
return config::Lto::No
|
||||||
|
}
|
||||||
|
|
||||||
|
// If `-Z thinlto` specified process that, but note that this is mostly
|
||||||
|
// a deprecated option now that `-C lto=thin` exists.
|
||||||
|
if let Some(enabled) = self.opts.debugging_opts.thinlto {
|
||||||
|
if enabled {
|
||||||
|
return config::Lto::ThinLocal
|
||||||
|
} else {
|
||||||
|
return config::Lto::No
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If there's only one codegen unit and LTO isn't enabled then there's
|
||||||
|
// no need for ThinLTO so just return false.
|
||||||
|
if self.codegen_units() == 1 {
|
||||||
|
return config::Lto::No
|
||||||
|
}
|
||||||
|
|
||||||
|
// Right now ThinLTO isn't compatible with incremental compilation.
|
||||||
|
if self.opts.incremental.is_some() {
|
||||||
|
return config::Lto::No
|
||||||
|
}
|
||||||
|
|
||||||
|
// Now we're in "defaults" territory. By default we enable ThinLTO for
|
||||||
|
// optimized compiles (anything greater than O0).
|
||||||
|
match self.opts.optimize {
|
||||||
|
config::OptLevel::No => config::Lto::No,
|
||||||
|
_ => config::Lto::ThinLocal,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the panic strategy for this compile session. If the user explicitly selected one
|
/// Returns the panic strategy for this compile session. If the user explicitly selected one
|
||||||
/// using '-C panic', use that, otherwise use the panic strategy defined by the target.
|
/// using '-C panic', use that, otherwise use the panic strategy defined by the target.
|
||||||
pub fn panic_strategy(&self) -> PanicStrategy {
|
pub fn panic_strategy(&self) -> PanicStrategy {
|
||||||
@ -804,38 +860,6 @@ impl Session {
|
|||||||
// scientific.
|
// scientific.
|
||||||
16
|
16
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether ThinLTO is enabled for this compilation
|
|
||||||
pub fn thinlto(&self) -> bool {
|
|
||||||
// If processing command line options determined that we're incompatible
|
|
||||||
// with ThinLTO (e.g. `-C lto --emit llvm-ir`) then return that option.
|
|
||||||
if let Some(enabled) = self.opts.cli_forced_thinlto {
|
|
||||||
return enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
// If explicitly specified, use that with the next highest priority
|
|
||||||
if let Some(enabled) = self.opts.debugging_opts.thinlto {
|
|
||||||
return enabled
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there's only one codegen unit and LTO isn't enabled then there's
|
|
||||||
// no need for ThinLTO so just return false.
|
|
||||||
if self.codegen_units() == 1 && !self.lto() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Right now ThinLTO isn't compatible with incremental compilation.
|
|
||||||
if self.opts.incremental.is_some() {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
// Now we're in "defaults" territory. By default we enable ThinLTO for
|
|
||||||
// optimized compiles (anything greater than O0).
|
|
||||||
match self.opts.optimize {
|
|
||||||
config::OptLevel::No => false,
|
|
||||||
_ => true,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn build_session(sopts: config::Options,
|
pub fn build_session(sopts: config::Options,
|
||||||
|
@ -16,7 +16,7 @@ use super::rpath::RPathConfig;
|
|||||||
use super::rpath;
|
use super::rpath;
|
||||||
use metadata::METADATA_FILENAME;
|
use metadata::METADATA_FILENAME;
|
||||||
use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest};
|
use rustc::session::config::{self, NoDebugInfo, OutputFilenames, OutputType, PrintRequest};
|
||||||
use rustc::session::config::RUST_CGU_EXT;
|
use rustc::session::config::{RUST_CGU_EXT, Lto};
|
||||||
use rustc::session::filesearch;
|
use rustc::session::filesearch;
|
||||||
use rustc::session::search_paths::PathKind;
|
use rustc::session::search_paths::PathKind;
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
@ -503,7 +503,8 @@ fn link_staticlib(sess: &Session,
|
|||||||
});
|
});
|
||||||
ab.add_rlib(path,
|
ab.add_rlib(path,
|
||||||
&name.as_str(),
|
&name.as_str(),
|
||||||
sess.lto() && !ignored_for_lto(sess, &trans.crate_info, cnum),
|
is_full_lto_enabled(sess) &&
|
||||||
|
!ignored_for_lto(sess, &trans.crate_info, cnum),
|
||||||
skip_object_files).unwrap();
|
skip_object_files).unwrap();
|
||||||
|
|
||||||
all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned());
|
all_native_libs.extend(trans.crate_info.native_libraries[&cnum].iter().cloned());
|
||||||
@ -1211,7 +1212,8 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
|
|||||||
lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
|
lib.kind == NativeLibraryKind::NativeStatic && !relevant_lib(sess, lib)
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!sess.lto() || ignored_for_lto(sess, &trans.crate_info, cnum)) &&
|
if (!is_full_lto_enabled(sess) ||
|
||||||
|
ignored_for_lto(sess, &trans.crate_info, cnum)) &&
|
||||||
crate_type != config::CrateTypeDylib &&
|
crate_type != config::CrateTypeDylib &&
|
||||||
!skip_native {
|
!skip_native {
|
||||||
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
|
cmd.link_rlib(&fix_windows_verbatim_for_gcc(cratepath));
|
||||||
@ -1264,7 +1266,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
|
|||||||
// file, then we don't need the object file as it's part of the
|
// file, then we don't need the object file as it's part of the
|
||||||
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
|
// LTO module. Note that `#![no_builtins]` is excluded from LTO,
|
||||||
// though, so we let that object file slide.
|
// though, so we let that object file slide.
|
||||||
let skip_because_lto = sess.lto() &&
|
let skip_because_lto = is_full_lto_enabled(sess) &&
|
||||||
is_rust_object &&
|
is_rust_object &&
|
||||||
(sess.target.target.options.no_builtins ||
|
(sess.target.target.options.no_builtins ||
|
||||||
!trans.crate_info.is_no_builtins.contains(&cnum));
|
!trans.crate_info.is_no_builtins.contains(&cnum));
|
||||||
@ -1301,7 +1303,7 @@ fn add_upstream_rust_crates(cmd: &mut Linker,
|
|||||||
fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) {
|
fn add_dynamic_crate(cmd: &mut Linker, sess: &Session, cratepath: &Path) {
|
||||||
// If we're performing LTO, then it should have been previously required
|
// If we're performing LTO, then it should have been previously required
|
||||||
// that all upstream rust dependencies were available in an rlib format.
|
// that all upstream rust dependencies were available in an rlib format.
|
||||||
assert!(!sess.lto());
|
assert!(!is_full_lto_enabled(sess));
|
||||||
|
|
||||||
// Just need to tell the linker about where the library lives and
|
// Just need to tell the linker about where the library lives and
|
||||||
// what its name is
|
// what its name is
|
||||||
@ -1409,3 +1411,13 @@ fn link_binaryen(sess: &Session,
|
|||||||
e));
|
e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn is_full_lto_enabled(sess: &Session) -> bool {
|
||||||
|
match sess.lto() {
|
||||||
|
Lto::Yes |
|
||||||
|
Lto::Thin |
|
||||||
|
Lto::Fat => true,
|
||||||
|
Lto::No |
|
||||||
|
Lto::ThinLocal => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -18,7 +18,7 @@ use llvm::{ModuleRef, TargetMachineRef, True, False};
|
|||||||
use llvm;
|
use llvm;
|
||||||
use rustc::hir::def_id::LOCAL_CRATE;
|
use rustc::hir::def_id::LOCAL_CRATE;
|
||||||
use rustc::middle::exported_symbols::SymbolExportLevel;
|
use rustc::middle::exported_symbols::SymbolExportLevel;
|
||||||
use rustc::session::config;
|
use rustc::session::config::{self, Lto};
|
||||||
use rustc::util::common::time;
|
use rustc::util::common::time;
|
||||||
use time_graph::Timeline;
|
use time_graph::Timeline;
|
||||||
use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource};
|
use {ModuleTranslation, ModuleLlvm, ModuleKind, ModuleSource};
|
||||||
@ -95,25 +95,22 @@ impl LtoModuleTranslation {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub enum LTOMode {
|
|
||||||
WholeCrateGraph,
|
|
||||||
JustThisCrate,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) fn run(cgcx: &CodegenContext,
|
pub(crate) fn run(cgcx: &CodegenContext,
|
||||||
modules: Vec<ModuleTranslation>,
|
modules: Vec<ModuleTranslation>,
|
||||||
mode: LTOMode,
|
timeline: &mut Timeline)
|
||||||
timeline: &mut Timeline)
|
|
||||||
-> Result<Vec<LtoModuleTranslation>, FatalError>
|
-> Result<Vec<LtoModuleTranslation>, FatalError>
|
||||||
{
|
{
|
||||||
let diag_handler = cgcx.create_diag_handler();
|
let diag_handler = cgcx.create_diag_handler();
|
||||||
let export_threshold = match mode {
|
let export_threshold = match cgcx.lto {
|
||||||
LTOMode::WholeCrateGraph => {
|
// We're just doing LTO for our one crate
|
||||||
|
Lto::ThinLocal => SymbolExportLevel::Rust,
|
||||||
|
|
||||||
|
// We're doing LTO for the entire crate graph
|
||||||
|
Lto::Yes | Lto::Fat | Lto::Thin => {
|
||||||
symbol_export::crates_export_threshold(&cgcx.crate_types)
|
symbol_export::crates_export_threshold(&cgcx.crate_types)
|
||||||
}
|
}
|
||||||
LTOMode::JustThisCrate => {
|
|
||||||
SymbolExportLevel::Rust
|
Lto::No => panic!("didn't request LTO but we're doing LTO"),
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
|
let symbol_filter = &|&(ref name, _, level): &(String, _, SymbolExportLevel)| {
|
||||||
@ -140,7 +137,7 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
|||||||
// We save off all the bytecode and LLVM module ids for later processing
|
// We save off all the bytecode and LLVM module ids for later processing
|
||||||
// with either fat or thin LTO
|
// with either fat or thin LTO
|
||||||
let mut upstream_modules = Vec::new();
|
let mut upstream_modules = Vec::new();
|
||||||
if let LTOMode::WholeCrateGraph = mode {
|
if cgcx.lto != Lto::ThinLocal {
|
||||||
if cgcx.opts.cg.prefer_dynamic {
|
if cgcx.opts.cg.prefer_dynamic {
|
||||||
diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
|
diag_handler.struct_err("cannot prefer dynamic linking when performing LTO")
|
||||||
.note("only 'staticlib', 'bin', and 'cdylib' outputs are \
|
.note("only 'staticlib', 'bin', and 'cdylib' outputs are \
|
||||||
@ -186,13 +183,16 @@ pub(crate) fn run(cgcx: &CodegenContext,
|
|||||||
}
|
}
|
||||||
|
|
||||||
let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
|
let arr = symbol_white_list.iter().map(|c| c.as_ptr()).collect::<Vec<_>>();
|
||||||
match mode {
|
match cgcx.lto {
|
||||||
LTOMode::WholeCrateGraph if !cgcx.thinlto => {
|
Lto::Yes | // `-C lto` == fat LTO by default
|
||||||
|
Lto::Fat => {
|
||||||
fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
|
fat_lto(cgcx, &diag_handler, modules, upstream_modules, &arr, timeline)
|
||||||
}
|
}
|
||||||
_ => {
|
Lto::Thin |
|
||||||
|
Lto::ThinLocal => {
|
||||||
thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
|
thin_lto(&diag_handler, modules, upstream_modules, &arr, timeline)
|
||||||
}
|
}
|
||||||
|
Lto::No => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
|
|||||||
use rustc::dep_graph::{DepGraph, WorkProductFileKind};
|
use rustc::dep_graph::{DepGraph, WorkProductFileKind};
|
||||||
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
|
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
|
||||||
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
|
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
|
||||||
AllPasses, Sanitizer};
|
AllPasses, Sanitizer, Lto};
|
||||||
use rustc::session::Session;
|
use rustc::session::Session;
|
||||||
use rustc::util::nodemap::FxHashMap;
|
use rustc::util::nodemap::FxHashMap;
|
||||||
use rustc_back::LinkerFlavor;
|
use rustc_back::LinkerFlavor;
|
||||||
@ -329,8 +329,7 @@ struct AssemblerCommand {
|
|||||||
pub struct CodegenContext {
|
pub struct CodegenContext {
|
||||||
// Resouces needed when running LTO
|
// Resouces needed when running LTO
|
||||||
pub time_passes: bool,
|
pub time_passes: bool,
|
||||||
pub lto: bool,
|
pub lto: Lto,
|
||||||
pub thinlto: bool,
|
|
||||||
pub no_landing_pads: bool,
|
pub no_landing_pads: bool,
|
||||||
pub save_temps: bool,
|
pub save_temps: bool,
|
||||||
pub fewer_names: bool,
|
pub fewer_names: bool,
|
||||||
@ -589,12 +588,7 @@ fn generate_lto_work(cgcx: &CodegenContext,
|
|||||||
TRANS_WORK_PACKAGE_KIND,
|
TRANS_WORK_PACKAGE_KIND,
|
||||||
"generate lto")
|
"generate lto")
|
||||||
}).unwrap_or(Timeline::noop());
|
}).unwrap_or(Timeline::noop());
|
||||||
let mode = if cgcx.lto {
|
let lto_modules = lto::run(cgcx, modules, &mut timeline)
|
||||||
lto::LTOMode::WholeCrateGraph
|
|
||||||
} else {
|
|
||||||
lto::LTOMode::JustThisCrate
|
|
||||||
};
|
|
||||||
let lto_modules = lto::run(cgcx, modules, mode, &mut timeline)
|
|
||||||
.unwrap_or_else(|e| panic!(e));
|
.unwrap_or_else(|e| panic!(e));
|
||||||
|
|
||||||
lto_modules.into_iter().map(|module| {
|
lto_modules.into_iter().map(|module| {
|
||||||
@ -1296,28 +1290,51 @@ fn execute_work_item(cgcx: &CodegenContext,
|
|||||||
unsafe {
|
unsafe {
|
||||||
optimize(cgcx, &diag_handler, &mtrans, config, timeline)?;
|
optimize(cgcx, &diag_handler, &mtrans, config, timeline)?;
|
||||||
|
|
||||||
let lto = cgcx.lto;
|
// After we've done the initial round of optimizations we need to
|
||||||
|
// decide whether to synchronously codegen this module or ship it
|
||||||
let auto_thin_lto =
|
// back to the coordinator thread for further LTO processing (which
|
||||||
cgcx.thinlto &&
|
// has to wait for all the initial modules to be optimized).
|
||||||
cgcx.total_cgus > 1 &&
|
|
||||||
mtrans.kind != ModuleKind::Allocator;
|
|
||||||
|
|
||||||
// If we're a metadata module we never participate in LTO.
|
|
||||||
//
|
//
|
||||||
// If LTO was explicitly requested on the command line, we always
|
// Here we dispatch based on the `cgcx.lto` and kind of module we're
|
||||||
// LTO everything else.
|
// translating...
|
||||||
//
|
let needs_lto = match cgcx.lto {
|
||||||
// If LTO *wasn't* explicitly requested and we're not a metdata
|
Lto::No => false,
|
||||||
// module, then we may automatically do ThinLTO if we've got
|
|
||||||
// multiple codegen units. Note, however, that the allocator module
|
// Here we've got a full crate graph LTO requested. We ignore
|
||||||
// doesn't participate here automatically because of linker
|
// this, however, if the crate type is only an rlib as there's
|
||||||
// shenanigans later on.
|
// no full crate graph to process, that'll happen later.
|
||||||
if mtrans.kind == ModuleKind::Metadata || (!lto && !auto_thin_lto) {
|
//
|
||||||
|
// This use case currently comes up primarily for targets that
|
||||||
|
// require LTO so the request for LTO is always unconditionally
|
||||||
|
// passed down to the backend, but we don't actually want to do
|
||||||
|
// anything about it yet until we've got a final product.
|
||||||
|
Lto::Yes | Lto::Fat | Lto::Thin => {
|
||||||
|
cgcx.crate_types.len() != 1 ||
|
||||||
|
cgcx.crate_types[0] != config::CrateTypeRlib
|
||||||
|
}
|
||||||
|
|
||||||
|
// When we're automatically doing ThinLTO for multi-codegen-unit
|
||||||
|
// builds we don't actually want to LTO the allocator modules if
|
||||||
|
// it shows up. This is due to various linker shenanigans that
|
||||||
|
// we'll encounter later.
|
||||||
|
//
|
||||||
|
// Additionally here's where we also factor in the current LLVM
|
||||||
|
// version. If it doesn't support ThinLTO we skip this.
|
||||||
|
Lto::ThinLocal => {
|
||||||
|
mtrans.kind != ModuleKind::Allocator &&
|
||||||
|
llvm::LLVMRustThinLTOAvailable()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Metadata modules never participate in LTO regardless of the lto
|
||||||
|
// settings.
|
||||||
|
let needs_lto = needs_lto && mtrans.kind != ModuleKind::Metadata;
|
||||||
|
|
||||||
|
if needs_lto {
|
||||||
|
Ok(WorkItemResult::NeedsLTO(mtrans))
|
||||||
|
} else {
|
||||||
let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?;
|
let module = codegen(cgcx, &diag_handler, mtrans, config, timeline)?;
|
||||||
Ok(WorkItemResult::Compiled(module))
|
Ok(WorkItemResult::Compiled(module))
|
||||||
} else {
|
|
||||||
Ok(WorkItemResult::NeedsLTO(mtrans))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1393,10 +1410,6 @@ fn start_executing_work(tcx: TyCtxt,
|
|||||||
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
|
each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
|
||||||
}));
|
}));
|
||||||
|
|
||||||
let crate_types = sess.crate_types.borrow();
|
|
||||||
let only_rlib = crate_types.len() == 1 &&
|
|
||||||
crate_types[0] == config::CrateTypeRlib;
|
|
||||||
|
|
||||||
let wasm_import_memory =
|
let wasm_import_memory =
|
||||||
attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory");
|
attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory");
|
||||||
|
|
||||||
@ -1415,18 +1428,7 @@ fn start_executing_work(tcx: TyCtxt,
|
|||||||
let cgcx = CodegenContext {
|
let cgcx = CodegenContext {
|
||||||
crate_types: sess.crate_types.borrow().clone(),
|
crate_types: sess.crate_types.borrow().clone(),
|
||||||
each_linked_rlib_for_lto,
|
each_linked_rlib_for_lto,
|
||||||
// If we're only building an rlibc then allow the LTO flag to be passed
|
lto: sess.lto(),
|
||||||
// but don't actually do anything, the full LTO will happen later
|
|
||||||
lto: sess.lto() && !only_rlib,
|
|
||||||
|
|
||||||
// Enable ThinLTO if requested, but only if the target we're compiling
|
|
||||||
// for doesn't require full LTO. Some targets require one LLVM module
|
|
||||||
// (they effectively don't have a linker) so it's up to us to use LTO to
|
|
||||||
// link everything together.
|
|
||||||
thinlto: sess.thinlto() &&
|
|
||||||
!sess.target.target.options.requires_lto &&
|
|
||||||
unsafe { llvm::LLVMRustThinLTOAvailable() },
|
|
||||||
|
|
||||||
no_landing_pads: sess.no_landing_pads(),
|
no_landing_pads: sess.no_landing_pads(),
|
||||||
fewer_names: sess.fewer_names(),
|
fewer_names: sess.fewer_names(),
|
||||||
save_temps: sess.opts.cg.save_temps,
|
save_temps: sess.opts.cg.save_temps,
|
||||||
|
@ -16,11 +16,11 @@ all:
|
|||||||
$(RUSTC) -C extra-filename=foo dummy.rs 2>&1
|
$(RUSTC) -C extra-filename=foo dummy.rs 2>&1
|
||||||
#Option taking no argument
|
#Option taking no argument
|
||||||
$(RUSTC) -C lto= dummy.rs 2>&1 | \
|
$(RUSTC) -C lto= dummy.rs 2>&1 | \
|
||||||
$(CGREP) 'codegen option `lto` takes no value'
|
$(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
|
||||||
$(RUSTC) -C lto=1 dummy.rs 2>&1 | \
|
$(RUSTC) -C lto=1 dummy.rs 2>&1 | \
|
||||||
$(CGREP) 'codegen option `lto` takes no value'
|
$(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
|
||||||
$(RUSTC) -C lto=foo dummy.rs 2>&1 | \
|
$(RUSTC) -C lto=foo dummy.rs 2>&1 | \
|
||||||
$(CGREP) 'codegen option `lto` takes no value'
|
$(CGREP) 'codegen option `lto` - one of `thin`, `fat`, or'
|
||||||
$(RUSTC) -C lto dummy.rs
|
$(RUSTC) -C lto dummy.rs
|
||||||
|
|
||||||
# Should not link dead code...
|
# Should not link dead code...
|
||||||
|
17
src/test/run-pass/fat-lto.rs
Normal file
17
src/test/run-pass/fat-lto.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2018 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: -Clto=fat
|
||||||
|
// no-prefer-dynamic
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("hello!");
|
||||||
|
}
|
||||||
|
|
17
src/test/run-pass/thinlto/all-crates.rs
Normal file
17
src/test/run-pass/thinlto/all-crates.rs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
// Copyright 2018 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: -Clto=thin
|
||||||
|
// no-prefer-dynamic
|
||||||
|
// min-llvm-version 4.0
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("hello!");
|
||||||
|
}
|
@ -8,7 +8,7 @@
|
|||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
// compile-flags: -Z thinlto -C codegen-units=8 -O -C lto
|
// compile-flags: -C codegen-units=8 -O -C lto=thin
|
||||||
// aux-build:thin-lto-inlines-aux.rs
|
// aux-build:thin-lto-inlines-aux.rs
|
||||||
// min-llvm-version 4.0
|
// min-llvm-version 4.0
|
||||||
// no-prefer-dynamic
|
// no-prefer-dynamic
|
||||||
|
Loading…
Reference in New Issue
Block a user