*self.name_map.entry(ident).or_insert_with(|| Symbol::from_ident(ident))
}
- fn lower_opt_sp_ident(&mut self, o_id: Option<Spanned<Ident>>) -> Option<Spanned<Name>> {
- o_id.map(|sp_ident| respan(sp_ident.span, sp_ident.node.name))
+ fn lower_label(&mut self, label: Option<Label>) -> Option<hir::Label> {
+ label.map(|label| hir::Label { name: label.ident.name, span: label.span })
}
- fn lower_loop_destination(&mut self, destination: Option<(NodeId, Spanned<Ident>)>)
+ fn lower_loop_destination(&mut self, destination: Option<(NodeId, Label)>)
-> hir::Destination
{
match destination {
- Some((id, label_ident)) => {
+ Some((id, label)) => {
let target = if let Def::Label(loop_id) = self.expect_full_def(id) {
hir::LoopIdResult::Ok(self.lower_node_id(loop_id).node_id)
} else {
hir::LoopIdResult::Err(hir::LoopIdError::UnresolvedLabel)
};
hir::Destination {
- ident: Some(label_ident),
+ label: self.lower_label(Some(label)),
target_id: hir::ScopeTarget::Loop(target),
}
},
.map(|innermost_loop_id| *innermost_loop_id);
hir::Destination {
- ident: None,
+ label: None,
target_id: hir::ScopeTarget::Loop(
loop_id.map(|id| Ok(self.lower_node_id(id).node_id))
.unwrap_or(Err(hir::LoopIdError::OutsideLoopScope))
hir::ExprIf(P(self.lower_expr(cond)), P(then_expr), else_opt)
}
- ExprKind::While(ref cond, ref body, opt_ident) => {
+ ExprKind::While(ref cond, ref body, opt_label) => {
self.with_loop_scope(e.id, |this|
hir::ExprWhile(
this.with_loop_condition_scope(|this| P(this.lower_expr(cond))),
this.lower_block(body, false),
- this.lower_opt_sp_ident(opt_ident)))
+ this.lower_label(opt_label)))
}
- ExprKind::Loop(ref body, opt_ident) => {
+ ExprKind::Loop(ref body, opt_label) => {
self.with_loop_scope(e.id, |this|
hir::ExprLoop(this.lower_block(body, false),
- this.lower_opt_sp_ident(opt_ident),
+ this.lower_label(opt_label),
hir::LoopSource::Loop))
}
ExprKind::Catch(ref body) => {
(&None, &Some(..), Closed) => "RangeToInclusive",
(&Some(..), &Some(..), Closed) => "RangeInclusive",
(_, &None, Closed) =>
- panic!(self.diagnostic().span_fatal(
- e.span, "inclusive range with no end")),
+ self.diagnostic().span_fatal(
+ e.span, "inclusive range with no end").raise(),
};
let fields =
hir::ExprPath(self.lower_qpath(e.id, qself, path, ParamMode::Optional,
ImplTraitContext::Disallowed))
}
- ExprKind::Break(opt_ident, ref opt_expr) => {
- let label_result = if self.is_in_loop_condition && opt_ident.is_none() {
+ ExprKind::Break(opt_label, ref opt_expr) => {
+ let destination = if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
- ident: opt_ident,
+ label: None,
target_id: hir::ScopeTarget::Loop(
Err(hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
}
} else {
- self.lower_loop_destination(opt_ident.map(|ident| (e.id, ident)))
+ self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
};
hir::ExprBreak(
- label_result,
+ destination,
opt_expr.as_ref().map(|x| P(self.lower_expr(x))))
}
- ExprKind::Continue(opt_ident) =>
+ ExprKind::Continue(opt_label) =>
hir::ExprAgain(
- if self.is_in_loop_condition && opt_ident.is_none() {
+ if self.is_in_loop_condition && opt_label.is_none() {
hir::Destination {
- ident: opt_ident,
+ label: None,
target_id: hir::ScopeTarget::Loop(Err(
hir::LoopIdError::UnlabeledCfInWhileCondition).into()),
}
} else {
- self.lower_loop_destination(opt_ident.map( |ident| (e.id, ident)))
+ self.lower_loop_destination(opt_label.map(|label| (e.id, label)))
}),
ExprKind::Ret(ref e) => hir::ExprRet(e.as_ref().map(|x| P(self.lower_expr(x)))),
ExprKind::InlineAsm(ref asm) => {
// Desugar ExprWhileLet
// From: `[opt_ident]: while let <pat> = <sub_expr> <body>`
- ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_ident) => {
+ ExprKind::WhileLet(ref pat, ref sub_expr, ref body, opt_label) => {
// to:
//
// [opt_ident]: loop {
// `[opt_ident]: loop { ... }`
let loop_block = P(self.block_expr(P(match_expr)));
- let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+ let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
hir::LoopSource::WhileLet);
// add attributes to the outer returned expr node
loop_expr
// Desugar ExprForLoop
// From: `[opt_ident]: for <pat> in <head> <body>`
- ExprKind::ForLoop(ref pat, ref head, ref body, opt_ident) => {
+ ExprKind::ForLoop(ref pat, ref head, ref body, opt_label) => {
// to:
//
// {
None));
// `[opt_ident]: loop { ... }`
- let loop_expr = hir::ExprLoop(loop_block, self.lower_opt_sp_ident(opt_ident),
+ let loop_expr = hir::ExprLoop(loop_block, self.lower_label(opt_label),
hir::LoopSource::ForLoop);
let LoweredNodeId { node_id, hir_id } = self.lower_node_id(e.id);
let loop_expr = P(hir::Expr {
e.span,
hir::ExprBreak(
hir::Destination {
- ident: None,
+ label: None,
target_id: hir::ScopeTarget::Block(catch_node),
},
Some(from_err_expr)
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)]
pub enum DebugInfoLevel {
NoDebugInfo,
// commands like `--emit llvm-ir` which they're often incompatible with
// if we otherwise use the defaults of rustc.
cli_forced_codegen_units: Option<usize> [UNTRACKED],
- cli_forced_thinlto: Option<bool> [UNTRACKED],
+ cli_forced_thinlto_off: bool [UNTRACKED],
}
);
debug_assertions: true,
actually_rustdoc: false,
cli_forced_codegen_units: None,
- cli_forced_thinlto: None,
+ cli_forced_thinlto_off: false,
}
}
Some("crate=integer");
pub const parse_unpretty: Option<&'static str> =
Some("`string` or `string=string`");
+ pub const parse_lto: Option<&'static str> =
+ Some("one of `thin`, `fat`, or omitted");
}
#[allow(dead_code)]
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 std::path::PathBuf;
_ => 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
+ }
}
) }
"extra arguments to append to the linker invocation (space separated)"),
link_dead_code: bool = (false, parse_bool, [UNTRACKED],
"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"),
target_cpu: Option<String> = (None, parse_opt_string, [TRACKED],
"select target processor (rustc --print target-cpus for details)"),
sp.struct_fatal(&format!("Error loading target specification: {}", e))
.help("Use `--print target-list` for a list of built-in targets")
.emit();
- panic!(FatalError);
+ FatalError.raise();
}
};
"16" => (ast::IntTy::I16, ast::UintTy::U16),
"32" => (ast::IntTy::I32, ast::UintTy::U32),
"64" => (ast::IntTy::I64, ast::UintTy::U64),
- w => panic!(sp.fatal(&format!("target specification was invalid: \
- unrecognized target-pointer-width {}", w))),
+ w => sp.fatal(&format!("target specification was invalid: \
+ unrecognized target-pointer-width {}", w)).raise(),
};
Config {
let mut cg = build_codegen_options(matches, error_format);
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
// particular path, disable codegen-units.
}
early_warn(error_format, "resetting to default -C codegen-units=1");
codegen_units = Some(1);
- thinlto = Some(false);
+ disable_thinlto = true;
}
}
_ => {
codegen_units = Some(1);
- thinlto = Some(false);
+ disable_thinlto = true;
}
}
}
(&None, &None) => None,
}.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");
}
debug_assertions,
actually_rustdoc: false,
cli_forced_codegen_units: codegen_units,
- cli_forced_thinlto: thinlto,
+ cli_forced_thinlto_off: disable_thinlto,
},
cfg)
}
use std::hash::Hash;
use std::path::PathBuf;
use std::collections::hash_map::DefaultHasher;
- use super::{Passes, CrateType, OptLevel, DebugInfoLevel,
+ use super::{Passes, CrateType, OptLevel, DebugInfoLevel, Lto,
OutputTypes, Externs, ErrorOutputType, Sanitizer};
use syntax::feature_gate::UnstableFeatures;
use rustc_back::{PanicStrategy, RelroLevel};
impl_dep_tracking_hash_via_hash!(RelroLevel);
impl_dep_tracking_hash_via_hash!(Passes);
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!(UnstableFeatures);
impl_dep_tracking_hash_via_hash!(Externs);
use lint;
use middle::cstore;
use session::config::{build_configuration, build_session_options_and_crate_config};
+ use session::config::Lto;
use session::build_session;
use std::collections::{BTreeMap, BTreeSet};
use std::iter::FromIterator;
// Make sure changing a [TRACKED] option changes the hash
opts = reference.clone();
- opts.cg.lto = true;
+ opts.cg.lto = Lto::Fat;
assert!(reference.dep_tracking_hash() != opts.dep_tracking_hash());
opts = reference.clone();
}
pub fn span_fatal<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
- panic!(self.diagnostic().span_fatal(sp, msg))
+ self.diagnostic().span_fatal(sp, msg).raise()
}
pub fn span_fatal_with_code<S: Into<MultiSpan>>(
&self,
msg: &str,
code: DiagnosticId,
) -> ! {
- panic!(self.diagnostic().span_fatal_with_code(sp, msg, code))
+ self.diagnostic().span_fatal_with_code(sp, msg, code).raise()
}
pub fn fatal(&self, msg: &str) -> ! {
- panic!(self.diagnostic().fatal(msg))
+ self.diagnostic().fatal(msg).raise()
}
pub fn span_err_or_warn<S: Into<MultiSpan>>(&self, is_warning: bool, sp: S, msg: &str) {
if is_warning {
self.use_mir()
}
- pub fn lto(&self) -> bool {
- self.opts.cg.lto || self.target.target.options.requires_lto
+ /// Calculates the flavor of LTO to use for this compilation.
+ 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
/// using '-C panic', use that, otherwise use the panic strategy defined by the target.
pub fn panic_strategy(&self) -> PanicStrategy {
// scientific.
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,
let host = match Target::search(config::host_triple()) {
Ok(t) => t,
Err(e) => {
- panic!(span_diagnostic.fatal(&format!("Error loading host specification: {}", e)));
+ span_diagnostic.fatal(&format!("Error loading host specification: {}", e)).raise();
}
};
let target_cfg = config::build_target_config(&sopts, &span_diagnostic);
let working_dir = match env::current_dir() {
Ok(dir) => dir,
Err(e) => {
- panic!(p_s.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)))
+ p_s.span_diagnostic.fatal(&format!("Current directory is invalid: {}", e)).raise()
}
};
let working_dir = file_path_mapping.map_prefix(working_dir);
};
let handler = errors::Handler::with_emitter(true, false, emitter);
handler.emit(&MultiSpan::new(), msg, errors::Level::Fatal);
- panic!(errors::FatalError);
+ errors::FatalError.raise();
}
pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
use back::lto::{self, ModuleBuffer, ThinBuffer};
use back::link::{self, get_linker, remove};
+use back::command::Command;
use back::linker::LinkerInfo;
use back::symbol_export::ExportedSymbols;
use base;
use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
use rustc::dep_graph::{DepGraph, WorkProductFileKind};
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
-use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
- AllPasses, Sanitizer};
+use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
+ AllPasses, Sanitizer, Lto};
use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
use rustc_back::LinkerFlavor;
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
use rustc::ty::TyCtxt;
use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry};
-use rustc::util::fs::{link_or_copy, rename_or_copy_remove};
+use rustc::util::fs::{link_or_copy};
use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
use errors::emitter::{Emitter};
use syntax::attr;
("ropi-rwpi", llvm::RelocMode::ROPI_RWPI),
];
-pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [
- ("default", llvm::CodeModel::Default),
+pub const CODE_GEN_MODEL_ARGS: &[(&str, llvm::CodeModel)] = &[
("small", llvm::CodeModel::Small),
("kernel", llvm::CodeModel::Kernel),
("medium", llvm::CodeModel::Medium),
pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
target_machine_factory(sess)().unwrap_or_else(|err| {
- panic!(llvm_err(sess.diagnostic(), err))
+ llvm_err(sess.diagnostic(), err).raise()
})
}
let ffunction_sections = sess.target.target.options.function_sections;
let fdata_sections = ffunction_sections;
- let code_model_arg = match sess.opts.cg.code_model {
- Some(ref s) => &s,
- None => &sess.target.target.options.code_model,
- };
-
- let code_model = match CODE_GEN_MODEL_ARGS.iter().find(
- |&&arg| arg.0 == code_model_arg) {
- Some(x) => x.1,
- _ => {
- sess.err(&format!("{:?} is not a valid code model",
- code_model_arg));
- sess.abort_if_errors();
- bug!();
+ let code_model_arg = sess.opts.cg.code_model.as_ref().or(
+ sess.target.target.options.code_model.as_ref(),
+ );
+
+ let code_model = match code_model_arg {
+ Some(s) => {
+ match CODE_GEN_MODEL_ARGS.iter().find(|arg| arg.0 == s) {
+ Some(x) => x.1,
+ _ => {
+ sess.err(&format!("{:?} is not a valid code model",
+ code_model_arg));
+ sess.abort_if_errors();
+ bug!();
+ }
+ }
}
+ None => llvm::CodeModel::None,
};
let singlethread = sess.target.target.options.singlethread;
// make the object file bitcode. Provides easy compatibility with
// emscripten's ecc compiler, when used as the linker.
obj_is_bitcode: bool,
+ no_integrated_as: bool,
}
impl ModuleConfig {
emit_asm: false,
emit_obj: false,
obj_is_bitcode: false,
+ no_integrated_as: false,
no_verify: false,
no_prepopulate_passes: false,
}
}
+/// Assembler name and command used by codegen when no_integrated_as is enabled
+struct AssemblerCommand {
+ name: PathBuf,
+ cmd: Command,
+}
+
/// Additional resources used by optimize_and_codegen (not module specific)
#[derive(Clone)]
pub struct CodegenContext {
// Resouces needed when running LTO
pub time_passes: bool,
- pub lto: bool,
- pub thinlto: bool,
+ pub lto: Lto,
pub no_landing_pads: bool,
pub save_temps: bool,
pub fewer_names: bool,
// A reference to the TimeGraph so we can register timings. None means that
// measuring is disabled.
time_graph: Option<TimeGraph>,
+ // The assembler command if no_integrated_as option is enabled, None otherwise
+ assembler_cmd: Option<Arc<AssemblerCommand>>,
}
impl CodegenContext {
TRANS_WORK_PACKAGE_KIND,
"generate lto")
}).unwrap_or(Timeline::noop());
- let mode = if cgcx.lto {
- lto::LTOMode::WholeCrateGraph
- } else {
- lto::LTOMode::JustThisCrate
- };
- let lto_modules = lto::run(cgcx, modules, mode, &mut timeline)
+ let lto_modules = lto::run(cgcx, modules, &mut timeline)
- .unwrap_or_else(|e| panic!(e));
+ .unwrap_or_else(|e| e.raise());
lto_modules.into_iter().map(|module| {
let cost = module.cost();
!cgcx.crate_types.contains(&config::CrateTypeRlib) &&
mtrans.kind == ModuleKind::Regular;
+ // If we don't have the integrated assembler, then we need to emit asm
+ // from LLVM and use `gcc` to create the object file.
+ let asm_to_obj = config.emit_obj && config.no_integrated_as;
+
// Change what we write and cleanup based on whether obj files are
// just llvm bitcode. In that case write bitcode, and possibly
// delete the bitcode if it wasn't requested. Don't generate the
// machine code, instead copy the .o file from the .bc
let write_bc = config.emit_bc || (config.obj_is_bitcode && !asm2wasm);
let rm_bc = !config.emit_bc && config.obj_is_bitcode && !asm2wasm;
- let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm;
+ let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm && !asm_to_obj;
let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode && !asm2wasm;
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
timeline.record("ir");
}
- if config.emit_asm || (asm2wasm && config.emit_obj) {
+ if config.emit_asm || (asm2wasm && config.emit_obj) || asm_to_obj {
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
// We can't use the same module for asm and binary output, because that triggers
// various errors like invalid IR or broken binaries, so we might have to clone the
// module to produce the asm output
- let llmod = if config.emit_obj {
+ let llmod = if config.emit_obj && !asm2wasm {
llvm::LLVMCloneModule(llmod)
} else {
llmod
write_output_file(diag_handler, tm, cpm, llmod, &path,
llvm::FileType::AssemblyFile)
})?;
- if config.emit_obj {
+ if config.emit_obj && !asm2wasm {
llvm::LLVMDisposeModule(llmod);
}
timeline.record("asm");
llvm::FileType::ObjectFile)
})?;
timeline.record("obj");
+ } else if asm_to_obj {
+ let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
+ run_assembler(cgcx, diag_handler, &assembly, &obj_out);
+ timeline.record("asm_to_obj");
+
+ if !config.emit_asm && !cgcx.save_temps {
+ drop(fs::remove_file(&assembly));
+ }
}
Ok(())
total_cgus: usize)
-> OngoingCrateTranslation {
let sess = tcx.sess;
- let crate_output = tcx.output_filenames(LOCAL_CRATE);
let crate_name = tcx.crate_name(LOCAL_CRATE);
let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins");
let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs,
subsystem.to_string()
});
- let no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
- (tcx.sess.target.target.options.no_integrated_as &&
- (crate_output.outputs.contains_key(&OutputType::Object) ||
- crate_output.outputs.contains_key(&OutputType::Exe)));
let linker_info = LinkerInfo::new(tcx);
let crate_info = CrateInfo::new(tcx);
- let output_types_override = if no_integrated_as {
- OutputTypes::new(&[(OutputType::Assembly, None)])
- } else {
- sess.opts.output_types.clone()
- };
-
// Figure out what we actually need to build.
let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone());
let mut metadata_config = ModuleConfig::new(vec![]);
allocator_config.emit_bc_compressed = true;
}
- for output_type in output_types_override.keys() {
+ modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
+ tcx.sess.target.target.options.no_integrated_as;
+
+ for output_type in sess.opts.output_types.keys() {
match *output_type {
OutputType::Bitcode => { modules_config.emit_bc = true; }
OutputType::LlvmAssembly => { modules_config.emit_ir = true; }
metadata,
windows_subsystem,
linker_info,
- no_integrated_as,
crate_info,
time_graph,
unsafe {
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
+ // back to the coordinator thread for further LTO processing (which
+ // has to wait for all the initial modules to be optimized).
+ //
+ // Here we dispatch based on the `cgcx.lto` and kind of module we're
+ // translating...
+ let needs_lto = match cgcx.lto {
+ Lto::No => false,
+
+ // Here we've got a full crate graph LTO requested. We ignore
+ // this, however, if the crate type is only an rlib as there's
+ // no full crate graph to process, that'll happen later.
+ //
+ // 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
+ }
- let auto_thin_lto =
- cgcx.thinlto &&
- cgcx.total_cgus > 1 &&
- mtrans.kind != ModuleKind::Allocator;
+ // 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()
+ }
+ };
- // If we're a metadata module we never participate in LTO.
- //
- // If LTO was explicitly requested on the command line, we always
- // LTO everything else.
- //
- // If LTO *wasn't* explicitly requested and we're not a metdata
- // module, then we may automatically do ThinLTO if we've got
- // multiple codegen units. Note, however, that the allocator module
- // doesn't participate here automatically because of linker
- // shenanigans later on.
- if mtrans.kind == ModuleKind::Metadata || (!lto && !auto_thin_lto) {
+ // 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)?;
Ok(WorkItemResult::Compiled(module))
- } else {
- Ok(WorkItemResult::NeedsLTO(mtrans))
}
}
}
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 =
attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory");
+ let assembler_cmd = if modules_config.no_integrated_as {
+ // HACK: currently we use linker (gcc) as our assembler
+ let (name, mut cmd, _) = get_linker(sess);
+ cmd.args(&sess.target.target.options.asm_args);
+ Some(Arc::new(AssemblerCommand {
+ name,
+ cmd,
+ }))
+ } else {
+ None
+ };
+
let cgcx = CodegenContext {
crate_types: sess.crate_types.borrow().clone(),
each_linked_rlib_for_lto,
- // If we're only building an rlibc then allow the LTO flag to be passed
- // 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() },
-
+ lto: sess.lto(),
no_landing_pads: sess.no_landing_pads(),
fewer_names: sess.fewer_names(),
save_temps: sess.opts.cg.save_temps,
binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
debuginfo: tcx.sess.opts.debuginfo,
wasm_import_memory: wasm_import_memory,
+ assembler_cmd,
};
// This is the "main loop" of parallel work happening for parallel codegen.
});
}
-pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
- let (pname, mut cmd, _) = get_linker(sess);
-
- for arg in &sess.target.target.options.asm_args {
- cmd.arg(arg);
- }
+pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, object: &Path) {
+ let assembler = cgcx.assembler_cmd
+ .as_ref()
+ .expect("cgcx.assembler_cmd is missing?");
- cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
- .arg(&outputs.temp_path(OutputType::Assembly, None));
+ let pname = &assembler.name;
+ let mut cmd = assembler.cmd.clone();
+ cmd.arg("-c").arg("-o").arg(object).arg(assembly);
debug!("{:?}", cmd);
match cmd.output() {
let mut note = prog.stderr.clone();
note.extend_from_slice(&prog.stdout);
- sess.struct_err(&format!("linking with `{}` failed: {}",
- pname.display(),
- prog.status))
+ handler.struct_err(&format!("linking with `{}` failed: {}",
+ pname.display(),
+ prog.status))
.note(&format!("{:?}", &cmd))
.note(str::from_utf8(¬e[..]).unwrap())
.emit();
- sess.abort_if_errors();
+ handler.abort_if_errors();
}
},
Err(e) => {
- sess.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
- sess.abort_if_errors();
+ handler.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
+ handler.abort_if_errors();
}
}
}
metadata: EncodedMetadata,
windows_subsystem: Option<String>,
linker_info: LinkerInfo,
- no_integrated_as: bool,
crate_info: CrateInfo,
time_graph: Option<TimeGraph>,
coordinator_send: Sender<Box<Any + Send>>,
metadata_module: compiled_modules.metadata_module,
};
- if self.no_integrated_as {
- run_assembler(sess, &self.output_filenames);
-
- // HACK the linker expects the object file to be named foo.0.o but
- // `run_assembler` produces an object named just foo.o. Rename it if we
- // are going to build an executable
- if sess.opts.output_types.contains_key(&OutputType::Exe) {
- let f = self.output_filenames.path(OutputType::Object);
- rename_or_copy_remove(&f,
- f.with_file_name(format!("{}.0.o",
- f.file_stem().unwrap().to_string_lossy()))).unwrap();
- }
-
- // Remove assembly source, unless --save-temps was specified
- if !sess.opts.cg.save_temps {
- fs::remove_file(&self.output_filenames
- .temp_path(OutputType::Assembly, None)).unwrap();
- }
- }
-
trans
}