Skip to content

Commit

Permalink
Auto merge of #50249 - Zoxc:allocation-const, r=oli-obk
Browse files Browse the repository at this point in the history
Introduce ConstValue and use it instead of miri's Value for constant values

r? @oli-obk
  • Loading branch information
bors committed May 12, 2018
2 parents 388df82 + 0aa92ac commit c705877
Show file tree
Hide file tree
Showing 58 changed files with 1,090 additions and 753 deletions.
13 changes: 7 additions & 6 deletions src/librustc/dep_graph/dep_node.rs
Expand Up @@ -60,7 +60,7 @@
//! user of the `DepNode` API of having to know how to compute the expected
//! fingerprint for a given set of node parameters.

use mir::interpret::{GlobalId};
use mir::interpret::{GlobalId, ConstValue};
use hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX};
use hir::map::DefPathHash;
use hir::{HirId, ItemLocalId};
Expand Down Expand Up @@ -621,13 +621,14 @@ define_dep_nodes!( <'tcx>
[input] UsedCrateSource(CrateNum),
[input] PostorderCnums,

// This query is not expected to have inputs -- as a result, it's
// not a good candidate for "replay" because it's essentially a
// pure function of its input (and hence the expectation is that
// no caller would be green **apart** from just this
// query). Making it anonymous avoids hashing the result, which
// These queries are not expected to have inputs -- as a result, they
// are not good candidates for "replay" because they are essentially
// pure functions of their input (and hence the expectation is that
// no caller would be green **apart** from just these
// queries). Making them anonymous avoids hashing the result, which
// may save a bit of time.
[anon] EraseRegionsTy { ty: Ty<'tcx> },
[anon] ConstValueToAllocation { val: ConstValue<'tcx>, ty: Ty<'tcx> },

[input] Freevars(DefId),
[input] MaybeUnusedTraitImport(DefId),
Expand Down
24 changes: 24 additions & 0 deletions src/librustc/ich/impls_ty.rs
Expand Up @@ -384,6 +384,30 @@ for ::middle::const_val::ConstVal<'gcx> {
}
}

impl<'a, 'gcx> HashStable<StableHashingContext<'a>>
for ::mir::interpret::ConstValue<'gcx> {
fn hash_stable<W: StableHasherResult>(&self,
hcx: &mut StableHashingContext<'a>,
hasher: &mut StableHasher<W>) {
use mir::interpret::ConstValue::*;

mem::discriminant(self).hash_stable(hcx, hasher);

match *self {
ByVal(val) => {
val.hash_stable(hcx, hasher);
}
ByValPair(a, b) => {
a.hash_stable(hcx, hasher);
b.hash_stable(hcx, hasher);
}
ByRef(alloc) => {
alloc.hash_stable(hcx, hasher);
}
}
}
}

impl_stable_hash_for!(enum mir::interpret::Value {
ByVal(v),
ByValPair(a, b),
Expand Down
24 changes: 2 additions & 22 deletions src/librustc/middle/const_val.rs
Expand Up @@ -11,7 +11,7 @@
use hir::def_id::DefId;
use ty::{self, TyCtxt, layout};
use ty::subst::Substs;
use mir::interpret::{Value, PrimVal};
use mir::interpret::ConstValue;
use errors::DiagnosticBuilder;

use graphviz::IntoCow;
Expand All @@ -25,27 +25,7 @@ pub type EvalResult<'tcx> = Result<&'tcx ty::Const<'tcx>, ConstEvalErr<'tcx>>;
#[derive(Copy, Clone, Debug, Hash, RustcEncodable, RustcDecodable, Eq, PartialEq)]
pub enum ConstVal<'tcx> {
Unevaluated(DefId, &'tcx Substs<'tcx>),
Value(Value),
}

impl<'tcx> ConstVal<'tcx> {
pub fn to_raw_bits(&self) -> Option<u128> {
match *self {
ConstVal::Value(Value::ByVal(PrimVal::Bytes(b))) => {
Some(b)
},
_ => None,
}
}
pub fn unwrap_u64(&self) -> u64 {
match self.to_raw_bits() {
Some(val) => {
assert_eq!(val as u64 as u128, val);
val as u64
},
None => bug!("expected constant u64, got {:#?}", self),
}
}
Value(ConstValue<'tcx>),
}

#[derive(Clone, Debug)]
Expand Down
2 changes: 1 addition & 1 deletion src/librustc/middle/mem_categorization.rs
Expand Up @@ -945,7 +945,7 @@ impl<'a, 'gcx, 'tcx> MemCategorizationContext<'a, 'gcx, 'tcx> {

// Always promote `[T; 0]` (even when e.g. borrowed mutably).
let promotable = match expr_ty.sty {
ty::TyArray(_, len) if len.val.to_raw_bits() == Some(0) => true,
ty::TyArray(_, len) if len.assert_usize(self.tcx) == Some(0) => true,
_ => promotable,
};

Expand Down
62 changes: 58 additions & 4 deletions src/librustc/mir/interpret/mod.rs
Expand Up @@ -10,7 +10,7 @@ mod value;

pub use self::error::{EvalError, EvalResult, EvalErrorKind, AssertMessage};

pub use self::value::{PrimVal, PrimValKind, Value, Pointer};
pub use self::value::{PrimVal, PrimValKind, Value, Pointer, ConstValue};

use std::collections::BTreeMap;
use std::fmt;
Expand All @@ -20,8 +20,10 @@ use ty::{self, TyCtxt};
use ty::layout::{self, Align, HasDataLayout};
use middle::region;
use std::iter;
use std::io;
use syntax::ast::Mutability;
use rustc_serialize::{Encoder, Decoder, Decodable, Encodable};
use byteorder::{WriteBytesExt, ReadBytesExt, LittleEndian, BigEndian};

#[derive(Clone, Debug, PartialEq, RustcEncodable, RustcDecodable)]
pub enum Lock {
Expand Down Expand Up @@ -235,7 +237,7 @@ impl fmt::Display for AllocId {
}
}

#[derive(Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
#[derive(Clone, Debug, Eq, PartialEq, Hash, RustcEncodable, RustcDecodable)]
pub struct Allocation {
/// The actual bytes of the allocation.
/// Note that the bytes of a pointer represent the offset of the pointer
Expand All @@ -254,17 +256,69 @@ pub struct Allocation {
}

impl Allocation {
pub fn from_bytes(slice: &[u8]) -> Self {
pub fn from_bytes(slice: &[u8], align: Align) -> Self {
let mut undef_mask = UndefMask::new(0);
undef_mask.grow(slice.len() as u64, true);
Self {
bytes: slice.to_owned(),
relocations: BTreeMap::new(),
undef_mask,
align: Align::from_bytes(1, 1).unwrap(),
align,
runtime_mutability: Mutability::Immutable,
}
}

pub fn from_byte_aligned_bytes(slice: &[u8]) -> Self {
Allocation::from_bytes(slice, Align::from_bytes(1, 1).unwrap())
}

pub fn undef(size: u64, align: Align) -> Self {
assert_eq!(size as usize as u64, size);
Allocation {
bytes: vec![0; size as usize],
relocations: BTreeMap::new(),
undef_mask: UndefMask::new(size),
align,
runtime_mutability: Mutability::Immutable,
}
}
}

impl<'tcx> ::serialize::UseSpecializedDecodable for &'tcx Allocation {}

////////////////////////////////////////////////////////////////////////////////
// Methods to access integers in the target endianness
////////////////////////////////////////////////////////////////////////////////

pub fn write_target_uint(
endianness: layout::Endian,
mut target: &mut [u8],
data: u128,
) -> Result<(), io::Error> {
let len = target.len();
match endianness {
layout::Endian::Little => target.write_uint128::<LittleEndian>(data, len),
layout::Endian::Big => target.write_uint128::<BigEndian>(data, len),
}
}

pub fn write_target_int(
endianness: layout::Endian,
mut target: &mut [u8],
data: i128,
) -> Result<(), io::Error> {
let len = target.len();
match endianness {
layout::Endian::Little => target.write_int128::<LittleEndian>(data, len),
layout::Endian::Big => target.write_int128::<BigEndian>(data, len),
}
}

pub fn read_target_uint(endianness: layout::Endian, mut source: &[u8]) -> Result<u128, io::Error> {
match endianness {
layout::Endian::Little => source.read_uint128::<LittleEndian>(source.len()),
layout::Endian::Big => source.read_uint128::<BigEndian>(source.len()),
}
}

////////////////////////////////////////////////////////////////////////////////
Expand Down
64 changes: 63 additions & 1 deletion src/librustc/mir/interpret/value.rs
Expand Up @@ -3,7 +3,69 @@
use ty::layout::{Align, HasDataLayout};
use ty;

use super::{EvalResult, MemoryPointer, PointerArithmetic};
use super::{EvalResult, MemoryPointer, PointerArithmetic, Allocation};

/// Represents a constant value in Rust. ByVal and ByValPair are optimizations which
/// matches Value's optimizations for easy conversions between these two types
#[derive(Clone, Copy, Debug, Eq, PartialEq, RustcEncodable, RustcDecodable, Hash)]
pub enum ConstValue<'tcx> {
// Used only for types with layout::abi::Scalar ABI and ZSTs which use PrimVal::Undef
ByVal(PrimVal),
// Used only for types with layout::abi::ScalarPair
ByValPair(PrimVal, PrimVal),
// Used only for the remaining cases
ByRef(&'tcx Allocation),
}

impl<'tcx> ConstValue<'tcx> {
#[inline]
pub fn from_byval_value(val: Value) -> Self {
match val {
Value::ByRef(..) => bug!(),
Value::ByValPair(a, b) => ConstValue::ByValPair(a, b),
Value::ByVal(val) => ConstValue::ByVal(val),
}
}

#[inline]
pub fn to_byval_value(&self) -> Option<Value> {
match *self {
ConstValue::ByRef(..) => None,
ConstValue::ByValPair(a, b) => Some(Value::ByValPair(a, b)),
ConstValue::ByVal(val) => Some(Value::ByVal(val)),
}
}

#[inline]
pub fn from_primval(val: PrimVal) -> Self {
ConstValue::ByVal(val)
}

#[inline]
pub fn to_primval(&self) -> Option<PrimVal> {
match *self {
ConstValue::ByRef(..) => None,
ConstValue::ByValPair(..) => None,
ConstValue::ByVal(val) => Some(val),
}
}

#[inline]
pub fn to_bits(&self) -> Option<u128> {
match self.to_primval() {
Some(PrimVal::Bytes(val)) => Some(val),
_ => None,
}
}

#[inline]
pub fn to_ptr(&self) -> Option<MemoryPointer> {
match self.to_primval() {
Some(PrimVal::Ptr(ptr)) => Some(ptr),
_ => None,
}
}
}

/// A `Value` represents a single self-contained Rust value.
///
Expand Down
21 changes: 11 additions & 10 deletions src/librustc/mir/mod.rs
Expand Up @@ -13,7 +13,6 @@
//! [rustc guide]: https://rust-lang-nursery.github.io/rustc-guide/mir.html

use graphviz::IntoCow;
use middle::const_val::ConstVal;
use middle::region;
use rustc_data_structures::sync::{Lrc};
use rustc_data_structures::indexed_vec::{IndexVec, Idx};
Expand Down Expand Up @@ -1549,11 +1548,7 @@ impl<'tcx> Operand<'tcx> {
span,
ty,
literal: Literal::Value {
value: tcx.mk_const(ty::Const {
// ZST function type
val: ConstVal::Value(Value::ByVal(PrimVal::Undef)),
ty
})
value: ty::Const::zero_sized(tcx, ty),
},
})
}
Expand Down Expand Up @@ -1881,11 +1876,17 @@ impl<'tcx> Debug for Literal<'tcx> {
}

/// Write a `ConstVal` in a way closer to the original source code than the `Debug` output.
fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
use middle::const_val::ConstVal::*;
pub fn fmt_const_val<W: Write>(fmt: &mut W, const_val: &ty::Const) -> fmt::Result {
use middle::const_val::ConstVal;
match const_val.val {
Unevaluated(..) => write!(fmt, "{:?}", const_val),
Value(val) => print_miri_value(val, const_val.ty, fmt),
ConstVal::Unevaluated(..) => write!(fmt, "{:?}", const_val),
ConstVal::Value(val) => {
if let Some(value) = val.to_byval_value() {
print_miri_value(value, const_val.ty, fmt)
} else {
write!(fmt, "{:?}:{}", val, const_val.ty)
}
},
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/librustc/mir/tcx.rs
Expand Up @@ -69,7 +69,7 @@ impl<'a, 'gcx, 'tcx> PlaceTy<'tcx> {
PlaceTy::Ty {
ty: match ty.sty {
ty::TyArray(inner, size) => {
let size = size.val.unwrap_u64();
let size = size.unwrap_usize(tcx);
let len = size - (from as u64) - (to as u64);
tcx.mk_array(inner, len)
}
Expand Down
19 changes: 19 additions & 0 deletions src/librustc/ty/codec.rs
Expand Up @@ -24,6 +24,7 @@ use std::hash::Hash;
use std::intrinsics;
use ty::{self, Ty, TyCtxt};
use ty::subst::Substs;
use mir::interpret::Allocation;

/// The shorthand encoding uses an enum's variant index `usize`
/// and is offset by this value so it never matches a real variant.
Expand Down Expand Up @@ -262,6 +263,15 @@ pub fn decode_const<'a, 'tcx, D>(decoder: &mut D)
Ok(decoder.tcx().mk_const(Decodable::decode(decoder)?))
}

#[inline]
pub fn decode_allocation<'a, 'tcx, D>(decoder: &mut D)
-> Result<&'tcx Allocation, D::Error>
where D: TyDecoder<'a, 'tcx>,
'tcx: 'a,
{
Ok(decoder.tcx().intern_const_alloc(Decodable::decode(decoder)?))
}

#[macro_export]
macro_rules! __impl_decoder_methods {
($($name:ident -> $ty:ty;)*) => {
Expand Down Expand Up @@ -393,6 +403,15 @@ macro_rules! implement_ty_decoder {
decode_const(self)
}
}

impl<$($typaram),*> SpecializedDecoder<&'tcx $crate::mir::interpret::Allocation>
for $DecoderName<$($typaram),*> {
fn specialized_decode(
&mut self
) -> Result<&'tcx $crate::mir::interpret::Allocation, Self::Error> {
decode_allocation(self)
}
}
}
}
}
Expand Down

0 comments on commit c705877

Please sign in to comment.