提交 1d498d5a 编写于 作者: R Ralf Jung

make ptr_op finally reponsible for all ops involving pointers; make ValTy constructor private

Also remove public OpTy constructors, but a pub(crate) constructor remains
上级 ec056d51
......@@ -288,21 +288,17 @@ fn call_intrinsic<'a>(
)
}
fn try_ptr_op<'a>(
fn ptr_op<'a>(
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
_bin_op: mir::BinOp,
left: Scalar,
_left: Scalar,
_left_layout: TyLayout<'tcx>,
right: Scalar,
_right: Scalar,
_right_layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
if left.is_bits() && right.is_bits() {
Ok(None)
} else {
Err(
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
)
}
) -> EvalResult<'tcx, (Scalar, bool)> {
Err(
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
)
}
fn find_foreign_static<'a>(
......
......@@ -48,13 +48,13 @@ pub fn cast(
Misc => {
let src = self.read_value(src)?;
if self.type_is_fat_ptr(src_layout.ty) {
match (src.value, self.type_is_fat_ptr(dest.layout.ty)) {
match (*src, self.type_is_fat_ptr(dest.layout.ty)) {
// pointers to extern types
(Value::Scalar(_),_) |
// slices and trait objects to other slices/trait objects
(Value::ScalarPair(..), true) => {
// No change to value
self.write_value(src.value, dest)?;
self.write_value(*src, dest)?;
}
// slices and trait objects to thin pointers (dropping the metadata)
(Value::ScalarPair(data, _), false) => {
......
......@@ -69,20 +69,18 @@ fn find_foreign_static<'a>(
def_id: DefId,
) -> EvalResult<'tcx, &'tcx Allocation>;
/// Called for all binary operations except on float types.
///
/// Returns `None` if the operation should be handled by the integer
/// op code in order to share more code between machines
/// Called for all binary operations on integer(-like) types when one operand is a pointer
/// value, and for the `Offset` operation that is inherently about pointers.
///
/// Returns a (value, overflowed) pair if the operation succeeded
fn try_ptr_op<'a>(
fn ptr_op<'a>(
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
bin_op: mir::BinOp,
left: Scalar,
left_layout: TyLayout<'tcx>,
right: Scalar,
right_layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, Option<(Scalar, bool)>>;
) -> EvalResult<'tcx, (Scalar, bool)>;
/// Heap allocations via the `box` keyword
///
......
......@@ -15,7 +15,7 @@
use std::convert::TryInto;
use rustc::{mir, ty};
use rustc::ty::layout::{self, Size, Align, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
use rustc::ty::layout::{self, Size, LayoutOf, TyLayout, HasDataLayout, IntegerExt};
use rustc_data_structures::indexed_vec::Idx;
use rustc::mir::interpret::{
......@@ -85,7 +85,7 @@ pub fn to_scalar_ptr(self) -> EvalResult<'tcx, Scalar> {
// as input for binary and cast operations.
#[derive(Copy, Clone, Debug)]
pub struct ValTy<'tcx> {
pub value: Value,
value: Value,
pub layout: TyLayout<'tcx>,
}
......@@ -107,16 +107,6 @@ pub enum Operand {
}
impl Operand {
#[inline]
pub fn from_ptr(ptr: Pointer, align: Align) -> Self {
Operand::Indirect(MemPlace::from_ptr(ptr, align))
}
#[inline]
pub fn from_scalar_value(val: Scalar) -> Self {
Operand::Immediate(Value::Scalar(val.into()))
}
#[inline]
pub fn to_mem_place(self) -> MemPlace {
match self {
......@@ -138,7 +128,7 @@ pub fn to_immediate(self) -> Value {
#[derive(Copy, Clone, Debug)]
pub struct OpTy<'tcx> {
crate op: Operand, // ideally we'd make this private, but we are not there yet
crate op: Operand, // ideally we'd make this private, but const_prop needs this
pub layout: TyLayout<'tcx>,
}
......@@ -184,23 +174,6 @@ fn eq(&self, other: &Self) -> bool {
}
impl<'tcx> Eq for OpTy<'tcx> {}
impl<'tcx> OpTy<'tcx> {
#[inline]
pub fn from_ptr(ptr: Pointer, align: Align, layout: TyLayout<'tcx>) -> Self {
OpTy { op: Operand::from_ptr(ptr, align), layout }
}
#[inline]
pub fn from_aligned_ptr(ptr: Pointer, layout: TyLayout<'tcx>) -> Self {
OpTy { op: Operand::from_ptr(ptr, layout.align), layout }
}
#[inline]
pub fn from_scalar_value(val: Scalar, layout: TyLayout<'tcx>) -> Self {
OpTy { op: Operand::Immediate(Value::Scalar(val.into())), layout }
}
}
// Use the existing layout if given (but sanity check in debug mode),
// or compute the layout.
#[inline(always)]
......@@ -507,7 +480,7 @@ pub(super) fn const_value_to_op(
ConstValue::ByRef(id, alloc, offset) => {
// We rely on mutability being set correctly in that allocation to prevent writes
// where none should happen -- and for `static mut`, we copy on demand anyway.
Ok(Operand::from_ptr(Pointer::new(id, offset), alloc.align))
Ok(Operand::Indirect(MemPlace::from_ptr(Pointer::new(id, offset), alloc.align)))
},
ConstValue::ScalarPair(a, b) =>
Ok(Operand::Immediate(Value::ScalarPair(a.into(), b))),
......
......@@ -28,7 +28,7 @@ pub fn binop_with_overflow(
right: ValTy<'tcx>,
dest: PlaceTy<'tcx>,
) -> EvalResult<'tcx> {
let (val, overflowed) = self.binary_op(op, left, right)?;
let (val, overflowed) = self.binary_op_val(op, left, right)?;
let val = Value::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
self.write_value(val, dest)
}
......@@ -42,7 +42,7 @@ pub fn binop_ignore_overflow(
right: ValTy<'tcx>,
dest: PlaceTy<'tcx>,
) -> EvalResult<'tcx> {
let (val, _overflowed) = self.binary_op(op, left, right)?;
let (val, _overflowed) = self.binary_op_val(op, left, right)?;
self.write_scalar(val, dest)
}
}
......@@ -282,16 +282,31 @@ fn binary_int_op(
Ok((val, false))
}
/// Convenience wrapper that's useful when keeping the layout together with the
/// value.
#[inline]
pub fn binary_op_val(
&self,
bin_op: mir::BinOp,
left: ValTy<'tcx>,
right: ValTy<'tcx>,
) -> EvalResult<'tcx, (Scalar, bool)> {
self.binary_op(
bin_op,
left.to_scalar()?, left.layout,
right.to_scalar()?, right.layout,
)
}
/// Returns the result of the specified operation and whether it overflowed.
pub fn binary_op(
&self,
bin_op: mir::BinOp,
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
left: Scalar,
left_layout: TyLayout<'tcx>,
right: Scalar,
right_layout: TyLayout<'tcx>,
) -> EvalResult<'tcx, (Scalar, bool)> {
let left = left.to_scalar()?;
let right = right.to_scalar()?;
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
bin_op, left, left_layout.ty, right, right_layout.ty);
......@@ -322,15 +337,13 @@ pub fn binary_op(
right_layout.ty.is_fn());
// Handle operations that support pointer values
if let Some(handled) =
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
{
return Ok(handled);
if left.is_ptr() || right.is_ptr() || bin_op == mir::BinOp::Offset {
return M::ptr_op(self, bin_op, left, left_layout, right, right_layout);
}
// Everything else only works with "proper" bits
let left = left.to_bits(left_layout.size)?;
let right = right.to_bits(right_layout.size)?;
let left = left.to_bits(left_layout.size).expect("we checked is_ptr");
let right = right.to_bits(right_layout.size).expect("we checked is_ptr");
self.binary_int_op(bin_op, left, left_layout, right, right_layout)
}
}
......
......@@ -17,7 +17,7 @@
use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
use super::{
EvalContext, Machine, Value, OpTy, Place, PlaceTy, ValTy, Operand, StackPopCleanup
EvalContext, Machine, Value, OpTy, Place, PlaceTy, Operand, StackPopCleanup
};
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
......@@ -61,8 +61,8 @@ pub(super) fn eval_terminator(
// Compare using binary_op, to also support pointer values
let const_int = Scalar::from_uint(const_int, discr.layout.size);
let (res, _) = self.binary_op(mir::BinOp::Eq,
discr,
ValTy { value: Value::Scalar(const_int.into()), layout: discr.layout }
discr.to_scalar()?, discr.layout,
const_int, discr.layout,
)?;
if res.to_bool()? {
target_block = targets[index];
......
......@@ -22,7 +22,7 @@
};
use rustc::ty::{TyCtxt, self, Instance};
use interpret::{EvalContext, CompileTimeEvaluator, eval_promoted, mk_borrowck_eval_cx};
use interpret::{Value, OpTy, MemoryKind};
use interpret::{self, Value, OpTy, MemoryKind};
use transform::{MirPass, MirSource};
use syntax::source_map::{Span, DUMMY_SP};
use rustc::ty::subst::Substs;
......@@ -358,13 +358,15 @@ fn const_prop(
Rvalue::Len(_) => None,
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some((
OpTy::from_scalar_value(
Scalar::Bits {
bits: n as u128,
size: self.tcx.data_layout.pointer_size.bytes() as u8,
},
self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
),
OpTy {
op: interpret::Operand::Immediate(Value::Scalar(
Scalar::Bits {
bits: n as u128,
size: self.tcx.data_layout.pointer_size.bytes() as u8,
}.into()
)),
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
},
span,
)))
}
......@@ -399,7 +401,11 @@ fn const_prop(
// Now run the actual operation.
this.ecx.unary_op(op, prim, arg.layout)
})?;
Some((OpTy::from_scalar_value(val, place_layout), span))
let res = OpTy {
op: interpret::Operand::Immediate(Value::Scalar(val.into())),
layout: place_layout,
};
Some((res, span))
}
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
Rvalue::BinaryOp(op, ref left, ref right) => {
......@@ -454,7 +460,7 @@ fn const_prop(
})?;
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
let (val, overflow) = self.use_ecx(source_info, |this| {
this.ecx.binary_op(op, l, r)
this.ecx.binary_op_val(op, l, r)
})?;
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
Value::ScalarPair(
......@@ -470,7 +476,7 @@ fn const_prop(
Value::Scalar(val.into())
};
let res = OpTy {
op: ::interpret::Operand::Immediate(val),
op: interpret::Operand::Immediate(val),
layout: place_layout,
};
Some((res, span))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册