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

Const to op simplification #58511

Merged
merged 11 commits into from
Feb 24, 2019
2 changes: 1 addition & 1 deletion src/librustc/ich/impls_ty.rs
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ impl_stable_hash_for!(
impl<'tcx> for enum mir::interpret::ConstValue<'tcx> [ mir::interpret::ConstValue ] {
Scalar(val),
Slice(a, b),
ByRef(id, alloc, offset),
ByRef(ptr, alloc),
}
);
impl_stable_hash_for!(struct crate::mir::interpret::RawConst<'tcx> {
Expand Down
6 changes: 3 additions & 3 deletions src/librustc/mir/interpret/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,9 +31,9 @@ pub enum ConstValue<'tcx> {
/// it.
Slice(Scalar, u64),

/// An allocation together with an offset into the allocation.
/// Invariant: the `AllocId` matches the allocation.
ByRef(AllocId, &'tcx Allocation, Size),
/// An allocation together with a pointer into the allocation.
/// Invariant: the pointer's `AllocId` resolves to the allocation.
ByRef(Pointer, &'tcx Allocation),
oli-obk marked this conversation as resolved.
Show resolved Hide resolved
}

#[cfg(target_arch = "x86_64")]
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 @@ -499,8 +499,8 @@ impl<'a, 'tcx> Lift<'tcx> for ConstValue<'a> {
match *self {
ConstValue::Scalar(x) => Some(ConstValue::Scalar(x)),
ConstValue::Slice(x, y) => Some(ConstValue::Slice(x, y)),
ConstValue::ByRef(x, alloc, z) => Some(ConstValue::ByRef(
x, alloc.lift_to_tcx(tcx)?, z,
ConstValue::ByRef(ptr, alloc) => Some(ConstValue::ByRef(
ptr, alloc.lift_to_tcx(tcx)?,
)),
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_codegen_llvm/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ pub fn codegen_static_initializer(
let static_ = cx.tcx.const_eval(param_env.and(cid))?;

let alloc = match static_.val {
ConstValue::ByRef(_, alloc, n) if n.bytes() == 0 => alloc,
ConstValue::ByRef(ptr, alloc) if ptr.offset.bytes() == 0 => alloc,
_ => bug!("static const eval returned {:#?}", static_),
};
Ok((const_alloc_to_llvm(cx, alloc), alloc))
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_codegen_ssa/mir/operand.rs
Original file line number Diff line number Diff line change
Expand Up @@ -101,8 +101,8 @@ impl<'a, 'tcx: 'a, V: CodegenObject> OperandRef<'tcx, V> {
let b_llval = bx.cx().const_usize(b);
OperandValue::Pair(a_llval, b_llval)
},
ConstValue::ByRef(_, alloc, offset) => {
return Ok(bx.load_operand(bx.cx().from_const_alloc(layout, alloc, offset)));
ConstValue::ByRef(ptr, alloc) => {
return Ok(bx.load_operand(bx.cx().from_const_alloc(layout, alloc, ptr.offset)));
},
};

Expand Down
4 changes: 2 additions & 2 deletions src/librustc_codegen_ssa/mir/place.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,8 +417,8 @@ impl<'a, 'tcx: 'a, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let layout = cx.layout_of(self.monomorphize(&ty));
match bx.tcx().const_eval(param_env.and(cid)) {
Ok(val) => match val.val {
mir::interpret::ConstValue::ByRef(_, alloc, offset) => {
bx.cx().from_const_alloc(layout, alloc, offset)
mir::interpret::ConstValue::ByRef(ptr, alloc) => {
bx.cx().from_const_alloc(layout, alloc, ptr.offset)
}
_ => bug!("promoteds should have an allocation: {:?}", val),
},
Expand Down
86 changes: 44 additions & 42 deletions src/librustc_mir/const_eval.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use syntax::ast::Mutability;
use syntax::source_map::{Span, DUMMY_SP};

use crate::interpret::{self,
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Operand, Immediate, Scalar, Pointer,
PlaceTy, MPlaceTy, MemPlace, OpTy, ImmTy, Immediate, Scalar, Pointer,
RawConst, ConstValue,
EvalResult, EvalError, EvalErrorKind, GlobalId, EvalContext, StackPopCleanup,
Allocation, AllocId, MemoryKind,
Expand Down Expand Up @@ -62,45 +62,46 @@ pub(crate) fn eval_promoted<'a, 'mir, 'tcx>(
eval_body_using_ecx(&mut ecx, cid, Some(mir), param_env)
}

// FIXME: These two conversion functions are bad hacks. We should just always use allocations.
pub fn op_to_const<'tcx>(
fn mplace_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
mplace: MPlaceTy<'tcx>,
) -> EvalResult<'tcx, ty::Const<'tcx>> {
let MemPlace { ptr, align, meta } = *mplace;
// extract alloc-offset pair
assert!(meta.is_none());
let ptr = ptr.to_ptr()?;
let alloc = ecx.memory.get(ptr.alloc_id)?;
assert!(alloc.align >= align);
assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= mplace.layout.size.bytes());
let mut alloc = alloc.clone();
alloc.align = align;
// FIXME shouldn't it be the case that `mark_static_initialized` has already
// interned this? I thought that is the entire point of that `FinishStatic` stuff?
let alloc = ecx.tcx.intern_const_alloc(alloc);
let val = ConstValue::ByRef(ptr, alloc);
Ok(ty::Const { val, ty: mplace.layout.ty })
}

fn op_to_const<'tcx>(
ecx: &CompileTimeEvalContext<'_, '_, 'tcx>,
op: OpTy<'tcx>,
may_normalize: bool,
) -> EvalResult<'tcx, ty::Const<'tcx>> {
// We do not normalize just any data. Only scalar layout and slices.
let normalize = may_normalize
&& match op.layout.abi {
layout::Abi::Scalar(..) => true,
layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(),
_ => false,
};
let normalize = match op.layout.abi {
layout::Abi::Scalar(..) => true,
layout::Abi::ScalarPair(..) => op.layout.ty.is_slice(),
_ => false,
};
let normalized_op = if normalize {
ecx.try_read_immediate(op)?
Err(*ecx.read_immediate(op).expect("normalization works on validated constants"))
} else {
match *op {
Operand::Indirect(mplace) => Err(mplace),
Operand::Immediate(val) => Ok(val)
}
op.try_as_mplace()
};
let val = match normalized_op {
Err(MemPlace { ptr, align, meta }) => {
// extract alloc-offset pair
assert!(meta.is_none());
let ptr = ptr.to_ptr()?;
let alloc = ecx.memory.get(ptr.alloc_id)?;
assert!(alloc.align >= align);
assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= op.layout.size.bytes());
let mut alloc = alloc.clone();
alloc.align = align;
// FIXME shouldn't it be the case that `mark_static_initialized` has already
// interned this? I thought that is the entire point of that `FinishStatic` stuff?
let alloc = ecx.tcx.intern_const_alloc(alloc);
ConstValue::ByRef(ptr.alloc_id, alloc, ptr.offset)
},
Ok(Immediate::Scalar(x)) =>
Ok(mplace) => return mplace_to_const(ecx, mplace),
Err(Immediate::Scalar(x)) =>
ConstValue::Scalar(x.not_undef()?),
Ok(Immediate::ScalarPair(a, b)) =>
Err(Immediate::ScalarPair(a, b)) =>
ConstValue::Slice(a.not_undef()?, b.to_usize(ecx)?),
};
Ok(ty::Const { val, ty: op.layout.ty })
Expand Down Expand Up @@ -476,7 +477,7 @@ pub fn const_field<'a, 'tcx>(
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let result = (|| {
// get the operand again
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(value), value.ty)?;
let op = ecx.const_to_op(value, None)?;
// downcast
let down = match variant {
None => op,
Expand All @@ -486,7 +487,7 @@ pub fn const_field<'a, 'tcx>(
let field = ecx.operand_field(down, field.index() as u64)?;
// and finally move back to the const world, always normalizing because
// this is not called for statics.
op_to_const(&ecx, field, true)
op_to_const(&ecx, field)
})();
result.map_err(|error| {
let err = error_to_const_error(&ecx, error);
Expand All @@ -502,7 +503,7 @@ pub fn const_variant_index<'a, 'tcx>(
) -> EvalResult<'tcx, VariantIdx> {
trace!("const_variant_index: {:?}", val);
let ecx = mk_eval_cx(tcx, DUMMY_SP, param_env);
let op = ecx.lazy_const_to_op(ty::LazyConst::Evaluated(val), val.ty)?;
let op = ecx.const_to_op(val, None)?;
Ok(ecx.read_discriminant(op)?.1)
}

Expand All @@ -523,22 +524,23 @@ fn validate_and_turn_into_const<'a, 'tcx>(
let cid = key.value;
let ecx = mk_eval_cx(tcx, tcx.def_span(key.value.instance.def_id()), key.param_env);
let val = (|| {
let op = ecx.raw_const_to_mplace(constant)?.into();
// FIXME: Once the visitor infrastructure landed, change validation to
// work directly on `MPlaceTy`.
let mut ref_tracking = RefTracking::new(op);
while let Some((op, path)) = ref_tracking.todo.pop() {
let mplace = ecx.raw_const_to_mplace(constant)?;
let mut ref_tracking = RefTracking::new(mplace);
while let Some((mplace, path)) = ref_tracking.todo.pop() {
ecx.validate_operand(
op,
mplace.into(),
path,
Some(&mut ref_tracking),
true, // const mode
)?;
}
// Now that we validated, turn this into a proper constant.
let def_id = cid.instance.def.def_id();
let normalize = tcx.is_static(def_id).is_none() && cid.promoted.is_none();
op_to_const(&ecx, op, normalize)
if tcx.is_static(def_id).is_some() || cid.promoted.is_some() {
mplace_to_const(&ecx, mplace)
} else {
op_to_const(&ecx, mplace.into())
}
})();

val.map_err(|error| {
Expand Down
12 changes: 5 additions & 7 deletions src/librustc_mir/hair/pattern/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ use rustc::ty::{self, Ty, TyCtxt, TypeFoldable, Const};
use rustc::ty::layout::{Integer, IntegerExt, VariantIdx, Size};

use rustc::mir::Field;
use rustc::mir::interpret::{ConstValue, Pointer, Scalar};
use rustc::mir::interpret::{ConstValue, Scalar};
use rustc::util::common::ErrorReported;

use syntax::attr::{SignedInt, UnsignedInt};
Expand Down Expand Up @@ -214,9 +214,8 @@ impl<'a, 'tcx> LiteralExpander<'a, 'tcx> {
match (val, &crty.sty, &rty.sty) {
// the easy case, deref a reference
(ConstValue::Scalar(Scalar::Ptr(p)), x, y) if x == y => ConstValue::ByRef(
p.alloc_id,
p,
self.tcx.alloc_map.lock().unwrap_memory(p.alloc_id),
p.offset,
),
// unsize array to slice if pattern is array but match value or other patterns are slice
(ConstValue::Scalar(Scalar::Ptr(p)), ty::Array(t, n), ty::Slice(u)) => {
Expand Down Expand Up @@ -1428,15 +1427,14 @@ fn slice_pat_covered_by_const<'tcx>(
suffix: &[Pattern<'tcx>]
) -> Result<bool, ErrorReported> {
let data: &[u8] = match (const_val.val, &const_val.ty.sty) {
(ConstValue::ByRef(id, alloc, offset), ty::Array(t, n)) => {
(ConstValue::ByRef(ptr, alloc), ty::Array(t, n)) => {
if *t != tcx.types.u8 {
// FIXME(oli-obk): can't mix const patterns with slice patterns and get
// any sort of exhaustiveness/unreachable check yet
// This solely means that we don't lint about unreachable patterns, even if some
// are definitely unreachable.
return Ok(false);
}
let ptr = Pointer::new(id, offset);
let n = n.assert_usize(tcx).unwrap();
alloc.get_bytes(&tcx, ptr, Size::from_bytes(n)).unwrap()
},
Expand Down Expand Up @@ -1778,8 +1776,8 @@ fn specialize<'p, 'a: 'p, 'tcx: 'a>(
let (opt_ptr, n, ty) = match value.ty.sty {
ty::TyKind::Array(t, n) => {
match value.val {
ConstValue::ByRef(id, alloc, offset) => (
Some((Pointer::new(id, offset), alloc)),
ConstValue::ByRef(ptr, alloc) => (
Some((ptr, alloc)),
n.unwrap_usize(cx.tcx),
t,
),
Expand Down
Loading