Skip to content

Commit

Permalink
create leafs for slices
Browse files Browse the repository at this point in the history
  • Loading branch information
b-naber committed Apr 8, 2022
1 parent fcc4d8c commit 82217a6
Show file tree
Hide file tree
Showing 6 changed files with 64 additions and 145 deletions.
2 changes: 2 additions & 0 deletions compiler/rustc_const_eval/src/const_eval/eval_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ pub(super) fn op_to_const<'tcx>(
}
}

#[instrument(skip(tcx), level = "debug")]
fn turn_into_const_value<'tcx>(
tcx: TyCtxt<'tcx>,
constant: ConstAlloc<'tcx>,
Expand All @@ -206,6 +207,7 @@ fn turn_into_const_value<'tcx>(
!is_static || cid.promoted.is_some(),
"the `eval_to_const_value_raw` query should not be used for statics, use `eval_to_allocation` instead"
);

// Turn this into a proper constant.
op_to_const(&ecx, &mplace.into())
}
Expand Down
128 changes: 57 additions & 71 deletions compiler/rustc_const_eval/src/const_eval/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,14 @@ use rustc_hir::Mutability;
use rustc_middle::ty::{self, TyCtxt};
use rustc_middle::{
mir::{self, interpret::ConstAlloc},
ty::{ScalarInt, Ty},
ty::ScalarInt,
};
use rustc_span::{source_map::DUMMY_SP, symbol::Symbol};
use rustc_target::abi::VariantIdx;

use crate::interpret::{
intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, InterpResult, MPlaceTy,
MemPlaceMeta, Scalar,
intern_const_alloc_recursive, ConstValue, Immediate, InternKind, InterpCx, InterpResult,
MPlaceTy, MemPlaceMeta, Scalar,
};

mod error;
Expand Down Expand Up @@ -80,19 +80,28 @@ fn branches<'tcx>(
Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
}

fn slice_branches<'tcx>(
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
place: &MPlaceTy<'tcx>,
n: u64,
) -> Option<ty::ValTree<'tcx>> {
let elems = (0..n).map(|i| {
let place_elem = ecx.mplace_index(place, i).unwrap();
const_to_valtree_inner(ecx, &place_elem)
});

// Need `len` for the ValTree -> ConstValue conversion
let len = Some(Some(ty::ValTree::Leaf(ScalarInt::from(n))));
let branches = len.into_iter().chain(elems);

Some(ty::ValTree::Branch(ecx.tcx.arena.alloc_from_iter(branches.collect::<Option<Vec<_>>>()?)))
}

#[instrument(skip(ecx), level = "debug")]
fn const_to_valtree_inner<'tcx>(
ecx: &CompileTimeEvalContext<'tcx, 'tcx>,
place: &MPlaceTy<'tcx>,
) -> Option<ty::ValTree<'tcx>> {
// We only want to use raw bytes in ValTrees for string slices or &[<integer_ty>]
let use_bytes_for_ref = |ty: Ty<'tcx>| -> bool {
match ty.kind() {
ty::Str | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Bool => true,
_ => false,
}
};

match place.layout.ty.kind() {
ty::FnDef(..) => Some(ty::ValTree::zst()),
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
Expand All @@ -107,75 +116,52 @@ fn const_to_valtree_inner<'tcx>(
// agree with runtime equality tests.
ty::FnPtr(_) | ty::RawPtr(_) => None,

ty::Ref(_, ref_ty, _) if place.layout.ty.is_slice() => {
match ecx.try_read_immediate_from_mplace(&place) {
Ok(Some(imm)) => {
// `imm` is a ScalarPair. We try to get the underlying bytes behind that
// fat pointer for string slices and slices of integer types. For any other
// slice types we use `branches` to recursively construct the Valtree.

if use_bytes_for_ref(*ref_ty) {
let (alloc, range) = ecx.get_alloc_from_imm_scalar_pair(imm);
let alloc_bytes = match alloc.get_bytes(&ecx.tcx, range) {
Ok(bytes) => bytes,
Err(_e) => return None,
};
debug!(?alloc_bytes);

let bytes = ecx.tcx.arena.alloc_slice(alloc_bytes);
let len = bytes.len();
debug!(?bytes, ?len);

let slice = ty::ValSlice { bytes};

Some(ty::ValTree::SliceOrStr(slice))
} else {
let derefd = ecx.deref_operand(&imm.into()).expect(&format!("couldnt deref {:?}", imm));
debug!("derefd: {:?}", derefd);

let derefd_imm = match ecx.try_read_immediate_from_mplace(&derefd) {
Ok(Some(imm)) => imm,
_ => return None,
};
debug!(?derefd_imm);

let tcx = ecx.tcx.tcx;
let scalar_len= derefd.meta.unwrap_meta();
let len = match scalar_len {
Scalar::Int(int) => {
int.try_to_machine_usize(tcx).expect(&format!("Expected a valid ScalarInt in {:?}", scalar_len))
}
_ => bug!("expected a ScalarInt in meta data for {:?}", place),
};
debug!(?len);

let valtree = branches(ecx, place, len.try_into().expect("BLA"), None);
debug!(?valtree);

valtree
ty::Ref(_, inner_ty, _) => {
match inner_ty.kind() {
ty::Slice(_) | ty::Str => {
match ecx.try_read_immediate_from_mplace(&place) {
Ok(Some(imm)) => {
let mplace_ref = ecx.ref_to_mplace(&imm).unwrap();
let derefd = ecx.deref_operand(&place.into()).expect(&format!("couldnt deref {:?}", imm));
debug!(?mplace_ref, ?derefd);

let len = match imm.imm {
Immediate::ScalarPair(_, b) => {
let len = b.to_machine_usize(&ecx.tcx.tcx).unwrap();
len
}
_ => bug!("expected ScalarPair for &[T] or &str"),
};
debug!(?len);

let valtree = slice_branches(ecx, &derefd, len);
debug!(?valtree);

valtree
}
_ => {
None
}
}
}
_ => {
None
}
}
}
let imm = ecx.try_read_immediate_from_mplace(&place).unwrap_or_else(|e| bug!("couldnt read immediate from {:?}, error: {:?}", place, e));

ty::Ref(_, inner_ty, _) => {
debug!("Ref with inner_ty: {:?}", inner_ty);
let imm = ecx.try_read_immediate_from_mplace(&place).unwrap_or_else(|e| bug!("couldnt read immediate from {:?}, error: {:?}", place, e));
match imm {
Some(imm) => {
debug!(?imm);
match imm {
Some(imm) => {
debug!(?imm);

let derefd_place = ecx.deref_mplace(place).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
debug!(?derefd_place);
let derefd_place = ecx.deref_operand(&place.into()).unwrap_or_else(|e| bug!("couldn't deref {:?}, error: {:?}", place, e));
debug!(?derefd_place);

const_to_valtree_inner(ecx, &derefd_place)
const_to_valtree_inner(ecx, &derefd_place)
}
None => bug!("couldn't read immediate from {:?}", place),
}
}
None => None,
}
}

ty::Str => {
bug!("ty::Str should have been handled in ty::Ref branch that uses raw bytes");
}
Expand Down
37 changes: 4 additions & 33 deletions compiler/rustc_const_eval/src/interpret/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ use rustc_target::abi::{Abi, HasDataLayout, Size, TagEncoding};
use rustc_target::abi::{VariantIdx, Variants};

use super::{
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, AllocRange, Allocation,
ConstValue, GlobalId, InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy,
Pointer, Provenance, Scalar, ScalarMaybeUninit,
alloc_range, from_known_layout, mir_assign_valid_types, AllocId, ConstValue, GlobalId,
InterpCx, InterpResult, MPlaceTy, Machine, MemPlace, Place, PlaceTy, Pointer, Provenance,
Scalar, ScalarMaybeUninit,
};

/// An `Immediate` represents a single immediate self-contained Rust value.
Expand Down Expand Up @@ -98,7 +98,7 @@ impl<'tcx, Tag: Provenance> Immediate<Tag> {
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
pub struct ImmTy<'tcx, Tag: Provenance = AllocId> {
imm: Immediate<Tag>,
pub(crate) imm: Immediate<Tag>,
pub layout: TyAndLayout<'tcx>,
}

Expand Down Expand Up @@ -777,32 +777,3 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
})
}
}

impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx, PointerTag = AllocId>> InterpCx<'mir, 'tcx, M> {
pub fn get_alloc_from_imm_scalar_pair(
&self,
imm: ImmTy<'tcx, M::PointerTag>,
) -> (&Allocation, AllocRange) {
match imm.imm {
Immediate::ScalarPair(a, b) => {
// We know `offset` is relative to the allocation, so we can use `into_parts`.
let (data, start) = match self.scalar_to_ptr(a.check_init().unwrap()).into_parts() {
(Some(alloc_id), offset) => {
(self.tcx.global_alloc(alloc_id).unwrap_memory(), offset.bytes())
}
(None, _offset) => (
self.tcx.intern_const_alloc(Allocation::from_bytes_byte_aligned_immutable(
b"" as &[u8],
)),
0,
),
};
let len = b.to_machine_usize(self).unwrap();
let size = Size::from_bytes(len);
let start = Size::from_bytes(start);
(data.inner(), AllocRange { start, size })
}
_ => bug!("{:?} not a ScalarPair", imm),
}
}
}
12 changes: 0 additions & 12 deletions compiler/rustc_const_eval/src/interpret/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -305,18 +305,6 @@ where
Ok(mplace)
}

#[instrument(skip(self), level = "debug")]
pub fn deref_mplace(
&self,
src: &MPlaceTy<'tcx, M::PointerTag>,
) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> {
let val = self.try_read_immediate_from_mplace(src)?;
let mplace = self.ref_to_mplace(&val.unwrap())?;
self.check_mplace_access(mplace, CheckInAllocMsg::DerefTest)?;

Ok(mplace)
}

#[inline]
pub(super) fn get_alloc(
&self,
Expand Down
28 changes: 0 additions & 28 deletions compiler/rustc_middle/src/ty/consts/valtree.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
use super::ScalarInt;
use crate::ty::codec::TyDecoder;
use rustc_macros::{HashStable, TyDecodable, TyEncodable};
use rustc_serialize::{Decodable, Encodable, Encoder};

#[derive(Copy, Clone, Debug, Hash, TyEncodable, TyDecodable, Eq, PartialEq, Ord, PartialOrd)]
#[derive(HashStable)]
Expand All @@ -22,7 +20,6 @@ pub enum ValTree<'tcx> {
/// See the `ScalarInt` documentation for how `ScalarInt` guarantees that equal values
/// of these types have the same representation.
Leaf(ScalarInt),
SliceOrStr(ValSlice<'tcx>),
/// The fields of any kind of aggregate. Structs, tuples and arrays are represented by
/// listing their fields' values in order.
/// Enums are represented by storing their discriminant as a field, followed by all
Expand All @@ -35,28 +32,3 @@ impl<'tcx> ValTree<'tcx> {
Self::Branch(&[])
}
}

#[derive(Copy, Clone, Debug, HashStable, Hash, Eq, PartialEq, PartialOrd, Ord)]
pub struct ValSlice<'tcx> {
pub bytes: &'tcx [u8],
}

impl<'tcx, S: Encoder> Encodable<S> for ValSlice<'tcx> {
fn encode(&self, s: &mut S) -> Result<(), S::Error> {
s.emit_usize(self.bytes.len())?;
s.emit_raw_bytes(self.bytes)?;

Ok(())
}
}

impl<'tcx, D: TyDecoder<'tcx>> Decodable<D> for ValSlice<'tcx> {
fn decode(d: &mut D) -> Self {
let tcx = d.tcx();
let len = d.read_usize();
let bytes_raw = d.read_raw_bytes(len);
let bytes = tcx.arena.alloc_slice(&bytes_raw[..]);

ValSlice { bytes }
}
}
2 changes: 1 addition & 1 deletion compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ pub use self::closure::{
CAPTURE_STRUCT_LOCAL,
};
pub use self::consts::{
Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValSlice, ValTree,
Const, ConstInt, ConstKind, ConstS, InferConst, ScalarInt, Unevaluated, ValTree,
};
pub use self::context::{
tls, CanonicalUserType, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations,
Expand Down

0 comments on commit 82217a6

Please sign in to comment.