]> git.lizzy.rs Git - rust.git/commitdiff
Fix no_integrated_as option to work with new codegen architecture.
authorVadzim Dambrouski <pftbest@gmail.com>
Mon, 15 Jan 2018 13:42:44 +0000 (16:42 +0300)
committerVadzim Dambrouski <pftbest@gmail.com>
Mon, 15 Jan 2018 13:42:44 +0000 (16:42 +0300)
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 #45836 (Can't compile core for msp430 in release mode)

src/librustc_trans/back/command.rs
src/librustc_trans/back/write.rs

index ea68e3b28b668e8047630f476b673c51fc0ec071..024f80f050f5174af88e1b65319b8e7868a2d749 100644 (file)
@@ -16,6 +16,7 @@
 use std::io;
 use std::process::{self, Output, Child};
 
+#[derive(Clone)]
 pub struct Command {
     program: OsString,
     args: Vec<OsString>,
index 1ee04a46243a264f1e73aa7e2149e47ddf58e5fa..d401d68783aa4001da95fc6721fef82e4ed7b959 100644 (file)
@@ -11,6 +11,7 @@
 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;
@@ -18,7 +19,7 @@
 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;
@@ -32,7 +33,7 @@
 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;
@@ -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 {
@@ -275,6 +277,7 @@ fn new(passes: Vec<String>) -> ModuleConfig {
             emit_asm: false,
             emit_obj: false,
             obj_is_bitcode: false,
+            no_integrated_as: false,
 
             no_verify: false,
             no_prepopulate_passes: false,
@@ -313,6 +316,12 @@ fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
     }
 }
 
+/// 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 {
@@ -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 {
@@ -639,13 +650,17 @@ unsafe fn with_codegen<F, R>(tm: TargetMachineRef,
         !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);
@@ -725,7 +740,7 @@ extern "C" fn demangle_callback(input_ptr: *const c_char,
             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
@@ -760,6 +775,14 @@ extern "C" fn demangle_callback(input_ptr: *const c_char,
                                   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(())
@@ -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,
@@ -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![]);
@@ -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; }
@@ -976,7 +991,6 @@ pub fn start_async_translation(tcx: TyCtxt,
         metadata,
         windows_subsystem,
         linker_info,
-        no_integrated_as,
         crate_info,
 
         time_graph,
@@ -1389,6 +1403,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,
@@ -1428,6 +1454,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.
@@ -1936,15 +1963,14 @@ fn drop(&mut self) {
     });
 }
 
-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() {
@@ -1953,18 +1979,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();
         }
     }
 }
@@ -2138,7 +2164,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>>,
@@ -2194,26 +2219,6 @@ pub fn join(self, sess: &Session, dep_graph: &DepGraph) -> CrateTranslation {
             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
     }