Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ConstValue and use it instead of miri's Value for constant values #50249

Merged
merged 2 commits into from
May 12, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 7 additions & 6 deletions src/librustc/dep_graph/dep_node.rs
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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
Original file line number Diff line number Diff line change
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>
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't this conflict with the derive on Allocation? IIRC this produces runtime issues if done incorrectly. Have a look at what AllocId does

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so. This decodes a pointer to an Allocation, while the derive is for Allocation itself.

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