From fcde9904dbe7c4426a72b39a49b892eadb5a8940 Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Wed, 9 Nov 2016 19:05:32 -0500 Subject: [PATCH] use msp430-as to emit object files from the assembly that LLVM emits --- src/librustc_back/target/mod.rs | 7 +++ src/librustc_trans/back/write.rs | 83 +++++++++++++++++++++++++++++--- 2 files changed, 83 insertions(+), 7 deletions(-) diff --git a/src/librustc_back/target/mod.rs b/src/librustc_back/target/mod.rs index 14fe02269d142..f6a0946dd5b8e 100644 --- a/src/librustc_back/target/mod.rs +++ b/src/librustc_back/target/mod.rs @@ -359,6 +359,10 @@ pub struct TargetOptions { // will 'just work'. pub obj_is_bitcode: bool, + // LLVM can't produce object files for MSP430. Instead, we'll make LLVM emit + // assembly and then use `msp430-as` to turn that assembly into an object file + pub obj_needs_as: bool, + /// Don't use this field; instead use the `.max_atomic_width()` method. pub max_atomic_width: Option, @@ -416,6 +420,7 @@ impl Default for TargetOptions { allow_asm: true, has_elf_tls: false, obj_is_bitcode: false, + obj_needs_as: false, max_atomic_width: None, panic_strategy: PanicStrategy::Unwind, abi_blacklist: vec![], @@ -576,6 +581,7 @@ impl Target { key!(exe_allocation_crate); key!(has_elf_tls, bool); key!(obj_is_bitcode, bool); + key!(obj_needs_as, bool); key!(max_atomic_width, Option); try!(key!(panic_strategy, PanicStrategy)); @@ -735,6 +741,7 @@ impl ToJson for Target { target_option_val!(exe_allocation_crate); target_option_val!(has_elf_tls); target_option_val!(obj_is_bitcode); + target_option_val!(obj_needs_as); target_option_val!(max_atomic_width); target_option_val!(panic_strategy); diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 9012914deeb09..0af7c66ccd42a 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -26,6 +26,9 @@ use errors::emitter::Emitter; use syntax_pos::MultiSpan; use context::{is_pie_binary, get_reloc_model}; +use std::ascii; +use std::char; +use std::process::Command; use std::ffi::{CStr, CString}; use std::fs; use std::path::{Path, PathBuf}; @@ -262,6 +265,9 @@ 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, + // LLVM can't produce object files for MSP430. Instead, we'll make LLVM emit + // assembly and then use `msp430-as` to turn that assembly into an object file + obj_needs_as: bool, } unsafe impl Send for ModuleConfig { } @@ -281,6 +287,7 @@ impl ModuleConfig { emit_asm: false, emit_obj: false, obj_is_bitcode: false, + obj_needs_as: false, no_verify: false, no_prepopulate_passes: false, @@ -300,6 +307,7 @@ impl ModuleConfig { self.time_passes = sess.time_passes(); self.inline_threshold = sess.opts.cg.inline_threshold; self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode; + self.obj_needs_as = sess.target.target.options.obj_needs_as; // Copy what clang does by turning on loop vectorization at O2 and // slp vectorization at O3. Otherwise configure other optimization aspects @@ -557,10 +565,13 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, // machine code, instead copy the .o file from the .bc let write_bc = config.emit_bc || config.obj_is_bitcode; let rm_bc = !config.emit_bc && config.obj_is_bitcode; + let write_asm = config.emit_asm || config.obj_needs_as; + let rm_asm = !config.emit_obj && config.obj_needs_as; let write_obj = config.emit_obj && !config.obj_is_bitcode; let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode; let bc_out = output_names.temp_path(OutputType::Bitcode, module_name); + let asm_out = output_names.temp_path(OutputType::Assembly, module_name); let obj_out = output_names.temp_path(OutputType::Object, module_name); if write_bc { @@ -578,27 +589,25 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, }) } - if config.emit_asm { - let path = output_names.temp_path(OutputType::Assembly, module_name); - + if write_asm { // 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 && !config.obj_needs_as { llvm::LLVMCloneModule(llmod) } else { llmod }; with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &path, + write_output_file(cgcx.handler, tm, cpm, llmod, &asm_out, llvm::FileType::AssemblyFile); }); - if config.emit_obj { + if config.emit_obj && !config.obj_needs_as { llvm::LLVMDisposeModule(llmod); } } - if write_obj { + if write_obj && !config.obj_needs_as { with_codegen(tm, llmod, config.no_builtins, |cpm| { write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile); @@ -613,6 +622,59 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } + if config.obj_needs_as { + // XXX most of the logic here has been copied from the link_natively + // function (src/librustc_trans/back/link.rs) + // TODO don't hardcode, maybe expose as a `as` field in the target + // specification + // TODO how to properly access `sess` here? + let mut cmd = Command::new("msp430-as"); + cmd.arg("-o"); + cmd.arg(obj_out); + cmd.arg(&asm_out); + + info!("{:?}", &cmd); + // let prog = time(sess.time_passes(), "running assembler", + // || cmd.output()); + let prog = cmd.output(); + match prog { + Ok(prog) => { + fn escape_string(s: &[u8]) -> String { + str::from_utf8(s).map(|s| s.to_owned()) + .unwrap_or_else(|_| { + let mut x = "Non-UTF-8 output: ".to_string(); + x.extend(s.iter() + .flat_map(|&b| ascii::escape_default(b)) + .map(|b| char::from_u32(b as u32).unwrap())); + x + }) + } + if !prog.status.success() { + let mut output = prog.stderr.clone(); + output.extend_from_slice(&prog.stdout); + // sess.struct_err(&format!("assembling with `msp430-as` failed: {}", + // prog.status)) + // .note(&format!("{:?}", &cmd)) + // .note(&escape_string(&output[..])) + // .emit(); + // sess.abort_if_errors(); + } + info!("linker stderr:\n{}", escape_string(&prog.stderr[..])); + info!("linker stdout:\n{}", escape_string(&prog.stdout[..])); + }, + Err(_) => { + // sess.struct_err(&format!("could not exec the assembler `msp430-as`: {}", e)) + // .note(&format!("{:?}", &cmd)) + // .emit(); + // if e.kind() == io::ErrorKind::NotFound { + // sess.note_without_error("MSP430 targets depend on the MSP430 assembler \ + // but `msp430-as` was not found"); + // } + // sess.abort_if_errors(); + }, + } + } + if rm_bc { debug!("removing_bitcode {:?}", bc_out); if let Err(e) = fs::remove_file(&bc_out) { @@ -620,6 +682,13 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, } } + if rm_asm { + debug!("removing_assembly {:?}", bc_out); + if let Err(e) = fs::remove_file(&asm_out) { + cgcx.handler.err(&format!("failed to remove assembly: {}", e)); + } + } + llvm::LLVMRustDisposeTargetMachine(tm); }