Skip to content

Commit 8cb36a0

Browse files
committed
introduce Reveal::Selection and deduplication for eval const queries
1 parent 80955cd commit 8cb36a0

File tree

6 files changed

+243
-1743
lines changed

6 files changed

+243
-1743
lines changed

compiler/rustc_middle/src/mir/interpret/mod.rs

Lines changed: 211 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ mod pointer;
9595
mod queries;
9696
mod value;
9797

98+
use std::cell::RefCell;
9899
use std::convert::TryFrom;
99100
use std::fmt;
101+
use std::fmt::Debug;
100102
use std::io;
101103
use std::io::{Read, Write};
102104
use std::num::{NonZeroU32, NonZeroU64};
@@ -106,10 +108,13 @@ use rustc_ast::LitKind;
106108
use rustc_data_structures::fx::FxHashMap;
107109
use rustc_data_structures::sync::{HashMapExt, Lock};
108110
use rustc_data_structures::tiny_list::TinyList;
111+
use rustc_hir as hir;
109112
use rustc_hir::def_id::DefId;
110-
use rustc_macros::HashStable;
113+
use rustc_hir::definitions::DefPathData;
114+
use rustc_middle::traits::Reveal;
111115
use rustc_middle::ty::print::with_no_trimmed_paths;
112116
use rustc_serialize::{Decodable, Encodable};
117+
use rustc_span::{Pos, Span};
113118
use rustc_target::abi::Endian;
114119

115120
use crate::mir;
@@ -446,6 +451,88 @@ impl<'tcx> AllocMap<'tcx> {
446451
}
447452
}
448453

454+
/// What we store about a frame in an interpreter backtrace.
455+
#[derive(Debug)]
456+
pub struct FrameInfo<'tcx> {
457+
pub instance: ty::Instance<'tcx>,
458+
pub span: Span,
459+
pub lint_root: Option<hir::HirId>,
460+
}
461+
462+
impl<'tcx> fmt::Display for FrameInfo<'tcx> {
463+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
464+
ty::tls::with(|tcx| {
465+
if tcx.def_key(self.instance.def_id()).disambiguated_data.data
466+
== DefPathData::ClosureExpr
467+
{
468+
write!(f, "inside closure")?;
469+
} else {
470+
write!(f, "inside `{}`", self.instance)?;
471+
}
472+
if !self.span.is_dummy() {
473+
let sm = tcx.sess.source_map();
474+
let lo = sm.lookup_char_pos(self.span.lo());
475+
write!(
476+
f,
477+
" at {}:{}:{}",
478+
sm.filename_for_diagnostics(&lo.file.name),
479+
lo.line,
480+
lo.col.to_usize() + 1
481+
)?;
482+
}
483+
Ok(())
484+
})
485+
}
486+
}
487+
488+
#[derive(Clone, Copy, Debug)]
489+
pub enum ConstDedupResult<T: Clone + Copy + Debug> {
490+
Selection(T),
491+
UserFacing(T),
492+
All(T),
493+
}
494+
495+
impl<T: Clone + Copy + Debug> ConstDedupResult<T> {
496+
pub fn new(reveal: Reveal, val: T) -> Self {
497+
match reveal {
498+
Reveal::Selection => ConstDedupResult::Selection(val),
499+
Reveal::UserFacing => ConstDedupResult::UserFacing(val),
500+
Reveal::All => ConstDedupResult::All(val),
501+
}
502+
}
503+
}
504+
505+
/// Used to store results of calls to `eval_to_allocation_raw` and
506+
/// `eval_to_const_value_raw`.
507+
#[derive(Debug)]
508+
pub struct ConstDedupMap<'tcx> {
509+
// interning for deduplication of `eval_to_allocation_raw`
510+
pub alloc_map: RefCell<FxHashMap<GlobalId<'tcx>, ConstDedupResult<ConstAlloc<'tcx>>>>,
511+
512+
// interning for deduplication of `eval_to_const_value_raw`
513+
pub const_val_map: RefCell<FxHashMap<GlobalId<'tcx>, ConstDedupResult<ConstValue<'tcx>>>>,
514+
}
515+
516+
impl<'tcx> ConstDedupMap<'tcx> {
517+
pub fn new() -> Self {
518+
ConstDedupMap { alloc_map: Default::default(), const_val_map: Default::default() }
519+
}
520+
521+
#[instrument(skip(self), level = "debug")]
522+
fn insert_alloc(&self, id: GlobalId<'tcx>, val: ConstDedupResult<ConstAlloc<'tcx>>) {
523+
let mut alloc_map = self.alloc_map.borrow_mut();
524+
alloc_map.insert(id, val);
525+
debug!("alloc_map after update: {:#?}", alloc_map);
526+
}
527+
528+
#[instrument(skip(self), level = "debug")]
529+
fn insert_const_val(&self, id: GlobalId<'tcx>, val: ConstDedupResult<ConstValue<'tcx>>) {
530+
let mut const_val_map = self.const_val_map.borrow_mut();
531+
const_val_map.insert(id, val);
532+
debug!("const_val_map after update: {:#?}", const_val_map);
533+
}
534+
}
535+
449536
impl<'tcx> TyCtxt<'tcx> {
450537
/// Obtains a new allocation ID that can be referenced but does not
451538
/// yet have an allocation backing it.
@@ -554,6 +641,129 @@ impl<'tcx> TyCtxt<'tcx> {
554641
fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) {
555642
self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem));
556643
}
644+
645+
/// Store the result of a call to `eval_to_allocation_raw` in order to
646+
/// allow deduplication.
647+
#[instrument(skip(self), level = "debug")]
648+
pub fn save_alloc_for_dedup(self, id: GlobalId<'tcx>, val: ConstDedupResult<ConstAlloc<'tcx>>) {
649+
let dedup_const_map = self.dedup_const_map.lock();
650+
dedup_const_map.insert_alloc(id, val);
651+
debug!("dedup_const_map after insert: {:#?}", dedup_const_map);
652+
}
653+
654+
/// Store the result of a call to `eval_to_const_value_raw` in order to deduplicate it.
655+
#[instrument(skip(self), level = "debug")]
656+
pub fn save_const_value_for_dedup(
657+
self,
658+
id: GlobalId<'tcx>,
659+
val: ConstDedupResult<ConstValue<'tcx>>,
660+
) {
661+
let dedup_const_map = self.dedup_const_map.lock();
662+
dedup_const_map.insert_const_val(id, val);
663+
debug!("dedup_const_map after insert: {:#?}", dedup_const_map);
664+
}
665+
666+
/// Tries to deduplicate a call to `eval_to_allocation_raw`. If deduplication isn't
667+
/// successful `eval_to_allocation_raw` query is executed.
668+
#[instrument(skip(self, opt_span), level = "debug")]
669+
pub fn dedup_eval_alloc_raw(
670+
self,
671+
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
672+
opt_span: Option<Span>,
673+
) -> EvalToAllocationRawResult<'tcx> {
674+
use ConstDedupResult::*;
675+
676+
let (param_env, id) = key.into_parts();
677+
let dedup_const_map = self.dedup_const_map.lock();
678+
debug!("dedup_const_map: {:#?}", dedup_const_map);
679+
let alloc_map = dedup_const_map.alloc_map.borrow();
680+
debug!("alloc_map: {:#?}", alloc_map);
681+
682+
let dedup_result = alloc_map.get(&id);
683+
debug!(?dedup_result);
684+
685+
match param_env.reveal() {
686+
Reveal::Selection => match dedup_result {
687+
Some(Selection(alloc) | UserFacing(alloc)) => return Ok(*alloc),
688+
_ => {}
689+
},
690+
Reveal::UserFacing => match dedup_result {
691+
Some(Selection(alloc) | UserFacing(alloc)) => {
692+
return Ok(*alloc);
693+
}
694+
_ => {}
695+
},
696+
Reveal::All => match dedup_result {
697+
Some(Selection(alloc) | UserFacing(alloc) | All(alloc)) => {
698+
return Ok(*alloc);
699+
}
700+
_ => {}
701+
},
702+
}
703+
704+
// Important to drop the lock here
705+
drop(alloc_map);
706+
drop(dedup_const_map);
707+
708+
debug!("unable to deduplicate");
709+
710+
// We weren't able to deduplicate
711+
match opt_span {
712+
Some(span) => self.at(span).eval_to_allocation_raw(key),
713+
None => self.eval_to_allocation_raw(key),
714+
}
715+
}
716+
717+
/// Tries to deduplicate a call to `eval_to_const_value_raw`. If deduplication isn't
718+
/// successful, `eval_to_const_value_raw` query is executed.
719+
#[instrument(skip(self), level = "debug")]
720+
pub fn dedup_eval_const_value_raw(
721+
self,
722+
key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
723+
opt_span: Option<Span>,
724+
) -> EvalToConstValueResult<'tcx> {
725+
use ConstDedupResult::*;
726+
727+
let (param_env, id) = key.into_parts();
728+
let dedup_const_map = self.dedup_const_map.lock();
729+
debug!("dedup_const_map: {:#?}", dedup_const_map);
730+
let const_val_map = dedup_const_map.const_val_map.borrow();
731+
debug!("const_val_map: {:#?}", const_val_map);
732+
733+
let dedup_result = const_val_map.get(&id);
734+
debug!(?dedup_result);
735+
736+
match param_env.reveal() {
737+
Reveal::Selection => match dedup_result {
738+
Some(Selection(const_val) | UserFacing(const_val)) => return Ok(*const_val),
739+
_ => {}
740+
},
741+
Reveal::UserFacing => match dedup_result {
742+
Some(Selection(const_value) | UserFacing(const_value)) => {
743+
return Ok(*const_value);
744+
}
745+
_ => {}
746+
},
747+
Reveal::All => match dedup_result {
748+
Some(Selection(const_value) | UserFacing(const_value) | All(const_value)) => {
749+
return Ok(*const_value);
750+
}
751+
_ => {}
752+
},
753+
}
754+
755+
// Important to drop the lock here
756+
drop(const_val_map);
757+
drop(dedup_const_map);
758+
759+
debug!("unable to deduplicate");
760+
761+
// We weren't able to deduplicate
762+
match opt_span {
763+
Some(span) => self.at(span).eval_to_const_value_raw(key),
764+
None => self.eval_to_const_value_raw(key),
765+
}
766+
}
557767
}
558768

559769
////////////////////////////////////////////////////////////////////////////////

compiler/rustc_middle/src/ty/consts/kind.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::fmt;
33

44
use crate::mir::interpret::{AllocId, ConstValue, Scalar};
55
use crate::mir::Promoted;
6+
use crate::traits::Reveal;
67
use crate::ty::subst::{InternalSubsts, SubstsRef};
78
use crate::ty::ParamEnv;
89
use crate::ty::{self, TyCtxt, TypeFoldable};
@@ -160,10 +161,15 @@ impl<'tcx> ConstKind<'tcx> {
160161
// Note that we erase regions *before* calling `with_reveal_all_normalized`,
161162
// so that we don't try to invoke this query with
162163
// any region variables.
163-
let param_env_and = tcx
164-
.erase_regions(param_env)
165-
.with_reveal_all_normalized(tcx)
166-
.and(tcx.erase_regions(unevaluated));
164+
let param_env_and = match param_env.reveal() {
165+
Reveal::Selection => {
166+
tcx.erase_regions(param_env).and(tcx.erase_regions(unevaluated))
167+
}
168+
_ => tcx
169+
.erase_regions(param_env)
170+
.with_reveal_all_normalized(tcx)
171+
.and(tcx.erase_regions(unevaluated)),
172+
};
167173

168174
// HACK(eddyb) when the query key would contain inference variables,
169175
// attempt using identity substs and `ParamEnv` instead, that will succeed

compiler/rustc_middle/src/ty/context.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,6 +1043,10 @@ pub struct GlobalCtxt<'tcx> {
10431043
/// Stores memory for globals (statics/consts).
10441044
pub(crate) alloc_map: Lock<interpret::AllocMap<'tcx>>,
10451045

1046+
/// Used to deduplicate calls to `eval_to_allocation_raw` and
1047+
/// `eval_to_const_value_raw`.
1048+
pub dedup_const_map: Lock<interpret::ConstDedupMap<'tcx>>,
1049+
10461050
output_filenames: Arc<OutputFilenames>,
10471051
}
10481052

@@ -1187,6 +1191,7 @@ impl<'tcx> TyCtxt<'tcx> {
11871191
stability_interner: Default::default(),
11881192
const_stability_interner: Default::default(),
11891193
alloc_map: Lock::new(interpret::AllocMap::new()),
1194+
dedup_const_map: Lock::new(interpret::ConstDedupMap::new()),
11901195
output_filenames: Arc::new(output_filenames),
11911196
}
11921197
}

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -150,11 +150,7 @@ pub struct MainDefinition {
150150

151151
impl MainDefinition {
152152
pub fn opt_fn_def_id(self) -> Option<DefId> {
153-
if let Res::Def(DefKind::Fn, def_id) = self.res {
154-
Some(def_id)
155-
} else {
156-
None
157-
}
153+
if let Res::Def(DefKind::Fn, def_id) = self.res { Some(def_id) } else { None }
158154
}
159155
}
160156

@@ -1184,11 +1180,7 @@ impl WithOptConstParam<LocalDefId> {
11841180
}
11851181

11861182
pub fn def_id_for_type_of(self) -> DefId {
1187-
if let Some(did) = self.const_param_did {
1188-
did
1189-
} else {
1190-
self.did.to_def_id()
1191-
}
1183+
if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() }
11921184
}
11931185
}
11941186

@@ -1245,23 +1237,28 @@ struct ParamTag {
12451237
}
12461238

12471239
unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag {
1248-
const BITS: usize = 2;
1240+
const BITS: usize = 3;
12491241
#[inline]
12501242
fn into_usize(self) -> usize {
12511243
match self {
1252-
Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
1253-
Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1,
1254-
Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2,
1255-
Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3,
1244+
Self { reveal: traits::Reveal::Selection, constness: hir::Constness::NotConst } => 0,
1245+
Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 1,
1246+
Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 2,
1247+
Self { reveal: traits::Reveal::Selection, constness: hir::Constness::Const } => 3,
1248+
Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 4,
1249+
Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 5,
12561250
}
12571251
}
1252+
12581253
#[inline]
12591254
unsafe fn from_usize(ptr: usize) -> Self {
12601255
match ptr {
1261-
0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
1262-
1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
1263-
2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
1264-
3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
1256+
0 => Self { reveal: traits::Reveal::Selection, constness: hir::Constness::NotConst },
1257+
1 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
1258+
2 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
1259+
3 => Self { reveal: traits::Reveal::Selection, constness: hir::Constness::Const },
1260+
4 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
1261+
5 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
12651262
_ => std::hint::unreachable_unchecked(),
12661263
}
12671264
}
@@ -1352,7 +1349,7 @@ impl<'tcx> ParamEnv<'tcx> {
13521349
}
13531350

13541351
pub fn with_reveal_selection(mut self) -> Self {
1355-
self.packed.set_tag(Reveal::Selection);
1352+
self.packed.set_tag(ParamTag { reveal: Reveal::Selection, ..self.packed.tag() });
13561353
self
13571354
}
13581355

0 commit comments

Comments
 (0)