Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix no_integrated_as option to work with new codegen architecture. #47453

Merged
merged 2 commits into from
Jan 26, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/librustc_trans/back/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ use std::fmt;
use std::io;
use std::process::{self, Output, Child};

#[derive(Clone)]
pub struct Command {
program: OsString,
args: Vec<OsString>,
Expand Down
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 @@ -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,
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -1936,15 +1963,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 @@ -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();
}
}
}
Expand Down Expand Up @@ -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>>,
Expand Down Expand Up @@ -2194,26 +2219,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!");
}