Introduce ConstValue and use it instead of miri's Value for constant values
This commit is contained in:
parent
41707d8df9
commit
fdd9787777
55 changed files with 999 additions and 751 deletions
|
|
@ -19,15 +19,17 @@ use rustc::mir::{TerminatorKind, ClearCrossCrate, SourceInfo, BinOp, ProjectionE
|
|||
use rustc::mir::visit::{Visitor, PlaceContext};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::{TyCtxt, self, Instance};
|
||||
use rustc::mir::interpret::{Value, PrimVal, GlobalId};
|
||||
use rustc::mir::interpret::{Value, PrimVal, GlobalId, EvalResult};
|
||||
use interpret::EvalContext;
|
||||
use interpret::CompileTimeEvaluator;
|
||||
use interpret::{eval_promoted, mk_borrowck_eval_cx, ValTy};
|
||||
use transform::{MirPass, MirSource};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::codemap::{Span, DUMMY_SP};
|
||||
use rustc::ty::subst::Substs;
|
||||
use rustc_data_structures::indexed_vec::IndexVec;
|
||||
use rustc::ty::ParamEnv;
|
||||
use rustc::ty::layout::{
|
||||
LayoutOf, TyLayout, LayoutError,
|
||||
LayoutOf, TyLayout, LayoutError, LayoutCx,
|
||||
HasTyCtxt, TargetDataLayout, HasDataLayout,
|
||||
};
|
||||
|
||||
|
|
@ -64,6 +66,7 @@ type Const<'tcx> = (Value, ty::Ty<'tcx>, Span);
|
|||
|
||||
/// Finds optimization opportunities on the MIR.
|
||||
struct ConstPropagator<'b, 'a, 'tcx:'a+'b> {
|
||||
ecx: EvalContext<'a, 'b, 'tcx, CompileTimeEvaluator>,
|
||||
mir: &'b Mir<'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
source: MirSource,
|
||||
|
|
@ -102,7 +105,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
source: MirSource,
|
||||
) -> ConstPropagator<'b, 'a, 'tcx> {
|
||||
let param_env = tcx.param_env(source.def_id);
|
||||
let substs = Substs::identity_for_item(tcx, source.def_id);
|
||||
let instance = Instance::new(source.def_id, substs);
|
||||
let ecx = mk_borrowck_eval_cx(tcx, instance, mir, DUMMY_SP).unwrap();
|
||||
ConstPropagator {
|
||||
ecx,
|
||||
mir,
|
||||
tcx,
|
||||
source,
|
||||
|
|
@ -112,7 +119,27 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
fn const_eval(&self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
|
||||
fn use_ecx<F, T>(
|
||||
&mut self,
|
||||
span: Span,
|
||||
f: F
|
||||
) -> Option<T>
|
||||
where
|
||||
F: FnOnce(&mut Self) -> EvalResult<'tcx, T>,
|
||||
{
|
||||
self.ecx.tcx.span = span;
|
||||
let r = match f(self) {
|
||||
Ok(val) => Some(val),
|
||||
Err(mut err) => {
|
||||
self.ecx.report(&mut err, false, Some(span));
|
||||
None
|
||||
},
|
||||
};
|
||||
self.ecx.tcx.span = DUMMY_SP;
|
||||
r
|
||||
}
|
||||
|
||||
fn const_eval(&mut self, cid: GlobalId<'tcx>, span: Span) -> Option<Const<'tcx>> {
|
||||
let value = match self.tcx.const_eval(self.param_env.and(cid)) {
|
||||
Ok(val) => val,
|
||||
Err(err) => {
|
||||
|
|
@ -121,7 +148,9 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
},
|
||||
};
|
||||
let val = match value.val {
|
||||
ConstVal::Value(v) => v,
|
||||
ConstVal::Value(v) => {
|
||||
self.use_ecx(span, |this| this.ecx.const_value_to_value(v, value.ty))?
|
||||
},
|
||||
_ => bug!("eval produced: {:?}", value),
|
||||
};
|
||||
let val = (val, value.ty, span);
|
||||
|
|
@ -132,7 +161,12 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<Const<'tcx>> {
|
||||
match c.literal {
|
||||
Literal::Value { value } => match value.val {
|
||||
ConstVal::Value(v) => Some((v, value.ty, c.span)),
|
||||
ConstVal::Value(v) => {
|
||||
let v = self.use_ecx(c.span, |this| {
|
||||
this.ecx.const_value_to_value(v, value.ty)
|
||||
})?;
|
||||
Some((v, value.ty, c.span))
|
||||
},
|
||||
ConstVal::Unevaluated(did, substs) => {
|
||||
let instance = Instance::resolve(
|
||||
self.tcx,
|
||||
|
|
@ -162,7 +196,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
};
|
||||
// cannot use `const_eval` here, because that would require having the MIR
|
||||
// for the current function available, but we're producing said MIR right now
|
||||
let (value, _, ty) = eval_promoted(self.tcx, cid, self.mir, self.param_env)?;
|
||||
let span = self.mir.span;
|
||||
let (value, _, ty) = self.use_ecx(span, |this| {
|
||||
Ok(eval_promoted(&mut this.ecx, cid, this.mir, this.param_env))
|
||||
})??;
|
||||
let val = (value, ty, c.span);
|
||||
trace!("evaluated {:?} to {:?}", c, val);
|
||||
Some(val)
|
||||
|
|
@ -185,7 +222,11 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
use rustc_data_structures::indexed_vec::Idx;
|
||||
let field_index = field.index();
|
||||
let val = [a, b][field_index];
|
||||
let field = base_layout.field(&*self, field_index).ok()?;
|
||||
let cx = LayoutCx {
|
||||
tcx: self.tcx,
|
||||
param_env: self.param_env,
|
||||
};
|
||||
let field = base_layout.field(cx, field_index).ok()?;
|
||||
trace!("projection resulted in: {:?}", val);
|
||||
Some((Value::ByVal(val), field.ty, span))
|
||||
},
|
||||
|
|
@ -258,19 +299,13 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
}
|
||||
let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
|
||||
let instance = Instance::new(self.source.def_id, substs);
|
||||
let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
|
||||
|
||||
let val = self.eval_operand(arg)?;
|
||||
let prim = ecx.value_to_primval(ValTy { value: val.0, ty: val.1 }).ok()?;
|
||||
match ecx.unary_op(op, prim, val.1) {
|
||||
Ok(val) => Some((Value::ByVal(val), place_ty, span)),
|
||||
Err(mut err) => {
|
||||
ecx.report(&mut err, false, Some(span));
|
||||
None
|
||||
},
|
||||
}
|
||||
let prim = self.use_ecx(span, |this| {
|
||||
this.ecx.value_to_primval(ValTy { value: val.0, ty: val.1 })
|
||||
})?;
|
||||
let val = self.use_ecx(span, |this| this.ecx.unary_op(op, prim, val.1))?;
|
||||
Some((Value::ByVal(val), place_ty, span))
|
||||
}
|
||||
Rvalue::CheckedBinaryOp(op, ref left, ref right) |
|
||||
Rvalue::BinaryOp(op, ref left, ref right) => {
|
||||
|
|
@ -287,11 +322,10 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
// FIXME: can't handle code with generics
|
||||
return None;
|
||||
}
|
||||
let substs = Substs::identity_for_item(self.tcx, self.source.def_id);
|
||||
let instance = Instance::new(self.source.def_id, substs);
|
||||
let ecx = mk_borrowck_eval_cx(self.tcx, instance, self.mir, span).unwrap();
|
||||
|
||||
let r = ecx.value_to_primval(ValTy { value: right.0, ty: right.1 }).ok()?;
|
||||
let r = self.use_ecx(span, |this| {
|
||||
this.ecx.value_to_primval(ValTy { value: right.0, ty: right.1 })
|
||||
})?;
|
||||
if op == BinOp::Shr || op == BinOp::Shl {
|
||||
let param_env = self.tcx.param_env(self.source.def_id);
|
||||
let left_ty = left.ty(self.mir, self.tcx);
|
||||
|
|
@ -316,31 +350,31 @@ impl<'b, 'a, 'tcx:'b> ConstPropagator<'b, 'a, 'tcx> {
|
|||
}
|
||||
}
|
||||
let left = self.eval_operand(left)?;
|
||||
let l = ecx.value_to_primval(ValTy { value: left.0, ty: left.1 }).ok()?;
|
||||
let l = self.use_ecx(span, |this| {
|
||||
this.ecx.value_to_primval(ValTy { value: left.0, ty: left.1 })
|
||||
})?;
|
||||
trace!("const evaluating {:?} for {:?} and {:?}", op, left, right);
|
||||
match ecx.binary_op(op, l, left.1, r, right.1) {
|
||||
Ok((val, overflow)) => {
|
||||
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
||||
Value::ByValPair(
|
||||
val,
|
||||
PrimVal::from_bool(overflow),
|
||||
)
|
||||
} else {
|
||||
if overflow {
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
let mut err = EvalErrorKind::Overflow(op).into();
|
||||
ecx.report(&mut err, false, Some(span));
|
||||
return None;
|
||||
}
|
||||
Value::ByVal(val)
|
||||
};
|
||||
Some((val, place_ty, span))
|
||||
},
|
||||
Err(mut err) => {
|
||||
ecx.report(&mut err, false, Some(span));
|
||||
None
|
||||
},
|
||||
}
|
||||
let (val, overflow) = self.use_ecx(span, |this| {
|
||||
this.ecx.binary_op(op, l, left.1, r, right.1)
|
||||
})?;
|
||||
let val = if let Rvalue::CheckedBinaryOp(..) = *rvalue {
|
||||
Value::ByValPair(
|
||||
val,
|
||||
PrimVal::from_bool(overflow),
|
||||
)
|
||||
} else {
|
||||
if overflow {
|
||||
use rustc::mir::interpret::EvalErrorKind;
|
||||
let mut err = EvalErrorKind::Overflow(op).into();
|
||||
self.use_ecx(span, |this| {
|
||||
this.ecx.report(&mut err, false, Some(span));
|
||||
Ok(())
|
||||
});
|
||||
return None;
|
||||
}
|
||||
Value::ByVal(val)
|
||||
};
|
||||
Some((val, place_ty, span))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,8 +17,6 @@ use dataflow::MoveDataParamEnv;
|
|||
use dataflow::{self, do_dataflow, DebugFormatted};
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::mir::*;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
use rustc::util::nodemap::FxHashMap;
|
||||
use rustc_data_structures::indexed_set::IdxSetBuf;
|
||||
use rustc_data_structures::indexed_vec::Idx;
|
||||
|
|
@ -533,10 +531,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
|
|||
span,
|
||||
ty: self.tcx.types.bool,
|
||||
literal: Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(val as u128))),
|
||||
ty: self.tcx.types.bool
|
||||
})
|
||||
value: ty::Const::from_bool(self.tcx, val)
|
||||
}
|
||||
})))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,7 +61,6 @@
|
|||
|
||||
use rustc::hir;
|
||||
use rustc::hir::def_id::DefId;
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::visit::{PlaceContext, Visitor, MutVisitor};
|
||||
use rustc::ty::{self, TyCtxt, AdtDef, Ty};
|
||||
|
|
@ -79,7 +78,6 @@ use transform::simplify;
|
|||
use transform::no_landing_pads::no_landing_pads;
|
||||
use dataflow::{do_dataflow, DebugFormatted, state_for_location};
|
||||
use dataflow::{MaybeStorageLive, HaveBeenBorrowedLocals};
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
|
||||
pub struct StateTransform;
|
||||
|
||||
|
|
@ -180,10 +178,10 @@ impl<'a, 'tcx> TransformVisitor<'a, 'tcx> {
|
|||
span: source_info.span,
|
||||
ty: self.tcx.types.u32,
|
||||
literal: Literal::Value {
|
||||
value: self.tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(state_disc.into()))),
|
||||
ty: self.tcx.types.u32
|
||||
}),
|
||||
value: ty::Const::from_bits(
|
||||
self.tcx,
|
||||
state_disc.into(),
|
||||
self.tcx.types.u32),
|
||||
},
|
||||
});
|
||||
Statement {
|
||||
|
|
@ -698,10 +696,7 @@ fn insert_panic_block<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||
span: mir.span,
|
||||
ty: tcx.types.bool,
|
||||
literal: Literal::Value {
|
||||
value: tcx.mk_const(ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(0))),
|
||||
ty: tcx.types.bool
|
||||
}),
|
||||
value: ty::Const::from_bool(tcx, false),
|
||||
},
|
||||
}),
|
||||
expected: true,
|
||||
|
|
|
|||
|
|
@ -595,7 +595,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
}
|
||||
Operand::Constant(ref constant) => {
|
||||
if let Literal::Value {
|
||||
value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty }
|
||||
value: &ty::Const { val: ConstVal::Unevaluated(def_id, _), ty, .. }
|
||||
} = constant.literal {
|
||||
// Don't peek inside trait associated constants.
|
||||
if self.tcx.trait_of_item(def_id).is_some() {
|
||||
|
|
@ -690,7 +690,7 @@ impl<'a, 'tcx> Visitor<'tcx> for Qualifier<'a, 'tcx, 'tcx> {
|
|||
_ => false
|
||||
}
|
||||
} else if let ty::TyArray(_, len) = ty.sty {
|
||||
len.val.unwrap_u64() == 0 &&
|
||||
len.unwrap_usize(self.tcx) == 0 &&
|
||||
self.mode == Mode::Fn
|
||||
} else {
|
||||
false
|
||||
|
|
|
|||
|
|
@ -10,10 +10,8 @@
|
|||
|
||||
//! A pass that simplifies branches when their condition is known.
|
||||
|
||||
use rustc::ty::{self, TyCtxt};
|
||||
use rustc::middle::const_val::ConstVal;
|
||||
use rustc::ty::TyCtxt;
|
||||
use rustc::mir::*;
|
||||
use rustc::mir::interpret::{Value, PrimVal};
|
||||
use transform::{MirPass, MirSource};
|
||||
|
||||
use std::borrow::Cow;
|
||||
|
|
@ -32,7 +30,7 @@ impl MirPass for SimplifyBranches {
|
|||
}
|
||||
|
||||
fn run_pass<'a, 'tcx>(&self,
|
||||
_tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||
_src: MirSource,
|
||||
mir: &mut Mir<'tcx>) {
|
||||
for block in mir.basic_blocks_mut() {
|
||||
|
|
@ -40,8 +38,8 @@ impl MirPass for SimplifyBranches {
|
|||
terminator.kind = match terminator.kind {
|
||||
TerminatorKind::SwitchInt { discr: Operand::Constant(box Constant {
|
||||
literal: Literal::Value { ref value }, ..
|
||||
}), ref values, ref targets, .. } => {
|
||||
if let Some(constint) = value.val.to_raw_bits() {
|
||||
}), switch_ty, ref values, ref targets, .. } => {
|
||||
if let Some(constint) = value.assert_bits(switch_ty) {
|
||||
let (otherwise, targets) = targets.split_last().unwrap();
|
||||
let mut ret = TerminatorKind::Goto { target: *otherwise };
|
||||
for (&v, t) in values.iter().zip(targets.iter()) {
|
||||
|
|
@ -57,12 +55,9 @@ impl MirPass for SimplifyBranches {
|
|||
},
|
||||
TerminatorKind::Assert { target, cond: Operand::Constant(box Constant {
|
||||
literal: Literal::Value {
|
||||
value: &ty::Const {
|
||||
val: ConstVal::Value(Value::ByVal(PrimVal::Bytes(cond))),
|
||||
.. }
|
||||
value
|
||||
}, ..
|
||||
}), expected, .. } if (cond == 1) == expected => {
|
||||
assert!(cond <= 1);
|
||||
}), expected, .. } if (value.assert_bool(tcx) == Some(true)) == expected => {
|
||||
TerminatorKind::Goto { target: target }
|
||||
},
|
||||
TerminatorKind::FalseEdges { real_target, .. } => {
|
||||
|
|
|
|||
|
|
@ -81,9 +81,9 @@ impl<'a, 'tcx> Visitor<'tcx> for UniformArrayMoveOutVisitor<'a, 'tcx> {
|
|||
} else {
|
||||
let place_ty = proj.base.ty(self.mir, self.tcx).to_ty(self.tcx);
|
||||
if let ty::TyArray(item_ty, const_size) = place_ty.sty {
|
||||
if let Some(size) = const_size.val.to_raw_bits() {
|
||||
assert!(size <= (u32::max_value() as u128),
|
||||
"unform array move out doesn't supported
|
||||
if let Some(size) = const_size.assert_usize(self.tcx) {
|
||||
assert!(size <= u32::max_value() as u64,
|
||||
"uniform array move out doesn't supported
|
||||
for array bigger then u32");
|
||||
self.uniform(location, dst_place, proj, item_ty, size as u32);
|
||||
}
|
||||
|
|
@ -203,7 +203,7 @@ impl MirPass for RestoreSubsliceArrayMoveOut {
|
|||
let opt_size = opt_src_place.and_then(|src_place| {
|
||||
let src_ty = src_place.ty(mir, tcx).to_ty(tcx);
|
||||
if let ty::TyArray(_, ref size_o) = src_ty.sty {
|
||||
size_o.val.to_raw_bits().map(|n| n as u64)
|
||||
size_o.assert_usize(tcx)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue