diff options
| -rw-r--r-- | src/librustc_trans/back/lto.rs | 26 | ||||
| -rw-r--r-- | src/librustc_trans/back/write.rs | 134 |
2 files changed, 78 insertions, 82 deletions
diff --git a/src/librustc_trans/back/lto.rs b/src/librustc_trans/back/lto.rs index feed127b0b6..e160d6b6c6a 100644 --- a/src/librustc_trans/back/lto.rs +++ b/src/librustc_trans/back/lto.rs @@ -12,7 +12,7 @@ use back::link; use back::write; use back::symbol_export; use rustc::session::config; -use errors::FatalError; +use errors::{FatalError, Handler}; use llvm; use llvm::archive_ro::ArchiveRO; use llvm::{ModuleRef, TargetMachineRef, True, False}; @@ -41,24 +41,24 @@ pub fn crate_type_allows_lto(crate_type: config::CrateType) -> bool { } pub fn run(cgcx: &CodegenContext, + diag_handler: &Handler, llmod: ModuleRef, tm: TargetMachineRef, config: &ModuleConfig, temp_no_opt_bc_filename: &Path) -> Result<(), FatalError> { - let handler = cgcx.handler; if cgcx.opts.cg.prefer_dynamic { - handler.struct_err("cannot prefer dynamic linking when performing LTO") - .note("only 'staticlib', 'bin', and 'cdylib' outputs are \ - supported with LTO") - .emit(); + diag_handler.struct_err("cannot prefer dynamic linking when performing LTO") + .note("only 'staticlib', 'bin', and 'cdylib' outputs are \ + supported with LTO") + .emit(); return Err(FatalError) } // Make sure we actually can run LTO for crate_type in cgcx.crate_types.iter() { if !crate_type_allows_lto(*crate_type) { - let e = handler.fatal("lto can only be run for executables, cdylibs and \ - static library outputs"); + let e = diag_handler.fatal("lto can only be run for executables, cdylibs and \ + static library outputs"); return Err(e) } } @@ -116,13 +116,13 @@ pub fn run(cgcx: &CodegenContext, if res.is_err() { let msg = format!("failed to decompress bc of `{}`", name); - Err(handler.fatal(&msg)) + Err(diag_handler.fatal(&msg)) } else { Ok(inflated) } } else { - Err(handler.fatal(&format!("Unsupported bytecode format version {}", - version))) + Err(diag_handler.fatal(&format!("Unsupported bytecode format version {}", + version))) } })? } else { @@ -136,7 +136,7 @@ pub fn run(cgcx: &CodegenContext, if res.is_err() { let msg = format!("failed to decompress bc of `{}`", name); - Err(handler.fatal(&msg)) + Err(diag_handler.fatal(&msg)) } else { Ok(inflated) } @@ -152,7 +152,7 @@ pub fn run(cgcx: &CodegenContext, Ok(()) } else { let msg = format!("failed to load bc of `{}`", name); - Err(write::llvm_err(handler, msg)) + Err(write::llvm_err(&diag_handler, msg)) } })?; } diff --git a/src/librustc_trans/back/write.rs b/src/librustc_trans/back/write.rs index 28d255d4204..d2fc9682852 100644 --- a/src/librustc_trans/back/write.rs +++ b/src/librustc_trans/back/write.rs @@ -282,6 +282,7 @@ impl ModuleConfig { } /// Additional resources used by optimize_and_codegen (not module specific) +#[derive(Clone)] pub struct CodegenContext<'a> { // Resouces needed when running LTO pub time_passes: bool, @@ -292,7 +293,7 @@ pub struct CodegenContext<'a> { pub crate_types: Vec<config::CrateType>, pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>, // Handler to use for diagnostics produced during codegen. - pub handler: &'a Handler, + pub diag_emitter: SharedEmitter, // LLVM passes added by plugins. pub plugin_passes: Vec<String>, // LLVM optimizations for which we want to print remarks. @@ -303,20 +304,24 @@ pub struct CodegenContext<'a> { // compiling incrementally pub incr_comp_session_dir: Option<PathBuf>, // Channel back to the main control thread to send messages to - pub tx: Sender<Message>, + pub coordinator_send: Sender<Message>, +} - // Error messages... - pub shared_emitter: SharedEmitter, +impl<'a> CodegenContext<'a> { + fn create_diag_handler(&self) -> Handler { + Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone())) + } } struct HandlerFreeVars<'a> { cgcx: &'a CodegenContext<'a>, + diag_handler: &'a Handler, } unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext<'a>, msg: &'b str, cookie: c_uint) { - cgcx.shared_emitter.inline_asm_error(cookie as u32, msg.to_string()); + cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string()); } unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, @@ -331,7 +336,7 @@ unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef, } unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) { - let HandlerFreeVars { cgcx, .. } = *(user as *const HandlerFreeVars); + let HandlerFreeVars { cgcx, diag_handler, .. } = *(user as *const HandlerFreeVars); match llvm::diagnostic::Diagnostic::unpack(info) { llvm::diagnostic::InlineAsm(inline) => { @@ -347,7 +352,7 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo }; if enabled { - cgcx.handler.note_without_error(&format!("optimization {} for {} at {}:{}:{}: {}", + diag_handler.note_without_error(&format!("optimization {} for {} at {}:{}:{}: {}", opt.kind.describe(), opt.pass_name, opt.filename, @@ -363,6 +368,7 @@ unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_vo // Unsafe due to LLVM calls. unsafe fn optimize_and_codegen(cgcx: &CodegenContext, + diag_handler: &Handler, mtrans: ModuleTranslation, mllvm: ModuleLlvm, config: ModuleConfig, @@ -375,6 +381,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let fv = HandlerFreeVars { cgcx: cgcx, + diag_handler: diag_handler, }; let fv = &fv as *const HandlerFreeVars as *mut c_void; @@ -409,7 +416,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llvm::PassKind::Function => fpm, llvm::PassKind::Module => mpm, llvm::PassKind::Other => { - cgcx.handler.err("Encountered LLVM pass kind we can't handle"); + diag_handler.err("Encountered LLVM pass kind we can't handle"); return true }, }; @@ -429,20 +436,20 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, for pass in &config.passes { if !addpass(pass) { - cgcx.handler.warn(&format!("unknown pass `{}`, ignoring", + diag_handler.warn(&format!("unknown pass `{}`, ignoring", pass)); } } for pass in &cgcx.plugin_passes { if !addpass(pass) { - cgcx.handler.err(&format!("a plugin asked for LLVM pass \ + diag_handler.err(&format!("a plugin asked for LLVM pass \ `{}` but LLVM does not \ recognize it", pass)); } } - cgcx.handler.abort_if_errors(); + diag_handler.abort_if_errors(); // Finally, run the actual optimization passes time(config.time_passes, &format!("llvm function passes [{}]", cgcx.worker), || @@ -459,6 +466,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, let temp_no_opt_bc_filename = output_names.temp_path_ext("no-opt.lto.bc", module_name); lto::run(cgcx, + diag_handler, llmod, tm, &config, @@ -564,7 +572,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, llmod }; with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &path, + write_output_file(diag_handler, tm, cpm, llmod, &path, llvm::FileType::AssemblyFile) })?; if config.emit_obj { @@ -574,7 +582,7 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if write_obj { with_codegen(tm, llmod, config.no_builtins, |cpm| { - write_output_file(cgcx.handler, tm, cpm, llmod, &obj_out, + write_output_file(diag_handler, tm, cpm, llmod, &obj_out, llvm::FileType::ObjectFile) })?; } @@ -585,14 +593,14 @@ unsafe fn optimize_and_codegen(cgcx: &CodegenContext, if copy_bc_to_obj { debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out); if let Err(e) = link_or_copy(&bc_out, &obj_out) { - cgcx.handler.err(&format!("failed to copy bitcode to object file: {}", e)); + diag_handler.err(&format!("failed to copy bitcode to object file: {}", e)); } } if rm_bc { debug!("removing_bitcode {:?}", bc_out); if let Err(e) = fs::remove_file(&bc_out) { - cgcx.handler.err(&format!("failed to remove bitcode: {}", e)); + diag_handler.err(&format!("failed to remove bitcode: {}", e)); } } @@ -991,11 +999,13 @@ fn build_work_item(sess: &Session, fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) -> Result<(), FatalError> { + let diag_handler = cgcx.create_diag_handler(); unsafe { match work_item.mtrans.source { ModuleSource::Translated(mllvm) => { debug!("llvm-optimizing {:?}", work_item.mtrans.name); optimize_and_codegen(cgcx, + &diag_handler, work_item.mtrans, mllvm, work_item.config, @@ -1017,7 +1027,7 @@ fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem) match link_or_copy(&source_file, &obj_out) { Ok(_) => { } Err(err) => { - cgcx.handler.err(&format!("unable to copy {} to {}: {}", + diag_handler.err(&format!("unable to copy {} to {}: {}", source_file.display(), obj_out.display(), err)); @@ -1069,6 +1079,30 @@ fn execute_work<'a>(sess: &'a Session, let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); + let mut each_linked_rlib_for_lto = Vec::new(); + drop(link::each_linked_rlib(sess, &mut |cnum, path| { + if link::ignored_for_lto(sess, cnum) { + return + } + each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); + })); + + let cgcx = CodegenContext { + crate_types: sess.crate_types.borrow().clone(), + each_linked_rlib_for_lto: each_linked_rlib_for_lto, + lto: sess.lto(), + no_landing_pads: sess.no_landing_pads(), + opts: &sess.opts, + time_passes: sess.time_passes(), + exported_symbols: exported_symbols, + plugin_passes: sess.plugin_llvm_passes.borrow().clone(), + remark: sess.opts.cg.remark.clone(), + worker: 0, + incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), + coordinator_send: tx.clone(), + diag_emitter: shared_emitter.clone(), + }; + // This is the "main loop" of parallel work happening for parallel codegen. // It's here that we manage parallelism, schedule work, and work with // messages coming from clients. @@ -1132,14 +1166,16 @@ fn execute_work<'a>(sess: &'a Session, // parallelism slots and work left to spawn. while work_items.len() > 0 && running < tokens.len() + 1 { let item = work_items.pop().unwrap(); - let index = work_items.len(); - spawn_work(sess, - exported_symbols, + let worker_index = work_items.len(); + + let cgcx = CodegenContext { + worker: worker_index, + .. cgcx.clone() + }; + + spawn_work(cgcx, scope, - tx.clone(), - shared_emitter.clone(), - item, - index); + item); running += 1; } @@ -1178,29 +1214,10 @@ fn execute_work<'a>(sess: &'a Session, sess.diagnostic().abort_if_errors(); } -fn spawn_work<'a>(sess: &'a Session, - exported_symbols: &'a ExportedSymbols, +fn spawn_work<'a>(cgcx: CodegenContext<'a>, scope: &Scope<'a>, - tx: Sender<Message>, - emitter: SharedEmitter, - work: WorkItem, - idx: usize) { - let plugin_passes = sess.plugin_llvm_passes.borrow().clone(); - let remark = sess.opts.cg.remark.clone(); - let incr_comp_session_dir = sess.incr_comp_session_dir_opt().map(|r| r.clone()); + work: WorkItem) { let depth = time_depth(); - let lto = sess.lto(); - let crate_types = sess.crate_types.borrow().clone(); - let mut each_linked_rlib_for_lto = Vec::new(); - drop(link::each_linked_rlib(sess, &mut |cnum, path| { - if link::ignored_for_lto(sess, cnum) { - return - } - each_linked_rlib_for_lto.push((cnum, path.to_path_buf())); - })); - let time_passes = sess.time_passes(); - let no_landing_pads = sess.no_landing_pads(); - let opts = &sess.opts; scope.spawn(move || { set_time_depth(depth); @@ -1208,41 +1225,20 @@ fn spawn_work<'a>(sess: &'a Session, // Set up a destructor which will fire off a message that we're done as // we exit. struct Bomb { - tx: Sender<Message>, + coordinator_send: Sender<Message>, success: bool, } impl Drop for Bomb { fn drop(&mut self) { - drop(self.tx.send(Message::Done { success: self.success })); + drop(self.coordinator_send.send(Message::Done { success: self.success })); } } + let mut bomb = Bomb { - tx: tx.clone(), + coordinator_send: cgcx.coordinator_send.clone(), success: false, }; - // Set up our non-`Send` `CodegenContext` now that we're in a helper - // thread and have all our info available to us. - // let emitter = SharedEmitter { tx: tx.clone() }; - let diag_handler = Handler::with_emitter(true, false, Box::new(emitter.clone())); - - let cgcx = CodegenContext { - crate_types: crate_types, - each_linked_rlib_for_lto: each_linked_rlib_for_lto, - lto: lto, - no_landing_pads: no_landing_pads, - opts: opts, - time_passes: time_passes, - exported_symbols: exported_symbols, - handler: &diag_handler, - plugin_passes: plugin_passes, - remark: remark, - worker: idx, - incr_comp_session_dir: incr_comp_session_dir, - tx: tx.clone(), - shared_emitter: emitter, - }; - // Execute the work itself, and if it finishes successfully then flag // ourselves as a success as well. // |
