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
This commit is contained in:
parent
ec056d5188
commit
1d498d5a43
7 changed files with 63 additions and 77 deletions
|
@ -288,21 +288,17 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeEvaluator {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn try_ptr_op<'a>(
|
fn ptr_op<'a>(
|
||||||
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
_ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
||||||
_bin_op: mir::BinOp,
|
_bin_op: mir::BinOp,
|
||||||
left: Scalar,
|
_left: Scalar,
|
||||||
_left_layout: TyLayout<'tcx>,
|
_left_layout: TyLayout<'tcx>,
|
||||||
right: Scalar,
|
_right: Scalar,
|
||||||
_right_layout: TyLayout<'tcx>,
|
_right_layout: TyLayout<'tcx>,
|
||||||
) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
|
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||||
if left.is_bits() && right.is_bits() {
|
Err(
|
||||||
Ok(None)
|
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
|
||||||
} else {
|
)
|
||||||
Err(
|
|
||||||
ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn find_foreign_static<'a>(
|
fn find_foreign_static<'a>(
|
||||||
|
|
|
@ -48,13 +48,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
Misc => {
|
Misc => {
|
||||||
let src = self.read_value(src)?;
|
let src = self.read_value(src)?;
|
||||||
if self.type_is_fat_ptr(src_layout.ty) {
|
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
|
// pointers to extern types
|
||||||
(Value::Scalar(_),_) |
|
(Value::Scalar(_),_) |
|
||||||
// slices and trait objects to other slices/trait objects
|
// slices and trait objects to other slices/trait objects
|
||||||
(Value::ScalarPair(..), true) => {
|
(Value::ScalarPair(..), true) => {
|
||||||
// No change to value
|
// 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)
|
// slices and trait objects to thin pointers (dropping the metadata)
|
||||||
(Value::ScalarPair(data, _), false) => {
|
(Value::ScalarPair(data, _), false) => {
|
||||||
|
|
|
@ -69,20 +69,18 @@ pub trait Machine<'mir, 'tcx>: Clone + Eq + Hash {
|
||||||
def_id: DefId,
|
def_id: DefId,
|
||||||
) -> EvalResult<'tcx, &'tcx Allocation>;
|
) -> EvalResult<'tcx, &'tcx Allocation>;
|
||||||
|
|
||||||
/// Called for all binary operations except on float types.
|
/// 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 `None` if the operation should be handled by the integer
|
|
||||||
/// op code in order to share more code between machines
|
|
||||||
///
|
///
|
||||||
/// Returns a (value, overflowed) pair if the operation succeeded
|
/// Returns a (value, overflowed) pair if the operation succeeded
|
||||||
fn try_ptr_op<'a>(
|
fn ptr_op<'a>(
|
||||||
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
|
||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
left: Scalar,
|
left: Scalar,
|
||||||
left_layout: TyLayout<'tcx>,
|
left_layout: TyLayout<'tcx>,
|
||||||
right: Scalar,
|
right: Scalar,
|
||||||
right_layout: TyLayout<'tcx>,
|
right_layout: TyLayout<'tcx>,
|
||||||
) -> EvalResult<'tcx, Option<(Scalar, bool)>>;
|
) -> EvalResult<'tcx, (Scalar, bool)>;
|
||||||
|
|
||||||
/// Heap allocations via the `box` keyword
|
/// Heap allocations via the `box` keyword
|
||||||
///
|
///
|
||||||
|
|
|
@ -15,7 +15,7 @@ use std::hash::{Hash, Hasher};
|
||||||
use std::convert::TryInto;
|
use std::convert::TryInto;
|
||||||
|
|
||||||
use rustc::{mir, ty};
|
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_data_structures::indexed_vec::Idx;
|
||||||
|
|
||||||
use rustc::mir::interpret::{
|
use rustc::mir::interpret::{
|
||||||
|
@ -85,7 +85,7 @@ impl<'tcx> Value {
|
||||||
// as input for binary and cast operations.
|
// as input for binary and cast operations.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct ValTy<'tcx> {
|
pub struct ValTy<'tcx> {
|
||||||
pub value: Value,
|
value: Value,
|
||||||
pub layout: TyLayout<'tcx>,
|
pub layout: TyLayout<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,16 +107,6 @@ pub enum Operand {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl 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]
|
#[inline]
|
||||||
pub fn to_mem_place(self) -> MemPlace {
|
pub fn to_mem_place(self) -> MemPlace {
|
||||||
match self {
|
match self {
|
||||||
|
@ -138,7 +128,7 @@ impl Operand {
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
pub struct OpTy<'tcx> {
|
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>,
|
pub layout: TyLayout<'tcx>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,23 +174,6 @@ impl<'tcx> PartialEq for OpTy<'tcx> {
|
||||||
}
|
}
|
||||||
impl<'tcx> Eq for OpTy<'tcx> {}
|
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),
|
// Use the existing layout if given (but sanity check in debug mode),
|
||||||
// or compute the layout.
|
// or compute the layout.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
@ -507,7 +480,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
ConstValue::ByRef(id, alloc, offset) => {
|
ConstValue::ByRef(id, alloc, offset) => {
|
||||||
// We rely on mutability being set correctly in that allocation to prevent writes
|
// 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.
|
// 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) =>
|
ConstValue::ScalarPair(a, b) =>
|
||||||
Ok(Operand::Immediate(Value::ScalarPair(a.into(), b))),
|
Ok(Operand::Immediate(Value::ScalarPair(a.into(), b))),
|
||||||
|
|
|
@ -28,7 +28,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
right: ValTy<'tcx>,
|
right: ValTy<'tcx>,
|
||||||
dest: PlaceTy<'tcx>,
|
dest: PlaceTy<'tcx>,
|
||||||
) -> EvalResult<'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());
|
let val = Value::ScalarPair(val.into(), Scalar::from_bool(overflowed).into());
|
||||||
self.write_value(val, dest)
|
self.write_value(val, dest)
|
||||||
}
|
}
|
||||||
|
@ -42,7 +42,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
right: ValTy<'tcx>,
|
right: ValTy<'tcx>,
|
||||||
dest: PlaceTy<'tcx>,
|
dest: PlaceTy<'tcx>,
|
||||||
) -> EvalResult<'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)
|
self.write_scalar(val, dest)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -282,16 +282,31 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
Ok((val, false))
|
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.
|
/// Returns the result of the specified operation and whether it overflowed.
|
||||||
pub fn binary_op(
|
pub fn binary_op(
|
||||||
&self,
|
&self,
|
||||||
bin_op: mir::BinOp,
|
bin_op: mir::BinOp,
|
||||||
ValTy { value: left, layout: left_layout }: ValTy<'tcx>,
|
left: Scalar,
|
||||||
ValTy { value: right, layout: right_layout }: ValTy<'tcx>,
|
left_layout: TyLayout<'tcx>,
|
||||||
|
right: Scalar,
|
||||||
|
right_layout: TyLayout<'tcx>,
|
||||||
) -> EvalResult<'tcx, (Scalar, bool)> {
|
) -> EvalResult<'tcx, (Scalar, bool)> {
|
||||||
let left = left.to_scalar()?;
|
|
||||||
let right = right.to_scalar()?;
|
|
||||||
|
|
||||||
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
trace!("Running binary op {:?}: {:?} ({:?}), {:?} ({:?})",
|
||||||
bin_op, left, left_layout.ty, right, right_layout.ty);
|
bin_op, left, left_layout.ty, right, right_layout.ty);
|
||||||
|
|
||||||
|
@ -322,15 +337,13 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
right_layout.ty.is_fn());
|
right_layout.ty.is_fn());
|
||||||
|
|
||||||
// Handle operations that support pointer values
|
// Handle operations that support pointer values
|
||||||
if let Some(handled) =
|
if left.is_ptr() || right.is_ptr() || bin_op == mir::BinOp::Offset {
|
||||||
M::try_ptr_op(self, bin_op, left, left_layout, right, right_layout)?
|
return M::ptr_op(self, bin_op, left, left_layout, right, right_layout);
|
||||||
{
|
|
||||||
return Ok(handled);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Everything else only works with "proper" bits
|
// Everything else only works with "proper" bits
|
||||||
let left = left.to_bits(left_layout.size)?;
|
let left = left.to_bits(left_layout.size).expect("we checked is_ptr");
|
||||||
let right = right.to_bits(right_layout.size)?;
|
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)
|
self.binary_int_op(bin_op, left, left_layout, right, right_layout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ use rustc_target::spec::abi::Abi;
|
||||||
|
|
||||||
use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
|
use rustc::mir::interpret::{EvalResult, PointerArithmetic, EvalErrorKind, Scalar};
|
||||||
use super::{
|
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> {
|
impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
|
@ -61,8 +61,8 @@ impl<'a, 'mir, 'tcx, M: Machine<'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M> {
|
||||||
// Compare using binary_op, to also support pointer values
|
// Compare using binary_op, to also support pointer values
|
||||||
let const_int = Scalar::from_uint(const_int, discr.layout.size);
|
let const_int = Scalar::from_uint(const_int, discr.layout.size);
|
||||||
let (res, _) = self.binary_op(mir::BinOp::Eq,
|
let (res, _) = self.binary_op(mir::BinOp::Eq,
|
||||||
discr,
|
discr.to_scalar()?, discr.layout,
|
||||||
ValTy { value: Value::Scalar(const_int.into()), layout: discr.layout }
|
const_int, discr.layout,
|
||||||
)?;
|
)?;
|
||||||
if res.to_bool()? {
|
if res.to_bool()? {
|
||||||
target_block = targets[index];
|
target_block = targets[index];
|
||||||
|
|
|
@ -22,7 +22,7 @@ use rustc::mir::interpret::{
|
||||||
};
|
};
|
||||||
use rustc::ty::{TyCtxt, self, Instance};
|
use rustc::ty::{TyCtxt, self, Instance};
|
||||||
use interpret::{EvalContext, CompileTimeEvaluator, eval_promoted, mk_borrowck_eval_cx};
|
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 transform::{MirPass, MirSource};
|
||||||
use syntax::source_map::{Span, DUMMY_SP};
|
use syntax::source_map::{Span, DUMMY_SP};
|
||||||
use rustc::ty::subst::Substs;
|
use rustc::ty::subst::Substs;
|
||||||
|
@ -358,13 +358,15 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
Rvalue::Len(_) => None,
|
Rvalue::Len(_) => None,
|
||||||
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
|
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
|
||||||
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some((
|
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some((
|
||||||
OpTy::from_scalar_value(
|
OpTy {
|
||||||
Scalar::Bits {
|
op: interpret::Operand::Immediate(Value::Scalar(
|
||||||
bits: n as u128,
|
Scalar::Bits {
|
||||||
size: self.tcx.data_layout.pointer_size.bytes() as u8,
|
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()?,
|
}.into()
|
||||||
),
|
)),
|
||||||
|
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
|
||||||
|
},
|
||||||
span,
|
span,
|
||||||
)))
|
)))
|
||||||
}
|
}
|
||||||
|
@ -399,7 +401,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
// Now run the actual operation.
|
// Now run the actual operation.
|
||||||
this.ecx.unary_op(op, prim, arg.layout)
|
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::CheckedBinaryOp(op, ref left, ref right) |
|
||||||
Rvalue::BinaryOp(op, ref left, ref right) => {
|
Rvalue::BinaryOp(op, ref left, ref right) => {
|
||||||
|
@ -454,7 +460,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
})?;
|
})?;
|
||||||
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
||||||
let (val, overflow) = self.use_ecx(source_info, |this| {
|
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 {
|
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
||||||
Value::ScalarPair(
|
Value::ScalarPair(
|
||||||
|
@ -470,7 +476,7 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
||||||
Value::Scalar(val.into())
|
Value::Scalar(val.into())
|
||||||
};
|
};
|
||||||
let res = OpTy {
|
let res = OpTy {
|
||||||
op: ::interpret::Operand::Immediate(val),
|
op: interpret::Operand::Immediate(val),
|
||||||
layout: place_layout,
|
layout: place_layout,
|
||||||
};
|
};
|
||||||
Some((res, span))
|
Some((res, span))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue