Skip to content

Increase parallelism in various locations #115003

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 15 additions & 8 deletions compiler/rustc_hir_analysis/src/check/wfcheck.rs
Original file line number Diff line number Diff line change
@@ -2323,14 +2323,21 @@ impl<'tcx> WfCheckingCtxt<'_, 'tcx> {

fn check_mod_type_wf(tcx: TyCtxt<'_>, module: LocalModDefId) -> Result<(), ErrorGuaranteed> {
let items = tcx.hir_module_items(module);
let res = items
.par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))
.and(items.par_impl_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
.and(items.par_trait_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)))
.and(
items.par_foreign_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id)),
)
.and(items.par_opaques(|item| tcx.ensure_ok().check_well_formed(item)));
let res =
items
.try_par_items(|item| tcx.ensure_ok().check_well_formed(item.owner_id.def_id))
.and(
items.try_par_impl_items(|item| {
tcx.ensure_ok().check_well_formed(item.owner_id.def_id)
}),
)
.and(items.try_par_trait_items(|item| {
tcx.ensure_ok().check_well_formed(item.owner_id.def_id)
}))
.and(items.try_par_foreign_items(|item| {
tcx.ensure_ok().check_well_formed(item.owner_id.def_id)
}))
.and(items.try_par_opaques(|item| tcx.ensure_ok().check_well_formed(item)));
if module == LocalModDefId::CRATE_DEF_ID {
super::entry::check_for_entry_fn(tcx);
}
11 changes: 8 additions & 3 deletions compiler/rustc_hir_analysis/src/lib.rs
Original file line number Diff line number Diff line change
@@ -93,6 +93,7 @@ mod variance;

pub use errors::NoVariantNamed;
use rustc_abi::ExternAbi;
use rustc_data_structures::sync::par_for_each_in;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_middle::middle;
@@ -178,6 +179,9 @@ pub fn provide(providers: &mut Providers) {
pub fn check_crate(tcx: TyCtxt<'_>) {
let _prof_timer = tcx.sess.timer("type_check_crate");

// Run dependencies of type checking before entering the loops below
tcx.ensure_done().inferred_outlives_crate(());

tcx.sess.time("coherence_checking", || {
// When discarding query call results, use an explicit type to indicate
// what we are intending to discard, to help future type-based refactoring.
@@ -187,9 +191,10 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
let _: R = tcx.ensure_ok().check_mod_type_wf(module);
});

for &trait_def_id in tcx.all_local_trait_impls(()).keys() {
let _: R = tcx.ensure_ok().coherent_trait(trait_def_id);
}
par_for_each_in(tcx.all_local_trait_impls(()), |(trait_def_id, _)| {
let _: R = tcx.ensure_ok().coherent_trait(*trait_def_id);
});

// these queries are executed for side-effects (error reporting):
let _: R = tcx.ensure_ok().crate_inherent_impls_validity_check(());
let _: R = tcx.ensure_ok().crate_inherent_impls_overlap_check(());
108 changes: 64 additions & 44 deletions compiler/rustc_interface/src/passes.rs
Original file line number Diff line number Diff line change
@@ -913,10 +913,24 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
CStore::from_tcx(tcx).report_unused_deps(tcx);
},
{
// Prefetch this as it is used later by the loop below
// to prevent multiple threads from blocking on it.
tcx.ensure_done().get_lang_items(());

let _timer = tcx.sess.timer("misc_module_passes");
tcx.par_hir_for_each_module(|module| {
tcx.ensure_ok().check_mod_loops(module);
tcx.ensure_ok().check_mod_attrs(module);
tcx.ensure_ok().check_mod_naked_functions(module);
});
},
{
// Prefetch this as it is used later by the loop below
// to prevent multiple threads from blocking on it.
tcx.ensure_done().stability_index(());

let _timer = tcx.sess.timer("check_unstable_api_usage");
tcx.par_hir_for_each_module(|module| {
tcx.ensure_ok().check_mod_unstable_api_usage(module);
});
},
@@ -951,30 +965,47 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
// This improves performance by allowing lock-free access to them.
tcx.untracked().definitions.freeze();

sess.time("MIR_borrow_checking", || {
tcx.par_hir_body_owners(|def_id| {
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure_ok().check_unsafety(def_id);
if !tcx.is_typeck_child(def_id.to_def_id()) {
tcx.ensure_ok().mir_borrowck(def_id)
}
});
});
sess.time("MIR_effect_checking", || {
tcx.par_hir_body_owners(|def_id| {
tcx.ensure_ok().has_ffi_unwind_calls(def_id);

// If we need to codegen, ensure that we emit all errors from
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering
// them later during codegen.
if tcx.sess.opts.output_types.should_codegen()
|| tcx.hir_body_const_context(def_id).is_some()
sess.time("misc_checking_2", || {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain why putting those in parallel is interesting?

parallel!(
{
// Prefetch this as it is used later by lint checking and privacy checking.
tcx.ensure_done().effective_visibilities(());
},
{
sess.time("MIR_borrow_checking", || {
tcx.par_hir_body_owners(|def_id| {
// Run unsafety check because it's responsible for stealing and
// deallocating THIR.
tcx.ensure_ok().check_unsafety(def_id);
if !tcx.is_typeck_child(def_id.to_def_id()) {
tcx.ensure_ok().mir_borrowck(def_id)
}
});
});
},
{
sess.time("MIR_effect_checking", || {
tcx.par_hir_body_owners(|def_id| {
tcx.ensure_ok().has_ffi_unwind_calls(def_id);

// If we need to codegen, ensure that we emit all errors from
// `mir_drops_elaborated_and_const_checked` now, to avoid discovering
// them later during codegen.
if tcx.sess.opts.output_types.should_codegen()
|| tcx.hir_body_const_context(def_id).is_some()
{
tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
}
});
});
},
{
tcx.ensure_ok().mir_drops_elaborated_and_const_checked(def_id);
sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));
}
});
)
});

sess.time("coroutine_obligations", || {
tcx.par_hir_body_owners(|def_id| {
if tcx.is_coroutine(def_id.to_def_id()) {
@@ -991,9 +1022,6 @@ fn run_required_analyses(tcx: TyCtxt<'_>) {
});
});

sess.time("layout_testing", || layout_test::test_layout(tcx));
sess.time("abi_testing", || abi_test::test_abi(tcx));

// If `-Zvalidate-mir` is set, we also want to compute the final MIR for each item
// (either its `mir_for_ctfe` or `optimized_mir`) since that helps uncover any bugs
// in MIR optimizations that may only be reachable through codegen, or other codepaths
@@ -1029,26 +1057,18 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) {
sess.time("misc_checking_3", || {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Likewise.

parallel!(
{
tcx.ensure_ok().effective_visibilities(());

parallel!(
{
tcx.ensure_ok().check_private_in_public(());
},
{
tcx.par_hir_for_each_module(|module| {
tcx.ensure_ok().check_mod_deathness(module)
});
},
{
sess.time("lint_checking", || {
rustc_lint::check_crate(tcx);
});
},
{
tcx.ensure_ok().clashing_extern_declarations(());
}
);
tcx.ensure_ok().check_private_in_public(());
},
{
tcx.par_hir_for_each_module(|module| tcx.ensure_ok().check_mod_deathness(module));
},
{
sess.time("lint_checking", || {
rustc_lint::check_crate(tcx);
});
},
{
tcx.ensure_ok().clashing_extern_declarations(());
},
{
sess.time("privacy_checking_modules", || {
28 changes: 22 additions & 6 deletions compiler/rustc_middle/src/hir/mod.rs
Original file line number Diff line number Diff line change
@@ -9,7 +9,7 @@ pub mod place;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::{DynSend, DynSync, try_par_for_each_in};
use rustc_data_structures::sync::{DynSend, DynSync, par_for_each_in, try_par_for_each_in};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId};
use rustc_hir::*;
@@ -79,40 +79,56 @@ impl ModuleItems {
self.owners().map(|id| id.def_id)
}

pub fn par_items(
pub fn try_par_items(
&self,
f: impl Fn(ItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.free_items[..], |&&id| f(id))
}

pub fn par_trait_items(
pub fn try_par_trait_items(
&self,
f: impl Fn(TraitItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.trait_items[..], |&&id| f(id))
}

pub fn par_impl_items(
pub fn try_par_impl_items(
&self,
f: impl Fn(ImplItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.impl_items[..], |&&id| f(id))
}

pub fn par_foreign_items(
pub fn try_par_foreign_items(
&self,
f: impl Fn(ForeignItemId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.foreign_items[..], |&&id| f(id))
}

pub fn par_opaques(
pub fn try_par_opaques(
&self,
f: impl Fn(LocalDefId) -> Result<(), ErrorGuaranteed> + DynSend + DynSync,
) -> Result<(), ErrorGuaranteed> {
try_par_for_each_in(&self.opaques[..], |&&id| f(id))
}

pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) {
par_for_each_in(&self.free_items[..], |&&id| f(id))
}

pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) {
par_for_each_in(&self.trait_items[..], |&&id| f(id))
}

pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) {
par_for_each_in(&self.impl_items[..], |&&id| f(id))
}

pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) {
par_for_each_in(&self.foreign_items[..], |&&id| f(id))
}
}

impl<'tcx> TyCtxt<'tcx> {
19 changes: 15 additions & 4 deletions compiler/rustc_monomorphize/src/collector.rs
Original file line number Diff line number Diff line change
@@ -209,7 +209,7 @@ use std::path::PathBuf;

use rustc_attr_parsing::InlineAttr;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{MTLock, par_for_each_in};
use rustc_data_structures::sync::{MTLock, join, par_for_each_in};
use rustc_data_structures::unord::{UnordMap, UnordSet};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@@ -1672,9 +1672,20 @@ pub(crate) fn collect_crate_mono_items<'tcx>(
) -> (Vec<MonoItem<'tcx>>, UsageMap<'tcx>) {
let _prof_timer = tcx.prof.generic_activity("monomorphization_collector");

let roots = tcx
.sess
.time("monomorphization_collector_root_collections", || collect_roots(tcx, strategy));
let (roots, _) = join(
|| {
tcx.sess.time("monomorphization_collector_root_collections", || {
collect_roots(tcx, strategy)
})
},
|| {
if tcx.sess.opts.share_generics() {
// Prefetch upstream_monomorphizations as it's very likely to be used in
// code generation later and this is decent spot to compute it.
tcx.ensure_ok().upstream_monomorphizations(());
}
},
);

debug!("building mono item graph, beginning at roots");

Original file line number Diff line number Diff line change
@@ -1,15 +1,5 @@
error[E0391]: cycle detected when computing predicates of `Foo`
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
|
note: ...which requires computing inferred outlives-predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
error[E0391]: cycle detected when computing the inferred outlives-predicates for items in this crate
|
LL | struct Foo {
| ^^^^^^^^^^
= note: ...which requires computing the inferred outlives-predicates for items in this crate...
note: ...which requires computing type of `Foo::bar`...
--> $DIR/cycle-iat-inside-of-adt.rs:8:5
|
@@ -20,12 +10,18 @@ note: ...which requires computing normalized predicates of `Foo`...
|
LL | struct Foo {
| ^^^^^^^^^^
= note: ...which again requires computing predicates of `Foo`, completing the cycle
note: cycle used when checking that `Foo` is well-formed
note: ...which requires computing predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
note: ...which requires computing inferred outlives-predicates of `Foo`...
--> $DIR/cycle-iat-inside-of-adt.rs:7:1
|
LL | struct Foo {
| ^^^^^^^^^^
= note: ...which again requires computing the inferred outlives-predicates for items in this crate, completing the cycle
= note: cycle used when running analysis passes on this crate
= note: see https://rustc-dev-guide.rust-lang.org/overview.html#queries and https://rustc-dev-guide.rust-lang.org/query.html for more information

error: aborting due to 1 previous error
2 changes: 1 addition & 1 deletion tests/ui/span/issue-35987.rs
Original file line number Diff line number Diff line change
@@ -3,7 +3,7 @@ struct Foo<T: Clone>(T);
use std::ops::Add;

impl<T: Clone, Add> Add for Foo<T> {
//~^ ERROR expected trait, found type parameter
//~^ ERROR expected trait, found type parameter
type Output = usize;

fn add(self, rhs: Self) -> Self::Output {
Original file line number Diff line number Diff line change
@@ -16,6 +16,12 @@ error[E0404]: expected trait, found builtin type `usize`
LL | x: usize + 'a,
| ^^^^^ not a trait

error[E0782]: expected a type, found a trait
--> $DIR/suggestion-trait-object-issue-139174.rs:16:8
|
LL | x: usize + 'a,
| ^^^^^^^^^^

error[E0782]: expected a type, found a trait
--> $DIR/suggestion-trait-object-issue-139174.rs:3:36
|
@@ -28,12 +34,6 @@ error[E0782]: expected a type, found a trait
LL | fn create_adder<'a>(x: i32) -> usize + 'a {
| ^^^^^^^^^^

error[E0782]: expected a type, found a trait
--> $DIR/suggestion-trait-object-issue-139174.rs:16:8
|
LL | x: usize + 'a,
| ^^^^^^^^^^

error: aborting due to 6 previous errors

Some errors have detailed explanations: E0404, E0782.