Skip to content

Commit 3f61742

Browse files
committed
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)
1 parent 8ff449d commit 3f61742

File tree

2 files changed

+58
-52
lines changed

2 files changed

+58
-52
lines changed

src/librustc_trans/back/command.rs

+1
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use std::fmt;
1616
use std::io;
1717
use std::process::{self, Output, Child};
1818

19+
#[derive(Clone)]
1920
pub struct Command {
2021
program: OsString,
2122
args: Vec<OsString>,

src/librustc_trans/back/write.rs

+57-52
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,15 @@
1111
use back::bytecode::{self, RLIB_BYTECODE_EXTENSION};
1212
use back::lto::{self, ModuleBuffer, ThinBuffer};
1313
use back::link::{self, get_linker, remove};
14+
use back::command::Command;
1415
use back::linker::LinkerInfo;
1516
use back::symbol_export::ExportedSymbols;
1617
use base;
1718
use consts;
1819
use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
1920
use rustc::dep_graph::{DepGraph, WorkProductFileKind};
2021
use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
21-
use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
22+
use rustc::session::config::{self, OutputFilenames, OutputType, Passes, SomePasses,
2223
AllPasses, Sanitizer};
2324
use rustc::session::Session;
2425
use rustc::util::nodemap::FxHashMap;
@@ -32,7 +33,7 @@ use CrateInfo;
3233
use rustc::hir::def_id::{CrateNum, LOCAL_CRATE};
3334
use rustc::ty::TyCtxt;
3435
use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry};
35-
use rustc::util::fs::{link_or_copy, rename_or_copy_remove};
36+
use rustc::util::fs::{link_or_copy};
3637
use errors::{self, Handler, Level, DiagnosticBuilder, FatalError, DiagnosticId};
3738
use errors::emitter::{Emitter};
3839
use syntax::attr;
@@ -258,6 +259,7 @@ pub struct ModuleConfig {
258259
// make the object file bitcode. Provides easy compatibility with
259260
// emscripten's ecc compiler, when used as the linker.
260261
obj_is_bitcode: bool,
262+
no_integrated_as: bool,
261263
}
262264

263265
impl ModuleConfig {
@@ -275,6 +277,7 @@ impl ModuleConfig {
275277
emit_asm: false,
276278
emit_obj: false,
277279
obj_is_bitcode: false,
280+
no_integrated_as: false,
278281

279282
no_verify: false,
280283
no_prepopulate_passes: false,
@@ -313,6 +316,12 @@ impl ModuleConfig {
313316
}
314317
}
315318

319+
/// Assembler name and command used by codegen when no_integrated_as is enabled
320+
struct AssemblerCommand {
321+
name: PathBuf,
322+
cmd: Command,
323+
}
324+
316325
/// Additional resources used by optimize_and_codegen (not module specific)
317326
#[derive(Clone)]
318327
pub struct CodegenContext {
@@ -356,6 +365,8 @@ pub struct CodegenContext {
356365
// A reference to the TimeGraph so we can register timings. None means that
357366
// measuring is disabled.
358367
time_graph: Option<TimeGraph>,
368+
// The assembler command if no_integrated_as option is enabled, None otherwise
369+
assembler_cmd: Option<Arc<AssemblerCommand>>,
359370
}
360371

361372
impl CodegenContext {
@@ -639,13 +650,17 @@ unsafe fn codegen(cgcx: &CodegenContext,
639650
!cgcx.crate_types.contains(&config::CrateTypeRlib) &&
640651
mtrans.kind == ModuleKind::Regular;
641652

653+
// If we don't have the integrated assembler, then we need to emit asm
654+
// from LLVM and use `gcc` to create the object file.
655+
let asm_to_obj = config.emit_obj && config.no_integrated_as;
656+
642657
// Change what we write and cleanup based on whether obj files are
643658
// just llvm bitcode. In that case write bitcode, and possibly
644659
// delete the bitcode if it wasn't requested. Don't generate the
645660
// machine code, instead copy the .o file from the .bc
646661
let write_bc = config.emit_bc || (config.obj_is_bitcode && !asm2wasm);
647662
let rm_bc = !config.emit_bc && config.obj_is_bitcode && !asm2wasm;
648-
let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm;
663+
let write_obj = config.emit_obj && !config.obj_is_bitcode && !asm2wasm && !asm_to_obj;
649664
let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode && !asm2wasm;
650665

651666
let bc_out = cgcx.output_filenames.temp_path(OutputType::Bitcode, module_name);
@@ -725,7 +740,7 @@ unsafe fn codegen(cgcx: &CodegenContext,
725740
timeline.record("ir");
726741
}
727742

728-
if config.emit_asm || (asm2wasm && config.emit_obj) {
743+
if config.emit_asm || (asm2wasm && config.emit_obj) || asm_to_obj {
729744
let path = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
730745

731746
// We can't use the same module for asm and binary output, because that triggers
@@ -760,6 +775,14 @@ unsafe fn codegen(cgcx: &CodegenContext,
760775
llvm::FileType::ObjectFile)
761776
})?;
762777
timeline.record("obj");
778+
} else if asm_to_obj {
779+
let assembly = cgcx.output_filenames.temp_path(OutputType::Assembly, module_name);
780+
run_assembler(cgcx, diag_handler, &assembly, &obj_out);
781+
timeline.record("asm_to_obj");
782+
783+
if !config.emit_asm && !cgcx.save_temps {
784+
drop(fs::remove_file(&assembly));
785+
}
763786
}
764787

765788
Ok(())
@@ -841,7 +864,6 @@ pub fn start_async_translation(tcx: TyCtxt,
841864
total_cgus: usize)
842865
-> OngoingCrateTranslation {
843866
let sess = tcx.sess;
844-
let crate_output = tcx.output_filenames(LOCAL_CRATE);
845867
let crate_name = tcx.crate_name(LOCAL_CRATE);
846868
let no_builtins = attr::contains_name(&tcx.hir.krate().attrs, "no_builtins");
847869
let subsystem = attr::first_attr_value_str_by_name(&tcx.hir.krate().attrs,
@@ -855,19 +877,9 @@ pub fn start_async_translation(tcx: TyCtxt,
855877
subsystem.to_string()
856878
});
857879

858-
let no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
859-
(tcx.sess.target.target.options.no_integrated_as &&
860-
(crate_output.outputs.contains_key(&OutputType::Object) ||
861-
crate_output.outputs.contains_key(&OutputType::Exe)));
862880
let linker_info = LinkerInfo::new(tcx);
863881
let crate_info = CrateInfo::new(tcx);
864882

865-
let output_types_override = if no_integrated_as {
866-
OutputTypes::new(&[(OutputType::Assembly, None)])
867-
} else {
868-
sess.opts.output_types.clone()
869-
};
870-
871883
// Figure out what we actually need to build.
872884
let mut modules_config = ModuleConfig::new(sess.opts.cg.passes.clone());
873885
let mut metadata_config = ModuleConfig::new(vec![]);
@@ -913,7 +925,10 @@ pub fn start_async_translation(tcx: TyCtxt,
913925
allocator_config.emit_bc_compressed = true;
914926
}
915927

916-
for output_type in output_types_override.keys() {
928+
modules_config.no_integrated_as = tcx.sess.opts.cg.no_integrated_as ||
929+
tcx.sess.target.target.options.no_integrated_as;
930+
931+
for output_type in sess.opts.output_types.keys() {
917932
match *output_type {
918933
OutputType::Bitcode => { modules_config.emit_bc = true; }
919934
OutputType::LlvmAssembly => { modules_config.emit_ir = true; }
@@ -976,7 +991,6 @@ pub fn start_async_translation(tcx: TyCtxt,
976991
metadata,
977992
windows_subsystem,
978993
linker_info,
979-
no_integrated_as,
980994
crate_info,
981995

982996
time_graph,
@@ -1389,6 +1403,18 @@ fn start_executing_work(tcx: TyCtxt,
13891403
let wasm_import_memory =
13901404
attr::contains_name(&tcx.hir.krate().attrs, "wasm_import_memory");
13911405

1406+
let assembler_cmd = if modules_config.no_integrated_as {
1407+
// HACK: currently we use linker (gcc) as our assembler
1408+
let (name, mut cmd, _) = get_linker(sess);
1409+
cmd.args(&sess.target.target.options.asm_args);
1410+
Some(Arc::new(AssemblerCommand {
1411+
name,
1412+
cmd,
1413+
}))
1414+
} else {
1415+
None
1416+
};
1417+
13921418
let cgcx = CodegenContext {
13931419
crate_types: sess.crate_types.borrow().clone(),
13941420
each_linked_rlib_for_lto,
@@ -1428,6 +1454,7 @@ fn start_executing_work(tcx: TyCtxt,
14281454
binaryen_linker: tcx.sess.linker_flavor() == LinkerFlavor::Binaryen,
14291455
debuginfo: tcx.sess.opts.debuginfo,
14301456
wasm_import_memory: wasm_import_memory,
1457+
assembler_cmd,
14311458
};
14321459

14331460
// This is the "main loop" of parallel work happening for parallel codegen.
@@ -1936,15 +1963,14 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
19361963
});
19371964
}
19381965

1939-
pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
1940-
let (pname, mut cmd, _) = get_linker(sess);
1966+
pub fn run_assembler(cgcx: &CodegenContext, handler: &Handler, assembly: &Path, object: &Path) {
1967+
let assembler = cgcx.assembler_cmd
1968+
.as_ref()
1969+
.expect("cgcx.assembler_cmd is missing?");
19411970

1942-
for arg in &sess.target.target.options.asm_args {
1943-
cmd.arg(arg);
1944-
}
1945-
1946-
cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
1947-
.arg(&outputs.temp_path(OutputType::Assembly, None));
1971+
let pname = &assembler.name;
1972+
let mut cmd = assembler.cmd.clone();
1973+
cmd.arg("-c").arg("-o").arg(object).arg(assembly);
19481974
debug!("{:?}", cmd);
19491975

19501976
match cmd.output() {
@@ -1953,18 +1979,18 @@ pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
19531979
let mut note = prog.stderr.clone();
19541980
note.extend_from_slice(&prog.stdout);
19551981

1956-
sess.struct_err(&format!("linking with `{}` failed: {}",
1957-
pname.display(),
1958-
prog.status))
1982+
handler.struct_err(&format!("linking with `{}` failed: {}",
1983+
pname.display(),
1984+
prog.status))
19591985
.note(&format!("{:?}", &cmd))
19601986
.note(str::from_utf8(&note[..]).unwrap())
19611987
.emit();
1962-
sess.abort_if_errors();
1988+
handler.abort_if_errors();
19631989
}
19641990
},
19651991
Err(e) => {
1966-
sess.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
1967-
sess.abort_if_errors();
1992+
handler.err(&format!("could not exec the linker `{}`: {}", pname.display(), e));
1993+
handler.abort_if_errors();
19681994
}
19691995
}
19701996
}
@@ -2138,7 +2164,6 @@ pub struct OngoingCrateTranslation {
21382164
metadata: EncodedMetadata,
21392165
windows_subsystem: Option<String>,
21402166
linker_info: LinkerInfo,
2141-
no_integrated_as: bool,
21422167
crate_info: CrateInfo,
21432168
time_graph: Option<TimeGraph>,
21442169
coordinator_send: Sender<Box<Any + Send>>,
@@ -2194,26 +2219,6 @@ impl OngoingCrateTranslation {
21942219
metadata_module: compiled_modules.metadata_module,
21952220
};
21962221

2197-
if self.no_integrated_as {
2198-
run_assembler(sess, &self.output_filenames);
2199-
2200-
// HACK the linker expects the object file to be named foo.0.o but
2201-
// `run_assembler` produces an object named just foo.o. Rename it if we
2202-
// are going to build an executable
2203-
if sess.opts.output_types.contains_key(&OutputType::Exe) {
2204-
let f = self.output_filenames.path(OutputType::Object);
2205-
rename_or_copy_remove(&f,
2206-
f.with_file_name(format!("{}.0.o",
2207-
f.file_stem().unwrap().to_string_lossy()))).unwrap();
2208-
}
2209-
2210-
// Remove assembly source, unless --save-temps was specified
2211-
if !sess.opts.cg.save_temps {
2212-
fs::remove_file(&self.output_filenames
2213-
.temp_path(OutputType::Assembly, None)).unwrap();
2214-
}
2215-
}
2216-
22172222
trans
22182223
}
22192224

0 commit comments

Comments
 (0)