Skip to content

Commit dba944a

Browse files
committed
Auto merge of #69808 - cjgillot:vtbl, r=pnkfelix
Avoid duplicating code for each query There are at the moment roughly 170 queries in librustc. The way `ty::query` is structured, a lot of code is duplicated for each query. I suspect this to be responsible for a part of librustc'c compile time. The first part of this PR reduces the amount of code generic on the query, replacing it by code generic on the key-value types. I can split it out if needed. In a second part, the non-inlined methods in the `QueryAccessors` and `QueryDescription` traits are made into a virtual dispatch table. This allows to reduce even more the number of generated functions. This allows to save 1.5s on check build, and 10% on the size of the librustc.rlib. (Attributed roughly half and half). My computer is not good enough to measure properly compiling time. I have no idea of the effect on performance. A perf run may be required. cc #65031
2 parents 7f65393 + e4976d0 commit dba944a

File tree

10 files changed

+240
-103
lines changed

10 files changed

+240
-103
lines changed

src/librustc_macros/src/query.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -365,7 +365,7 @@ fn add_query_description_impl(
365365
#[allow(unused_variables, unused_braces)]
366366
fn cache_on_disk(
367367
#tcx: TyCtxt<'tcx>,
368-
#key: Self::Key,
368+
#key: &Self::Key,
369369
#value: Option<&Self::Value>
370370
) -> bool {
371371
#expr
@@ -441,7 +441,7 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
441441
.unwrap_or(false));
442442

443443
let key = <#arg as DepNodeParams<TyCtxt<'_>>>::recover($tcx, $dep_node).unwrap();
444-
if queries::#name::cache_on_disk($tcx, key, None) {
444+
if queries::#name::cache_on_disk($tcx, &key, None) {
445445
let _ = $tcx.#name(key);
446446
}
447447
}

src/librustc_middle/dep_graph/dep_node.rs

+2-23
Original file line numberDiff line numberDiff line change
@@ -183,31 +183,10 @@ macro_rules! define_dep_nodes {
183183
// tuple args
184184
$({
185185
erase!($tuple_arg_ty);
186-
let hash = DepNodeParams::to_fingerprint(&arg, _tcx);
187-
let dep_node = DepNode {
188-
kind: DepKind::$variant,
189-
hash
190-
};
191-
192-
#[cfg(debug_assertions)]
193-
{
194-
if !dep_node.kind.can_reconstruct_query_key() &&
195-
(_tcx.sess.opts.debugging_opts.incremental_info ||
196-
_tcx.sess.opts.debugging_opts.query_dep_graph)
197-
{
198-
_tcx.dep_graph.register_dep_node_debug_str(dep_node, || {
199-
arg.to_debug_str(_tcx)
200-
});
201-
}
202-
}
203-
204-
return dep_node;
186+
return DepNode::construct(_tcx, DepKind::$variant, &arg)
205187
})*
206188

207-
DepNode {
208-
kind: DepKind::$variant,
209-
hash: Fingerprint::ZERO,
210-
}
189+
return DepNode::construct(_tcx, DepKind::$variant, &())
211190
}
212191
)*
213192
}

src/librustc_middle/dep_graph/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,10 @@ impl<'tcx> DepContext for TyCtxt<'tcx> {
9898
fn debug_dep_tasks(&self) -> bool {
9999
self.sess.opts.debugging_opts.dep_tasks
100100
}
101+
fn debug_dep_node(&self) -> bool {
102+
self.sess.opts.debugging_opts.incremental_info
103+
|| self.sess.opts.debugging_opts.query_dep_graph
104+
}
101105

102106
fn try_force_from_dep_node(&self, dep_node: &DepNode) -> bool {
103107
// FIXME: This match is just a workaround for incremental bugs and should

src/librustc_middle/ty/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use crate::dep_graph::{self, DepConstructor, DepNode, DepNodeParams};
1+
use crate::dep_graph::{self, DepNode, DepNodeParams};
22
use crate::hir::exports::Export;
33
use crate::hir::map;
44
use crate::infer::canonical::{self, Canonical};

src/librustc_middle/ty/query/on_disk_cache.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1009,7 +1009,7 @@ where
10091009

10101010
state.iter_results(|results| {
10111011
for (key, value, dep_node) in results {
1012-
if Q::cache_on_disk(tcx, key.clone(), Some(&value)) {
1012+
if Q::cache_on_disk(tcx, &key, Some(&value)) {
10131013
let dep_node = SerializedDepNodeIndex::new(dep_node.index());
10141014

10151015
// Record position of the cache entry.

src/librustc_middle/ty/query/plumbing.rs

-6
Original file line numberDiff line numberDiff line change
@@ -348,12 +348,6 @@ macro_rules! define_queries_inner {
348348
&tcx.queries.$name
349349
}
350350

351-
#[allow(unused)]
352-
#[inline(always)]
353-
fn to_dep_node(tcx: TyCtxt<$tcx>, key: &Self::Key) -> DepNode {
354-
DepConstructor::$node(tcx, *key)
355-
}
356-
357351
#[inline]
358352
fn compute(tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
359353
let provider = tcx.queries.providers.get(key.query_crate())

src/librustc_query_system/dep_graph/dep_node.rs

+24
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,24 @@ impl<K: DepKind> DepNode<K> {
6464
debug_assert!(!kind.has_params());
6565
DepNode { kind, hash: Fingerprint::ZERO }
6666
}
67+
68+
pub fn construct<Ctxt, Key>(tcx: Ctxt, kind: K, arg: &Key) -> DepNode<K>
69+
where
70+
Ctxt: crate::query::QueryContext<DepKind = K>,
71+
Key: DepNodeParams<Ctxt>,
72+
{
73+
let hash = arg.to_fingerprint(tcx);
74+
let dep_node = DepNode { kind, hash };
75+
76+
#[cfg(debug_assertions)]
77+
{
78+
if !kind.can_reconstruct_query_key() && tcx.debug_dep_node() {
79+
tcx.dep_graph().register_dep_node_debug_str(dep_node, || arg.to_debug_str(tcx));
80+
}
81+
}
82+
83+
return dep_node;
84+
}
6785
}
6886

6987
impl<K: DepKind> fmt::Debug for DepNode<K> {
@@ -120,6 +138,12 @@ where
120138
}
121139
}
122140

141+
impl<Ctxt: DepContext> DepNodeParams<Ctxt> for () {
142+
fn to_fingerprint(&self, _: Ctxt) -> Fingerprint {
143+
Fingerprint::ZERO
144+
}
145+
}
146+
123147
/// A "work product" corresponds to a `.o` (or other) file that we
124148
/// save in between runs. These IDs do not have a `DefId` but rather
125149
/// some independent path or string that persists between runs without

src/librustc_query_system/dep_graph/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ pub trait DepContext: Copy {
2828
fn create_stable_hashing_context(&self) -> Self::StableHashingContext;
2929

3030
fn debug_dep_tasks(&self) -> bool;
31+
fn debug_dep_node(&self) -> bool;
3132

3233
/// Try to force a dep node to execute and see if it's green.
3334
fn try_force_from_dep_node(&self, dep_node: &DepNode<Self::DepKind>) -> bool;

src/librustc_query_system/query/config.rs

+76-3
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,53 @@ pub trait QueryConfig<CTX> {
2424
type Stored: Clone;
2525
}
2626

27+
pub(crate) struct QueryVtable<CTX: QueryContext, K, V> {
28+
pub anon: bool,
29+
pub dep_kind: CTX::DepKind,
30+
pub eval_always: bool,
31+
32+
// Don't use this method to compute query results, instead use the methods on TyCtxt
33+
pub compute: fn(CTX, K) -> V,
34+
35+
pub hash_result: fn(&mut CTX::StableHashingContext, &V) -> Option<Fingerprint>,
36+
pub handle_cycle_error: fn(CTX, CycleError<CTX::Query>) -> V,
37+
pub cache_on_disk: fn(CTX, &K, Option<&V>) -> bool,
38+
pub try_load_from_disk: fn(CTX, SerializedDepNodeIndex) -> Option<V>,
39+
}
40+
41+
impl<CTX: QueryContext, K, V> QueryVtable<CTX, K, V> {
42+
pub(crate) fn to_dep_node(&self, tcx: CTX, key: &K) -> DepNode<CTX::DepKind>
43+
where
44+
K: crate::dep_graph::DepNodeParams<CTX>,
45+
{
46+
DepNode::construct(tcx, self.dep_kind, key)
47+
}
48+
49+
pub(crate) fn compute(&self, tcx: CTX, key: K) -> V {
50+
(self.compute)(tcx, key)
51+
}
52+
53+
pub(crate) fn hash_result(
54+
&self,
55+
hcx: &mut CTX::StableHashingContext,
56+
value: &V,
57+
) -> Option<Fingerprint> {
58+
(self.hash_result)(hcx, value)
59+
}
60+
61+
pub(crate) fn handle_cycle_error(&self, tcx: CTX, error: CycleError<CTX::Query>) -> V {
62+
(self.handle_cycle_error)(tcx, error)
63+
}
64+
65+
pub(crate) fn cache_on_disk(&self, tcx: CTX, key: &K, value: Option<&V>) -> bool {
66+
(self.cache_on_disk)(tcx, key, value)
67+
}
68+
69+
pub(crate) fn try_load_from_disk(&self, tcx: CTX, index: SerializedDepNodeIndex) -> Option<V> {
70+
(self.try_load_from_disk)(tcx, index)
71+
}
72+
}
73+
2774
pub trait QueryAccessors<CTX: QueryContext>: QueryConfig<CTX> {
2875
const ANON: bool;
2976
const EVAL_ALWAYS: bool;
@@ -34,7 +81,12 @@ pub trait QueryAccessors<CTX: QueryContext>: QueryConfig<CTX> {
3481
// Don't use this method to access query results, instead use the methods on TyCtxt
3582
fn query_state<'a>(tcx: CTX) -> &'a QueryState<CTX, Self::Cache>;
3683

37-
fn to_dep_node(tcx: CTX, key: &Self::Key) -> DepNode<CTX::DepKind>;
84+
fn to_dep_node(tcx: CTX, key: &Self::Key) -> DepNode<CTX::DepKind>
85+
where
86+
Self::Key: crate::dep_graph::DepNodeParams<CTX>,
87+
{
88+
DepNode::construct(tcx, Self::DEP_KIND, key)
89+
}
3890

3991
// Don't use this method to compute query results, instead use the methods on TyCtxt
4092
fn compute(tcx: CTX, key: Self::Key) -> Self::Value;
@@ -51,7 +103,7 @@ pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
51103
fn describe(tcx: CTX, key: Self::Key) -> Cow<'static, str>;
52104

53105
#[inline]
54-
fn cache_on_disk(_: CTX, _: Self::Key, _: Option<&Self::Value>) -> bool {
106+
fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool {
55107
false
56108
}
57109

@@ -60,6 +112,27 @@ pub trait QueryDescription<CTX: QueryContext>: QueryAccessors<CTX> {
60112
}
61113
}
62114

115+
pub(crate) trait QueryVtableExt<CTX: QueryContext, K, V> {
116+
const VTABLE: QueryVtable<CTX, K, V>;
117+
}
118+
119+
impl<CTX, Q> QueryVtableExt<CTX, Q::Key, Q::Value> for Q
120+
where
121+
CTX: QueryContext,
122+
Q: QueryDescription<CTX>,
123+
{
124+
const VTABLE: QueryVtable<CTX, Q::Key, Q::Value> = QueryVtable {
125+
anon: Q::ANON,
126+
dep_kind: Q::DEP_KIND,
127+
eval_always: Q::EVAL_ALWAYS,
128+
compute: Q::compute,
129+
hash_result: Q::hash_result,
130+
handle_cycle_error: Q::handle_cycle_error,
131+
cache_on_disk: Q::cache_on_disk,
132+
try_load_from_disk: Q::try_load_from_disk,
133+
};
134+
}
135+
63136
impl<CTX: QueryContext, M> QueryDescription<CTX> for M
64137
where
65138
M: QueryAccessors<CTX, Key = DefId>,
@@ -73,7 +146,7 @@ where
73146
}
74147
}
75148

76-
default fn cache_on_disk(_: CTX, _: Self::Key, _: Option<&Self::Value>) -> bool {
149+
default fn cache_on_disk(_: CTX, _: &Self::Key, _: Option<&Self::Value>) -> bool {
77150
false
78151
}
79152

0 commit comments

Comments
 (0)