1 // Copyright 2013-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
12 use back::link::{self, get_linker, remove};
13 use back::linker::LinkerInfo;
14 use back::symbol_export::ExportedSymbols;
15 use rustc_incremental::{save_trans_partition, in_incr_comp_dir};
16 use rustc::middle::cstore::{LinkMeta, EncodedMetadata};
17 use rustc::session::config::{self, OutputFilenames, OutputType, OutputTypes, Passes, SomePasses,
18 AllPasses, Sanitizer};
19 use rustc::session::Session;
20 use time_graph::{self, TimeGraph};
22 use llvm::{ModuleRef, TargetMachineRef, PassManagerRef, DiagnosticInfoRef};
23 use llvm::SMDiagnosticRef;
24 use {CrateTranslation, ModuleSource, ModuleTranslation, CompiledModule, ModuleKind};
26 use rustc::hir::def_id::CrateNum;
27 use rustc::util::common::{time, time_depth, set_time_depth, path2cstr, print_time_passes_entry};
28 use rustc::util::fs::{link_or_copy, rename_or_copy_remove};
29 use errors::{self, Handler, Level, DiagnosticBuilder, FatalError};
30 use errors::emitter::{Emitter};
31 use syntax::ext::hygiene::Mark;
32 use syntax_pos::MultiSpan;
33 use syntax_pos::symbol::Symbol;
34 use context::{is_pie_binary, get_reloc_model};
35 use jobserver::{Client, Acquired};
38 use std::ffi::CString;
43 use std::path::{Path, PathBuf};
46 use std::sync::mpsc::{channel, Sender, Receiver};
48 use std::time::Instant;
50 use libc::{c_uint, c_void, c_char, size_t};
52 pub const RELOC_MODEL_ARGS : [(&'static str, llvm::RelocMode); 7] = [
53 ("pic", llvm::RelocMode::PIC),
54 ("static", llvm::RelocMode::Static),
55 ("default", llvm::RelocMode::Default),
56 ("dynamic-no-pic", llvm::RelocMode::DynamicNoPic),
57 ("ropi", llvm::RelocMode::ROPI),
58 ("rwpi", llvm::RelocMode::RWPI),
59 ("ropi-rwpi", llvm::RelocMode::ROPI_RWPI),
62 pub const CODE_GEN_MODEL_ARGS : [(&'static str, llvm::CodeModel); 5] = [
63 ("default", llvm::CodeModel::Default),
64 ("small", llvm::CodeModel::Small),
65 ("kernel", llvm::CodeModel::Kernel),
66 ("medium", llvm::CodeModel::Medium),
67 ("large", llvm::CodeModel::Large),
70 pub fn llvm_err(handler: &errors::Handler, msg: String) -> FatalError {
71 match llvm::last_error() {
72 Some(err) => handler.fatal(&format!("{}: {}", msg, err)),
73 None => handler.fatal(&msg),
77 pub fn write_output_file(
78 handler: &errors::Handler,
79 target: llvm::TargetMachineRef,
80 pm: llvm::PassManagerRef,
83 file_type: llvm::FileType) -> Result<(), FatalError> {
85 let output_c = path2cstr(output);
86 let result = llvm::LLVMRustWriteOutputFile(
87 target, pm, m, output_c.as_ptr(), file_type);
88 if result.into_result().is_err() {
89 let msg = format!("could not write output to {}", output.display());
90 Err(llvm_err(handler, msg))
97 // On android, we by default compile for armv7 processors. This enables
98 // things like double word CAS instructions (rather than emulating them)
99 // which are *far* more efficient. This is obviously undesirable in some
100 // cases, so if any sort of target feature is specified we don't append v7
101 // to the feature list.
103 // On iOS only armv7 and newer are supported. So it is useful to
104 // get all hardware potential via VFP3 (hardware floating point)
105 // and NEON (SIMD) instructions supported by LLVM.
106 // Note that without those flags various linking errors might
107 // arise as some of intrinsics are converted into function calls
108 // and nobody provides implementations those functions
109 fn target_feature(sess: &Session) -> String {
110 let rustc_features = [
113 let requested_features = sess.opts.cg.target_feature.split(',');
114 let llvm_features = requested_features.filter(|f| {
115 !rustc_features.iter().any(|s| f.contains(s))
118 sess.target.target.options.features,
119 llvm_features.collect::<Vec<_>>().join(","))
122 fn get_llvm_opt_level(optimize: config::OptLevel) -> llvm::CodeGenOptLevel {
124 config::OptLevel::No => llvm::CodeGenOptLevel::None,
125 config::OptLevel::Less => llvm::CodeGenOptLevel::Less,
126 config::OptLevel::Default => llvm::CodeGenOptLevel::Default,
127 config::OptLevel::Aggressive => llvm::CodeGenOptLevel::Aggressive,
128 _ => llvm::CodeGenOptLevel::Default,
132 fn get_llvm_opt_size(optimize: config::OptLevel) -> llvm::CodeGenOptSize {
134 config::OptLevel::Size => llvm::CodeGenOptSizeDefault,
135 config::OptLevel::SizeMin => llvm::CodeGenOptSizeAggressive,
136 _ => llvm::CodeGenOptSizeNone,
140 pub fn create_target_machine(sess: &Session) -> TargetMachineRef {
141 let reloc_model = get_reloc_model(sess);
143 let opt_level = get_llvm_opt_level(sess.opts.optimize);
144 let use_softfp = sess.opts.cg.soft_float;
146 let ffunction_sections = sess.target.target.options.function_sections;
147 let fdata_sections = ffunction_sections;
149 let code_model_arg = match sess.opts.cg.code_model {
151 None => &sess.target.target.options.code_model,
154 let code_model = match CODE_GEN_MODEL_ARGS.iter().find(
155 |&&arg| arg.0 == code_model_arg) {
158 sess.err(&format!("{:?} is not a valid code model",
162 sess.abort_if_errors();
167 let triple = &sess.target.target.llvm_target;
170 let triple = CString::new(triple.as_bytes()).unwrap();
171 let cpu = match sess.opts.cg.target_cpu {
173 None => &*sess.target.target.options.cpu
175 let cpu = CString::new(cpu.as_bytes()).unwrap();
176 let features = CString::new(target_feature(sess).as_bytes()).unwrap();
177 llvm::LLVMRustCreateTargetMachine(
178 triple.as_ptr(), cpu.as_ptr(), features.as_ptr(),
190 let msg = format!("Could not create LLVM TargetMachine for triple: {}",
192 panic!(llvm_err(sess.diagnostic(), msg));
199 /// Module-specific configuration for `optimize_and_codegen`.
200 pub struct ModuleConfig {
201 /// LLVM TargetMachine to use for codegen.
202 tm: TargetMachineRef,
203 /// Names of additional optimization passes to run.
205 /// Some(level) to optimize at a certain level, or None to run
206 /// absolutely no optimizations (used for the metadata module).
207 opt_level: Option<llvm::CodeGenOptLevel>,
209 /// Some(level) to optimize binary size, or None to not affect program size.
210 opt_size: Option<llvm::CodeGenOptSize>,
212 // Flags indicating which outputs to produce.
213 emit_no_opt_bc: bool,
219 // Miscellaneous flags. These are mostly copied from command-line
222 no_prepopulate_passes: bool,
225 vectorize_loop: bool,
227 merge_functions: bool,
228 inline_threshold: Option<usize>,
229 // Instead of creating an object file by doing LLVM codegen, just
230 // make the object file bitcode. Provides easy compatibility with
231 // emscripten's ecc compiler, when used as the linker.
232 obj_is_bitcode: bool,
235 unsafe impl Send for ModuleConfig { }
238 fn new(sess: &Session, passes: Vec<String>) -> ModuleConfig {
240 tm: create_target_machine(sess),
245 emit_no_opt_bc: false,
251 obj_is_bitcode: false,
254 no_prepopulate_passes: false,
257 vectorize_loop: false,
258 vectorize_slp: false,
259 merge_functions: false,
260 inline_threshold: None
264 fn set_flags(&mut self, sess: &Session, no_builtins: bool) {
265 self.no_verify = sess.no_verify();
266 self.no_prepopulate_passes = sess.opts.cg.no_prepopulate_passes;
267 self.no_builtins = no_builtins;
268 self.time_passes = sess.time_passes();
269 self.inline_threshold = sess.opts.cg.inline_threshold;
270 self.obj_is_bitcode = sess.target.target.options.obj_is_bitcode;
272 // Copy what clang does by turning on loop vectorization at O2 and
273 // slp vectorization at O3. Otherwise configure other optimization aspects
274 // of this pass manager builder.
275 // Turn off vectorization for emscripten, as it's not very well supported.
276 self.vectorize_loop = !sess.opts.cg.no_vectorize_loops &&
277 (sess.opts.optimize == config::OptLevel::Default ||
278 sess.opts.optimize == config::OptLevel::Aggressive) &&
279 !sess.target.target.options.is_like_emscripten;
281 self.vectorize_slp = !sess.opts.cg.no_vectorize_slp &&
282 sess.opts.optimize == config::OptLevel::Aggressive &&
283 !sess.target.target.options.is_like_emscripten;
285 self.merge_functions = sess.opts.optimize == config::OptLevel::Default ||
286 sess.opts.optimize == config::OptLevel::Aggressive;
289 fn clone(&self, sess: &Session) -> ModuleConfig {
291 tm: create_target_machine(sess),
292 passes: self.passes.clone(),
293 opt_level: self.opt_level,
294 opt_size: self.opt_size,
296 emit_no_opt_bc: self.emit_no_opt_bc,
297 emit_bc: self.emit_bc,
298 emit_lto_bc: self.emit_lto_bc,
299 emit_ir: self.emit_ir,
300 emit_asm: self.emit_asm,
301 emit_obj: self.emit_obj,
302 obj_is_bitcode: self.obj_is_bitcode,
304 no_verify: self.no_verify,
305 no_prepopulate_passes: self.no_prepopulate_passes,
306 no_builtins: self.no_builtins,
307 time_passes: self.time_passes,
308 vectorize_loop: self.vectorize_loop,
309 vectorize_slp: self.vectorize_slp,
310 merge_functions: self.merge_functions,
311 inline_threshold: self.inline_threshold,
316 impl Drop for ModuleConfig {
319 llvm::LLVMRustDisposeTargetMachine(self.tm);
324 /// Additional resources used by optimize_and_codegen (not module specific)
326 pub struct CodegenContext {
327 // Resouces needed when running LTO
328 pub time_passes: bool,
330 pub no_landing_pads: bool,
331 pub exported_symbols: Arc<ExportedSymbols>,
332 pub opts: Arc<config::Options>,
333 pub crate_types: Vec<config::CrateType>,
334 pub each_linked_rlib_for_lto: Vec<(CrateNum, PathBuf)>,
335 // Handler to use for diagnostics produced during codegen.
336 pub diag_emitter: SharedEmitter,
337 // LLVM passes added by plugins.
338 pub plugin_passes: Vec<String>,
339 // LLVM optimizations for which we want to print remarks.
341 // Worker thread number
343 // The incremental compilation session directory, or None if we are not
344 // compiling incrementally
345 pub incr_comp_session_dir: Option<PathBuf>,
346 // Channel back to the main control thread to send messages to
347 coordinator_send: Sender<Message>,
348 // A reference to the TimeGraph so we can register timings. None means that
349 // measuring is disabled.
350 time_graph: Option<TimeGraph>,
353 impl CodegenContext {
354 fn create_diag_handler(&self) -> Handler {
355 Handler::with_emitter(true, false, Box::new(self.diag_emitter.clone()))
359 struct HandlerFreeVars<'a> {
360 cgcx: &'a CodegenContext,
361 diag_handler: &'a Handler,
364 unsafe extern "C" fn report_inline_asm<'a, 'b>(cgcx: &'a CodegenContext,
367 cgcx.diag_emitter.inline_asm_error(cookie as u32, msg.to_string());
370 unsafe extern "C" fn inline_asm_handler(diag: SMDiagnosticRef,
373 let HandlerFreeVars { cgcx, .. } = *(user as *const HandlerFreeVars);
375 let msg = llvm::build_string(|s| llvm::LLVMRustWriteSMDiagnosticToString(diag, s))
376 .expect("non-UTF8 SMDiagnostic");
378 report_inline_asm(cgcx, &msg, cookie);
381 unsafe extern "C" fn diagnostic_handler(info: DiagnosticInfoRef, user: *mut c_void) {
382 let HandlerFreeVars { cgcx, diag_handler, .. } = *(user as *const HandlerFreeVars);
384 match llvm::diagnostic::Diagnostic::unpack(info) {
385 llvm::diagnostic::InlineAsm(inline) => {
386 report_inline_asm(cgcx,
387 &llvm::twine_to_string(inline.message),
391 llvm::diagnostic::Optimization(opt) => {
392 let enabled = match cgcx.remark {
394 SomePasses(ref v) => v.iter().any(|s| *s == opt.pass_name),
398 diag_handler.note_without_error(&format!("optimization {} for {} at {}:{}:{}: {}",
412 // Unsafe due to LLVM calls.
413 unsafe fn optimize_and_codegen(cgcx: &CodegenContext,
414 diag_handler: &Handler,
415 mtrans: ModuleTranslation,
416 config: ModuleConfig,
417 output_names: OutputFilenames)
418 -> Result<CompiledModule, FatalError>
420 let (llmod, llcx) = match mtrans.source {
421 ModuleSource::Translated(ref llvm) => (llvm.llmod, llvm.llcx),
422 ModuleSource::Preexisting(_) => {
423 bug!("optimize_and_codegen: called with ModuleSource::Preexisting")
429 let fv = HandlerFreeVars {
433 let fv = &fv as *const HandlerFreeVars as *mut c_void;
435 llvm::LLVMRustSetInlineAsmDiagnosticHandler(llcx, inline_asm_handler, fv);
436 llvm::LLVMContextSetDiagnosticHandler(llcx, diagnostic_handler, fv);
438 let module_name = mtrans.name.clone();
439 let module_name = Some(&module_name[..]);
441 if config.emit_no_opt_bc {
442 let out = output_names.temp_path_ext("no-opt.bc", module_name);
443 let out = path2cstr(&out);
444 llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
447 if config.opt_level.is_some() {
448 // Create the two optimizing pass managers. These mirror what clang
449 // does, and are by populated by LLVM's default PassManagerBuilder.
450 // Each manager has a different set of passes, but they also share
451 // some common passes.
452 let fpm = llvm::LLVMCreateFunctionPassManagerForModule(llmod);
453 let mpm = llvm::LLVMCreatePassManager();
455 // If we're verifying or linting, add them to the function pass
457 let addpass = |pass_name: &str| {
458 let pass_name = CString::new(pass_name).unwrap();
459 let pass = llvm::LLVMRustFindAndCreatePass(pass_name.as_ptr());
463 let pass_manager = match llvm::LLVMRustPassKind(pass) {
464 llvm::PassKind::Function => fpm,
465 llvm::PassKind::Module => mpm,
466 llvm::PassKind::Other => {
467 diag_handler.err("Encountered LLVM pass kind we can't handle");
471 llvm::LLVMRustAddPass(pass_manager, pass);
475 if !config.no_verify { assert!(addpass("verify")); }
476 if !config.no_prepopulate_passes {
477 llvm::LLVMRustAddAnalysisPasses(tm, fpm, llmod);
478 llvm::LLVMRustAddAnalysisPasses(tm, mpm, llmod);
479 with_llvm_pmb(llmod, &config, &mut |b| {
480 llvm::LLVMPassManagerBuilderPopulateFunctionPassManager(b, fpm);
481 llvm::LLVMPassManagerBuilderPopulateModulePassManager(b, mpm);
485 for pass in &config.passes {
487 diag_handler.warn(&format!("unknown pass `{}`, ignoring",
492 for pass in &cgcx.plugin_passes {
494 diag_handler.err(&format!("a plugin asked for LLVM pass \
495 `{}` but LLVM does not \
496 recognize it", pass));
500 diag_handler.abort_if_errors();
502 // Finally, run the actual optimization passes
503 time(config.time_passes, &format!("llvm function passes [{}]", module_name.unwrap()), ||
504 llvm::LLVMRustRunFunctionPassManager(fpm, llmod));
505 time(config.time_passes, &format!("llvm module passes [{}]", module_name.unwrap()), ||
506 llvm::LLVMRunPassManager(mpm, llmod));
508 // Deallocate managers that we're now done with
509 llvm::LLVMDisposePassManager(fpm);
510 llvm::LLVMDisposePassManager(mpm);
513 time(cgcx.time_passes, "all lto passes", || {
514 let temp_no_opt_bc_filename =
515 output_names.temp_path_ext("no-opt.lto.bc", module_name);
521 &temp_no_opt_bc_filename)
523 if config.emit_lto_bc {
524 let out = output_names.temp_path_ext("lto.bc", module_name);
525 let out = path2cstr(&out);
526 llvm::LLVMWriteBitcodeToFile(llmod, out.as_ptr());
531 // A codegen-specific pass manager is used to generate object
532 // files for an LLVM module.
534 // Apparently each of these pass managers is a one-shot kind of
535 // thing, so we create a new one for each type of output. The
536 // pass manager passed to the closure should be ensured to not
537 // escape the closure itself, and the manager should only be
539 unsafe fn with_codegen<F, R>(tm: TargetMachineRef,
543 where F: FnOnce(PassManagerRef) -> R,
545 let cpm = llvm::LLVMCreatePassManager();
546 llvm::LLVMRustAddAnalysisPasses(tm, cpm, llmod);
547 llvm::LLVMRustAddLibraryInfo(cpm, llmod, no_builtins);
551 // Change what we write and cleanup based on whether obj files are
552 // just llvm bitcode. In that case write bitcode, and possibly
553 // delete the bitcode if it wasn't requested. Don't generate the
554 // machine code, instead copy the .o file from the .bc
555 let write_bc = config.emit_bc || config.obj_is_bitcode;
556 let rm_bc = !config.emit_bc && config.obj_is_bitcode;
557 let write_obj = config.emit_obj && !config.obj_is_bitcode;
558 let copy_bc_to_obj = config.emit_obj && config.obj_is_bitcode;
560 let bc_out = output_names.temp_path(OutputType::Bitcode, module_name);
561 let obj_out = output_names.temp_path(OutputType::Object, module_name);
564 let bc_out_c = path2cstr(&bc_out);
565 llvm::LLVMWriteBitcodeToFile(llmod, bc_out_c.as_ptr());
568 time(config.time_passes, &format!("codegen passes [{}]", module_name.unwrap()),
569 || -> Result<(), FatalError> {
571 let out = output_names.temp_path(OutputType::LlvmAssembly, module_name);
572 let out = path2cstr(&out);
574 extern "C" fn demangle_callback(input_ptr: *const c_char,
576 output_ptr: *mut c_char,
577 output_len: size_t) -> size_t {
579 slice::from_raw_parts(input_ptr as *const u8, input_len as usize)
582 let input = match str::from_utf8(input) {
587 let output = unsafe {
588 slice::from_raw_parts_mut(output_ptr as *mut u8, output_len as usize)
590 let mut cursor = io::Cursor::new(output);
592 let demangled = match rustc_demangle::try_demangle(input) {
597 if let Err(_) = write!(cursor, "{:#}", demangled) {
598 // Possible only if provided buffer is not big enough
602 cursor.position() as size_t
605 with_codegen(tm, llmod, config.no_builtins, |cpm| {
606 llvm::LLVMRustPrintModule(cpm, llmod, out.as_ptr(), demangle_callback);
607 llvm::LLVMDisposePassManager(cpm);
612 let path = output_names.temp_path(OutputType::Assembly, module_name);
614 // We can't use the same module for asm and binary output, because that triggers
615 // various errors like invalid IR or broken binaries, so we might have to clone the
616 // module to produce the asm output
617 let llmod = if config.emit_obj {
618 llvm::LLVMCloneModule(llmod)
622 with_codegen(tm, llmod, config.no_builtins, |cpm| {
623 write_output_file(diag_handler, tm, cpm, llmod, &path,
624 llvm::FileType::AssemblyFile)
627 llvm::LLVMDisposeModule(llmod);
632 with_codegen(tm, llmod, config.no_builtins, |cpm| {
633 write_output_file(diag_handler, tm, cpm, llmod, &obj_out,
634 llvm::FileType::ObjectFile)
642 debug!("copying bitcode {:?} to obj {:?}", bc_out, obj_out);
643 if let Err(e) = link_or_copy(&bc_out, &obj_out) {
644 diag_handler.err(&format!("failed to copy bitcode to object file: {}", e));
649 debug!("removing_bitcode {:?}", bc_out);
650 if let Err(e) = fs::remove_file(&bc_out) {
651 diag_handler.err(&format!("failed to remove bitcode: {}", e));
655 Ok(mtrans.into_compiled_module(config.emit_obj, config.emit_bc))
658 pub struct CompiledModules {
659 pub modules: Vec<CompiledModule>,
660 pub metadata_module: CompiledModule,
661 pub allocator_module: Option<CompiledModule>,
664 fn need_crate_bitcode_for_rlib(sess: &Session) -> bool {
665 sess.crate_types.borrow().contains(&config::CrateTypeRlib) &&
666 sess.opts.output_types.contains_key(&OutputType::Exe)
669 pub fn start_async_translation(sess: &Session,
670 crate_output: &OutputFilenames,
671 time_graph: Option<TimeGraph>,
674 metadata: EncodedMetadata,
675 exported_symbols: Arc<ExportedSymbols>,
677 windows_subsystem: Option<String>,
678 linker_info: LinkerInfo,
679 crate_info: CrateInfo,
680 no_integrated_as: bool)
681 -> OngoingCrateTranslation {
682 let output_types_override = if no_integrated_as {
683 OutputTypes::new(&[(OutputType::Assembly, None)])
685 sess.opts.output_types.clone()
688 // Figure out what we actually need to build.
689 let mut modules_config = ModuleConfig::new(sess, sess.opts.cg.passes.clone());
690 let mut metadata_config = ModuleConfig::new(sess, vec![]);
691 let mut allocator_config = ModuleConfig::new(sess, vec![]);
693 if let Some(ref sanitizer) = sess.opts.debugging_opts.sanitizer {
695 Sanitizer::Address => {
696 modules_config.passes.push("asan".to_owned());
697 modules_config.passes.push("asan-module".to_owned());
699 Sanitizer::Memory => {
700 modules_config.passes.push("msan".to_owned())
702 Sanitizer::Thread => {
703 modules_config.passes.push("tsan".to_owned())
709 if sess.opts.debugging_opts.profile {
710 modules_config.passes.push("insert-gcov-profiling".to_owned())
713 modules_config.opt_level = Some(get_llvm_opt_level(sess.opts.optimize));
714 modules_config.opt_size = Some(get_llvm_opt_size(sess.opts.optimize));
716 // Save all versions of the bytecode if we're saving our temporaries.
717 if sess.opts.cg.save_temps {
718 modules_config.emit_no_opt_bc = true;
719 modules_config.emit_bc = true;
720 modules_config.emit_lto_bc = true;
721 metadata_config.emit_bc = true;
722 allocator_config.emit_bc = true;
725 // Emit bitcode files for the crate if we're emitting an rlib.
726 // Whenever an rlib is created, the bitcode is inserted into the
727 // archive in order to allow LTO against it.
728 if need_crate_bitcode_for_rlib(sess) {
729 modules_config.emit_bc = true;
732 for output_type in output_types_override.keys() {
734 OutputType::Bitcode => { modules_config.emit_bc = true; }
735 OutputType::LlvmAssembly => { modules_config.emit_ir = true; }
736 OutputType::Assembly => {
737 modules_config.emit_asm = true;
738 // If we're not using the LLVM assembler, this function
739 // could be invoked specially with output_type_assembly, so
740 // in this case we still want the metadata object file.
741 if !sess.opts.output_types.contains_key(&OutputType::Assembly) {
742 metadata_config.emit_obj = true;
743 allocator_config.emit_obj = true;
746 OutputType::Object => { modules_config.emit_obj = true; }
747 OutputType::Metadata => { metadata_config.emit_obj = true; }
749 modules_config.emit_obj = true;
750 metadata_config.emit_obj = true;
751 allocator_config.emit_obj = true;
753 OutputType::Mir => {}
754 OutputType::DepInfo => {}
758 modules_config.set_flags(sess, no_builtins);
759 metadata_config.set_flags(sess, no_builtins);
760 allocator_config.set_flags(sess, no_builtins);
762 // Exclude metadata and allocator modules from time_passes output, since
763 // they throw off the "LLVM passes" measurement.
764 metadata_config.time_passes = false;
765 allocator_config.time_passes = false;
767 let client = sess.jobserver_from_env.clone().unwrap_or_else(|| {
768 // Pick a "reasonable maximum" if we don't otherwise have a jobserver in
769 // our environment, capping out at 32 so we don't take everything down
770 // by hogging the process run queue.
771 Client::new(32).expect("failed to create jobserver")
774 let (shared_emitter, shared_emitter_main) = SharedEmitter::new();
775 let (trans_worker_send, trans_worker_receive) = channel();
776 let (coordinator_send, coordinator_receive) = channel();
778 let coordinator_thread = start_executing_work(sess,
782 coordinator_send.clone(),
786 exported_symbols.clone());
787 OngoingCrateTranslation {
796 regular_module_config: modules_config,
797 metadata_module_config: metadata_config,
798 allocator_module_config: allocator_config,
801 output_filenames: crate_output.clone(),
803 trans_worker_receive,
805 future: coordinator_thread
809 fn copy_module_artifacts_into_incr_comp_cache(sess: &Session,
810 compiled_modules: &CompiledModules,
811 crate_output: &OutputFilenames) {
812 if sess.opts.incremental.is_none() {
816 for module in compiled_modules.modules.iter() {
817 let mut files = vec![];
820 let path = crate_output.temp_path(OutputType::Object, Some(&module.name));
821 files.push((OutputType::Object, path));
825 let path = crate_output.temp_path(OutputType::Bitcode, Some(&module.name));
826 files.push((OutputType::Bitcode, path));
829 save_trans_partition(sess, &module.name, module.symbol_name_hash, &files);
833 fn produce_final_output_artifacts(sess: &Session,
834 compiled_modules: &CompiledModules,
835 crate_output: &OutputFilenames) {
836 let mut user_wants_bitcode = false;
837 let mut user_wants_objects = false;
839 // Produce final compile outputs.
840 let copy_gracefully = |from: &Path, to: &Path| {
841 if let Err(e) = fs::copy(from, to) {
842 sess.err(&format!("could not copy {:?} to {:?}: {}", from, to, e));
846 let copy_if_one_unit = |output_type: OutputType,
847 keep_numbered: bool| {
848 if compiled_modules.modules.len() == 1 {
849 // 1) Only one codegen unit. In this case it's no difficulty
850 // to copy `foo.0.x` to `foo.x`.
851 let module_name = Some(&compiled_modules.modules[0].name[..]);
852 let path = crate_output.temp_path(output_type, module_name);
853 copy_gracefully(&path,
854 &crate_output.path(output_type));
855 if !sess.opts.cg.save_temps && !keep_numbered {
856 // The user just wants `foo.x`, not `foo.#module-name#.x`.
860 let ext = crate_output.temp_path(output_type, None)
867 if crate_output.outputs.contains_key(&output_type) {
868 // 2) Multiple codegen units, with `--emit foo=some_name`. We have
869 // no good solution for this case, so warn the user.
870 sess.warn(&format!("ignoring emit path because multiple .{} files \
871 were produced", ext));
872 } else if crate_output.single_output_file.is_some() {
873 // 3) Multiple codegen units, with `-o some_name`. We have
874 // no good solution for this case, so warn the user.
875 sess.warn(&format!("ignoring -o because multiple .{} files \
876 were produced", ext));
878 // 4) Multiple codegen units, but no explicit name. We
879 // just leave the `foo.0.x` files in place.
880 // (We don't have to do any work in this case.)
885 // Flag to indicate whether the user explicitly requested bitcode.
886 // Otherwise, we produced it only as a temporary output, and will need
888 for output_type in crate_output.outputs.keys() {
890 OutputType::Bitcode => {
891 user_wants_bitcode = true;
892 // Copy to .bc, but always keep the .0.bc. There is a later
893 // check to figure out if we should delete .0.bc files, or keep
894 // them for making an rlib.
895 copy_if_one_unit(OutputType::Bitcode, true);
897 OutputType::LlvmAssembly => {
898 copy_if_one_unit(OutputType::LlvmAssembly, false);
900 OutputType::Assembly => {
901 copy_if_one_unit(OutputType::Assembly, false);
903 OutputType::Object => {
904 user_wants_objects = true;
905 copy_if_one_unit(OutputType::Object, true);
908 OutputType::Metadata |
910 OutputType::DepInfo => {}
914 // Clean up unwanted temporary files.
916 // We create the following files by default:
917 // - #crate#.#module-name#.bc
918 // - #crate#.#module-name#.o
919 // - #crate#.crate.metadata.bc
920 // - #crate#.crate.metadata.o
921 // - #crate#.o (linked from crate.##.o)
922 // - #crate#.bc (copied from crate.##.bc)
923 // We may create additional files if requested by the user (through
924 // `-C save-temps` or `--emit=` flags).
926 if !sess.opts.cg.save_temps {
927 // Remove the temporary .#module-name#.o objects. If the user didn't
928 // explicitly request bitcode (with --emit=bc), and the bitcode is not
929 // needed for building an rlib, then we must remove .#module-name#.bc as
932 // Specific rules for keeping .#module-name#.bc:
933 // - If we're building an rlib (`needs_crate_bitcode`), then keep
935 // - If the user requested bitcode (`user_wants_bitcode`), and
936 // codegen_units > 1, then keep it.
937 // - If the user requested bitcode but codegen_units == 1, then we
938 // can toss .#module-name#.bc because we copied it to .bc earlier.
939 // - If we're not building an rlib and the user didn't request
940 // bitcode, then delete .#module-name#.bc.
941 // If you change how this works, also update back::link::link_rlib,
942 // where .#module-name#.bc files are (maybe) deleted after making an
944 let needs_crate_bitcode = need_crate_bitcode_for_rlib(sess);
945 let needs_crate_object = crate_output.outputs.contains_key(&OutputType::Exe);
947 let keep_numbered_bitcode = needs_crate_bitcode ||
948 (user_wants_bitcode && sess.opts.cg.codegen_units > 1);
950 let keep_numbered_objects = needs_crate_object ||
951 (user_wants_objects && sess.opts.cg.codegen_units > 1);
953 for module in compiled_modules.modules.iter() {
954 let module_name = Some(&module.name[..]);
956 if module.emit_obj && !keep_numbered_objects {
957 let path = crate_output.temp_path(OutputType::Object, module_name);
961 if module.emit_bc && !keep_numbered_bitcode {
962 let path = crate_output.temp_path(OutputType::Bitcode, module_name);
967 if compiled_modules.metadata_module.emit_bc && !user_wants_bitcode {
968 let path = crate_output.temp_path(OutputType::Bitcode,
969 Some(&compiled_modules.metadata_module.name));
973 if let Some(ref allocator_module) = compiled_modules.allocator_module {
974 if allocator_module.emit_bc && !user_wants_bitcode {
975 let path = crate_output.temp_path(OutputType::Bitcode,
976 Some(&allocator_module.name));
982 // We leave the following files around by default:
984 // - #crate#.crate.metadata.o
986 // These are used in linking steps and will be cleaned up afterward.
989 pub fn dump_incremental_data(trans: &CrateTranslation) {
991 for mtrans in trans.modules.iter() {
992 if mtrans.pre_existing {
996 eprintln!("incremental: re-using {} out of {} modules", reuse, trans.modules.len());
1000 mtrans: ModuleTranslation,
1001 config: ModuleConfig,
1002 output_names: OutputFilenames
1005 impl fmt::Debug for WorkItem {
1006 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1007 write!(f, "WorkItem({})", self.mtrans.name)
1011 fn build_work_item(mtrans: ModuleTranslation,
1012 config: ModuleConfig,
1013 output_names: OutputFilenames)
1023 fn execute_work_item(cgcx: &CodegenContext, work_item: WorkItem)
1024 -> Result<CompiledModule, FatalError>
1026 let diag_handler = cgcx.create_diag_handler();
1027 let module_name = work_item.mtrans.name.clone();
1029 let pre_existing = match work_item.mtrans.source {
1030 ModuleSource::Translated(_) => None,
1031 ModuleSource::Preexisting(ref wp) => Some(wp.clone()),
1034 if let Some(wp) = pre_existing {
1035 let incr_comp_session_dir = cgcx.incr_comp_session_dir
1038 let name = &work_item.mtrans.name;
1039 for (kind, saved_file) in wp.saved_files {
1040 let obj_out = work_item.output_names.temp_path(kind, Some(name));
1041 let source_file = in_incr_comp_dir(&incr_comp_session_dir,
1043 debug!("copying pre-existing module `{}` from {:?} to {}",
1044 work_item.mtrans.name,
1047 match link_or_copy(&source_file, &obj_out) {
1050 diag_handler.err(&format!("unable to copy {} to {}: {}",
1051 source_file.display(),
1060 kind: ModuleKind::Regular,
1062 symbol_name_hash: work_item.mtrans.symbol_name_hash,
1063 emit_bc: work_item.config.emit_bc,
1064 emit_obj: work_item.config.emit_obj,
1067 debug!("llvm-optimizing {:?}", module_name);
1070 optimize_and_codegen(cgcx,
1074 work_item.output_names)
1081 Token(io::Result<Acquired>),
1083 result: Result<CompiledModule, ()>,
1087 llvm_work_item: WorkItem,
1096 code: Option<String>,
1100 #[derive(PartialEq, Clone, Copy, Debug)]
1101 enum MainThreadWorkerState {
1107 fn start_executing_work(sess: &Session,
1108 crate_info: &CrateInfo,
1109 shared_emitter: SharedEmitter,
1110 trans_worker_send: Sender<Message>,
1111 coordinator_send: Sender<Message>,
1112 coordinator_receive: Receiver<Message>,
1114 time_graph: Option<TimeGraph>,
1115 exported_symbols: Arc<ExportedSymbols>)
1116 -> thread::JoinHandle<CompiledModules> {
1117 // First up, convert our jobserver into a helper thread so we can use normal
1118 // mpsc channels to manage our messages and such. Once we've got the helper
1119 // thread then request `n-1` tokens because all of our work items are ready
1122 // Note that the `n-1` is here because we ourselves have a token (our
1123 // process) and we'll use that token to execute at least one unit of work.
1125 // After we've requested all these tokens then we'll, when we can, get
1126 // tokens on `rx` above which will get managed in the main loop below.
1127 let coordinator_send2 = coordinator_send.clone();
1128 let helper = jobserver.into_helper_thread(move |token| {
1129 drop(coordinator_send2.send(Message::Token(token)));
1130 }).expect("failed to spawn helper thread");
1132 let mut each_linked_rlib_for_lto = Vec::new();
1133 drop(link::each_linked_rlib(sess, crate_info, &mut |cnum, path| {
1134 if link::ignored_for_lto(crate_info, cnum) {
1137 each_linked_rlib_for_lto.push((cnum, path.to_path_buf()));
1140 let cgcx = CodegenContext {
1141 crate_types: sess.crate_types.borrow().clone(),
1142 each_linked_rlib_for_lto,
1144 no_landing_pads: sess.no_landing_pads(),
1145 opts: Arc::new(sess.opts.clone()),
1146 time_passes: sess.time_passes(),
1148 plugin_passes: sess.plugin_llvm_passes.borrow().clone(),
1149 remark: sess.opts.cg.remark.clone(),
1151 incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()),
1153 diag_emitter: shared_emitter.clone(),
1157 // This is the "main loop" of parallel work happening for parallel codegen.
1158 // It's here that we manage parallelism, schedule work, and work with
1159 // messages coming from clients.
1161 // There are a few environmental pre-conditions that shape how the system
1164 // - Error reporting only can happen on the main thread because that's the
1165 // only place where we have access to the compiler `Session`.
1166 // - LLVM work can be done on any thread.
1167 // - Translation can only happen on the main thread.
1168 // - Each thread doing substantial work most be in possession of a `Token`
1169 // from the `Jobserver`.
1170 // - The compiler process always holds one `Token`. Any additional `Tokens`
1171 // have to be requested from the `Jobserver`.
1175 // The error reporting restriction is handled separately from the rest: We
1176 // set up a `SharedEmitter` the holds an open channel to the main thread.
1177 // When an error occurs on any thread, the shared emitter will send the
1178 // error message to the receiver main thread (`SharedEmitterMain`). The
1179 // main thread will periodically query this error message queue and emit
1180 // any error messages it has received. It might even abort compilation if
1181 // has received a fatal error. In this case we rely on all other threads
1182 // being torn down automatically with the main thread.
1183 // Since the main thread will often be busy doing translation work, error
1184 // reporting will be somewhat delayed, since the message queue can only be
1185 // checked in between to work packages.
1187 // Work Processing Infrastructure
1188 // ==============================
1189 // The work processing infrastructure knows three major actors:
1191 // - the coordinator thread,
1192 // - the main thread, and
1193 // - LLVM worker threads
1195 // The coordinator thread is running a message loop. It instructs the main
1196 // thread about what work to do when, and it will spawn off LLVM worker
1197 // threads as open LLVM WorkItems become available.
1199 // The job of the main thread is to translate CGUs into LLVM work package
1200 // (since the main thread is the only thread that can do this). The main
1201 // thread will block until it receives a message from the coordinator, upon
1202 // which it will translate one CGU, send it to the coordinator and block
1203 // again. This way the coordinator can control what the main thread is
1206 // The coordinator keeps a queue of LLVM WorkItems, and when a `Token` is
1207 // available, it will spawn off a new LLVM worker thread and let it process
1208 // that a WorkItem. When a LLVM worker thread is done with its WorkItem,
1209 // it will just shut down, which also frees all resources associated with
1210 // the given LLVM module, and sends a message to the coordinator that the
1211 // has been completed.
1215 // The scheduler's goal is to minimize the time it takes to complete all
1216 // work there is, however, we also want to keep memory consumption low
1217 // if possible. These two goals are at odds with each other: If memory
1218 // consumption were not an issue, we could just let the main thread produce
1219 // LLVM WorkItems at full speed, assuring maximal utilization of
1220 // Tokens/LLVM worker threads. However, since translation usual is faster
1221 // than LLVM processing, the queue of LLVM WorkItems would fill up and each
1222 // WorkItem potentially holds on to a substantial amount of memory.
1224 // So the actual goal is to always produce just enough LLVM WorkItems as
1225 // not to starve our LLVM worker threads. That means, once we have enough
1226 // WorkItems in our queue, we can block the main thread, so it does not
1227 // produce more until we need them.
1229 // Doing LLVM Work on the Main Thread
1230 // ----------------------------------
1231 // Since the main thread owns the compiler processes implicit `Token`, it is
1232 // wasteful to keep it blocked without doing any work. Therefore, what we do
1233 // in this case is: We spawn off an additional LLVM worker thread that helps
1234 // reduce the queue. The work it is doing corresponds to the implicit
1235 // `Token`. The coordinator will mark the main thread as being busy with
1236 // LLVM work. (The actual work happens on another OS thread but we just care
1237 // about `Tokens`, not actual threads).
1239 // When any LLVM worker thread finishes while the main thread is marked as
1240 // "busy with LLVM work", we can do a little switcheroo: We give the Token
1241 // of the just finished thread to the LLVM worker thread that is working on
1242 // behalf of the main thread's implicit Token, thus freeing up the main
1243 // thread again. The coordinator can then again decide what the main thread
1244 // should do. This allows the coordinator to make decisions at more points
1247 // Striking a Balance between Throughput and Memory Consumption
1248 // ------------------------------------------------------------
1249 // Since our two goals, (1) use as many Tokens as possible and (2) keep
1250 // memory consumption as low as possible, are in conflict with each other,
1251 // we have to find a trade off between them. Right now, the goal is to keep
1252 // all workers busy, which means that no worker should find the queue empty
1253 // when it is ready to start.
1254 // How do we do achieve this? Good question :) We actually never know how
1255 // many `Tokens` are potentially available so it's hard to say how much to
1256 // fill up the queue before switching the main thread to LLVM work. Also we
1257 // currently don't have a means to estimate how long a running LLVM worker
1258 // will still be busy with it's current WorkItem. However, we know the
1259 // maximal count of available Tokens that makes sense (=the number of CPU
1260 // cores), so we can take a conservative guess. The heuristic we use here
1261 // is implemented in the `queue_full_enough()` function.
1263 // Some Background on Jobservers
1264 // -----------------------------
1265 // It's worth also touching on the management of parallelism here. We don't
1266 // want to just spawn a thread per work item because while that's optimal
1267 // parallelism it may overload a system with too many threads or violate our
1268 // configuration for the maximum amount of cpu to use for this process. To
1269 // manage this we use the `jobserver` crate.
1271 // Job servers are an artifact of GNU make and are used to manage
1272 // parallelism between processes. A jobserver is a glorified IPC semaphore
1273 // basically. Whenever we want to run some work we acquire the semaphore,
1274 // and whenever we're done with that work we release the semaphore. In this
1275 // manner we can ensure that the maximum number of parallel workers is
1276 // capped at any one point in time.
1277 return thread::spawn(move || {
1278 // We pretend to be within the top-level LLVM time-passes task here:
1281 let max_workers = ::num_cpus::get();
1282 let mut worker_id_counter = 0;
1283 let mut free_worker_ids = Vec::new();
1284 let mut get_worker_id = |free_worker_ids: &mut Vec<usize>| {
1285 if let Some(id) = free_worker_ids.pop() {
1288 let id = worker_id_counter;
1289 worker_id_counter += 1;
1294 // This is where we collect codegen units that have gone all the way
1295 // through translation and LLVM.
1296 let mut compiled_modules = vec![];
1297 let mut compiled_metadata_module = None;
1298 let mut compiled_allocator_module = None;
1300 // This flag tracks whether all items have gone through translations
1301 let mut translation_done = false;
1303 // This is the queue of LLVM work items that still need processing.
1304 let mut work_items = Vec::new();
1306 // This are the Jobserver Tokens we currently hold. Does not include
1307 // the implicit Token the compiler process owns no matter what.
1308 let mut tokens = Vec::new();
1310 let mut main_thread_worker_state = MainThreadWorkerState::Idle;
1311 let mut running = 0;
1313 let mut llvm_start_time = None;
1315 // Run the message loop while there's still anything that needs message
1317 while !translation_done ||
1318 work_items.len() > 0 ||
1320 main_thread_worker_state != MainThreadWorkerState::Idle {
1322 // While there are still CGUs to be translated, the coordinator has
1323 // to decide how to utilize the compiler processes implicit Token:
1324 // For translating more CGU or for running them through LLVM.
1325 if !translation_done {
1326 if main_thread_worker_state == MainThreadWorkerState::Idle {
1327 if !queue_full_enough(work_items.len(), running, max_workers) {
1328 // The queue is not full enough, translate more items:
1329 if let Err(_) = trans_worker_send.send(Message::TranslateItem) {
1330 panic!("Could not send Message::TranslateItem to main thread")
1332 main_thread_worker_state = MainThreadWorkerState::Translating;
1334 // The queue is full enough to not let the worker
1335 // threads starve. Use the implicit Token to do some
1337 let (item, _) = work_items.pop()
1338 .expect("queue empty - queue_full_enough() broken?");
1339 let cgcx = CodegenContext {
1340 worker: get_worker_id(&mut free_worker_ids),
1343 maybe_start_llvm_timer(&item, &mut llvm_start_time);
1344 main_thread_worker_state = MainThreadWorkerState::LLVMing;
1345 spawn_work(cgcx, item);
1349 // In this branch, we know that everything has been translated,
1350 // so it's just a matter of determining whether the implicit
1351 // Token is free to use for LLVM work.
1352 match main_thread_worker_state {
1353 MainThreadWorkerState::Idle => {
1354 if let Some((item, _)) = work_items.pop() {
1355 let cgcx = CodegenContext {
1356 worker: get_worker_id(&mut free_worker_ids),
1359 maybe_start_llvm_timer(&item, &mut llvm_start_time);
1360 main_thread_worker_state = MainThreadWorkerState::LLVMing;
1361 spawn_work(cgcx, item);
1363 // There is no unstarted work, so let the main thread
1364 // take over for a running worker. Otherwise the
1365 // implicit token would just go to waste.
1366 // We reduce the `running` counter by one. The
1367 // `tokens.truncate()` below will take care of
1368 // giving the Token back.
1369 debug_assert!(running > 0);
1371 main_thread_worker_state = MainThreadWorkerState::LLVMing;
1374 MainThreadWorkerState::Translating => {
1375 bug!("trans worker should not be translating after \
1376 translation was already completed")
1378 MainThreadWorkerState::LLVMing => {
1379 // Already making good use of that token
1384 // Spin up what work we can, only doing this while we've got available
1385 // parallelism slots and work left to spawn.
1386 while work_items.len() > 0 && running < tokens.len() {
1387 let (item, _) = work_items.pop().unwrap();
1389 maybe_start_llvm_timer(&item, &mut llvm_start_time);
1391 let cgcx = CodegenContext {
1392 worker: get_worker_id(&mut free_worker_ids),
1396 spawn_work(cgcx, item);
1400 // Relinquish accidentally acquired extra tokens
1401 tokens.truncate(running);
1403 match coordinator_receive.recv().unwrap() {
1404 // Save the token locally and the next turn of the loop will use
1405 // this to spawn a new unit of work, or it may get dropped
1406 // immediately if we have no more work to spawn.
1407 Message::Token(token) => {
1412 if main_thread_worker_state == MainThreadWorkerState::LLVMing {
1413 // If the main thread token is used for LLVM work
1414 // at the moment, we turn that thread into a regular
1415 // LLVM worker thread, so the main thread is free
1416 // to react to translation demand.
1417 main_thread_worker_state = MainThreadWorkerState::Idle;
1422 let msg = &format!("failed to acquire jobserver token: {}", e);
1423 shared_emitter.fatal(msg);
1424 // Exit the coordinator thread
1430 Message::TranslationDone { llvm_work_item, cost, is_last } => {
1431 // We keep the queue sorted by estimated processing cost,
1432 // so that more expensive items are processed earlier. This
1433 // is good for throughput as it gives the main thread more
1434 // time to fill up the queue and it avoids scheduling
1435 // expensive items to the end.
1436 // Note, however, that this is not ideal for memory
1437 // consumption, as LLVM module sizes are not evenly
1439 let insertion_index =
1440 work_items.binary_search_by_key(&cost, |&(_, cost)| cost);
1441 let insertion_index = match insertion_index {
1442 Ok(idx) | Err(idx) => idx
1444 work_items.insert(insertion_index, (llvm_work_item, cost));
1447 // If this is the last, don't request a token because
1448 // the trans worker thread will be free to handle this
1450 translation_done = true;
1452 helper.request_token();
1455 assert_eq!(main_thread_worker_state,
1456 MainThreadWorkerState::Translating);
1457 main_thread_worker_state = MainThreadWorkerState::Idle;
1460 // If a thread exits successfully then we drop a token associated
1461 // with that worker and update our `running` count. We may later
1462 // re-acquire a token to continue running more work. We may also not
1463 // actually drop a token here if the worker was running with an
1464 // "ephemeral token"
1466 // Note that if the thread failed that means it panicked, so we
1467 // abort immediately.
1468 Message::Done { result: Ok(compiled_module), worker_id } => {
1469 if main_thread_worker_state == MainThreadWorkerState::LLVMing {
1470 main_thread_worker_state = MainThreadWorkerState::Idle;
1475 free_worker_ids.push(worker_id);
1477 match compiled_module.kind {
1478 ModuleKind::Regular => {
1479 compiled_modules.push(compiled_module);
1481 ModuleKind::Metadata => {
1482 assert!(compiled_metadata_module.is_none());
1483 compiled_metadata_module = Some(compiled_module);
1485 ModuleKind::Allocator => {
1486 assert!(compiled_allocator_module.is_none());
1487 compiled_allocator_module = Some(compiled_module);
1491 Message::Done { result: Err(()), worker_id: _ } => {
1492 shared_emitter.fatal("aborting due to worker thread panic");
1493 // Exit the coordinator thread
1494 panic!("aborting due to worker thread panic")
1496 Message::TranslateItem => {
1497 bug!("the coordinator should not receive translation requests")
1502 if let Some(llvm_start_time) = llvm_start_time {
1503 let total_llvm_time = Instant::now().duration_since(llvm_start_time);
1504 // This is the top-level timing for all of LLVM, set the time-depth
1507 print_time_passes_entry(cgcx.time_passes,
1512 let compiled_metadata_module = compiled_metadata_module
1513 .expect("Metadata module not compiled?");
1516 modules: compiled_modules,
1517 metadata_module: compiled_metadata_module,
1518 allocator_module: compiled_allocator_module,
1522 // A heuristic that determines if we have enough LLVM WorkItems in the
1523 // queue so that the main thread can do LLVM work instead of translation
1524 fn queue_full_enough(items_in_queue: usize,
1525 workers_running: usize,
1526 max_workers: usize) -> bool {
1528 items_in_queue > 0 &&
1529 items_in_queue >= max_workers.saturating_sub(workers_running / 2)
1532 fn maybe_start_llvm_timer(work_item: &WorkItem,
1533 llvm_start_time: &mut Option<Instant>) {
1534 // We keep track of the -Ztime-passes output manually,
1535 // since the closure-based interface does not fit well here.
1536 if work_item.config.time_passes {
1537 if llvm_start_time.is_none() {
1538 *llvm_start_time = Some(Instant::now());
1544 pub const TRANS_WORKER_ID: usize = ::std::usize::MAX;
1545 pub const TRANS_WORKER_TIMELINE: time_graph::TimelineId =
1546 time_graph::TimelineId(TRANS_WORKER_ID);
1547 pub const TRANS_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
1548 time_graph::WorkPackageKind(&["#DE9597", "#FED1D3", "#FDC5C7", "#B46668", "#88494B"]);
1549 const LLVM_WORK_PACKAGE_KIND: time_graph::WorkPackageKind =
1550 time_graph::WorkPackageKind(&["#7DB67A", "#C6EEC4", "#ACDAAA", "#579354", "#3E6F3C"]);
1552 fn spawn_work(cgcx: CodegenContext, work: WorkItem) {
1553 let depth = time_depth();
1555 thread::spawn(move || {
1556 set_time_depth(depth);
1558 // Set up a destructor which will fire off a message that we're done as
1561 coordinator_send: Sender<Message>,
1562 result: Option<CompiledModule>,
1565 impl Drop for Bomb {
1566 fn drop(&mut self) {
1567 let result = match self.result.take() {
1568 Some(compiled_module) => Ok(compiled_module),
1572 drop(self.coordinator_send.send(Message::Done {
1574 worker_id: self.worker_id,
1579 let mut bomb = Bomb {
1580 coordinator_send: cgcx.coordinator_send.clone(),
1582 worker_id: cgcx.worker,
1585 // Execute the work itself, and if it finishes successfully then flag
1586 // ourselves as a success as well.
1588 // Note that we ignore the result coming out of `execute_work_item`
1589 // which will tell us if the worker failed with a `FatalError`. If that
1590 // has happened, however, then a diagnostic was sent off to the main
1591 // thread, along with an `AbortIfErrors` message. In that case the main
1592 // thread is already exiting anyway most likely.
1594 // In any case, there's no need for us to take further action here, so
1595 // we just ignore the result and then send off our message saying that
1596 // we're done, which if `execute_work_item` failed is unlikely to be
1597 // seen by the main thread, but hey we might as well try anyway.
1599 let _timing_guard = cgcx.time_graph
1601 .map(|tg| tg.start(time_graph::TimelineId(cgcx.worker),
1602 LLVM_WORK_PACKAGE_KIND));
1603 Some(execute_work_item(&cgcx, work).unwrap())
1608 pub fn run_assembler(sess: &Session, outputs: &OutputFilenames) {
1609 let (pname, mut cmd, _) = get_linker(sess);
1611 for arg in &sess.target.target.options.asm_args {
1615 cmd.arg("-c").arg("-o").arg(&outputs.path(OutputType::Object))
1616 .arg(&outputs.temp_path(OutputType::Assembly, None));
1617 debug!("{:?}", cmd);
1619 match cmd.output() {
1621 if !prog.status.success() {
1622 let mut note = prog.stderr.clone();
1623 note.extend_from_slice(&prog.stdout);
1625 sess.struct_err(&format!("linking with `{}` failed: {}",
1628 .note(&format!("{:?}", &cmd))
1629 .note(str::from_utf8(¬e[..]).unwrap())
1631 sess.abort_if_errors();
1635 sess.err(&format!("could not exec the linker `{}`: {}", pname, e));
1636 sess.abort_if_errors();
1641 pub unsafe fn with_llvm_pmb(llmod: ModuleRef,
1642 config: &ModuleConfig,
1643 f: &mut FnMut(llvm::PassManagerBuilderRef)) {
1644 // Create the PassManagerBuilder for LLVM. We configure it with
1645 // reasonable defaults and prepare it to actually populate the pass
1647 let builder = llvm::LLVMPassManagerBuilderCreate();
1648 let opt_level = config.opt_level.unwrap_or(llvm::CodeGenOptLevel::None);
1649 let opt_size = config.opt_size.unwrap_or(llvm::CodeGenOptSizeNone);
1650 let inline_threshold = config.inline_threshold;
1652 llvm::LLVMRustConfigurePassManagerBuilder(builder, opt_level,
1653 config.merge_functions,
1654 config.vectorize_slp,
1655 config.vectorize_loop);
1656 llvm::LLVMPassManagerBuilderSetSizeLevel(builder, opt_size as u32);
1658 if opt_size != llvm::CodeGenOptSizeNone {
1659 llvm::LLVMPassManagerBuilderSetDisableUnrollLoops(builder, 1);
1662 llvm::LLVMRustAddBuilderLibraryInfo(builder, llmod, config.no_builtins);
1664 // Here we match what clang does (kinda). For O0 we only inline
1665 // always-inline functions (but don't add lifetime intrinsics), at O1 we
1666 // inline with lifetime intrinsics, and O2+ we add an inliner with a
1667 // thresholds copied from clang.
1668 match (opt_level, opt_size, inline_threshold) {
1670 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, t as u32);
1672 (llvm::CodeGenOptLevel::Aggressive, ..) => {
1673 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 275);
1675 (_, llvm::CodeGenOptSizeDefault, _) => {
1676 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 75);
1678 (_, llvm::CodeGenOptSizeAggressive, _) => {
1679 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 25);
1681 (llvm::CodeGenOptLevel::None, ..) => {
1682 llvm::LLVMRustAddAlwaysInlinePass(builder, false);
1684 (llvm::CodeGenOptLevel::Less, ..) => {
1685 llvm::LLVMRustAddAlwaysInlinePass(builder, true);
1687 (llvm::CodeGenOptLevel::Default, ..) => {
1688 llvm::LLVMPassManagerBuilderUseInlinerWithThreshold(builder, 225);
1690 (llvm::CodeGenOptLevel::Other, ..) => {
1691 bug!("CodeGenOptLevel::Other selected")
1696 llvm::LLVMPassManagerBuilderDispose(builder);
1700 enum SharedEmitterMessage {
1701 Diagnostic(Diagnostic),
1702 InlineAsmError(u32, String),
1708 pub struct SharedEmitter {
1709 sender: Sender<SharedEmitterMessage>,
1712 pub struct SharedEmitterMain {
1713 receiver: Receiver<SharedEmitterMessage>,
1716 impl SharedEmitter {
1717 pub fn new() -> (SharedEmitter, SharedEmitterMain) {
1718 let (sender, receiver) = channel();
1720 (SharedEmitter { sender }, SharedEmitterMain { receiver })
1723 fn inline_asm_error(&self, cookie: u32, msg: String) {
1724 drop(self.sender.send(SharedEmitterMessage::InlineAsmError(cookie, msg)));
1727 fn fatal(&self, msg: &str) {
1728 drop(self.sender.send(SharedEmitterMessage::Fatal(msg.to_string())));
1732 impl Emitter for SharedEmitter {
1733 fn emit(&mut self, db: &DiagnosticBuilder) {
1734 drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
1736 code: db.code.clone(),
1739 for child in &db.children {
1740 drop(self.sender.send(SharedEmitterMessage::Diagnostic(Diagnostic {
1741 msg: child.message(),
1746 drop(self.sender.send(SharedEmitterMessage::AbortIfErrors));
1750 impl SharedEmitterMain {
1751 pub fn check(&self, sess: &Session, blocking: bool) {
1753 let message = if blocking {
1754 match self.receiver.recv() {
1755 Ok(message) => Ok(message),
1759 match self.receiver.try_recv() {
1760 Ok(message) => Ok(message),
1766 Ok(SharedEmitterMessage::Diagnostic(diag)) => {
1767 let handler = sess.diagnostic();
1770 handler.emit_with_code(&MultiSpan::new(),
1776 handler.emit(&MultiSpan::new(),
1782 Ok(SharedEmitterMessage::InlineAsmError(cookie, msg)) => {
1783 match Mark::from_u32(cookie).expn_info() {
1784 Some(ei) => sess.span_err(ei.call_site, &msg),
1785 None => sess.err(&msg),
1788 Ok(SharedEmitterMessage::AbortIfErrors) => {
1789 sess.abort_if_errors();
1791 Ok(SharedEmitterMessage::Fatal(msg)) => {
1803 pub struct OngoingCrateTranslation {
1806 metadata: EncodedMetadata,
1807 windows_subsystem: Option<String>,
1808 linker_info: LinkerInfo,
1809 no_integrated_as: bool,
1810 crate_info: CrateInfo,
1812 output_filenames: OutputFilenames,
1813 regular_module_config: ModuleConfig,
1814 metadata_module_config: ModuleConfig,
1815 allocator_module_config: ModuleConfig,
1817 time_graph: Option<TimeGraph>,
1818 coordinator_send: Sender<Message>,
1819 trans_worker_receive: Receiver<Message>,
1820 shared_emitter_main: SharedEmitterMain,
1821 future: thread::JoinHandle<CompiledModules>,
1824 impl OngoingCrateTranslation {
1825 pub fn join(self, sess: &Session) -> CrateTranslation {
1826 self.shared_emitter_main.check(sess, true);
1827 let compiled_modules = match self.future.join() {
1828 Ok(compiled_modules) => compiled_modules,
1830 sess.fatal("Error during translation/LLVM phase.");
1834 sess.abort_if_errors();
1836 if let Some(time_graph) = self.time_graph {
1837 time_graph.dump(&format!("{}-timings", self.crate_name));
1840 copy_module_artifacts_into_incr_comp_cache(sess,
1842 &self.output_filenames);
1843 produce_final_output_artifacts(sess,
1845 &self.output_filenames);
1847 // FIXME: time_llvm_passes support - does this use a global context or
1849 if sess.opts.cg.codegen_units == 1 && sess.time_llvm_passes() {
1850 unsafe { llvm::LLVMRustPrintPassTimings(); }
1853 let trans = CrateTranslation {
1854 crate_name: self.crate_name,
1856 metadata: self.metadata,
1857 windows_subsystem: self.windows_subsystem,
1858 linker_info: self.linker_info,
1859 crate_info: self.crate_info,
1861 modules: compiled_modules.modules,
1862 allocator_module: compiled_modules.allocator_module,
1865 if self.no_integrated_as {
1866 run_assembler(sess, &self.output_filenames);
1868 // HACK the linker expects the object file to be named foo.0.o but
1869 // `run_assembler` produces an object named just foo.o. Rename it if we
1870 // are going to build an executable
1871 if sess.opts.output_types.contains_key(&OutputType::Exe) {
1872 let f = self.output_filenames.path(OutputType::Object);
1873 rename_or_copy_remove(&f,
1874 f.with_file_name(format!("{}.0.o",
1875 f.file_stem().unwrap().to_string_lossy()))).unwrap();
1878 // Remove assembly source, unless --save-temps was specified
1879 if !sess.opts.cg.save_temps {
1880 fs::remove_file(&self.output_filenames
1881 .temp_path(OutputType::Assembly, None)).unwrap();
1888 pub fn submit_translated_module_to_llvm(&self,
1890 mtrans: ModuleTranslation,
1893 let module_config = match mtrans.kind {
1894 ModuleKind::Regular => self.regular_module_config.clone(sess),
1895 ModuleKind::Metadata => self.metadata_module_config.clone(sess),
1896 ModuleKind::Allocator => self.allocator_module_config.clone(sess),
1899 let llvm_work_item = build_work_item(mtrans,
1901 self.output_filenames.clone());
1903 drop(self.coordinator_send.send(Message::TranslationDone {
1910 pub fn submit_pre_translated_module_to_llvm(&self,
1912 mtrans: ModuleTranslation,
1914 self.wait_for_signal_to_translate_item();
1915 self.check_for_errors(sess);
1917 // These are generally cheap and won't through off scheduling.
1919 self.submit_translated_module_to_llvm(sess, mtrans, cost, is_last);
1922 pub fn check_for_errors(&self, sess: &Session) {
1923 self.shared_emitter_main.check(sess, false);
1926 pub fn wait_for_signal_to_translate_item(&self) {
1927 match self.trans_worker_receive.recv() {
1928 Ok(Message::TranslateItem) => {
1932 panic!("unexpected message: {:?}", message)
1935 // One of the LLVM threads must have panicked, fall through so
1936 // error handling can be reached.