async-llvm(8): Clean up resource management and drop LLVM modules ASAP.
This commit is contained in:
parent
4282dd87ea
commit
645841ea44
4 changed files with 256 additions and 151 deletions
|
@ -237,8 +237,6 @@ pub fn compile_input(sess: &Session,
|
||||||
phase5_result);
|
phase5_result);
|
||||||
phase5_result?;
|
phase5_result?;
|
||||||
|
|
||||||
write::cleanup_llvm(&trans);
|
|
||||||
|
|
||||||
phase_6_link_output(sess, &trans, &outputs);
|
phase_6_link_output(sess, &trans, &outputs);
|
||||||
|
|
||||||
// Now that we won't touch anything in the incremental compilation directory
|
// Now that we won't touch anything in the incremental compilation directory
|
||||||
|
|
|
@ -18,7 +18,8 @@ use rustc::session::Session;
|
||||||
use llvm;
|
use llvm;
|
||||||
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
|
use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
|
||||||
use llvm::SMDiagnosticRef;
|
use llvm::SMDiagnosticRef;
|
||||||
use {CrateTranslation, OngoingCrateTranslation, ModuleLlvm, ModuleSource, ModuleTranslation};
|
use {CrateTranslation, OngoingCrateTranslation, ModuleSource, ModuleTranslation,
|
||||||
|
CompiledModule, ModuleKind};
|
||||||
use rustc::hir::def_id::CrateNum;
|
use rustc::hir::def_id::CrateNum;
|
||||||
use rustc::util::common::{time, time_depth, set_time_depth, path2cstr};
|
use rustc::util::common::{time, time_depth, set_time_depth, path2cstr};
|
||||||
use rustc::util::fs::link_or_copy;
|
use rustc::util::fs::link_or_copy;
|
||||||
|
@ -192,7 +193,6 @@ pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
|
||||||
|
|
||||||
|
|
||||||
/// Module-specific configuration for `optimize_and_codegen`.
|
/// Module-specific configuration for `optimize_and_codegen`.
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ModuleConfig {
|
pub struct ModuleConfig {
|
||||||
/// LLVM TargetMachine to use for codegen.
|
/// LLVM TargetMachine to use for codegen.
|
||||||
tm: TargetMachineRef,
|
tm: TargetMachineRef,
|
||||||
|
@ -231,9 +231,9 @@ pub struct ModuleConfig {
|
||||||
unsafe impl Send for ModuleConfig { }
|
unsafe impl Send for ModuleConfig { }
|
||||||
|
|
||||||
impl ModuleConfig {
|
impl ModuleConfig {
|
||||||
fn new(tm: TargetMachineRef, passes: Vec<String>) -> ModuleConfig {
|
fn new(sess: &Session, passes: Vec<String>) -> ModuleConfig {
|
||||||
ModuleConfig {
|
ModuleConfig {
|
||||||
tm: tm,
|
tm: create_target_machine(sess),
|
||||||
passes: passes,
|
passes: passes,
|
||||||
opt_level: None,
|
opt_level: None,
|
||||||
opt_size: None,
|
opt_size: None,
|
||||||
|
@ -281,6 +281,40 @@ impl ModuleConfig {
|
||||||
self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
|
self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
|
||||||
sess.opts.optimize == config::OptLevel::Aggressive;
|
sess.opts.optimize == config::OptLevel::Aggressive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn clone(&self, sess: &Session) -> ModuleConfig {
|
||||||
|
ModuleConfig {
|
||||||
|
tm: create_target_machine(sess),
|
||||||
|
passes: self.passes.clone(),
|
||||||
|
opt_level: self.opt_level,
|
||||||
|
opt_size: self.opt_size,
|
||||||
|
|
||||||
|
emit_no_opt_bc: self.emit_no_opt_bc,
|
||||||
|
emit_bc: self.emit_bc,
|
||||||
|
emit_lto_bc: self.emit_lto_bc,
|
||||||
|
emit_ir: self.emit_ir,
|
||||||
|
emit_asm: self.emit_asm,
|
||||||
|
emit_obj: self.emit_obj,
|
||||||
|
obj_is_bitcode: self.obj_is_bitcode,
|
||||||
|
|
||||||
|
no_verify: self.no_verify,
|
||||||
|
no_prepopulate_passes: self.no_prepopulate_passes,
|
||||||
|
no_builtins: self.no_builtins,
|
||||||
|
time_passes: self.time_passes,
|
||||||
|
vectorize_loop: self.vectorize_loop,
|
||||||
|
vectorize_slp: self.vectorize_slp,
|
||||||
|
merge_functions: self.merge_functions,
|
||||||
|
inline_threshold: self.inline_threshold,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ModuleConfig {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
unsafe {
|
||||||
|
llvm::LLVMRustDisposeTargetMachine(self.tm);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Additional resources used by optimize_and_codegen (not module specific)
|
/// Additional resources used by optimize_and_codegen (not module specific)
|
||||||
|
@ -372,13 +406,17 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo
|
||||||
unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||||
diag_handler: &Handler,
|
diag_handler: &Handler,
|
||||||
mtrans: ModuleTranslation,
|
mtrans: ModuleTranslation,
|
||||||
mllvm: ModuleLlvm,
|
|
||||||
config: ModuleConfig,
|
config: ModuleConfig,
|
||||||
output_names: OutputFilenames)
|
output_names: OutputFilenames)
|
||||||
-> Result<(), FatalError>
|
-> Result<CompiledModule, FatalError>
|
||||||
{
|
{
|
||||||
let llmod = mllvm.llmod;
|
let (llmod, llcx) = match mtrans.source {
|
||||||
let llcx = mllvm.llcx;
|
ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx),
|
||||||
|
ModuleSource::Preexisting(_) => {
|
||||||
|
bug!("optimize_and_codegen: called with ModuleSource::Preexisting")
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let tm = config.tm;
|
let tm = config.tm;
|
||||||
|
|
||||||
let fv = HandlerFreeVars {
|
let fv = HandlerFreeVars {
|
||||||
|
@ -390,7 +428,8 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||||
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
|
llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
|
||||||
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv);
|
llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv);
|
||||||
|
|
||||||
let module_name = Some(&mtrans.name[..]);
|
let module_name = mtrans.name.clone();
|
||||||
|
let module_name = Some(&module_name[..]);
|
||||||
|
|
||||||
if config.emit_no_opt_bc {
|
if config.emit_no_opt_bc {
|
||||||
let out = output_names.temp_path_ext("no-opt.bc", module_name);
|
let out = output_names.temp_path_ext("no-opt.bc", module_name);
|
||||||
|
@ -606,30 +645,13 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::LLVMRustDisposeTargetMachine(tm);
|
Ok(mtrans.into_compiled_module(config.emit_obj, config.emit_bc))
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CompiledModules {
|
||||||
pub fn cleanup_llvm(trans: &CrateTranslation) {
|
pub modules: Vec<CompiledModule>,
|
||||||
for module in trans.modules.iter() {
|
pub metadata_module: CompiledModule,
|
||||||
unsafe {
|
pub allocator_module: Option<CompiledModule>,
|
||||||
match module.source {
|
|
||||||
ModuleSource::Translated(llvm) => {
|
|
||||||
llvm::LLVMDisposeModule(llvm.llmod);
|
|
||||||
llvm::LLVMContextDispose(llvm.llcx);
|
|
||||||
}
|
|
||||||
ModuleSource::Preexisting(_) => {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct RunLLVMPassesResult {
|
|
||||||
pub modules: Vec<ModuleTranslation>,
|
|
||||||
pub metadata_module: ModuleTranslation,
|
|
||||||
pub allocator_module: Option<ModuleTranslation>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn run_passes(sess: &Session,
|
pub fn run_passes(sess: &Session,
|
||||||
|
@ -658,13 +680,11 @@ pub fn run_passes(sess: &Session,
|
||||||
!sess.opts.output_types.should_trans() ||
|
!sess.opts.output_types.should_trans() ||
|
||||||
sess.opts.debugging_opts.no_trans);
|
sess.opts.debugging_opts.no_trans);
|
||||||
|
|
||||||
let tm = create_target_machine(sess);
|
|
||||||
|
|
||||||
// Figure out what we actually need to build.
|
// Figure out what we actually need to build.
|
||||||
|
|
||||||
let mut modules_config = ModuleConfig::new(tm, sess.opts.cg.passes.clone());
|
let mut modules_config = ModuleConfig::new(sess, sess.opts.cg.passes.clone());
|
||||||
let mut metadata_config = ModuleConfig::new(tm, vec![]);
|
let mut metadata_config = ModuleConfig::new(sess, vec![]);
|
||||||
let mut allocator_config = ModuleConfig::new(tm, vec![]);
|
let mut allocator_config = ModuleConfig::new(sess, vec![]);
|
||||||
|
|
||||||
if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
|
if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
|
||||||
match *sanitizer {
|
match *sanitizer {
|
||||||
|
@ -747,25 +767,22 @@ pub fn run_passes(sess: &Session,
|
||||||
let mut work_items = Vec::with_capacity(1 + modules.len());
|
let mut work_items = Vec::with_capacity(1 + modules.len());
|
||||||
|
|
||||||
{
|
{
|
||||||
let work = build_work_item(sess,
|
let work = build_work_item(metadata_module,
|
||||||
metadata_module.clone(),
|
metadata_config.clone(sess),
|
||||||
metadata_config.clone(),
|
|
||||||
crate_output.clone());
|
crate_output.clone());
|
||||||
work_items.push(work);
|
work_items.push(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(allocator) = allocator_module.clone() {
|
if let Some(allocator) = allocator_module {
|
||||||
let work = build_work_item(sess,
|
let work = build_work_item(allocator,
|
||||||
allocator,
|
allocator_config.clone(sess),
|
||||||
allocator_config.clone(),
|
|
||||||
crate_output.clone());
|
crate_output.clone());
|
||||||
work_items.push(work);
|
work_items.push(work);
|
||||||
}
|
}
|
||||||
|
|
||||||
for mtrans in modules.iter() {
|
for mtrans in modules {
|
||||||
let work = build_work_item(sess,
|
let work = build_work_item(mtrans,
|
||||||
mtrans.clone(),
|
modules_config.clone(sess),
|
||||||
modules_config.clone(),
|
|
||||||
crate_output.clone());
|
crate_output.clone());
|
||||||
work_items.push(work);
|
work_items.push(work);
|
||||||
}
|
}
|
||||||
|
@ -778,6 +795,10 @@ pub fn run_passes(sess: &Session,
|
||||||
Client::new(num_workers).expect("failed to create jobserver")
|
Client::new(num_workers).expect("failed to create jobserver")
|
||||||
});
|
});
|
||||||
|
|
||||||
|
drop(modules_config);
|
||||||
|
drop(metadata_config);
|
||||||
|
drop(allocator_config);
|
||||||
|
|
||||||
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
|
let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
|
||||||
let (trans_worker_send, trans_worker_receive) = channel();
|
let (trans_worker_send, trans_worker_receive) = channel();
|
||||||
let (coordinator_send, coordinator_receive) = channel();
|
let (coordinator_send, coordinator_receive) = channel();
|
||||||
|
@ -813,37 +834,27 @@ pub fn run_passes(sess: &Session,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
match coordinator_thread.join() {
|
let compiled_modules = coordinator_thread.join().unwrap();
|
||||||
Ok(()) => {},
|
|
||||||
Err(err) => {
|
|
||||||
panic!("error: {:?}", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Just in case, check this on the way out.
|
// Just in case, check this on the way out.
|
||||||
shared_emitter_main.check(sess);
|
shared_emitter_main.check(sess);
|
||||||
sess.diagnostic().abort_if_errors();
|
sess.diagnostic().abort_if_errors();
|
||||||
|
|
||||||
// If in incr. comp. mode, preserve the `.o` files for potential re-use
|
// If in incr. comp. mode, preserve the `.o` files for potential re-use
|
||||||
for mtrans in modules.iter() {
|
for module in compiled_modules.modules.iter() {
|
||||||
let mut files = vec![];
|
let mut files = vec![];
|
||||||
|
|
||||||
if modules_config.emit_obj {
|
if module.emit_obj {
|
||||||
let path = crate_output.temp_path(OutputType::Object, Some(&mtrans.name));
|
let path = crate_output.temp_path(OutputType::Object, Some(&module.name));
|
||||||
files.push((OutputType::Object, path));
|
files.push((OutputType::Object, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
if modules_config.emit_bc {
|
if module.emit_bc {
|
||||||
let path = crate_output.temp_path(OutputType::Bitcode, Some(&mtrans.name));
|
let path = crate_output.temp_path(OutputType::Bitcode, Some(&module.name));
|
||||||
files.push((OutputType::Bitcode, path));
|
files.push((OutputType::Bitcode, path));
|
||||||
}
|
}
|
||||||
|
|
||||||
save_trans_partition(sess, &mtrans.name, mtrans.symbol_name_hash, &files);
|
save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
|
||||||
}
|
|
||||||
|
|
||||||
// All codegen is finished.
|
|
||||||
unsafe {
|
|
||||||
llvm::LLVMRustDisposeTargetMachine(tm);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut user_wants_bitcode = false;
|
let mut user_wants_bitcode = false;
|
||||||
|
@ -858,10 +869,10 @@ pub fn run_passes(sess: &Session,
|
||||||
|
|
||||||
let copy_if_one_unit = |output_type: OutputType,
|
let copy_if_one_unit = |output_type: OutputType,
|
||||||
keep_numbered: bool| {
|
keep_numbered: bool| {
|
||||||
if modules.len() == 1 {
|
if compiled_modules.modules.len() == 1 {
|
||||||
// 1) Only one codegen unit. In this case it's no difficulty
|
// 1) Only one codegen unit. In this case it's no difficulty
|
||||||
// to copy `foo.0.x` to `foo.x`.
|
// to copy `foo.0.x` to `foo.x`.
|
||||||
let module_name = Some(&modules[0].name[..]);
|
let module_name = Some(&compiled_modules.modules[0].name[..]);
|
||||||
let path = crate_output.temp_path(output_type, module_name);
|
let path = crate_output.temp_path(output_type, module_name);
|
||||||
copy_gracefully(&path,
|
copy_gracefully(&path,
|
||||||
&crate_output.path(output_type));
|
&crate_output.path(output_type));
|
||||||
|
@ -962,27 +973,30 @@ pub fn run_passes(sess: &Session,
|
||||||
let keep_numbered_objects = needs_crate_object ||
|
let keep_numbered_objects = needs_crate_object ||
|
||||||
(user_wants_objects && sess.opts.cg.codegen_units > 1);
|
(user_wants_objects && sess.opts.cg.codegen_units > 1);
|
||||||
|
|
||||||
for module_name in modules.iter().map(|m| Some(&m.name[..])) {
|
for module in compiled_modules.modules.iter() {
|
||||||
if modules_config.emit_obj && !keep_numbered_objects {
|
let module_name = Some(&module.name[..]);
|
||||||
|
|
||||||
|
if module.emit_obj && !keep_numbered_objects {
|
||||||
let path = crate_output.temp_path(OutputType::Object, module_name);
|
let path = crate_output.temp_path(OutputType::Object, module_name);
|
||||||
remove(sess, &path);
|
remove(sess, &path);
|
||||||
}
|
}
|
||||||
|
|
||||||
if modules_config.emit_bc && !keep_numbered_bitcode {
|
if module.emit_bc && !keep_numbered_bitcode {
|
||||||
let path = crate_output.temp_path(OutputType::Bitcode, module_name);
|
let path = crate_output.temp_path(OutputType::Bitcode, module_name);
|
||||||
remove(sess, &path);
|
remove(sess, &path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if metadata_config.emit_bc && !user_wants_bitcode {
|
if compiled_modules.metadata_module.emit_bc && !user_wants_bitcode {
|
||||||
let path = crate_output.temp_path(OutputType::Bitcode,
|
let path = crate_output.temp_path(OutputType::Bitcode,
|
||||||
Some(&metadata_module.name));
|
Some(&compiled_modules.metadata_module.name));
|
||||||
remove(sess, &path);
|
remove(sess, &path);
|
||||||
}
|
}
|
||||||
if allocator_config.emit_bc && !user_wants_bitcode {
|
|
||||||
if let Some(ref module) = allocator_module {
|
if let Some(ref allocator_module) = compiled_modules.allocator_module {
|
||||||
|
if allocator_module.emit_bc && !user_wants_bitcode {
|
||||||
let path = crate_output.temp_path(OutputType::Bitcode,
|
let path = crate_output.temp_path(OutputType::Bitcode,
|
||||||
Some(&module.name));
|
Some(&allocator_module.name));
|
||||||
remove(sess, &path);
|
remove(sess, &path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1000,21 +1014,14 @@ pub fn run_passes(sess: &Session,
|
||||||
unsafe { llvm::LLVMRustPrintPassTimings(); }
|
unsafe { llvm::LLVMRustPrintPassTimings(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
*trans.result.borrow_mut() = Some(
|
*trans.result.borrow_mut() = Some(compiled_modules);
|
||||||
RunLLVMPassesResult {
|
|
||||||
modules,
|
|
||||||
metadata_module,
|
|
||||||
allocator_module,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn dump_incremental_data(trans: &CrateTranslation) {
|
pub fn dump_incremental_data(trans: &CrateTranslation) {
|
||||||
let mut reuse = 0;
|
let mut reuse = 0;
|
||||||
for mtrans in trans.modules.iter() {
|
for mtrans in trans.modules.iter() {
|
||||||
match mtrans.source {
|
if mtrans.pre_existing {
|
||||||
ModuleSource::Preexisting(..) => reuse += 1,
|
reuse += 1;
|
||||||
ModuleSource::Translated(..) => (),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
eprintln!("incremental: re-using {} out of {} modules", reuse, trans.modules.len());
|
eprintln!("incremental: re-using {} out of {} modules", reuse, trans.modules.len());
|
||||||
|
@ -1032,14 +1039,11 @@ impl fmt::Debug for WorkItem {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn build_work_item(sess: &Session,
|
fn build_work_item(mtrans: ModuleTranslation,
|
||||||
mtrans: ModuleTranslation,
|
|
||||||
config: ModuleConfig,
|
config: ModuleConfig,
|
||||||
output_names: OutputFilenames)
|
output_names: OutputFilenames)
|
||||||
-> WorkItem
|
-> WorkItem
|
||||||
{
|
{
|
||||||
let mut config = config;
|
|
||||||
config.tm = create_target_machine(sess);
|
|
||||||
WorkItem {
|
WorkItem {
|
||||||
mtrans: mtrans,
|
mtrans: mtrans,
|
||||||
config: config,
|
config: config,
|
||||||
|
@ -1048,54 +1052,65 @@ fn build_work_item(sess: &Session,
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
|
fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
|
||||||
-> Result<(), FatalError>
|
-> Result<CompiledModule, FatalError>
|
||||||
{
|
{
|
||||||
let diag_handler = cgcx.create_diag_handler();
|
let diag_handler = cgcx.create_diag_handler();
|
||||||
unsafe {
|
let module_name = work_item.mtrans.name.clone();
|
||||||
match work_item.mtrans.source {
|
|
||||||
ModuleSource::Translated(mllvm) => {
|
let pre_existing = match work_item.mtrans.source {
|
||||||
debug!("llvm-optimizing {:?}", work_item.mtrans.name);
|
ModuleSource::Translated(_) => None,
|
||||||
optimize_and_codegen(cgcx,
|
ModuleSource::Preexisting(ref wp) => Some(wp.clone()),
|
||||||
&diag_handler,
|
};
|
||||||
work_item.mtrans,
|
|
||||||
mllvm,
|
if let Some(wp) = pre_existing {
|
||||||
work_item.config,
|
let incr_comp_session_dir = cgcx.incr_comp_session_dir
|
||||||
work_item.output_names)?;
|
.as_ref()
|
||||||
}
|
.unwrap();
|
||||||
ModuleSource::Preexisting(wp) => {
|
let name = &work_item.mtrans.name;
|
||||||
let incr_comp_session_dir = cgcx.incr_comp_session_dir
|
for (kind, saved_file) in wp.saved_files {
|
||||||
.as_ref()
|
let obj_out = work_item.output_names.temp_path(kind, Some(name));
|
||||||
.unwrap();
|
let source_file = in_incr_comp_dir(&incr_comp_session_dir,
|
||||||
let name = &work_item.mtrans.name;
|
&saved_file);
|
||||||
for (kind, saved_file) in wp.saved_files {
|
debug!("copying pre-existing module `{}` from {:?} to {}",
|
||||||
let obj_out = work_item.output_names.temp_path(kind, Some(name));
|
work_item.mtrans.name,
|
||||||
let source_file = in_incr_comp_dir(&incr_comp_session_dir,
|
source_file,
|
||||||
&saved_file);
|
obj_out.display());
|
||||||
debug!("copying pre-existing module `{}` from {:?} to {}",
|
match link_or_copy(&source_file, &obj_out) {
|
||||||
work_item.mtrans.name,
|
Ok(_) => { }
|
||||||
source_file,
|
Err(err) => {
|
||||||
obj_out.display());
|
diag_handler.err(&format!("unable to copy {} to {}: {}",
|
||||||
match link_or_copy(&source_file, &obj_out) {
|
source_file.display(),
|
||||||
Ok(_) => { }
|
obj_out.display(),
|
||||||
Err(err) => {
|
err));
|
||||||
diag_handler.err(&format!("unable to copy {} to {}: {}",
|
|
||||||
source_file.display(),
|
|
||||||
obj_out.display(),
|
|
||||||
err));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Ok(())
|
Ok(CompiledModule {
|
||||||
|
name: module_name,
|
||||||
|
kind: ModuleKind::Regular,
|
||||||
|
pre_existing: true,
|
||||||
|
symbol_name_hash: work_item.mtrans.symbol_name_hash,
|
||||||
|
emit_bc: work_item.config.emit_bc,
|
||||||
|
emit_obj: work_item.config.emit_obj,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
debug!("llvm-optimizing {:?}", module_name);
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
optimize_and_codegen(cgcx,
|
||||||
|
&diag_handler,
|
||||||
|
work_item.mtrans,
|
||||||
|
work_item.config,
|
||||||
|
work_item.output_names)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
Token(io::Result<Acquired>),
|
Token(io::Result<Acquired>),
|
||||||
Done { success: bool },
|
Done { result: Result<CompiledModule, ()> },
|
||||||
WorkItem(WorkItem),
|
WorkItem(WorkItem),
|
||||||
CheckErrorMessages,
|
CheckErrorMessages,
|
||||||
}
|
}
|
||||||
|
@ -1115,7 +1130,7 @@ fn start_executing_work(sess: &Session,
|
||||||
coordinator_receive: Receiver<Message>,
|
coordinator_receive: Receiver<Message>,
|
||||||
jobserver: Client,
|
jobserver: Client,
|
||||||
exported_symbols: Arc<ExportedSymbols>)
|
exported_symbols: Arc<ExportedSymbols>)
|
||||||
-> thread::JoinHandle<()> {
|
-> thread::JoinHandle<CompiledModules> {
|
||||||
// First up, convert our jobserver into a helper thread so we can use normal
|
// First up, convert our jobserver into a helper thread so we can use normal
|
||||||
// mpsc channels to manage our messages and such. Once we've got the helper
|
// mpsc channels to manage our messages and such. Once we've got the helper
|
||||||
// thread then request `n-1` tokens because all of our work items are ready
|
// thread then request `n-1` tokens because all of our work items are ready
|
||||||
|
@ -1215,6 +1230,10 @@ fn start_executing_work(sess: &Session,
|
||||||
// the jobserver.
|
// the jobserver.
|
||||||
|
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
|
let mut compiled_modules = vec![];
|
||||||
|
let mut compiled_metadata_module = None;
|
||||||
|
let mut compiled_allocator_module = None;
|
||||||
|
|
||||||
let mut work_items_left = total_work_item_count;
|
let mut work_items_left = total_work_item_count;
|
||||||
let mut work_items = Vec::with_capacity(total_work_item_count);
|
let mut work_items = Vec::with_capacity(total_work_item_count);
|
||||||
let mut tokens = Vec::new();
|
let mut tokens = Vec::new();
|
||||||
|
@ -1253,7 +1272,8 @@ fn start_executing_work(sess: &Session,
|
||||||
} else {
|
} else {
|
||||||
shared_emitter.fatal("failed to acquire jobserver token");
|
shared_emitter.fatal("failed to acquire jobserver token");
|
||||||
drop(trans_worker_send.send(Message::CheckErrorMessages));
|
drop(trans_worker_send.send(Message::CheckErrorMessages));
|
||||||
return
|
// Exit the coordinator thread
|
||||||
|
panic!()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1269,21 +1289,42 @@ fn start_executing_work(sess: &Session,
|
||||||
//
|
//
|
||||||
// Note that if the thread failed that means it panicked, so we
|
// Note that if the thread failed that means it panicked, so we
|
||||||
// abort immediately.
|
// abort immediately.
|
||||||
Message::Done { success: true } => {
|
Message::Done { result: Ok(compiled_module) } => {
|
||||||
drop(tokens.pop());
|
drop(tokens.pop());
|
||||||
running -= 1;
|
running -= 1;
|
||||||
drop(trans_worker_send.send(Message::CheckErrorMessages));
|
drop(trans_worker_send.send(Message::CheckErrorMessages));
|
||||||
|
|
||||||
|
match compiled_module.kind {
|
||||||
|
ModuleKind::Regular => {
|
||||||
|
compiled_modules.push(compiled_module);
|
||||||
|
}
|
||||||
|
ModuleKind::Metadata => {
|
||||||
|
assert!(compiled_metadata_module.is_none());
|
||||||
|
compiled_metadata_module = Some(compiled_module);
|
||||||
|
}
|
||||||
|
ModuleKind::Allocator => {
|
||||||
|
assert!(compiled_allocator_module.is_none());
|
||||||
|
compiled_allocator_module = Some(compiled_module);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Message::Done { success: false } => {
|
Message::Done { result: Err(()) } => {
|
||||||
shared_emitter.fatal("aborting due to worker thread panic");
|
shared_emitter.fatal("aborting due to worker thread panic");
|
||||||
drop(trans_worker_send.send(Message::CheckErrorMessages));
|
drop(trans_worker_send.send(Message::CheckErrorMessages));
|
||||||
return
|
// Exit the coordinator thread
|
||||||
|
panic!()
|
||||||
}
|
}
|
||||||
msg @ Message::CheckErrorMessages => {
|
msg @ Message::CheckErrorMessages => {
|
||||||
bug!("unexpected message: {:?}", msg);
|
bug!("unexpected message: {:?}", msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CompiledModules {
|
||||||
|
modules: compiled_modules,
|
||||||
|
metadata_module: compiled_metadata_module.unwrap(),
|
||||||
|
allocator_module: compiled_allocator_module,
|
||||||
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1297,17 +1338,22 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
|
||||||
// we exit.
|
// we exit.
|
||||||
struct Bomb {
|
struct Bomb {
|
||||||
coordinator_send: Sender<Message>,
|
coordinator_send: Sender<Message>,
|
||||||
success: bool,
|
result: Option<CompiledModule>,
|
||||||
}
|
}
|
||||||
impl Drop for Bomb {
|
impl Drop for Bomb {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
drop(self.coordinator_send.send(Message::Done { success: self.success }));
|
let result = match self.result.take() {
|
||||||
|
Some(compiled_module) => Ok(compiled_module),
|
||||||
|
None => Err(())
|
||||||
|
};
|
||||||
|
|
||||||
|
drop(self.coordinator_send.send(Message::Done { result }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut bomb = Bomb {
|
let mut bomb = Bomb {
|
||||||
coordinator_send: cgcx.coordinator_send.clone(),
|
coordinator_send: cgcx.coordinator_send.clone(),
|
||||||
success: false,
|
result: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Execute the work itself, and if it finishes successfully then flag
|
// Execute the work itself, and if it finishes successfully then flag
|
||||||
|
@ -1323,8 +1369,7 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
|
||||||
// we just ignore the result and then send off our message saying that
|
// we just ignore the result and then send off our message saying that
|
||||||
// we're done, which if `execute_work_item` failed is unlikely to be
|
// we're done, which if `execute_work_item` failed is unlikely to be
|
||||||
// seen by the main thread, but hey we might as well try anyway.
|
// seen by the main thread, but hey we might as well try anyway.
|
||||||
drop(execute_work_item(&cgcx, work).is_err());
|
bomb.result = Some(execute_work_item(&cgcx, work).unwrap());
|
||||||
bomb.success = true;
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ use super::OngoingCrateTranslation;
|
||||||
use super::ModuleLlvm;
|
use super::ModuleLlvm;
|
||||||
use super::ModuleSource;
|
use super::ModuleSource;
|
||||||
use super::ModuleTranslation;
|
use super::ModuleTranslation;
|
||||||
|
use super::ModuleKind;
|
||||||
|
|
||||||
use assert_module_sources;
|
use assert_module_sources;
|
||||||
use back::link;
|
use back::link;
|
||||||
|
@ -952,6 +953,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
llcx: metadata_llcx,
|
llcx: metadata_llcx,
|
||||||
llmod: metadata_llmod,
|
llmod: metadata_llmod,
|
||||||
}),
|
}),
|
||||||
|
kind: ModuleKind::Metadata,
|
||||||
};
|
};
|
||||||
|
|
||||||
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
|
let no_builtins = attr::contains_name(&krate.attrs, "no_builtins");
|
||||||
|
@ -961,7 +963,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
!tcx.sess.opts.output_types.should_trans() {
|
!tcx.sess.opts.output_types.should_trans() {
|
||||||
let empty_exported_symbols = ExportedSymbols::empty();
|
let empty_exported_symbols = ExportedSymbols::empty();
|
||||||
let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
|
let linker_info = LinkerInfo::new(&shared_ccx, &empty_exported_symbols);
|
||||||
return OngoingCrateTranslation {
|
let crate_translation = OngoingCrateTranslation {
|
||||||
crate_name: tcx.crate_name(LOCAL_CRATE),
|
crate_name: tcx.crate_name(LOCAL_CRATE),
|
||||||
link: link_meta,
|
link: link_meta,
|
||||||
metadata: metadata,
|
metadata: metadata,
|
||||||
|
@ -970,12 +972,18 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
linker_info: linker_info,
|
linker_info: linker_info,
|
||||||
windows_subsystem: None,
|
windows_subsystem: None,
|
||||||
no_integrated_as: false,
|
no_integrated_as: false,
|
||||||
result: ::std::cell::RefCell::new(Some(::back::write::RunLLVMPassesResult {
|
result: ::std::cell::RefCell::new(None),
|
||||||
modules: vec![],
|
|
||||||
metadata_module: metadata_module,
|
|
||||||
allocator_module: None,
|
|
||||||
})),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
::back::write::run_passes(tcx.sess,
|
||||||
|
&crate_translation,
|
||||||
|
vec![],
|
||||||
|
metadata_module,
|
||||||
|
None,
|
||||||
|
&output_filenames.outputs,
|
||||||
|
output_filenames);
|
||||||
|
|
||||||
|
return crate_translation;
|
||||||
}
|
}
|
||||||
|
|
||||||
let exported_symbols = Arc::new(ExportedSymbols::compute(tcx,
|
let exported_symbols = Arc::new(ExportedSymbols::compute(tcx,
|
||||||
|
@ -1047,7 +1055,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
let module = ModuleTranslation {
|
let module = ModuleTranslation {
|
||||||
name: cgu_name,
|
name: cgu_name,
|
||||||
symbol_name_hash,
|
symbol_name_hash,
|
||||||
source: ModuleSource::Preexisting(buf.clone())
|
source: ModuleSource::Preexisting(buf.clone()),
|
||||||
|
kind: ModuleKind::Regular,
|
||||||
};
|
};
|
||||||
return (Stats::default(), module);
|
return (Stats::default(), module);
|
||||||
}
|
}
|
||||||
|
@ -1108,7 +1117,8 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
source: ModuleSource::Translated(ModuleLlvm {
|
source: ModuleSource::Translated(ModuleLlvm {
|
||||||
llcx: ccx.llcx(),
|
llcx: ccx.llcx(),
|
||||||
llmod: ccx.llmod(),
|
llmod: ccx.llmod(),
|
||||||
})
|
}),
|
||||||
|
kind: ModuleKind::Regular,
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1196,6 +1206,7 @@ pub fn trans_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
name: link::ALLOCATOR_MODULE_NAME.to_string(),
|
name: link::ALLOCATOR_MODULE_NAME.to_string(),
|
||||||
symbol_name_hash: 0, // we always rebuild allocator shims
|
symbol_name_hash: 0, // we always rebuild allocator shims
|
||||||
source: ModuleSource::Translated(modules),
|
source: ModuleSource::Translated(modules),
|
||||||
|
kind: ModuleKind::Allocator,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -135,7 +135,6 @@ mod type_;
|
||||||
mod type_of;
|
mod type_of;
|
||||||
mod value;
|
mod value;
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ModuleTranslation {
|
pub struct ModuleTranslation {
|
||||||
/// The name of the module. When the crate may be saved between
|
/// The name of the module. When the crate may be saved between
|
||||||
/// compilations, incremental compilation requires that name be
|
/// compilations, incremental compilation requires that name be
|
||||||
|
@ -145,6 +144,58 @@ pub struct ModuleTranslation {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub symbol_name_hash: u64,
|
pub symbol_name_hash: u64,
|
||||||
pub source: ModuleSource,
|
pub source: ModuleSource,
|
||||||
|
pub kind: ModuleKind,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub enum ModuleKind {
|
||||||
|
Regular,
|
||||||
|
Metadata,
|
||||||
|
Allocator,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ModuleTranslation {
|
||||||
|
pub fn into_compiled_module(self, emit_obj: bool, emit_bc: bool) -> CompiledModule {
|
||||||
|
let pre_existing = match self.source {
|
||||||
|
ModuleSource::Preexisting(_) => true,
|
||||||
|
ModuleSource::Translated(_) => false,
|
||||||
|
};
|
||||||
|
|
||||||
|
CompiledModule {
|
||||||
|
name: self.name.clone(),
|
||||||
|
kind: self.kind,
|
||||||
|
symbol_name_hash: self.symbol_name_hash,
|
||||||
|
pre_existing,
|
||||||
|
emit_obj,
|
||||||
|
emit_bc,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for ModuleTranslation {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
match self.source {
|
||||||
|
ModuleSource::Preexisting(_) => {
|
||||||
|
// Nothing to dispose.
|
||||||
|
},
|
||||||
|
ModuleSource::Translated(llvm) => {
|
||||||
|
unsafe {
|
||||||
|
llvm::LLVMDisposeModule(llvm.llmod);
|
||||||
|
llvm::LLVMContextDispose(llvm.llcx);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct CompiledModule {
|
||||||
|
pub name: String,
|
||||||
|
pub kind: ModuleKind,
|
||||||
|
pub symbol_name_hash: u64,
|
||||||
|
pub pre_existing: bool,
|
||||||
|
pub emit_obj: bool,
|
||||||
|
pub emit_bc: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -156,7 +207,7 @@ pub enum ModuleSource {
|
||||||
Translated(ModuleLlvm),
|
Translated(ModuleLlvm),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ModuleLlvm {
|
pub struct ModuleLlvm {
|
||||||
pub llcx: llvm::ContextRef,
|
pub llcx: llvm::ContextRef,
|
||||||
pub llmod: llvm::ModuleRef,
|
pub llmod: llvm::ModuleRef,
|
||||||
|
@ -167,9 +218,9 @@ unsafe impl Sync for ModuleTranslation { }
|
||||||
|
|
||||||
pub struct CrateTranslation {
|
pub struct CrateTranslation {
|
||||||
pub crate_name: Symbol,
|
pub crate_name: Symbol,
|
||||||
pub modules: Vec<ModuleTranslation>,
|
pub modules: Vec<CompiledModule>,
|
||||||
pub metadata_module: ModuleTranslation,
|
pub metadata_module: CompiledModule,
|
||||||
pub allocator_module: Option<ModuleTranslation>,
|
pub allocator_module: Option<CompiledModule>,
|
||||||
pub link: rustc::middle::cstore::LinkMeta,
|
pub link: rustc::middle::cstore::LinkMeta,
|
||||||
pub metadata: rustc::middle::cstore::EncodedMetadata,
|
pub metadata: rustc::middle::cstore::EncodedMetadata,
|
||||||
pub exported_symbols: Arc<back::symbol_export::ExportedSymbols>,
|
pub exported_symbols: Arc<back::symbol_export::ExportedSymbols>,
|
||||||
|
@ -189,7 +240,7 @@ pub struct OngoingCrateTranslation {
|
||||||
pub no_integrated_as: bool,
|
pub no_integrated_as: bool,
|
||||||
|
|
||||||
// This will be replaced by a Future.
|
// This will be replaced by a Future.
|
||||||
pub result: ::std::cell::RefCell<Option<back::write::RunLLVMPassesResult>>,
|
pub result: ::std::cell::RefCell<Option<back::write::CompiledModules>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OngoingCrateTranslation {
|
impl OngoingCrateTranslation {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue