diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs index 85e030c8aa0c5..3cd8add214853 100644 --- a/compiler/rustc_data_structures/src/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -38,8 +38,8 @@ pub use self::mode::{ FromDyn, check_dyn_thread_safe, is_dyn_thread_safe, set_dyn_thread_safe_mode, }; pub use self::parallel::{ - broadcast, par_fns, par_for_each_in, par_for_each_slice, par_join, par_map, parallel_guard, - spawn, try_par_for_each_in, + broadcast, par_fns, par_for_each_in, par_for_each_slice, par_join, par_map, par_range, + parallel_guard, spawn, try_par_for_each_in, }; pub use self::vec::{AppendOnlyIndexVec, AppendOnlyVec}; pub use self::worker_local::{Registry, WorkerLocal}; diff --git a/compiler/rustc_data_structures/src/sync/parallel.rs b/compiler/rustc_data_structures/src/sync/parallel.rs index f8ddde4298c40..ad01a0358df7a 100644 --- a/compiler/rustc_data_structures/src/sync/parallel.rs +++ b/compiler/rustc_data_structures/src/sync/parallel.rs @@ -2,6 +2,7 @@ //! one way for the serial compiler, and another way the parallel compiler. use std::any::Any; +use std::ops::Range; use std::panic::{AssertUnwindSafe, catch_unwind, resume_unwind}; use parking_lot::Mutex; @@ -123,6 +124,8 @@ where } } +const MAX_GROUP_COUNT: usize = 128; + fn par_slice( items: &mut [I], guard: &ParallelGuard, @@ -143,7 +146,6 @@ fn par_slice( rustc_thread_pool::scope(|s| { let proof = items.derive(()); - const MAX_GROUP_COUNT: usize = 128; let group_size = items.len().div_ceil(MAX_GROUP_COUNT); let mut groups = items.chunks_mut(group_size); @@ -169,6 +171,41 @@ fn par_slice( }); } +pub fn par_range(range: Range, op: impl Fn(usize) + DynSync + DynSend) { + parallel_guard(|guard| { + if let Some(proof) = mode::check_dyn_thread_safe() { + let op = proof.derive(op); + + rustc_thread_pool::scope(|s| { + let len = range.end - range.start; + let group_size = len.div_ceil(MAX_GROUP_COUNT); + let mut current = range.start + group_size; + + while current < range.end { + let mut c_range = current..(current + group_size); + c_range.end = range.end.min(c_range.end); + + s.spawn(|_| { + for idx in c_range { + guard.run(|| op(idx)); + } + }); + + current += group_size; + } + + for idx in range.start..range.end.min(range.start + group_size) { + guard.run(|| op(idx)); + } + }); + } else { + for idx in range { + guard.run(|| op(idx)); + } + } + }); +} + pub fn par_for_each_in>( t: T, for_each: impl Fn(&I) + DynSync + DynSend, diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 8975f01de5216..4c9f7cf0c1269 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -14,7 +14,8 @@ use rustc_crate_store::Untracked; use rustc_data_structures::indexmap::IndexMap; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{ - AppendOnlyIndexVec, DynSend, DynSync, FreezeLock, WorkerLocal, par_fns, + AppendOnlyIndexVec, DynSend, DynSync, FreezeLock, WorkerLocal, is_dyn_thread_safe, par_fns, + par_range, }; use rustc_data_structures::thousands; use rustc_errors::timings::TimingSection; @@ -22,7 +23,8 @@ use rustc_errors::{Diag, DiagCtxtHandle, Diagnostic, Level}; use rustc_expand::base::{ExtCtxt, LintStoreExpand}; use rustc_feature::Features; use rustc_fs_util::try_canonicalize; -use rustc_hir::def_id::{LOCAL_CRATE, StableCrateId, StableCrateIdMap}; +use rustc_hir::OwnerId; +use rustc_hir::def_id::{DefIndex, LOCAL_CRATE, LocalDefId, StableCrateId, StableCrateIdMap}; use rustc_hir::definitions::Definitions; use rustc_incremental::setup_dep_graph; use rustc_lint::{BufferedEarlyLint, EarlyCheckNode, LintStore, unerased_lint_store}; @@ -1091,9 +1093,29 @@ pub fn emit_delayed_lints(tcx: TyCtxt<'_>) { /// Runs all analyses that we guarantee to run, even if errors were reported in earlier analyses. /// This function never fails. fn run_required_analyses(tcx: TyCtxt<'_>) { + let is_parallel = is_dyn_thread_safe(); + + // There is no point in prefectching hir owners when parallel compiler is + // deisabled, `print_hir_stats`, `check_crate` or `hir_crate_items` below will do it. + if is_parallel { + tcx.untracked().definitions.write().commit_end_of_determinism(); + tcx.ensure_done().resolve_type_relative_delegations(()); + + let index = tcx.index_ast(()); + + par_range(0..index.len(), |idx| { + let id = LocalDefId { local_def_index: DefIndex::from_usize(idx) }; + if index[id].is_some() { + tcx.ensure_done().hir_owner(id); + tcx.ensure_done().hir_attr_map(OwnerId { def_id: id }); + } + }); + } + if tcx.sess.opts.unstable_opts.input_stats { rustc_passes::input_stats::print_hir_stats(tcx); } + // When using rustdoc's "jump to def" feature, it enters this code and `check_crate` // is not defined. So we need to cfg it out. #[cfg(all(not(doc), debug_assertions))] @@ -1104,7 +1126,9 @@ fn run_required_analyses(tcx: TyCtxt<'_>) { // to use `hir_crate_items`. tcx.ensure_done().hir_crate_items(()); - tcx.untracked().definitions.write().commit_end_of_determinism(); + if !is_parallel { + tcx.untracked().definitions.write().commit_end_of_determinism(); + } rustc_passes::delegation::check_glob_and_list_delegations_target_expr(tcx);