Skip to content

Commit

Permalink
Rollup merge of rust-lang#47453 - pftbest:nointas, r=alexcrichton
Browse files Browse the repository at this point in the history
Fix no_integrated_as option to work with new codegen architecture.

Old implementation called the assembler once per crate, but we need to call
it for each object file instead, because a single crate can now have more
than one object file.

This patch fixes issue rust-lang#45836 (Can't compile core for msp430 in release mode)

This change can be tested on x86_64 using
```sh
export RUSTFLAGS="-C no_integrated_as -C save_temps"
```

r? @alexcrichton
cc @japaric
  • Loading branch information
alexcrichton committed Jan 25, 2018
2 parents 6eb1430 + 98dee04 commit 1bdef2f
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 52 deletions.
109 changes: 57 additions & 52 deletions src/librustc_trans/back/write.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,15 @@
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 consts;
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,
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
AllPasses, Sanitizer};
use rustc::session::Session;
use rustc::util::nodemap::FxHashMap;
Expand All @@ -32,7 +33,7 @@ use CrateInfo;
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;
Expand Down Expand Up @@ -258,6 +259,7 @@ pub struct ModuleConfig {
// 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 {
Expand All @@ -275,6 +277,7 @@ impl ModuleConfig {
emit_asm: false,
emit_obj: false,
obj_is_bitcode: false,
no_integrated_as: false,

no_verify: false,
no_prepopulate_passes: false,
Expand Down Expand Up @@ -313,6 +316,12 @@ impl ModuleConfig {
}
}

/// 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 {
Expand Down Expand Up @@ -356,6 +365,8 @@ pub struct CodegenContext {
// 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 {
Expand Down Expand Up @@ -639,13 +650,17 @@ unsafe fn codegen(cgcx: &CodegenContext,
!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);
Expand Down Expand Up @@ -725,7 +740,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
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
Expand Down Expand Up @@ -760,6 +775,14 @@ unsafe fn codegen(cgcx: &CodegenContext,
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(())
Expand Down Expand Up @@ -841,7 +864,6 @@ pub fn start_async_translation(tcx: TyCtxt,
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,
Expand All @@ -855,19 +877,9 @@ pub fn start_async_translation(tcx: TyCtxt,
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![]);
Expand Down Expand Up @@ -913,7 +925,10 @@ pub fn start_async_translation(tcx: TyCtxt,
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; }
Expand Down Expand Up @@ -976,7 +991,6 @@ pub fn start_async_translation(tcx: TyCtxt,
metadata,
windows_subsystem,
linker_info,
no_integrated_as,
crate_info,

time_graph,
Expand Down Expand Up @@ -1384,6 +1398,18 @@ fn start_executing_work(tcx: TyCtxt,
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,
Expand Down Expand Up @@ -1423,6 +1449,7 @@ fn start_executing_work(tcx: TyCtxt,
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.
Expand Down Expand Up @@ -1931,15 +1958,14 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
});
}

pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
let (pname, mut cmd, _) = get_linker(sess);
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?");

for arg in &sess.target.target.options.asm_args {
cmd.arg(arg);
}

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() {
Expand All @@ -1948,18 +1974,18 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
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(&note[..]).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();
}
}
}
Expand Down Expand Up @@ -2133,7 +2159,6 @@ pub struct OngoingCrateTranslation {
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>>,
Expand Down Expand Up @@ -2189,26 +2214,6 @@ impl OngoingCrateTranslation {
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
}

Expand Down
7 changes: 7 additions & 0 deletions src/test/run-make/no-integrated-as/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
-include ../tools.mk

all:
ifeq ($(TARGET),x86_64-unknown-linux-gnu)
$(RUSTC) hello.rs -C no_integrated_as
$(call RUN,hello)
endif
13 changes: 13 additions & 0 deletions src/test/run-make/no-integrated-as/hello.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// 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.

fn main() {
println!("Hello, world!");
}

0 comments on commit 1bdef2f

Please sign in to comment.