From af099bb2401bc9fe7aa753a20086d51c49816bcd Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Fri, 9 Mar 2018 07:09:24 +0100 Subject: [PATCH 1/2] Cache const eval queries --- src/librustc/ty/maps/config.rs | 12 +++++ src/librustc/ty/maps/mod.rs | 2 +- src/librustc/ty/maps/on_disk_cache.rs | 68 +++++++++++++++++++++++++++ 3 files changed, 81 insertions(+), 1 deletion(-) diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 21affcbc9ede7..7e2ece1b334b9 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -156,6 +156,18 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { fn describe(tcx: TyCtxt, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) -> String { format!("const-evaluating `{}`", tcx.item_path_str(key.value.instance.def.def_id())) } + + #[inline] + fn cache_on_disk(key: Self::Key) -> bool { + key.value.instance.def_id().is_local() + } + + #[inline] + fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + id: SerializedDepNodeIndex) + -> Option { + tcx.on_disk_query_result_cache.load_constant(tcx, id).map(Ok) + } } impl<'tcx> QueryDescription<'tcx> for queries::mir_keys<'tcx> { diff --git a/src/librustc/ty/maps/mod.rs b/src/librustc/ty/maps/mod.rs index 0ded759fec730..27eb7de2d06aa 100644 --- a/src/librustc/ty/maps/mod.rs +++ b/src/librustc/ty/maps/mod.rs @@ -82,7 +82,7 @@ pub use self::on_disk_cache::OnDiskCache; // the driver creates (using several `rustc_*` crates). // // The result of query must implement Clone. They must also implement ty::maps::values::Value -// which produces an appropiate error value if the query resulted in a query cycle. +// which produces an appropriate error value if the query resulted in a query cycle. // Queries marked with `fatal_cycle` do not need that implementation // as they will raise an fatal error on query cycles instead. define_maps! { <'tcx> diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index 49c4b8bc49d8c..bb0b1975b9e46 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -75,6 +75,10 @@ pub struct OnDiskCache<'sess> { // A map from dep-node to the position of any associated diagnostics in // `serialized_data`. prev_diagnostics_index: FxHashMap, + + // A map from dep-node to the position of any associated constants in + // `serialized_data`. + prev_constants_index: FxHashMap, } // This type is used only for (de-)serialization. @@ -84,8 +88,10 @@ struct Footer { prev_cnums: Vec<(u32, String, CrateDisambiguator)>, query_result_index: EncodedQueryResultIndex, diagnostics_index: EncodedQueryResultIndex, + constants_index: EncodedConstantsIndex, } +type EncodedConstantsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedDiagnostics = Vec; @@ -139,6 +145,7 @@ impl<'sess> OnDiskCache<'sess> { current_diagnostics: RefCell::new(FxHashMap()), query_result_index: footer.query_result_index.into_iter().collect(), prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), + prev_constants_index: footer.constants_index.into_iter().collect(), synthetic_expansion_infos: RefCell::new(FxHashMap()), } } @@ -154,6 +161,7 @@ impl<'sess> OnDiskCache<'sess> { current_diagnostics: RefCell::new(FxHashMap()), query_result_index: FxHashMap(), prev_diagnostics_index: FxHashMap(), + prev_constants_index: FxHashMap(), synthetic_expansion_infos: RefCell::new(FxHashMap()), } } @@ -223,6 +231,45 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; } + // encode successful constant evaluations + let constants_index = { + let mut constants_index = EncodedConstantsIndex::new(); + use ty::maps::queries::const_eval; + use ty::maps::plumbing::GetCacheInternal; + use ty::maps::config::QueryDescription; + for (key, entry) in const_eval::get_cache_internal(tcx).map.iter() { + if let Ok(ref constant) = entry.value { + if const_eval::cache_on_disk(key.clone()) { + trace!("caching constant {:?} with value {:#?}", key, constant); + let dep_node = SerializedDepNodeIndex::new(entry.index.index()); + + // Record position of the cache entry + constants_index.push(( + dep_node, + AbsoluteBytePos::new(encoder.position()), + )); + let did = key.value.instance.def_id(); + let constant = if key.value.promoted.is_none() + && tcx.is_static(did).is_some() { + // memorize the allocation for the static, too, so + // we can refer to the static, not just read its value + // since we have had a successful query, the cached value must + // exist, so we can unwrap it + let cached = tcx.interpret_interner.get_cached(did).unwrap(); + (constant, Some(cached)) + } else { + (constant, None) + }; + + // Encode the type check tables with the SerializedDepNodeIndex + // as tag. + encoder.encode_tagged(dep_node, &constant)?; + } + } + } + constants_index + }; + // Encode diagnostics let diagnostics_index = { let mut diagnostics_index = EncodedDiagnosticsIndex::new(); @@ -256,6 +303,7 @@ impl<'sess> OnDiskCache<'sess> { prev_cnums, query_result_index, diagnostics_index, + constants_index, })?; // Encode the position of the footer as the last 8 bytes of the @@ -278,6 +326,25 @@ impl<'sess> OnDiskCache<'sess> { }) } + /// Load a constant emitted during the previous compilation session. + pub fn load_constant<'a, 'tcx>(&self, + tcx: TyCtxt<'a, 'tcx, 'tcx>, + dep_node_index: SerializedDepNodeIndex) + -> Option<&'tcx ty::Const<'tcx>> { + type Encoded<'tcx> = (ty::Const<'tcx>, Option); + let constant: Option> = self.load_indexed( + tcx, + dep_node_index, + &self.prev_constants_index, + "constants"); + + constant.map(|(c, _alloc_id)| { + // the AllocId decoding already registers the AllocId to its DefId + // so we don't need to take additional actions here + tcx.mk_const(c) + }) + } + /// Load a diagnostic emitted during the previous compilation session. pub fn load_diagnostics<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, @@ -563,6 +630,7 @@ impl<'a, 'tcx, 'x> SpecializedDecoder for CacheDecoder<'a, ' tcx.interpret_interner.intern_at_reserved(alloc_id, allocation); if let Some(glob) = Option::::decode(self)? { + trace!("connecting alloc {:?} with {:?}", alloc_id, glob); tcx.interpret_interner.cache(glob, alloc_id); } From 0d88db1693a07095555d07d14ffdcb373b6bc352 Mon Sep 17 00:00:00 2001 From: Oliver Schneider Date: Tue, 13 Mar 2018 16:21:54 +0100 Subject: [PATCH 2/2] Reuse the query caching infrastructure for const eval --- src/librustc/ty/maps/config.rs | 6 +-- src/librustc/ty/maps/on_disk_cache.rs | 63 +++--------------------- src/librustc_mir/interpret/const_eval.rs | 8 ++- 3 files changed, 16 insertions(+), 61 deletions(-) diff --git a/src/librustc/ty/maps/config.rs b/src/librustc/ty/maps/config.rs index 7e2ece1b334b9..bcd58e993044d 100644 --- a/src/librustc/ty/maps/config.rs +++ b/src/librustc/ty/maps/config.rs @@ -158,15 +158,15 @@ impl<'tcx> QueryDescription<'tcx> for queries::const_eval<'tcx> { } #[inline] - fn cache_on_disk(key: Self::Key) -> bool { - key.value.instance.def_id().is_local() + fn cache_on_disk(_key: Self::Key) -> bool { + true } #[inline] fn try_load_from_disk<'a>(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: SerializedDepNodeIndex) -> Option { - tcx.on_disk_query_result_cache.load_constant(tcx, id).map(Ok) + tcx.on_disk_query_result_cache.try_load_query_result(tcx, id).map(Ok) } } diff --git a/src/librustc/ty/maps/on_disk_cache.rs b/src/librustc/ty/maps/on_disk_cache.rs index bb0b1975b9e46..35e874b74d9ae 100644 --- a/src/librustc/ty/maps/on_disk_cache.rs +++ b/src/librustc/ty/maps/on_disk_cache.rs @@ -75,10 +75,6 @@ pub struct OnDiskCache<'sess> { // A map from dep-node to the position of any associated diagnostics in // `serialized_data`. prev_diagnostics_index: FxHashMap, - - // A map from dep-node to the position of any associated constants in - // `serialized_data`. - prev_constants_index: FxHashMap, } // This type is used only for (de-)serialization. @@ -88,10 +84,8 @@ struct Footer { prev_cnums: Vec<(u32, String, CrateDisambiguator)>, query_result_index: EncodedQueryResultIndex, diagnostics_index: EncodedQueryResultIndex, - constants_index: EncodedConstantsIndex, } -type EncodedConstantsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedQueryResultIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedDiagnosticsIndex = Vec<(SerializedDepNodeIndex, AbsoluteBytePos)>; type EncodedDiagnostics = Vec; @@ -145,7 +139,6 @@ impl<'sess> OnDiskCache<'sess> { current_diagnostics: RefCell::new(FxHashMap()), query_result_index: footer.query_result_index.into_iter().collect(), prev_diagnostics_index: footer.diagnostics_index.into_iter().collect(), - prev_constants_index: footer.constants_index.into_iter().collect(), synthetic_expansion_infos: RefCell::new(FxHashMap()), } } @@ -161,7 +154,6 @@ impl<'sess> OnDiskCache<'sess> { current_diagnostics: RefCell::new(FxHashMap()), query_result_index: FxHashMap(), prev_diagnostics_index: FxHashMap(), - prev_constants_index: FxHashMap(), synthetic_expansion_infos: RefCell::new(FxHashMap()), } } @@ -229,46 +221,25 @@ impl<'sess> OnDiskCache<'sess> { encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; encode_query_results::(tcx, enc, qri)?; - } - // encode successful constant evaluations - let constants_index = { - let mut constants_index = EncodedConstantsIndex::new(); - use ty::maps::queries::const_eval; + // const eval is special, it only encodes successfully evaluated constants use ty::maps::plumbing::GetCacheInternal; - use ty::maps::config::QueryDescription; for (key, entry) in const_eval::get_cache_internal(tcx).map.iter() { - if let Ok(ref constant) = entry.value { - if const_eval::cache_on_disk(key.clone()) { - trace!("caching constant {:?} with value {:#?}", key, constant); + use ty::maps::config::QueryDescription; + if const_eval::cache_on_disk(key.clone()) { + if let Ok(ref value) = entry.value { let dep_node = SerializedDepNodeIndex::new(entry.index.index()); // Record position of the cache entry - constants_index.push(( - dep_node, - AbsoluteBytePos::new(encoder.position()), - )); - let did = key.value.instance.def_id(); - let constant = if key.value.promoted.is_none() - && tcx.is_static(did).is_some() { - // memorize the allocation for the static, too, so - // we can refer to the static, not just read its value - // since we have had a successful query, the cached value must - // exist, so we can unwrap it - let cached = tcx.interpret_interner.get_cached(did).unwrap(); - (constant, Some(cached)) - } else { - (constant, None) - }; + qri.push((dep_node, AbsoluteBytePos::new(enc.position()))); // Encode the type check tables with the SerializedDepNodeIndex // as tag. - encoder.encode_tagged(dep_node, &constant)?; + enc.encode_tagged(dep_node, value)?; } } } - constants_index - }; + } // Encode diagnostics let diagnostics_index = { @@ -303,7 +274,6 @@ impl<'sess> OnDiskCache<'sess> { prev_cnums, query_result_index, diagnostics_index, - constants_index, })?; // Encode the position of the footer as the last 8 bytes of the @@ -326,25 +296,6 @@ impl<'sess> OnDiskCache<'sess> { }) } - /// Load a constant emitted during the previous compilation session. - pub fn load_constant<'a, 'tcx>(&self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - dep_node_index: SerializedDepNodeIndex) - -> Option<&'tcx ty::Const<'tcx>> { - type Encoded<'tcx> = (ty::Const<'tcx>, Option); - let constant: Option> = self.load_indexed( - tcx, - dep_node_index, - &self.prev_constants_index, - "constants"); - - constant.map(|(c, _alloc_id)| { - // the AllocId decoding already registers the AllocId to its DefId - // so we don't need to take additional actions here - tcx.mk_const(c) - }) - } - /// Load a diagnostic emitted during the previous compilation session. pub fn load_diagnostics<'a, 'tcx>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>, diff --git a/src/librustc_mir/interpret/const_eval.rs b/src/librustc_mir/interpret/const_eval.rs index ee5874be9d70a..82eb28287b033 100644 --- a/src/librustc_mir/interpret/const_eval.rs +++ b/src/librustc_mir/interpret/const_eval.rs @@ -110,6 +110,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( span = mir.span; let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?; let alloc = tcx.interpret_interner.get_cached(cid.instance.def_id()); + let is_static = tcx.is_static(cid.instance.def_id()).is_some(); let alloc = match alloc { Some(alloc) => { assert!(cid.promoted.is_none()); @@ -123,7 +124,7 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( layout.align, None, )?; - if tcx.is_static(cid.instance.def_id()).is_some() { + if is_static { tcx.interpret_interner.cache(cid.instance.def_id(), ptr.alloc_id); } let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span); @@ -151,8 +152,11 @@ fn eval_body_and_ecx<'a, 'mir, 'tcx>( } }; let ptr = MemoryPointer::new(alloc, 0).into(); + // always try to read the value and report errors let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? { - Some(val) => val, + // if it's a constant (so it needs no address, directly compute its value) + Some(val) if !is_static => val, + // point at the allocation _ => Value::ByRef(ptr, layout.align), }; Ok((value, ptr, layout.ty))