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

Get rid of ConstValue::ScalarPair #55392

Closed
wants to merge 3 commits into from
Closed
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
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ impl_stable_hash_for!(
impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] {
Unevaluated(def_id, substs),
Scalar(val),
ScalarPair(a, b),
Slice(id, alloc),
ByRef(id, alloc, offset),
}
);
Expand Down
51 changes: 50 additions & 1 deletion src/librustc/mir/interpret/allocation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use super::{
truncate,
};

use ty::layout::{Size, Align};
use ty::layout::{Size, Align, self};
use syntax::ast::Mutability;
use std::iter;
use mir;
Expand Down Expand Up @@ -325,6 +325,33 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
Ok(())
}

pub fn write_scalar_pair<MemoryExtra>(
&mut self,
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
a_val: ScalarMaybeUndef<Tag>,
b_val: ScalarMaybeUndef<Tag>,
layout: layout::TyLayout<'tcx>,
) -> EvalResult<'tcx>
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
where Extra: AllocationExtra<Tag, MemoryExtra>
{
let (a, b) = match layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (&a.value, &b.value),
_ => bug!("write_scalar_pair: invalid ScalarPair layout: {:#?}", layout),
};
let (a_size, b_size) = (a.size(cx), b.size(cx));
let b_offset = a_size.align_to(b.align(cx).abi);
let b_ptr = ptr.offset(b_offset, cx)?;

// It is tempting to verify `b_offset` against `layout.fields.offset(1)`,
// but that does not work: We could be a newtype around a pair, then the
// fields do not match the `ScalarPair` components.

self.write_scalar(cx, ptr, a_val, a_size)?;
self.write_scalar(cx, b_ptr, b_val, b_size)
}

/// Sets `count` bytes starting at `ptr.offset` with `val`. Basically `memset`.
pub fn write_repeat<MemoryExtra>(
&mut self,
Expand Down Expand Up @@ -400,6 +427,28 @@ impl<'tcx, Tag: Copy, Extra> Allocation<Tag, Extra> {
self.read_scalar(cx, ptr, cx.data_layout().pointer_size)
}

pub fn read_usize<MemoryExtra>(
&self,
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
) -> EvalResult<'tcx, u64>
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
where Extra: AllocationExtra<Tag, MemoryExtra>
{
self.read_ptr_sized(cx, ptr)?.not_undef()?.to_usize(cx)
}

pub fn read_ptr<MemoryExtra>(
&self,
cx: &impl HasDataLayout,
ptr: Pointer<Tag>,
) -> EvalResult<'tcx, Pointer<Tag>>
// FIXME: Working around https://github.com/rust-lang/rust/issues/56209
where Extra: AllocationExtra<Tag, MemoryExtra>
{
self.read_ptr_sized(cx, ptr)?.not_undef()?.to_ptr()
}

/// Write a *non-ZST* scalar
///
/// zsts can't be read out of two reasons:
Expand Down
49 changes: 32 additions & 17 deletions src/librustc/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@

use std::fmt;

use crate::ty::{Ty, subst::Substs, layout::{HasDataLayout, Size}};
use crate::ty::{Ty, subst::Substs, layout::{HasDataLayout, Size}, TyCtxt};
use crate::hir::def_id::DefId;

use super::{EvalResult, Pointer, PointerArithmetic, Allocation, AllocId, sign_extend, truncate};
Expand Down Expand Up @@ -39,10 +39,13 @@ pub enum ConstValue<'tcx> {
/// Not using the enum `Value` to encode that this must not be `Undef`
Scalar(Scalar),

/// Used only for *fat pointers* with layout::abi::ScalarPair
/// Strings and byte strings have a custom variant for performance reasons.
/// Otherwise we'd be converting
/// from an allocation of a pointer + length to the pointer + length and back all the tim
///
/// Needed for pattern matching code related to slices and strings.
ScalarPair(Scalar, Scalar),
/// The allocation of the bytes of the string. The size of the allocation is the length
/// of the string in bytes
Slice(AllocId, &'tcx Allocation),

/// An allocation + offset into the allocation.
/// Invariant: The AllocId matches the allocation.
Expand All @@ -54,8 +57,8 @@ impl<'tcx> ConstValue<'tcx> {
pub fn try_to_scalar(&self) -> Option<Scalar> {
match *self {
ConstValue::Unevaluated(..) |
ConstValue::ByRef(..) |
ConstValue::ScalarPair(..) => None,
ConstValue::Slice(..) |
ConstValue::ByRef(..) => None,
ConstValue::Scalar(val) => Some(val),
}
}
Expand All @@ -71,20 +74,32 @@ impl<'tcx> ConstValue<'tcx> {
}

#[inline]
pub fn new_slice(
val: Scalar,
len: u64,
cx: &impl HasDataLayout
) -> Self {
ConstValue::ScalarPair(val, Scalar::Bits {
bits: len as u128,
size: cx.data_layout().pointer_size.bytes() as u8,
})
/// Used for trait object fat pointers
fn new_ptr_sized_seq(scalars: &[Scalar], tcx: TyCtxt<'_, '_, 'tcx>) -> Self {
let mut allocation = Allocation::undef(
tcx.data_layout.pointer_size * scalars.len() as u64,
tcx.data_layout.pointer_align.abi,
Default::default(),
);
let alloc_id = tcx.alloc_map.lock().reserve();
let mut ptr = Pointer::from(alloc_id);
for &scalar in scalars {
allocation.write_scalar(
&tcx,
ptr,
scalar.into(),
tcx.data_layout.pointer_size,
).unwrap();
ptr = ptr.offset(tcx.data_layout.pointer_size, &tcx).unwrap();
}
let allocation = tcx.intern_const_alloc(allocation);
tcx.alloc_map.lock().set_id_memory(alloc_id, allocation);
ConstValue::ByRef(alloc_id, allocation, Size::ZERO)
}

#[inline]
pub fn new_dyn_trait(val: Scalar, vtable: Pointer) -> Self {
ConstValue::ScalarPair(val, Scalar::Ptr(vtable))
pub fn new_dyn_trait(val: Scalar, vtable: Pointer, tcx: TyCtxt<'_, '_, 'tcx>) -> Self {
Self::new_ptr_sized_seq(&[val, Scalar::Ptr(vtable)], tcx)
}
}

Expand Down
22 changes: 5 additions & 17 deletions src/librustc/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2623,23 +2623,11 @@ pub fn fmt_const_val(f: &mut impl Write, const_val: &ty::Const<'_>) -> fmt::Resu
return write!(f, "{}", item_path_str(did));
}
// print string literals
if let ConstValue::ScalarPair(ptr, len) = value {
if let Scalar::Ptr(ptr) = ptr {
if let Scalar::Bits { bits: len, .. } = len {
if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
return ty::tls::with(|tcx| {
let alloc = tcx.alloc_map.lock().get(ptr.alloc_id);
if let Some(interpret::AllocType::Memory(alloc)) = alloc {
assert_eq!(len as usize as u128, len);
let slice =
&alloc.bytes[(ptr.offset.bytes() as usize)..][..(len as usize)];
let s = ::std::str::from_utf8(slice).expect("non utf8 str from miri");
write!(f, "{:?}", s)
} else {
write!(f, "pointer to erroneous constant {:?}, {:?}", ptr, len)
}
});
}
if let ConstValue::Slice(_, alloc) = value {
if let Ref(_, &ty::TyS { sty: Str, .. }, _) = ty.sty {
return match ::std::str::from_utf8(&alloc.bytes) {
Ok(s) => write!(f, "{:?}", s),
Err(_) => write!(f, "broken str slice: {:?}", alloc),
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1053,11 +1053,11 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
}

/// Allocates a byte or string literal for `mir::interpret`, read-only
pub fn allocate_bytes(self, bytes: &[u8]) -> interpret::AllocId {
pub fn allocate_bytes(self, bytes: &[u8]) -> (interpret::AllocId, &'tcx Allocation) {
// create an allocation that just contains these bytes
let alloc = interpret::Allocation::from_byte_aligned_bytes(bytes, ());
let alloc = self.intern_const_alloc(alloc);
self.alloc_map.lock().allocate(alloc)
(self.alloc_map.lock().allocate(alloc), alloc)
}

pub fn intern_stability(self, stab: attr::Stability) -> &'gcx attr::Stability {
Expand Down
4 changes: 2 additions & 2 deletions src/librustc/ty/structural_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1032,8 +1032,8 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
fn super_fold_with<'gcx: 'tcx, F: TypeFolder<'gcx, 'tcx>>(&self, folder: &mut F) -> Self {
match *self {
ConstValue::Scalar(v) => ConstValue::Scalar(v),
ConstValue::ScalarPair(a, b) => ConstValue::ScalarPair(a, b),
ConstValue::ByRef(id, alloc, offset) => ConstValue::ByRef(id, alloc, offset),
ConstValue::Slice(id, alloc) => ConstValue::Slice(id, alloc),
ConstValue::Unevaluated(def_id, substs) => {
ConstValue::Unevaluated(def_id, substs.fold_with(folder))
}
Expand All @@ -1043,7 +1043,7 @@ impl<'tcx> TypeFoldable<'tcx> for ConstValue<'tcx> {
fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
match *self {
ConstValue::Scalar(_) |
ConstValue::ScalarPair(_, _) |
ConstValue::Slice(..) |
ConstValue::ByRef(_, _, _) => false,
ConstValue::Unevaluated(_, substs) => substs.visit_with(visitor),
}
Expand Down
64 changes: 35 additions & 29 deletions src/librustc_codegen_ssa/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,10 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use rustc::mir::interpret::{ConstValue, ErrorHandled};
use rustc::mir::interpret::{ConstValue, ErrorHandled, Scalar};
use rustc::mir;
use rustc::ty;
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout};
use rustc::ty::layout::{self, Align, LayoutOf, TyLayout, HasTyCtxt};

use base;
use MemFlags;
Expand Down Expand Up @@ -85,36 +85,42 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
return Ok(OperandRef::new_zst(bx.cx(), layout));
}

let imm = |x| {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
};
let llval = bx.cx().scalar_to_backend(
x,
scalar,
bx.cx().immediate_backend_type(layout),
);
OperandValue::Immediate(llval)
};

let val = match val.val {
ConstValue::Unevaluated(..) => bug!(),
ConstValue::Scalar(x) => {
let scalar = match layout.abi {
layout::Abi::Scalar(ref x) => x,
_ => bug!("from_const: invalid ByVal layout: {:#?}", layout)
};
let llval = bx.cx().scalar_to_backend(
x,
scalar,
bx.cx().immediate_backend_type(layout),
);
OperandValue::Immediate(llval)
},
ConstValue::ScalarPair(a, b) => {
let (a_scalar, b_scalar) = match layout.abi {
layout::Abi::ScalarPair(ref a, ref b) => (a, b),
ConstValue::Scalar(x) => imm(x),
ConstValue::Slice(id, alloc) => {
match layout.ty.builtin_deref(false).unwrap().ty.sty {
ty::TyKind::Str => {
let a_scalar = match layout.abi {
layout::Abi::ScalarPair(ref a, _) => a,
_ => bug!("from_const: invalid layout: {:#?}", layout)
};
let a_llval = bx.cx().scalar_to_backend(
Scalar::Ptr(id.into()),
a_scalar,
bx.cx().scalar_pair_element_backend_type(layout, 0, true),
);
let b_llval = bx.cx().const_usize(alloc.bytes.len() as u64);
OperandValue::Pair(a_llval, b_llval)
},
ty::TyKind::Array(u, _) if u == bx.cx().tcx().types.u8 => {
imm(Scalar::Ptr(id.into()))
}
_ => bug!("from_const: invalid ScalarPair layout: {:#?}", layout)
};
let a_llval = bx.cx().scalar_to_backend(
a,
a_scalar,
bx.cx().scalar_pair_element_backend_type(layout, 0, true),
);
let b_llval = bx.cx().scalar_to_backend(
b,
b_scalar,
bx.cx().scalar_pair_element_backend_type(layout, 1, true),
);
OperandValue::Pair(a_llval, b_llval)
}
},
ConstValue::ByRef(_, alloc, offset) => {
return Ok(bx.load_operand(bx.cx().from_const_alloc(layout, alloc, offset)));
Expand Down
22 changes: 18 additions & 4 deletions src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use rustc::hir::def::Def;
use rustc::mir::interpret::{ConstEvalErr, ErrorHandled};
use rustc::mir;
use rustc::ty::{self, TyCtxt, Instance, query::TyCtxtAt};
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx};
use rustc::ty::layout::{self, LayoutOf, TyLayout, VariantIdx, Size};
use rustc::ty::subst::Subst;
use rustc::traits::Reveal;
use rustc_data_structures::indexed_vec::IndexVec;
Expand Down Expand Up @@ -141,16 +141,30 @@ pub fn op_to_const<'tcx>(
},
Ok(Immediate::Scalar(x)) =>
ConstValue::Scalar(x.not_undef()?),
Ok(Immediate::ScalarPair(a, b)) =>
ConstValue::ScalarPair(a.not_undef()?, b.not_undef()?),
Ok(Immediate::ScalarPair(a, b)) => {
// create an allocation just for the fat pointer
let mut allocation = Allocation::undef(
op.layout.size,
op.layout.align.abi,
Default::default(),
);
let alloc_id = ecx.tcx.alloc_map.lock().reserve();
let ptr = Pointer::from(alloc_id);
// write the fat pointer into the allocation
allocation.write_scalar_pair(&ecx.tcx.tcx, ptr, a, b, op.layout)?;
// intern everything
let allocation = ecx.tcx.intern_const_alloc(allocation);
ecx.tcx.alloc_map.lock().set_id_memory(alloc_id, allocation);
ConstValue::ByRef(alloc_id, allocation, Size::ZERO)
},
};
Ok(ty::Const::from_const_value(ecx.tcx.tcx, val, op.layout.ty))
}
pub fn const_to_op<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
cnst: &ty::Const<'tcx>,
) -> EvalResult<'tcx, OpTy<'tcx>> {
let op = ecx.const_value_to_op(cnst.val)?;
let op = ecx.const_value_to_op(cnst)?;
Ok(OpTy { op, layout: ecx.layout_of(cnst.ty)? })
}

Expand Down
8 changes: 4 additions & 4 deletions src/librustc_mir/hair/cx/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,12 @@ impl<'a, 'gcx, 'tcx> Cx<'a, 'gcx, 'tcx> {
let lit = match *lit {
LitKind::Str(ref s, _) => {
let s = s.as_str();
let id = self.tcx.allocate_bytes(s.as_bytes());
ConstValue::new_slice(Scalar::Ptr(id.into()), s.len() as u64, &self.tcx)
let (id, a) = self.tcx.allocate_bytes(s.as_bytes());
ConstValue::Slice(id, a)
},
LitKind::ByteStr(ref data) => {
let id = self.tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::Ptr(id.into()))
let (id, a) = self.tcx.allocate_bytes(data);
ConstValue::Slice(id, a)
},
LitKind::Byte(n) => ConstValue::Scalar(Scalar::Bits {
bits: n as u128,
Expand Down
20 changes: 6 additions & 14 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1387,20 +1387,12 @@ fn slice_pat_covered_by_constructor<'tcx>(
) -> Result<bool, ErrorReported> {
let data: &[u8] = match *ctor {
ConstantValue(const_val) => {
let val = match const_val.val {
ConstValue::Unevaluated(..) |
ConstValue::ByRef(..) => bug!("unexpected ConstValue: {:?}", const_val),
ConstValue::Scalar(val) | ConstValue::ScalarPair(val, _) => val,
};
if let Ok(ptr) = val.to_ptr() {
let is_array_ptr = const_val.ty
.builtin_deref(true)
.and_then(|t| t.ty.builtin_index())
.map_or(false, |t| t == tcx.types.u8);
assert!(is_array_ptr);
tcx.alloc_map.lock().unwrap_memory(ptr.alloc_id).bytes.as_ref()
} else {
bug!("unexpected non-ptr ConstantValue")
match const_val.val {
ConstValue::Slice(_, alloc) => {
assert!(alloc.relocations.len() == 0);
&alloc.bytes
}
_ => bug!("unexpected ConstValue: {:#?}", const_val),
}
}
_ => bug!()
Expand Down
Loading