1
Fork 0

Handle discriminant_value intrinsic.

This commit is contained in:
Scott Olson 2016-05-09 23:41:57 -06:00
parent 2d32503409
commit f63206ed2f
3 changed files with 63 additions and 56 deletions

View file

@ -297,35 +297,14 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
Switch { ref discr, ref targets, adt_def } => { Switch { ref discr, ref targets, adt_def } => {
let adt_ptr = self.eval_lvalue(discr)?.to_ptr(); let adt_ptr = self.eval_lvalue(discr)?.to_ptr();
let adt_layout = self.type_layout(self.lvalue_ty(discr)); let adt_ty = self.lvalue_ty(discr);
let discr_val = self.read_discriminant_value(adt_ptr, adt_ty)?;
let matching = adt_def.variants.iter()
.position(|v| discr_val == v.disr_val.to_u64_unchecked());
match *adt_layout { match matching {
Layout::General { discr, .. } | Layout::CEnum { discr, .. } => { Some(i) => TerminatorTarget::Block(targets[i]),
let discr_size = discr.size().bytes(); None => return Err(EvalError::InvalidDiscriminant),
let discr_val = self.memory.read_uint(adt_ptr, discr_size as usize)?;
let matching = adt_def.variants.iter()
.position(|v| discr_val == v.disr_val.to_u64_unchecked());
match matching {
Some(i) => TerminatorTarget::Block(targets[i]),
None => return Err(EvalError::InvalidDiscriminant),
}
}
Layout::RawNullablePointer { nndiscr, .. } => {
let is_null = match self.memory.read_usize(adt_ptr) {
Ok(0) => true,
Ok(_) | Err(EvalError::ReadPointerAsBytes) => false,
Err(e) => return Err(e),
};
assert!(nndiscr == 0 || nndiscr == 1);
let target = if is_null { 1 - nndiscr } else { nndiscr };
TerminatorTarget::Block(targets[target as usize])
}
_ => panic!("attempted to switch on non-aggregate type"),
} }
} }
@ -477,6 +456,36 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
Ok(()) Ok(())
} }
fn read_discriminant_value(&self, adt_ptr: Pointer, adt_ty: ty::Ty<'tcx>) -> EvalResult<u64> {
use rustc::ty::layout::Layout::*;
let adt_layout = self.type_layout(adt_ty);
let discr_val = match *adt_layout {
General { discr, .. } | CEnum { discr, .. } => {
let discr_size = discr.size().bytes();
self.memory.read_uint(adt_ptr, discr_size as usize)?
}
RawNullablePointer { nndiscr, .. } => {
let not_null = match self.memory.read_usize(adt_ptr) {
Ok(0) => false,
Ok(_) | Err(EvalError::ReadPointerAsBytes) => true,
Err(e) => return Err(e),
};
assert!(nndiscr == 0 || nndiscr == 1);
if not_null { nndiscr } else { 1 - nndiscr }
}
StructWrappedNullablePointer { .. } => unimplemented!(),
// The discriminant_value intrinsic returns 0 for non-sum types.
Array { .. } | FatPointer { .. } | Scalar { .. } | Univariant { .. } |
Vector { .. } => 0,
};
Ok(discr_val)
}
fn call_intrinsic( fn call_intrinsic(
&mut self, &mut self,
name: &str, name: &str,
@ -491,6 +500,19 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
let args = args_res?; let args = args_res?;
match name { match name {
// FIXME(solson): Handle different integer types correctly.
"add_with_overflow" => {
let ty = *substs.types.get(subst::FnSpace, 0);
let size = self.type_size(ty);
let left = self.memory.read_int(args[0], size)?;
let right = self.memory.read_int(args[1], size)?;
let (n, overflowed) = unsafe {
::std::intrinsics::add_with_overflow::<i64>(left, right)
};
self.memory.write_int(dest, n, size)?;
self.memory.write_bool(dest.offset(size as isize), overflowed)?;
}
"assume" => {} "assume" => {}
"copy_nonoverlapping" => { "copy_nonoverlapping" => {
@ -502,6 +524,13 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
self.memory.copy(src, dest, count as usize * elem_size)?; self.memory.copy(src, dest, count as usize * elem_size)?;
} }
"discriminant_value" => {
let ty = *substs.types.get(subst::FnSpace, 0);
let adt_ptr = self.memory.read_ptr(args[0])?;
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
self.memory.write_uint(dest, discr_val, dest_size)?;
}
"forget" => { "forget" => {
let arg_ty = *substs.types.get(subst::FnSpace, 0); let arg_ty = *substs.types.get(subst::FnSpace, 0);
let arg_size = self.type_size(arg_ty); let arg_size = self.type_size(arg_ty);
@ -520,19 +549,6 @@ impl<'a, 'b, 'mir, 'tcx> FnEvalContext<'a, 'b, 'mir, 'tcx> {
self.move_(args[1], ptr, ty)?; self.move_(args[1], ptr, ty)?;
} }
// FIXME(solson): Handle different integer types correctly.
"add_with_overflow" => {
let ty = *substs.types.get(subst::FnSpace, 0);
let size = self.type_size(ty);
let left = self.memory.read_int(args[0], size)?;
let right = self.memory.read_int(args[1], size)?;
let (n, overflowed) = unsafe {
::std::intrinsics::add_with_overflow::<i64>(left, right)
};
self.memory.write_int(dest, n, size)?;
self.memory.write_bool(dest.offset(size as isize), overflowed)?;
}
// FIXME(solson): Handle different integer types correctly. // FIXME(solson): Handle different integer types correctly.
"mul_with_overflow" => { "mul_with_overflow" => {
let ty = *substs.types.get(subst::FnSpace, 0); let ty = *substs.types.get(subst::FnSpace, 0);

View file

@ -1,9 +0,0 @@
#![feature(custom_attribute)]
#![allow(dead_code, unused_attributes)]
// error-pattern:can't handle intrinsic: discriminant_value
#[miri_run]
fn main() {
assert_eq!(None::<i32>, None);
}

View file

@ -57,12 +57,12 @@ fn two_nones() -> (Option<i16>, Option<i16>) {
#[miri_run] #[miri_run]
fn main() { fn main() {
//assert_eq!(two_nones(), (None, None)); assert_eq!(two_nones(), (None, None));
assert_eq!(match_opt_some(), 13); assert_eq!(match_opt_some(), 13);
assert_eq!(match_opt_none(), 42); assert_eq!(match_opt_none(), 42);
//assert_eq!(return_some(), Some(42)); assert_eq!(return_some(), Some(42));
//assert_eq!(return_none(), None); assert_eq!(return_none(), None);
//assert_eq!(return_false(), MyBool::False); assert_eq!(return_false(), MyBool::False(()));
//assert_eq!(return_true(), MyBool::True); assert_eq!(return_true(), MyBool::True(()));
//assert_eq!(return_unit(), Unit::Unit); assert_eq!(return_unit(), Unit::Unit(()));
} }