diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index a62dff641cfec..463b2d5cb2a37 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -22,8 +22,8 @@ use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mono::{MonoItem, MonoItemData, Visibility}; -use rustc_session::Session; use rustc_session::config::{OptLevel, OutputFilenames, OutputType}; +use rustc_session::{BorrowedIncrCompSession, Session}; use rustc_span::Symbol; use crate::base::CodegenedFunction; @@ -337,6 +337,7 @@ impl WriteBackendMethods for AotDriver { fn run_thin_lto( _cgcx: &CodegenContext, _prof: &SelfProfilerRef, + _incr_comp_session: Option<&BorrowedIncrCompSession>, _dcx: rustc_errors::DiagCtxtHandle<'_>, _exported_symbols_for_lto: &[String], _each_linked_rlib_for_lto: &[PathBuf], diff --git a/compiler/rustc_codegen_gcc/src/back/lto.rs b/compiler/rustc_codegen_gcc/src/back/lto.rs index baf1fda02e258..28cabc36dbe63 100644 --- a/compiler/rustc_codegen_gcc/src/back/lto.rs +++ b/compiler/rustc_codegen_gcc/src/back/lto.rs @@ -148,11 +148,11 @@ fn fat_lto( for module in modules { match module { FatLtoInput::InMemory(m) => in_memory.push(m), - FatLtoInput::Serialized { name, bitcode_path } => { - info!("pushing serialized module {:?}", name); + FatLtoInput::Serialized { wp, bitcode_path } => { + info!("pushing serialized module {:?}", wp.cgu_name); serialized_modules.push(( SerializedModule::from_file(&bitcode_path), - CString::new(name).unwrap(), + CString::new(wp.cgu_name).unwrap(), )); } } diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index b82d05dc211aa..59585c520a6cd 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -93,7 +93,9 @@ use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_middle::dep_graph::{WorkProduct, WorkProductMap}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OptLevel, OutputFilenames}; -use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session}; +use rustc_session::{ + BorrowedIncrCompSession, CodegenBackendInit, EarlySession, IncrCompSession, Session, +}; use rustc_span::{Symbol, sym}; use rustc_target::spec::{RelocModel, TargetTuple}; use tempfile::TempDir; @@ -404,6 +406,7 @@ impl WriteBackendMethods for GccCodegenBackend { fn run_thin_lto( _cgcx: &CodegenContext, _prof: &SelfProfilerRef, + _incr_comp_session: Option<&BorrowedIncrCompSession>, _dcx: DiagCtxtHandle<'_>, // FIXME(bjorn3): Limit LTO exports to these symbols _exported_symbols_for_lto: &[String], diff --git a/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs b/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs index 8780af2f6d595..14309aa345150 100644 --- a/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs +++ b/compiler/rustc_codegen_llvm/src/back/llvm_backend.rs @@ -20,7 +20,9 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductMap}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{OptLevel, OutputFilenames, PrintKind, PrintRequest}; -use rustc_session::{CodegenBackendInit, EarlySession, IncrCompSession, Session}; +use rustc_session::{ + BorrowedIncrCompSession, CodegenBackendInit, EarlySession, IncrCompSession, Session, +}; use rustc_span::{Symbol, sym}; use rustc_target::spec::{RelocModel, TlsModel}; @@ -120,6 +122,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { fn run_thin_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, + incr_comp_session: Option<&BorrowedIncrCompSession>, dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], @@ -128,6 +131,7 @@ impl WriteBackendMethods for LlvmCodegenBackend { back::lto::run_thin( cgcx, prof, + incr_comp_session, dcx, exported_symbols_for_lto, each_linked_rlib_for_lto, @@ -377,21 +381,35 @@ impl CodegenBackend for LlvmCodegenBackend { }); } - (compiled_modules, work_products) - } + if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes { + let timings = + llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); + print!("{timings}"); + } - fn print_pass_timings(&self) { - let timings = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintPassTimings(s) }).unwrap(); - print!("{timings}"); - } + if sess.print_llvm_stats() { + let stats = + llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap(); + print!("{stats}"); + } - fn print_statistics(&self) { - let stats = llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatistics(s) }).unwrap(); - print!("{stats}"); - } + if let Some(out_path) = sess.print_llvm_stats_json() { + let llvm_stats_json = + llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatisticsJSON(s) }).unwrap(); + + if !llvm_stats_json.is_empty() { + if let Err(e) = std::fs::write(&out_path, llvm_stats_json) { + sess.dcx().err(format!("failed to write stats to {out_path}: {e}")); + } + } else { + sess.dcx().warn(format!( + "requested to print LLVM statistics to JSON file {out_path}, but the codegen backend \ + did not provide any statistics", + )); + } + } - fn print_statistics_json(&self) -> String { - llvm::build_string(|s| unsafe { llvm::LLVMRustPrintStatisticsJSON(s) }).unwrap() + (compiled_modules, work_products) } fn link( diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index d52e34d30fb7d..309451b7e9772 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -19,7 +19,7 @@ use rustc_data_structures::memmap::Mmap; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::{DiagCtxt, DiagCtxtHandle}; use rustc_middle::dep_graph::WorkProduct; -use rustc_session::config; +use rustc_session::{BorrowedIncrCompSession, config}; use rustc_span::bug; use rustc_structures::SanitizerSet; use tracing::{debug, info}; @@ -184,6 +184,7 @@ pub(crate) fn run_fat( pub(crate) fn run_thin( cgcx: &CodegenContext, prof: &SelfProfilerRef, + incr_comp_session: Option<&BorrowedIncrCompSession>, dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], @@ -199,7 +200,7 @@ pub(crate) fn run_thin( is deferred to the linker" ); } - thin_lto(cgcx, prof, dcx, modules, upstream_modules, &symbols_below_threshold) + thin_lto(prof, incr_comp_session, dcx, modules, upstream_modules, &symbols_below_threshold) } fn fat_lto( @@ -225,11 +226,11 @@ fn fat_lto( for module in modules { match module { FatLtoInput::InMemory(m) => in_memory.push(m), - FatLtoInput::Serialized { name, bitcode_path } => { - info!("pushing serialized module {:?}", name); + FatLtoInput::Serialized { wp, bitcode_path } => { + info!("pushing serialized module {:?}", wp.cgu_name); serialized_modules.push(( SerializedModule::from_file(&bitcode_path), - CString::new(name).unwrap(), + CString::new(wp.cgu_name).unwrap(), )); } } @@ -371,8 +372,8 @@ fn fat_lto( /// all of the `LtoModuleCodegen` units returned below and destroyed once /// they all go out of scope. fn thin_lto( - cgcx: &CodegenContext, prof: &SelfProfilerRef, + incr_comp_session: Option<&BorrowedIncrCompSession>, dcx: DiagCtxtHandle<'_>, modules: Vec>, serialized_modules: Vec<(SerializedModule, CString)>, @@ -463,13 +464,12 @@ fn thin_lto( info!("thin LTO data created"); - let new_key_map_path = cgcx - .new_incr_comp_session_dir - .as_ref() - .map(|dir| dir.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME)); + let new_key_map_path = incr_comp_session.as_ref().map(|incr_comp_session| { + incr_comp_session.new_session_directory.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME) + }); - let prev_key_map = if let Some(ref old_incr_comp_session_dir) = - cgcx.old_incr_comp_session_dir + let prev_key_map = if let Some(ref old_incr_comp_session_dir) = incr_comp_session + .and_then(|incr_comp_session| incr_comp_session.old_session_directory.as_deref()) { let old_path = old_incr_comp_session_dir.join(THIN_LTO_KEYS_INCR_COMP_FILE_NAME); @@ -481,7 +481,7 @@ fn thin_lto( assert!(green_modules.is_empty()); None }; - let curr_key_map = if cgcx.new_incr_comp_session_dir.is_some() { + let curr_key_map = if incr_comp_session.is_some() { ThinLTOKeysMap::from_thin_lto_modules(&data, &thin_modules, &module_names) } else { assert!(green_modules.is_empty()); @@ -506,8 +506,7 @@ fn thin_lto( if let (Some(prev_key_map), true) = (prev_key_map.as_ref(), green_modules.contains_key(module_name)) { - assert!(cgcx.old_incr_comp_session_dir.is_some()); - assert!(cgcx.new_incr_comp_session_dir.is_some()); + assert!(incr_comp_session.unwrap().old_session_directory.is_some()); // If a module exists in both the current and the previous session, // and has the same LTO cache key in both sessions, then we can re-use it diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 431783552bcd0..792ab9873378a 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -111,7 +111,7 @@ impl<'tcx> AssertModuleSource<'tcx> { if !self.check_config(cfg) { debug!("check_attr: config does not match, ignoring attr"); - return; + continue; } let user_path = module.as_str(); diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index 04be7956e8278..b9b5c7ae36b19 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -9,6 +9,7 @@ use std::{assert_matches, fs, io, str, thread}; use rustc_abi::Size; use rustc_data_structures::jobserver::{self, Acquired}; use rustc_data_structures::profiling::{SelfProfilerRef, VerboseTimingGuard}; +use rustc_data_structures::unord::UnordMap; use rustc_errors::emitter::Emitter; use rustc_errors::{ Diag, DiagCtxt, DiagCtxtHandle, DiagInner, FatalError, FatalErrorMarker, Level, @@ -20,12 +21,12 @@ use rustc_incremental::{ }; use rustc_macros::{Decodable, Encodable}; use rustc_metadata::fs::copy_to_stdout; -use rustc_middle::dep_graph::{WorkProduct, WorkProductMap}; +use rustc_middle::dep_graph::{WorkProduct, WorkProductId, WorkProductMap}; use rustc_middle::ty::TyCtxt; use rustc_session::config::{ self, Lto, OptLevel, OutFileName, OutputFilenames, OutputType, Passes, SwitchWithOptPath, }; -use rustc_session::{IncrCompSession, Session}; +use rustc_session::{BorrowedIncrCompSession, IncrCompSession, Session}; use rustc_span::source_map::SourceMap; use rustc_span::{BytePos, FileName, InnerSpan, Span, SyntaxContext, bug}; use rustc_structures::CrateType; @@ -348,12 +349,6 @@ pub struct CodegenContext { /// Directory into which should the LLVM optimization remarks be written. /// If `None`, they will be written to stderr. pub remark_dir: Option, - /// The previous incremental compilation session directory, or None if we - /// are not compiling incrementally or there is no previous session. - pub old_incr_comp_session_dir: Option, - /// The incremental compilation session directory, or None if we are not - /// compiling incrementally - pub new_incr_comp_session_dir: Option, /// `Some(limit)` if the codegen should be run in parallel. /// /// Depends on [`WriteBackendMethods::supports_parallel()`] and `--jobs-backend`. @@ -363,6 +358,7 @@ pub struct CodegenContext { fn generate_thin_lto_work( cgcx: &CodegenContext, prof: &SelfProfilerRef, + incr_comp_session: Option<&BorrowedIncrCompSession>, dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], @@ -373,6 +369,7 @@ fn generate_thin_lto_work( let (lto_modules, copy_jobs) = B::run_thin_lto( cgcx, prof, + incr_comp_session, dcx, exported_symbols_for_lto, each_linked_rlib_for_lto, @@ -773,7 +770,7 @@ pub(crate) enum WorkItemResult { } pub enum FatLtoInput { - Serialized { name: String, bitcode_path: PathBuf }, + Serialized { wp: WorkProduct, bitcode_path: PathBuf }, InMemory(ModuleCodegen), } @@ -819,6 +816,7 @@ pub(crate) fn compute_per_cgu_lto_type( fn execute_optimize_work_item( cgcx: &CodegenContext, prof: &SelfProfilerRef, + new_incr_comp_session_dir: Option<&Path>, shared_emitter: SharedEmitter, mut module: ModuleCodegen, ) -> WorkItemResult { @@ -838,7 +836,7 @@ fn execute_optimize_work_item( // save our module to disk first. let bitcode = if cgcx.module_config.emit_pre_lto_bc { let filename = pre_lto_bitcode_filename(&module.name); - cgcx.new_incr_comp_session_dir.as_ref().map(|path| path.join(&filename)) + new_incr_comp_session_dir.map(|path| path.join(&filename)) } else { None }; @@ -864,7 +862,13 @@ fn execute_optimize_work_item( panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); WorkItemResult::NeedsFatLto(FatLtoInput::Serialized { - name: module.name, + wp: WorkProduct { + cgu_name: module.name.clone(), + saved_files: UnordMap::from_iter([( + PRE_LTO_BC_EXT.to_owned(), + pre_lto_bitcode_filename(&module.name), + )]), + }, bitcode_path: path, }) } @@ -876,6 +880,7 @@ fn execute_optimize_work_item( fn execute_copy_from_cache_work_item( cgcx: &CodegenContext, prof: &SelfProfilerRef, + old_incr_comp_session_dir: &Path, shared_emitter: SharedEmitter, module: CachedModuleCodegen, ) -> CompiledModule { @@ -885,10 +890,8 @@ fn execute_copy_from_cache_work_item( let dcx = DiagCtxt::new(Box::new(shared_emitter)); let dcx = dcx.handle(); - let incr_comp_session_dir = cgcx.old_incr_comp_session_dir.as_ref().unwrap(); - let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| { - let source_file_in_incr_comp_dir = incr_comp_session_dir.join(saved_path); + let source_file_in_incr_comp_dir = old_incr_comp_session_dir.join(saved_path); debug!( "copying preexisting module `{}` from {:?} to {}", module.name, @@ -988,6 +991,7 @@ fn do_fat_lto( fn do_thin_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, + incr_comp_session: Option, shared_emitter: SharedEmitter, tm_factory: TargetMachineFactoryFn, exported_symbols_for_lto: &[String], @@ -1031,6 +1035,7 @@ fn do_thin_lto( for (i, (work, cost)) in generate_thin_lto_work::( cgcx, prof, + incr_comp_session.as_ref(), dcx, &exported_symbols_for_lto, &each_linked_rlib_for_lto, @@ -1080,6 +1085,12 @@ fn do_thin_lto( spawn_thin_lto_work( &cgcx, prof, + incr_comp_session + .as_ref() + .and_then(|incr_comp_session| { + incr_comp_session.old_session_directory.as_deref() + }) + .map(ToOwned::to_owned), shared_emitter.clone(), Arc::clone(&tm_factory), coordinator_send.clone(), @@ -1213,6 +1224,8 @@ fn start_executing_work( ) -> thread::JoinHandle, ()>> { let sess = tcx.sess; let prof = sess.prof.clone(); + let incr_comp_session = + tcx.incr_comp_session.map(|incr_comp_session| incr_comp_session.borrow()); // Compute the set of symbols we need to retain when doing thin local LTO (if we need to) let exported_symbols_for_lto = @@ -1265,15 +1278,6 @@ fn start_executing_work( time_trace: sess.opts.unstable_opts.llvm_time_trace, remark: sess.opts.cg.remark.clone(), remark_dir, - old_incr_comp_session_dir: tcx - .incr_comp_session - .as_ref() - .and_then(|incr_comp_session| incr_comp_session.old_session_directory.as_deref()) - .map(ToOwned::to_owned), - new_incr_comp_session_dir: tcx - .incr_comp_session - .as_ref() - .map(|incr_comp_session| (&*incr_comp_session.new_session_directory).to_owned()), output_filenames: Arc::clone(tcx.output_filenames(())), module_config: regular_config, opt_level, @@ -1512,6 +1516,7 @@ fn start_executing_work( spawn_work( &cgcx, &prof, + incr_comp_session.as_ref(), shared_emitter.clone(), coordinator_send.clone(), &mut llvm_start_time, @@ -1538,6 +1543,7 @@ fn start_executing_work( spawn_work( &cgcx, &prof, + incr_comp_session.as_ref(), shared_emitter.clone(), coordinator_send.clone(), &mut llvm_start_time, @@ -1582,6 +1588,7 @@ fn start_executing_work( spawn_work( &cgcx, &prof, + incr_comp_session.as_ref(), shared_emitter.clone(), coordinator_send.clone(), &mut llvm_start_time, @@ -1734,7 +1741,7 @@ fn start_executing_work( } for (bitcode_path, wp) in lto_import_only_modules { - needs_fat_lto.push(FatLtoInput::Serialized { name: wp.cgu_name, bitcode_path }) + needs_fat_lto.push(FatLtoInput::Serialized { wp, bitcode_path }) } return Ok(MaybeLtoModules::FatLto { cgcx, needs_fat_lto }); @@ -1750,6 +1757,7 @@ fn start_executing_work( compiled_modules.extend(do_thin_lto::( &cgcx, &prof, + incr_comp_session, shared_emitter.clone(), tm_factory, &exported_symbols_for_lto, @@ -1847,6 +1855,7 @@ pub(crate) struct WorkerFatalError; fn spawn_work<'a, B: WriteBackendMethods>( cgcx: &CodegenContext, prof: &'a SelfProfilerRef, + incr_comp_session: Option<&BorrowedIncrCompSession>, shared_emitter: SharedEmitter, coordinator_send: Sender>, llvm_start_time: &mut Option>, @@ -1857,6 +1866,11 @@ fn spawn_work<'a, B: WriteBackendMethods>( *llvm_start_time = Some(prof.verbose_generic_activity("LLVM_passes")); } + let old_incr_comp_session_dir = incr_comp_session + .and_then(|incr_comp_session| incr_comp_session.old_session_directory.clone()); + let new_incr_comp_session_dir = + incr_comp_session.map(|incr_comp_session| incr_comp_session.new_session_directory.clone()); + let cgcx = cgcx.clone(); let prof = prof.clone(); @@ -1865,10 +1879,22 @@ fn spawn_work<'a, B: WriteBackendMethods>( let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { - WorkItem::Optimize(m) => execute_optimize_work_item(&cgcx, &prof, shared_emitter, m), - WorkItem::CopyPostLtoArtifacts(m) => WorkItemResult::Finished( - execute_copy_from_cache_work_item(&cgcx, &prof, shared_emitter, m), + WorkItem::Optimize(m) => execute_optimize_work_item( + &cgcx, + &prof, + new_incr_comp_session_dir.as_deref(), + shared_emitter, + m, ), + WorkItem::CopyPostLtoArtifacts(m) => { + WorkItemResult::Finished(execute_copy_from_cache_work_item( + &cgcx, + &prof, + old_incr_comp_session_dir.as_deref().unwrap(), + shared_emitter, + m, + )) + } })); let msg = match result { @@ -1895,6 +1921,7 @@ fn spawn_work<'a, B: WriteBackendMethods>( fn spawn_thin_lto_work( cgcx: &CodegenContext, prof: &SelfProfilerRef, + old_incr_comp_session_dir: Option, shared_emitter: SharedEmitter, tm_factory: TargetMachineFactoryFn, coordinator_send: Sender, @@ -1909,9 +1936,13 @@ fn spawn_thin_lto_work( let _profiler = if cgcx.time_trace { B::thread_profiler() } else { Box::new(()) }; let result = std::panic::catch_unwind(AssertUnwindSafe(|| match work { - ThinLtoWorkItem::CopyPostLtoArtifacts(m) => { - execute_copy_from_cache_work_item(&cgcx, &prof, shared_emitter, m) - } + ThinLtoWorkItem::CopyPostLtoArtifacts(m) => execute_copy_from_cache_work_item( + &cgcx, + &prof, + old_incr_comp_session_dir.as_deref().unwrap(), + shared_emitter, + m, + ), ThinLtoWorkItem::ThinLto(m) => { let _timer = prof.generic_activity_with_arg("codegen_module_perform_lto", m.name()); B::optimize_and_codegen_thin(&cgcx, &prof, &shared_emitter, tm_factory, m) @@ -2111,34 +2142,58 @@ impl OngoingCodegen { let (shared_emitter, shared_emitter_main) = SharedEmitter::new(); // Catch fatal errors to ensure shared_emitter_main.check() can emit the actual diagnostics - let compiled_modules = catch_fatal_errors(|| match maybe_lto_modules { + let compilation_output = catch_fatal_errors(|| match maybe_lto_modules { MaybeLtoModules::NoLto(compiled_modules) => { drop(shared_emitter); - compiled_modules + + let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir( + sess, + incr_comp_session, + &compiled_modules, + ); + + (compiled_modules, work_products) } MaybeLtoModules::FatLto { cgcx, needs_fat_lto } => { let tm_factory = self.backend.target_machine_factory(sess, cgcx.opt_level); - CompiledModules { - modules: vec![do_fat_lto( - sess, - &cgcx, - shared_emitter, - tm_factory, - &crate_info.exported_symbols_for_lto, - &crate_info.each_linked_rlib_file_for_lto, - needs_fat_lto, - )], - allocator_module: None, + let mut work_products = WorkProductMap::default(); + if sess.opts.incremental.is_some() { + for module in &needs_fat_lto { + match module { + FatLtoInput::Serialized { wp, bitcode_path: _ } => { + work_products + .insert(WorkProductId::from_cgu_name(&wp.cgu_name), wp.clone()); + } + FatLtoInput::InMemory(_) => {} + } + } } + + ( + CompiledModules { + modules: vec![do_fat_lto( + sess, + &cgcx, + shared_emitter, + tm_factory, + &crate_info.exported_symbols_for_lto, + &crate_info.each_linked_rlib_file_for_lto, + needs_fat_lto, + )], + allocator_module: None, + }, + work_products, + ) } MaybeLtoModules::ThinLto { cgcx, needs_thin_lto } => { let tm_factory = self.backend.target_machine_factory(sess, cgcx.opt_level); - CompiledModules { + let compiled_modules = CompiledModules { modules: do_thin_lto::( &cgcx, &sess.prof, + incr_comp_session.map(|incr_comp_session| incr_comp_session.borrow()), shared_emitter, tm_factory, &crate_info.exported_symbols_for_lto, @@ -2147,7 +2202,17 @@ impl OngoingCodegen { sess.opts.recommended_stack_size, ), allocator_module: None, - } + }; + + // FIXME include pre-LTO bitcode in workproduct tracking + // FIXME add separate incr comp session for post-LTO outputs to use during link step + let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir( + sess, + incr_comp_session, + &compiled_modules, + ); + + (compiled_modules, work_products) } }); @@ -2155,19 +2220,14 @@ impl OngoingCodegen { sess.dcx().abort_if_errors(); - let mut compiled_modules = - compiled_modules.expect("fatal error emitted but not sent to SharedEmitter"); + let (mut compiled_modules, work_products) = + compilation_output.expect("fatal error emitted but not sent to SharedEmitter"); // Regardless of what order these modules completed in, report them to // the backend in the same order every time to ensure that we're handing // out deterministic results. compiled_modules.modules.sort_by(|a, b| a.name.cmp(&b.name)); - let work_products = copy_all_cgu_workproducts_to_incr_comp_cache_dir( - sess, - incr_comp_session, - &compiled_modules, - ); produce_final_output_artifacts(sess, &compiled_modules, &self.output_filenames); (compiled_modules, work_products) diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs index e06ac36fd758a..bf5d67c213573 100644 --- a/compiler/rustc_codegen_ssa/src/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -120,14 +120,6 @@ pub trait CodegenBackend { crate_info: &CrateInfo, ) -> (CompiledModules, WorkProductMap); - fn print_pass_timings(&self) {} - - fn print_statistics(&self) {} - - fn print_statistics_json(&self) -> String { - String::new() - } - /// This is called on the returned [`CompiledModules`] from [`join_codegen`](Self::join_codegen). fn link( &self, diff --git a/compiler/rustc_codegen_ssa/src/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs index bb63e189d20d3..4c0df97a41985 100644 --- a/compiler/rustc_codegen_ssa/src/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -5,7 +5,7 @@ use std::path::PathBuf; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_errors::DiagCtxtHandle; use rustc_middle::dep_graph::WorkProduct; -use rustc_session::{Session, config}; +use rustc_session::{BorrowedIncrCompSession, Session, config}; use crate::back::lto::ThinModule; use crate::back::write::{ @@ -50,6 +50,7 @@ pub trait WriteBackendMethods: Clone + 'static { fn run_thin_lto( cgcx: &CodegenContext, prof: &SelfProfilerRef, + incr_comp_session: Option<&BorrowedIncrCompSession>, dcx: DiagCtxtHandle<'_>, exported_symbols_for_lto: &[String], each_linked_rlib_for_lto: &[PathBuf], diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs index 3f896584eaef2..038bddaa021d2 100644 --- a/compiler/rustc_incremental/src/persist/fs.rs +++ b/compiler/rustc_incremental/src/persist/fs.rs @@ -268,7 +268,7 @@ pub(crate) fn prepare_session_directory( None }; - IncrCompSession { old_session_directory, new_session_directory } + IncrCompSession::new(old_session_directory, new_session_directory) } /// This function finalizes and thus 'publishes' the session directory by diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 759297bc69592..94cc1484586c8 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -67,30 +67,6 @@ impl Linker { } }); - if sess.codegen_units().as_usize() == 1 && sess.opts.unstable_opts.time_llvm_passes { - codegen_backend.print_pass_timings() - } - - if sess.print_llvm_stats() { - codegen_backend.print_statistics() - } - - if let Some(out_path) = sess.print_llvm_stats_json() { - let llvm_stats_json = codegen_backend.print_statistics_json(); - - if !llvm_stats_json.is_empty() { - if let Err(e) = std::fs::write(&out_path, llvm_stats_json) { - sess.dcx().err(format!("failed to write stats to {}: {}", out_path, e)); - } - } else { - sess.dcx().warn(format!( - "requested to print LLVM statistics to JSON file {}, but the codegen backend \ - did not provide any statistics", - out_path, - )); - } - } - sess.timings.end_section(sess.dcx(), TimingSection::Codegen); if sess.opts.incremental.is_some() diff --git a/compiler/rustc_middle/src/dep_graph/graph.rs b/compiler/rustc_middle/src/dep_graph/graph.rs index dcb5775f20595..f93b80cc6c95c 100644 --- a/compiler/rustc_middle/src/dep_graph/graph.rs +++ b/compiler/rustc_middle/src/dep_graph/graph.rs @@ -861,12 +861,6 @@ impl DepGraph { self.data.as_ref().and_then(|data| data.previous_work_products.get(v).cloned()) } - /// Access the map of work-products created during the cached run. Only - /// used during saving of the dep-graph. - pub fn previous_work_products(&self) -> &WorkProductMap { - &self.data.as_ref().unwrap().previous_work_products - } - pub fn debug_was_loaded_from_disk(&self, dep_node: DepNode) -> bool { self.data.as_ref().unwrap().debug_loaded_from_disk.lock().contains(&dep_node) } diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index f068aaa584dce..d86ee5e5a4898 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1867,6 +1867,45 @@ pub struct IncrCompSession { /// The directory to which cached data for the current session can be /// written to. pub new_session_directory: flock::LockedDir, + borrows: Arc<()>, +} + +impl IncrCompSession { + pub fn new( + old_session_directory: Option, + new_session_directory: flock::LockedDir, + ) -> Self { + IncrCompSession { old_session_directory, new_session_directory, borrows: Arc::new(()) } + } + + pub fn borrow(&self) -> BorrowedIncrCompSession { + BorrowedIncrCompSession { + old_session_directory: self.old_session_directory.as_deref().map(ToOwned::to_owned), + new_session_directory: (&*self.new_session_directory).to_owned(), + _borrows: Arc::clone(&self.borrows), + } + } +} + +impl Drop for IncrCompSession { + fn drop(&mut self) { + // Check that there are no worker threads remaining that use the incr + // comp session before we unlock the old and new session dir. If there + // does exist a worker thread, there is not much we can do, but at + // least we will unconditionally complain rather than the worker thread + // sometimes crashing depending on what other rustc instances run. + assert!( + Arc::strong_count(&self.borrows) == 1, + "Incr comp session dropped while there are still references", + ); + } +} + +/// A runtime tracked borrow of the incr comp session. Can be sent to worker threads. +pub struct BorrowedIncrCompSession { + pub old_session_directory: Option, + pub new_session_directory: PathBuf, + _borrows: Arc<()>, } /// A wrapper around an [`DiagCtxt`] that is used for early error emissions. diff --git a/tests/incremental/lto.rs b/tests/incremental/lto.rs index ddeddf95f8aee..7e3c5f2f42bf6 100644 --- a/tests/incremental/lto.rs +++ b/tests/incremental/lto.rs @@ -1,11 +1,20 @@ //@ no-prefer-dynamic //@ revisions:rpass1 rpass2 -//@ compile-flags: -C lto +//@ compile-flags: -Z query-dep-graph -C lto=fat //@ ignore-backends: gcc +#![feature(rustc_attrs)] +#![rustc_partition_codegened(module = "lto", cfg = "rpass1")] +#![rustc_partition_codegened(module = "lto-x", cfg = "rpass1")] +#![rustc_partition_codegened(module = "lto-y", cfg = "rpass1")] +#![rustc_partition_reused(module = "lto", cfg = "rpass2")] +#![rustc_partition_codegened(module = "lto-x", cfg = "rpass2")] +#![rustc_partition_reused(module = "lto-y", cfg = "rpass2")] + mod x { pub struct X { - x: u32, y: u32, + x: u32, + y: u32, } #[cfg(rpass1)]