Skip to content

Commit dc96b91

Browse files
committed
Auto merge of #58486 - oli-obk:import_miri_from_future, r=<try>
always back `ty::Const` by an `Allocation` This reduces the number of conversion between `Allocation` and `Value` by caching both. r? @RalfJung
2 parents f058741 + b0857a7 commit dc96b91

File tree

16 files changed

+226
-133
lines changed

16 files changed

+226
-133
lines changed

src/librustc/ich/impls_ty.rs

+29-6
Original file line numberDiff line numberDiff line change
@@ -300,15 +300,18 @@ impl_stable_hash_for!(struct ty::FieldDef {
300300
});
301301

302302
impl_stable_hash_for!(
303-
impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] {
303+
impl<'tcx> for enum mir::interpret::ConstValue [ mir::interpret::ConstValue ] {
304304
Scalar(val),
305305
Slice(a, b),
306-
ByRef(id, alloc, offset),
306+
ByRef,
307307
}
308308
);
309+
309310
impl_stable_hash_for!(struct crate::mir::interpret::RawConst<'tcx> {
311+
// FIXME(oli-obk): is ignoring the `alloc_id` for perf reasons ok?
310312
alloc_id,
311313
ty,
314+
alloc,
312315
});
313316

314317
impl_stable_hash_for! {
@@ -372,10 +375,30 @@ impl_stable_hash_for!(enum ::syntax::ast::Mutability {
372375
Mutable
373376
});
374377

375-
impl_stable_hash_for!(struct ty::Const<'tcx> {
376-
ty,
377-
val
378-
});
378+
379+
impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::Const<'gcx> {
380+
fn hash_stable<W: StableHasherResult>(
381+
&self,
382+
hcx: &mut StableHashingContext<'a>,
383+
hasher: &mut StableHasher<W>,
384+
) {
385+
let ty::Const { ty, val, alloc } = self;
386+
ty.hash_stable(hcx, hasher);
387+
val.hash_stable(hcx, hasher);
388+
// don't hash the memory for `Scalar` and `Slice`. There's nothing to be gained
389+
// by it. All the relevant info is contained in the value.
390+
if let mir::interpret::ConstValue::ByRef = val {
391+
let (alloc, ptr) = alloc.unwrap();
392+
// type check for future changes
393+
let alloc: &'gcx mir::interpret::Allocation = alloc;
394+
alloc.hash_stable(hcx, hasher);
395+
ptr.offset.hash_stable(hcx, hasher);
396+
// do not hash the alloc id in the pointer. It does not add anything new to the hash.
397+
// If the hash of the alloc id is the same, then the hash of the allocation would also
398+
// be the same.
399+
}
400+
}
401+
}
379402

380403
impl_stable_hash_for!(impl<'tcx> for enum ty::LazyConst<'tcx> [ty::LazyConst] {
381404
Unevaluated(did, substs),

src/librustc/mir/interpret/value.rs

+14-10
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,27 @@ use std::fmt;
22

33
use crate::ty::{Ty, layout::{HasDataLayout, Size}};
44

5-
use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
5+
use super::{EvalResult, Pointer, PointerArithmetic, AllocId, sign_extend, truncate, Allocation};
66

77
/// Represents the result of a raw const operation, pre-validation.
88
#[derive(Copy, Clone, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
99
pub struct RawConst<'tcx> {
10-
// the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory`
11-
// (so you can use `AllocMap::unwrap_memory`).
10+
/// the value lives here, at offset 0, and the allocation that it refers to is the one in the
11+
/// `alloc` field
1212
pub alloc_id: AllocId,
1313
pub ty: Ty<'tcx>,
14+
/// the allocation that would be returned by using
15+
/// `tcx.alloc_map.lock().unwrap_memory(self.alloc_id)`
16+
///
17+
/// This is an optimization so we don't actually have to go fetch said allocation from the
18+
/// `alloc_map` at most use sites of the `const_eval_raw` query
19+
pub alloc: &'tcx Allocation,
1420
}
1521

1622
/// Represents a constant value in Rust. `Scalar` and `ScalarPair` are optimizations that
1723
/// match the `LocalState` optimizations for easy conversions between `Value` and `ConstValue`.
1824
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, RustcEncodable, RustcDecodable, Hash)]
19-
pub enum ConstValue<'tcx> {
25+
pub enum ConstValue {
2026
/// Used only for types with `layout::abi::Scalar` ABI and ZSTs.
2127
///
2228
/// Not using the enum `Value` to encode that this must not be `Undef`.
@@ -31,19 +37,17 @@ pub enum ConstValue<'tcx> {
3137
/// it.
3238
Slice(Scalar, u64),
3339

34-
/// An allocation together with an offset into the allocation.
35-
/// Invariant: the `AllocId` matches the allocation.
36-
ByRef(AllocId, &'tcx Allocation, Size),
40+
ByRef,
3741
}
3842

3943
#[cfg(target_arch = "x86_64")]
40-
static_assert!(CONST_SIZE: ::std::mem::size_of::<ConstValue<'static>>() == 40);
44+
static_assert!(CONST_SIZE: ::std::mem::size_of::<ConstValue>() == 40);
4145

42-
impl<'tcx> ConstValue<'tcx> {
46+
impl ConstValue {
4347
#[inline]
4448
pub fn try_to_scalar(&self) -> Option<Scalar> {
4549
match *self {
46-
ConstValue::ByRef(..) |
50+
ConstValue::ByRef |
4751
ConstValue::Slice(..) => None,
4852
ConstValue::Scalar(val) => Some(val),
4953
}

src/librustc/mir/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1665,6 +1665,7 @@ impl<'tcx> TerminatorKind<'tcx> {
16651665
}.into(),
16661666
),
16671667
ty: switch_ty,
1668+
alloc: None,
16681669
};
16691670
fmt_const_val(&mut s, c).unwrap();
16701671
s.into()

src/librustc/ty/structural_impls.rs

+16-30
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
//! `BraceStructLiftImpl!`) to help with the tedium.
55
66
use crate::mir::ProjectionKind;
7-
use crate::mir::interpret::ConstValue;
87
use crate::ty::{self, Lift, Ty, TyCtxt};
98
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor};
109
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
@@ -486,23 +485,20 @@ BraceStructLiftImpl! {
486485
}
487486
}
488487

489-
BraceStructLiftImpl! {
490-
impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> {
491-
type Lifted = ty::Const<'tcx>;
492-
val, ty
493-
}
494-
}
495-
496-
impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
497-
type Lifted = ConstValue<'tcx>;
488+
impl<'a, 'tcx> Lift<'tcx> for ty::Const<'a> {
489+
type Lifted = ty::Const<'tcx>;
498490
fn lift_to_tcx<'b, 'gcx>(&self, tcx: TyCtxt<'b, 'gcx, 'tcx>) -> Option<Self::Lifted> {
499-
match *self {
500-
ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)),
501-
ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)),
502-
ConstValue::ByRef(x, alloc, z) => Some(ConstValue::ByRef(
503-
x, alloc.lift_to_tcx(tcx)?, z,
504-
)),
505-
}
491+
let ty = self.ty.lift_to_tcx(tcx)?;
492+
let alloc = match self.alloc {
493+
// can't use `and_then` or `map`, because the inner `lift_to_tcx` needs to early return
494+
Some((a, p)) => Some((a.lift_to_tcx(tcx)?, p)),
495+
None => None,
496+
};
497+
Some(ty::Const {
498+
val: self.val,
499+
ty,
500+
alloc,
501+
})
506502
}
507503
}
508504

@@ -1064,24 +1060,14 @@ impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::LazyConst<'tcx> {
10641060
impl<'tcx> TypeFoldable<'tcx> for ty::Const<'tcx> {
10651061
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
10661062
let ty = self.ty.fold_with(folder);
1067-
let val = self.val.fold_with(folder);
10681063
ty::Const {
10691064
ty,
1070-
val
1065+
val: self.val,
1066+
alloc: self.alloc,
10711067
}
10721068
}
10731069

10741070
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
1075-
self.ty.visit_with(visitor) || self.val.visit_with(visitor)
1076-
}
1077-
}
1078-
1079-
impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
1080-
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, _folder: &mut F) -> Self {
1081-
*self
1082-
}
1083-
1084-
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, _visitor: &mut V) -> bool {
1085-
false
1071+
self.ty.visit_with(visitor)
10861072
}
10871073
}

src/librustc/ty/sty.rs

+60-5
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ use crate::ty::subst::{Substs, Subst, Kind, UnpackedKind};
1111
use crate::ty::{self, AdtDef, TypeFlags, Ty, TyCtxt, TypeFoldable};
1212
use crate::ty::{List, TyS, ParamEnvAnd, ParamEnv};
1313
use crate::util::captures::Captures;
14-
use crate::mir::interpret::{Scalar, Pointer};
14+
use crate::mir::interpret::{Scalar, Pointer, Allocation};
1515

16+
use std::hash::{Hash, Hasher};
1617
use smallvec::SmallVec;
1718
use std::iter;
1819
use std::cmp::Ordering;
@@ -2065,7 +2066,7 @@ pub enum LazyConst<'tcx> {
20652066
}
20662067

20672068
#[cfg(target_arch = "x86_64")]
2068-
static_assert!(LAZY_CONST_SIZE: ::std::mem::size_of::<LazyConst<'static>>() == 56);
2069+
static_assert!(LAZY_CONST_SIZE: ::std::mem::size_of::<LazyConst<'static>>() == 80);
20692070

20702071
impl<'tcx> LazyConst<'tcx> {
20712072
pub fn map_evaluated<R>(self, f: impl FnOnce(Const<'tcx>) -> Option<R>) -> Option<R> {
@@ -2086,15 +2087,68 @@ impl<'tcx> LazyConst<'tcx> {
20862087
}
20872088

20882089
/// Typed constant value.
2089-
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq, Ord, PartialOrd)]
2090+
#[derive(Copy, Clone, Debug, RustcEncodable, RustcDecodable, Eq, Ord, PartialOrd)]
20902091
pub struct Const<'tcx> {
20912092
pub ty: Ty<'tcx>,
20922093

2093-
pub val: ConstValue<'tcx>,
2094+
/// This field is an optimization for caching commonly needed values of constants like `usize`
2095+
/// (or other integers for enum discriminants) and slices (e.g. from `b"foo"` and `"foo"`
2096+
/// literals)
2097+
pub val: ConstValue,
2098+
2099+
/// The actual backing storage of the constant and a pointer which can be resolved back to the
2100+
/// `allocation` field
2101+
///
2102+
/// Can be `None` for trivial constants created from literals or directly. Is always `Some` for
2103+
/// aggregate constants or any named constant that you can actually end up taking a reference
2104+
/// to. This will get unwrapped in situations where we do know that it's a referencable
2105+
pub alloc: Option<(&'tcx Allocation, Pointer)>,
2106+
}
2107+
2108+
impl<'tcx> PartialEq for Const<'tcx> {
2109+
fn eq(&self, other: &Self) -> bool {
2110+
2111+
self.ty == other.ty && match (self.val, other.val) {
2112+
(ConstValue::ByRef, ConstValue::ByRef) => {
2113+
let (a, pa) = self.alloc.unwrap();
2114+
let (b, pb) = other.alloc.unwrap();
2115+
// only use the alloc ids to not have to compare the full allocations
2116+
// the ids may differ if the allocation is the same
2117+
(pa.offset == pb.offset) && (pa.alloc_id == pb.alloc_id || a == b)
2118+
},
2119+
// ignore the actual allocation, just compare the values
2120+
(ConstValue::Scalar(a), ConstValue::Scalar(b)) => a == b,
2121+
(ConstValue::Slice(a, an), ConstValue::Slice(b, bn)) => an == bn && a == b,
2122+
// if the values don't match, the consts can't be equal and the type equality should
2123+
// have already failed, because we make the decision for non-byref solely based on the
2124+
// type
2125+
_ => bug!("same type but different value kind in constant: {:#?} {:#?}", self, other),
2126+
}
2127+
}
2128+
}
2129+
2130+
impl<'tcx> Hash for Const<'tcx> {
2131+
fn hash<H: Hasher>(&self, hasher: &mut H) {
2132+
let Const { ty, val, alloc } = self;
2133+
ty.hash(hasher);
2134+
val.hash(hasher);
2135+
// don't hash the memory for `Scalar` and `Slice`. There's nothing to be gained
2136+
// by it. All the relevant info is contained in the value.
2137+
if let ConstValue::ByRef = val {
2138+
let (alloc, ptr) = alloc.unwrap();
2139+
// type check for future changes
2140+
let alloc: &'tcx Allocation = alloc;
2141+
alloc.hash(hasher);
2142+
ptr.offset.hash(hasher);
2143+
// do not hash the alloc id in the pointer. It does not add anything new to the hash.
2144+
// If the hash of the alloc id is the same, then the hash of the allocation would also
2145+
// be the same.
2146+
}
2147+
}
20942148
}
20952149

20962150
#[cfg(target_arch = "x86_64")]
2097-
static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 48);
2151+
static_assert!(CONST_SIZE: ::std::mem::size_of::<Const<'static>>() == 72);
20982152

20992153
impl<'tcx> Const<'tcx> {
21002154
#[inline]
@@ -2105,6 +2159,7 @@ impl<'tcx> Const<'tcx> {
21052159
Self {
21062160
val: ConstValue::Scalar(val),
21072161
ty,
2162+
alloc: None,
21082163
}
21092164
}
21102165

src/librustc_codegen_llvm/consts.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use libc::c_uint;
22
use llvm::{self, SetUnnamedAddr, True};
33
use rustc::hir::def_id::DefId;
4-
use rustc::mir::interpret::{ConstValue, Allocation, read_target_uint,
4+
use rustc::mir::interpret::{Allocation, read_target_uint,
55
Pointer, ErrorHandled, GlobalId};
66
use rustc::hir::Node;
77
use debuginfo;
@@ -69,11 +69,11 @@ pub fn codegen_static_initializer(
6969
};
7070
let param_env = ty::ParamEnv::reveal_all();
7171
let static_ = cx.tcx.const_eval(param_env.and(cid))?;
72-
73-
let alloc = match static_.val {
74-
ConstValue::ByRef(_, alloc, n) if n.bytes() == 0 => alloc,
72+
let (alloc, ptr) = match static_.alloc {
73+
Some(alloc) => alloc,
7574
_ => bug!("static const eval returned {:#?}", static_),
7675
};
76+
assert_eq!(ptr.offset.bytes(), 0);
7777
Ok((const_alloc_to_llvm(cx, alloc), alloc))
7878
}
7979

src/librustc_codegen_ssa/mir/operand.rs

+3-2
Original file line numberDiff line numberDiff line change
@@ -101,8 +101,9 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
101101
let b_llval = bx.cx().const_usize(b);
102102
OperandValue::Pair(a_llval, b_llval)
103103
},
104-
ConstValue::ByRef(_, alloc, offset) => {
105-
return Ok(bx.load_operand(bx.cx().from_const_alloc(layout, alloc, offset)));
104+
ConstValue::ByRef => {
105+
let (alloc, ptr) = val.alloc.unwrap();
106+
return Ok(bx.load_operand(bx.cx().from_const_alloc(layout, alloc, ptr.offset)));
106107
},
107108
};
108109

src/librustc_codegen_ssa/mir/place.rs

+2-4
Original file line numberDiff line numberDiff line change
@@ -416,10 +416,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
416416
};
417417
let layout = cx.layout_of(self.monomorphize(&ty));
418418
match bx.tcx().const_eval(param_env.and(cid)) {
419-
Ok(val) => match val.val {
420-
mir::interpret::ConstValue::ByRef(_, alloc, offset) => {
421-
bx.cx().from_const_alloc(layout, alloc, offset)
422-
}
419+
Ok(val) => match val.alloc {
420+
Some((alloc, ptr)) => bx.cx().from_const_alloc(layout, alloc, ptr.offset),
423421
_ => bug!("promoteds should have an allocation: {:?}", val),
424422
},
425423
Err(_) => {

0 commit comments

Comments
 (0)