2016-11-03 04:38:08 -05:00
|
|
|
use rustc::mir;
|
2017-06-02 20:00:35 -05:00
|
|
|
use rustc::traits::Reveal;
|
2017-07-28 03:16:36 -05:00
|
|
|
use rustc::ty::layout::Layout;
|
2016-09-26 10:49:30 -05:00
|
|
|
use rustc::ty::{self, Ty};
|
2016-09-20 09:05:30 -05:00
|
|
|
|
2017-07-28 06:08:27 -05:00
|
|
|
use rustc_miri::interpret::{
|
2017-08-02 09:59:01 -05:00
|
|
|
EvalResult,
|
2017-07-21 06:39:06 -05:00
|
|
|
Lvalue, LvalueExtra,
|
|
|
|
PrimVal, PrimValKind, Value, Pointer,
|
|
|
|
HasMemory,
|
2017-08-08 08:53:07 -05:00
|
|
|
EvalContext, PtrAndAlign,
|
2017-07-21 06:39:06 -05:00
|
|
|
};
|
2016-09-20 09:05:30 -05:00
|
|
|
|
2017-07-28 06:08:27 -05:00
|
|
|
use helpers::EvalContextExt as HelperEvalContextExt;
|
|
|
|
|
|
|
|
pub trait EvalContextExt<'tcx> {
|
|
|
|
fn call_intrinsic(
|
|
|
|
&mut self,
|
|
|
|
instance: ty::Instance<'tcx>,
|
|
|
|
args: &[mir::Operand<'tcx>],
|
2017-08-08 07:22:11 -05:00
|
|
|
dest: Lvalue,
|
2017-07-28 06:08:27 -05:00
|
|
|
dest_ty: Ty<'tcx>,
|
|
|
|
dest_layout: &'tcx Layout,
|
|
|
|
target: mir::BasicBlock,
|
|
|
|
) -> EvalResult<'tcx>;
|
|
|
|
}
|
|
|
|
|
|
|
|
impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
|
|
|
|
fn call_intrinsic(
|
2016-09-20 09:05:30 -05:00
|
|
|
&mut self,
|
2017-03-21 07:53:55 -05:00
|
|
|
instance: ty::Instance<'tcx>,
|
2016-09-20 09:05:30 -05:00
|
|
|
args: &[mir::Operand<'tcx>],
|
2017-08-08 07:22:11 -05:00
|
|
|
dest: Lvalue,
|
2016-09-26 10:49:30 -05:00
|
|
|
dest_ty: Ty<'tcx>,
|
2016-09-20 09:05:30 -05:00
|
|
|
dest_layout: &'tcx Layout,
|
2016-11-04 11:51:13 -05:00
|
|
|
target: mir::BasicBlock,
|
2017-02-04 15:09:10 -06:00
|
|
|
) -> EvalResult<'tcx> {
|
2016-10-21 04:17:53 -05:00
|
|
|
let arg_vals: EvalResult<Vec<Value>> = args.iter()
|
2016-09-23 03:27:14 -05:00
|
|
|
.map(|arg| self.eval_operand(arg))
|
2016-09-20 09:05:30 -05:00
|
|
|
.collect();
|
2016-10-21 04:17:53 -05:00
|
|
|
let arg_vals = arg_vals?;
|
2016-09-23 03:27:14 -05:00
|
|
|
let i32 = self.tcx.types.i32;
|
|
|
|
let isize = self.tcx.types.isize;
|
|
|
|
let usize = self.tcx.types.usize;
|
|
|
|
let f32 = self.tcx.types.f32;
|
|
|
|
let f64 = self.tcx.types.f64;
|
2017-03-29 02:10:05 -05:00
|
|
|
let substs = instance.substs;
|
2016-09-20 09:05:30 -05:00
|
|
|
|
2017-03-21 07:53:55 -05:00
|
|
|
let intrinsic_name = &self.tcx.item_name(instance.def_id()).as_str()[..];
|
2016-09-29 09:42:01 -05:00
|
|
|
match intrinsic_name {
|
2016-10-16 18:18:06 -05:00
|
|
|
"add_with_overflow" =>
|
|
|
|
self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_ty)?,
|
2016-10-14 04:31:45 -05:00
|
|
|
|
2016-10-16 18:18:06 -05:00
|
|
|
"sub_with_overflow" =>
|
|
|
|
self.intrinsic_with_overflow(mir::BinOp::Sub, &args[0], &args[1], dest, dest_ty)?,
|
|
|
|
|
|
|
|
"mul_with_overflow" =>
|
|
|
|
self.intrinsic_with_overflow(mir::BinOp::Mul, &args[0], &args[1], dest, dest_ty)?,
|
2016-10-14 04:31:45 -05:00
|
|
|
|
2016-09-20 09:05:30 -05:00
|
|
|
|
|
|
|
"arith_offset" => {
|
2017-06-04 20:18:37 -05:00
|
|
|
let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2017-06-04 20:47:31 -05:00
|
|
|
let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
|
2017-07-04 07:33:15 -05:00
|
|
|
self.write_ptr(dest, result_ptr, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"assume" => {
|
2016-09-23 03:27:14 -05:00
|
|
|
let bool = self.tcx.types.bool;
|
2016-12-17 00:01:01 -06:00
|
|
|
let cond = self.value_to_primval(arg_vals[0], bool)?.to_bool()?;
|
2017-08-02 09:59:01 -05:00
|
|
|
if !cond { return err!(AssumptionNotHeld); }
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2016-10-14 04:49:02 -05:00
|
|
|
"atomic_load" |
|
2016-12-16 19:10:16 -06:00
|
|
|
"atomic_load_relaxed" |
|
2016-11-15 08:19:38 -06:00
|
|
|
"atomic_load_acq" |
|
2016-10-14 04:49:02 -05:00
|
|
|
"volatile_load" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2017-07-12 23:06:57 -05:00
|
|
|
self.write_value(Value::by_ref(ptr), dest, ty)?;
|
2016-10-14 04:49:02 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"atomic_store" |
|
2016-12-15 11:27:47 -06:00
|
|
|
"atomic_store_relaxed" |
|
|
|
|
"atomic_store_rel" |
|
2016-10-14 04:49:02 -05:00
|
|
|
"volatile_store" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-07-27 11:14:04 -05:00
|
|
|
let dest = arg_vals[0].into_ptr(&self.memory)?;
|
2016-10-21 04:17:53 -05:00
|
|
|
self.write_value_to_ptr(arg_vals[1], dest, ty)?;
|
2016-10-14 04:49:02 -05:00
|
|
|
}
|
|
|
|
|
2016-11-03 11:32:06 -05:00
|
|
|
"atomic_fence_acq" => {
|
|
|
|
// we are inherently singlethreaded and singlecored, this is a nop
|
|
|
|
}
|
|
|
|
|
2017-03-14 07:05:51 -05:00
|
|
|
_ if intrinsic_name.starts_with("atomic_xchg") => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2016-11-15 08:19:38 -06:00
|
|
|
let change = self.value_to_primval(arg_vals[1], ty)?;
|
|
|
|
let old = self.read_value(ptr, ty)?;
|
|
|
|
let old = match old {
|
|
|
|
Value::ByVal(val) => val,
|
2017-07-28 21:43:05 -05:00
|
|
|
Value::ByRef { .. } => bug!("just read the value, can't be byref"),
|
2016-11-15 08:19:38 -06:00
|
|
|
Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"),
|
|
|
|
};
|
2016-11-27 00:58:01 -06:00
|
|
|
self.write_primval(dest, old, ty)?;
|
2017-07-03 07:16:11 -05:00
|
|
|
self.write_primval(Lvalue::from_primval_ptr(ptr), change, ty)?;
|
2016-11-15 08:19:38 -06:00
|
|
|
}
|
|
|
|
|
2017-03-14 07:05:51 -05:00
|
|
|
_ if intrinsic_name.starts_with("atomic_cxchg") => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2016-11-15 08:19:38 -06:00
|
|
|
let expect_old = self.value_to_primval(arg_vals[1], ty)?;
|
|
|
|
let change = self.value_to_primval(arg_vals[2], ty)?;
|
|
|
|
let old = self.read_value(ptr, ty)?;
|
|
|
|
let old = match old {
|
|
|
|
Value::ByVal(val) => val,
|
2017-07-28 21:43:05 -05:00
|
|
|
Value::ByRef { .. } => bug!("just read the value, can't be byref"),
|
2016-11-15 08:19:38 -06:00
|
|
|
Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
|
|
|
|
};
|
2017-06-04 19:26:19 -05:00
|
|
|
let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
|
2017-06-19 03:58:59 -05:00
|
|
|
let dest = self.force_allocation(dest)?.to_ptr()?;
|
2016-11-15 08:19:38 -06:00
|
|
|
self.write_pair_to_ptr(old, val, dest, dest_ty)?;
|
2017-07-03 07:16:11 -05:00
|
|
|
self.write_primval(Lvalue::from_primval_ptr(ptr), change, ty)?;
|
2016-11-15 08:19:38 -06:00
|
|
|
}
|
|
|
|
|
2017-03-14 07:05:51 -05:00
|
|
|
"atomic_or" | "atomic_or_acq" | "atomic_or_rel" | "atomic_or_acqrel" | "atomic_or_relaxed" |
|
|
|
|
"atomic_xor" | "atomic_xor_acq" | "atomic_xor_rel" | "atomic_xor_acqrel" | "atomic_xor_relaxed" |
|
|
|
|
"atomic_and" | "atomic_and_acq" | "atomic_and_rel" | "atomic_and_acqrel" | "atomic_and_relaxed" |
|
|
|
|
"atomic_xadd" | "atomic_xadd_acq" | "atomic_xadd_rel" | "atomic_xadd_acqrel" | "atomic_xadd_relaxed" |
|
|
|
|
"atomic_xsub" | "atomic_xsub_acq" | "atomic_xsub_rel" | "atomic_xsub_acqrel" | "atomic_xsub_relaxed" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2016-11-15 08:19:38 -06:00
|
|
|
let change = self.value_to_primval(arg_vals[1], ty)?;
|
|
|
|
let old = self.read_value(ptr, ty)?;
|
|
|
|
let old = match old {
|
|
|
|
Value::ByVal(val) => val,
|
2017-07-28 21:43:05 -05:00
|
|
|
Value::ByRef { .. } => bug!("just read the value, can't be byref"),
|
2016-11-15 08:19:38 -06:00
|
|
|
Value::ByValPair(..) => bug!("atomic_xadd_relaxed doesn't work with nonprimitives"),
|
|
|
|
};
|
2016-11-27 00:58:01 -06:00
|
|
|
self.write_primval(dest, old, ty)?;
|
2017-03-14 07:05:51 -05:00
|
|
|
let op = match intrinsic_name.split('_').nth(1).unwrap() {
|
|
|
|
"or" => mir::BinOp::BitOr,
|
|
|
|
"xor" => mir::BinOp::BitXor,
|
|
|
|
"and" => mir::BinOp::BitAnd,
|
|
|
|
"xadd" => mir::BinOp::Add,
|
|
|
|
"xsub" => mir::BinOp::Sub,
|
|
|
|
_ => bug!(),
|
2016-11-03 11:32:06 -05:00
|
|
|
};
|
|
|
|
// FIXME: what do atomics do on overflow?
|
2017-06-04 19:26:19 -05:00
|
|
|
let (val, _) = self.binary_op(op, old, ty, change, ty)?;
|
2017-07-03 07:16:11 -05:00
|
|
|
self.write_primval(Lvalue::from_primval_ptr(ptr), val, ty)?;
|
2017-03-14 07:05:51 -05:00
|
|
|
},
|
2016-11-03 11:32:06 -05:00
|
|
|
|
2016-09-20 09:05:30 -05:00
|
|
|
"breakpoint" => unimplemented!(), // halt miri
|
|
|
|
|
|
|
|
"copy" |
|
|
|
|
"copy_nonoverlapping" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let elem_ty = substs.type_at(0);
|
2016-11-17 10:23:40 -06:00
|
|
|
let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value");
|
2017-07-20 15:20:33 -05:00
|
|
|
let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
|
|
|
|
if count * elem_size != 0 {
|
|
|
|
// TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next.
|
|
|
|
// Also see the write_bytes intrinsic.
|
2017-06-19 03:58:59 -05:00
|
|
|
let elem_align = self.type_align(elem_ty)?;
|
2017-07-27 11:14:04 -05:00
|
|
|
let src = arg_vals[0].into_ptr(&self.memory)?;
|
|
|
|
let dest = arg_vals[1].into_ptr(&self.memory)?;
|
2017-07-03 22:27:09 -05:00
|
|
|
self.memory.copy(src, dest, count * elem_size, elem_align, intrinsic_name.ends_with("_nonoverlapping"))?;
|
2017-06-19 03:58:59 -05:00
|
|
|
}
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2016-09-29 09:42:01 -05:00
|
|
|
"ctpop" |
|
|
|
|
"cttz" |
|
2017-06-22 02:08:19 -05:00
|
|
|
"cttz_nonzero" |
|
2016-09-29 09:42:01 -05:00
|
|
|
"ctlz" |
|
2017-06-22 02:08:19 -05:00
|
|
|
"ctlz_nonzero" |
|
2016-09-29 08:58:26 -05:00
|
|
|
"bswap" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-06-22 02:08:19 -05:00
|
|
|
let num = self.value_to_primval(arg_vals[0], ty)?.to_bytes()?;
|
2016-11-27 00:58:01 -06:00
|
|
|
let kind = self.ty_to_primval_kind(ty)?;
|
2017-06-22 02:08:19 -05:00
|
|
|
let num = if intrinsic_name.ends_with("_nonzero") {
|
|
|
|
if num == 0 {
|
2017-08-02 09:59:01 -05:00
|
|
|
return err!(Intrinsic(format!("{} called on 0", intrinsic_name)))
|
2017-06-22 02:08:19 -05:00
|
|
|
}
|
|
|
|
numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), num, kind)?
|
|
|
|
} else {
|
|
|
|
numeric_intrinsic(intrinsic_name, num, kind)?
|
|
|
|
};
|
2016-11-27 00:58:01 -06:00
|
|
|
self.write_primval(dest, num, ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"discriminant_value" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-07-27 11:14:04 -05:00
|
|
|
let adt_ptr = arg_vals[0].into_ptr(&self.memory)?.to_ptr()?;
|
2016-09-20 09:05:30 -05:00
|
|
|
let discr_val = self.read_discriminant_value(adt_ptr, ty)?;
|
2016-12-16 01:40:45 -06:00
|
|
|
self.write_primval(dest, PrimVal::Bytes(discr_val), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 06:35:38 -05:00
|
|
|
"sinf32" | "fabsf32" | "cosf32" |
|
|
|
|
"sqrtf32" | "expf32" | "exp2f32" |
|
|
|
|
"logf32" | "log10f32" | "log2f32" |
|
|
|
|
"floorf32" | "ceilf32" | "truncf32" => {
|
2017-02-10 16:53:56 -06:00
|
|
|
let f = self.value_to_primval(arg_vals[0], f32)?.to_f32()?;
|
2017-03-14 06:35:38 -05:00
|
|
|
let f = match intrinsic_name {
|
|
|
|
"sinf32" => f.sin(),
|
|
|
|
"fabsf32" => f.abs(),
|
|
|
|
"cosf32" => f.cos(),
|
|
|
|
"sqrtf32" => f.sqrt(),
|
|
|
|
"expf32" => f.exp(),
|
|
|
|
"exp2f32" => f.exp2(),
|
|
|
|
"logf32" => f.ln(),
|
|
|
|
"log10f32" => f.log10(),
|
|
|
|
"log2f32" => f.log2(),
|
|
|
|
"floorf32" => f.floor(),
|
|
|
|
"ceilf32" => f.ceil(),
|
|
|
|
"truncf32" => f.trunc(),
|
|
|
|
_ => bug!(),
|
|
|
|
};
|
|
|
|
self.write_primval(dest, PrimVal::from_f32(f), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 06:35:38 -05:00
|
|
|
"sinf64" | "fabsf64" | "cosf64" |
|
|
|
|
"sqrtf64" | "expf64" | "exp2f64" |
|
|
|
|
"logf64" | "log10f64" | "log2f64" |
|
|
|
|
"floorf64" | "ceilf64" | "truncf64" => {
|
2017-02-10 16:53:56 -06:00
|
|
|
let f = self.value_to_primval(arg_vals[0], f64)?.to_f64()?;
|
2017-03-14 06:35:38 -05:00
|
|
|
let f = match intrinsic_name {
|
|
|
|
"sinf64" => f.sin(),
|
|
|
|
"fabsf64" => f.abs(),
|
|
|
|
"cosf64" => f.cos(),
|
|
|
|
"sqrtf64" => f.sqrt(),
|
|
|
|
"expf64" => f.exp(),
|
|
|
|
"exp2f64" => f.exp2(),
|
|
|
|
"logf64" => f.ln(),
|
|
|
|
"log10f64" => f.log10(),
|
|
|
|
"log2f64" => f.log2(),
|
|
|
|
"floorf64" => f.floor(),
|
|
|
|
"ceilf64" => f.ceil(),
|
|
|
|
"truncf64" => f.trunc(),
|
|
|
|
_ => bug!(),
|
|
|
|
};
|
|
|
|
self.write_primval(dest, PrimVal::from_f64(f), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-02-10 07:58:34 -06:00
|
|
|
"fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2016-10-21 04:17:53 -05:00
|
|
|
let a = self.value_to_primval(arg_vals[0], ty)?;
|
2017-02-10 07:58:34 -06:00
|
|
|
let b = self.value_to_primval(arg_vals[1], ty)?;
|
|
|
|
let op = match intrinsic_name {
|
|
|
|
"fadd_fast" => mir::BinOp::Add,
|
|
|
|
"fsub_fast" => mir::BinOp::Sub,
|
|
|
|
"fmul_fast" => mir::BinOp::Mul,
|
|
|
|
"fdiv_fast" => mir::BinOp::Div,
|
|
|
|
"frem_fast" => mir::BinOp::Rem,
|
|
|
|
_ => bug!(),
|
|
|
|
};
|
2017-06-04 19:26:19 -05:00
|
|
|
let result = self.binary_op(op, a, ty, b, ty)?;
|
2016-11-27 00:58:01 -06:00
|
|
|
self.write_primval(dest, result.0, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"likely" |
|
|
|
|
"unlikely" |
|
|
|
|
"forget" => {}
|
|
|
|
|
2016-10-14 04:31:45 -05:00
|
|
|
"init" => {
|
2016-12-18 22:59:01 -06:00
|
|
|
let size = self.type_size(dest_ty)?.expect("cannot zero unsized value");
|
|
|
|
let init = |this: &mut Self, val: Value| {
|
2016-11-27 00:58:01 -06:00
|
|
|
let zero_val = match val {
|
2017-08-08 08:53:07 -05:00
|
|
|
Value::ByRef(PtrAndAlign { ptr, .. }) => {
|
2017-07-12 23:06:57 -05:00
|
|
|
// These writes have no alignment restriction anyway.
|
2016-11-03 06:52:13 -05:00
|
|
|
this.memory.write_repeat(ptr, 0, size)?;
|
2017-08-08 08:53:07 -05:00
|
|
|
val
|
2016-11-03 06:52:13 -05:00
|
|
|
},
|
2016-12-18 22:59:01 -06:00
|
|
|
// TODO(solson): Revisit this, it's fishy to check for Undef here.
|
|
|
|
Value::ByVal(PrimVal::Undef) => match this.ty_to_primval_kind(dest_ty) {
|
2016-12-16 01:40:45 -06:00
|
|
|
Ok(_) => Value::ByVal(PrimVal::Bytes(0)),
|
2016-11-03 06:52:13 -05:00
|
|
|
Err(_) => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ptr = this.alloc_ptr_with_substs(dest_ty, substs)?;
|
2017-07-04 07:33:15 -05:00
|
|
|
let ptr = Pointer::from(PrimVal::Ptr(ptr));
|
|
|
|
this.memory.write_repeat(ptr, 0, size)?;
|
2017-07-12 23:06:57 -05:00
|
|
|
Value::by_ref(ptr)
|
2016-11-03 06:52:13 -05:00
|
|
|
}
|
|
|
|
},
|
2016-12-18 22:59:01 -06:00
|
|
|
Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)),
|
|
|
|
Value::ByValPair(..) =>
|
2016-12-16 01:40:45 -06:00
|
|
|
Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0)),
|
2016-11-27 00:58:01 -06:00
|
|
|
};
|
2016-12-18 22:59:01 -06:00
|
|
|
Ok(zero_val)
|
2016-11-03 06:52:13 -05:00
|
|
|
};
|
|
|
|
match dest {
|
2017-06-27 06:36:41 -05:00
|
|
|
Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?,
|
2017-08-08 08:53:07 -05:00
|
|
|
Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::None } => self.memory.write_repeat(ptr, 0, size)?,
|
2017-07-12 19:46:56 -05:00
|
|
|
Lvalue::Ptr { .. } => bug!("init intrinsic tried to write to fat or unaligned ptr target"),
|
2016-11-03 06:31:04 -05:00
|
|
|
}
|
2016-10-14 04:31:45 -05:00
|
|
|
}
|
2016-09-20 09:05:30 -05:00
|
|
|
|
|
|
|
"min_align_of" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let elem_ty = substs.type_at(0);
|
2016-11-17 10:23:40 -06:00
|
|
|
let elem_align = self.type_align(elem_ty)?;
|
2017-01-12 01:28:42 -06:00
|
|
|
let align_val = PrimVal::from_u128(elem_align as u128);
|
2016-11-27 00:58:01 -06:00
|
|
|
self.write_primval(dest, align_val, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"pref_align_of" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2016-11-17 10:23:40 -06:00
|
|
|
let layout = self.type_layout(ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
let align = layout.align(&self.tcx.data_layout).pref();
|
2017-01-12 01:28:42 -06:00
|
|
|
let align_val = PrimVal::from_u128(align as u128);
|
2016-11-27 00:58:01 -06:00
|
|
|
self.write_primval(dest, align_val, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"move_val_init" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2016-10-21 04:17:53 -05:00
|
|
|
self.write_value_to_ptr(arg_vals[1], ptr, ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"needs_drop" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-06-02 20:00:35 -05:00
|
|
|
let env = ty::ParamEnv::empty(Reveal::All);
|
2017-05-23 22:40:39 -05:00
|
|
|
let needs_drop = ty.needs_drop(self.tcx, env);
|
2016-11-27 00:58:01 -06:00
|
|
|
self.write_primval(dest, PrimVal::from_bool(needs_drop), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"offset" => {
|
2017-01-12 01:28:42 -06:00
|
|
|
let offset = self.value_to_primval(arg_vals[1], isize)?.to_i128()? as i64;
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2017-06-04 19:26:19 -05:00
|
|
|
let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
|
2017-07-04 07:33:15 -05:00
|
|
|
self.write_ptr(dest, result_ptr, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"overflowing_sub" => {
|
2016-11-27 00:58:01 -06:00
|
|
|
self.intrinsic_overflowing(mir::BinOp::Sub, &args[0], &args[1], dest, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"overflowing_mul" => {
|
2016-11-27 00:58:01 -06:00
|
|
|
self.intrinsic_overflowing(mir::BinOp::Mul, &args[0], &args[1], dest, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"overflowing_add" => {
|
2016-11-27 00:58:01 -06:00
|
|
|
self.intrinsic_overflowing(mir::BinOp::Add, &args[0], &args[1], dest, dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 06:35:38 -05:00
|
|
|
"powf32" => {
|
2016-12-17 00:01:01 -06:00
|
|
|
let f = self.value_to_primval(arg_vals[0], f32)?.to_f32()?;
|
2017-03-14 06:35:38 -05:00
|
|
|
let f2 = self.value_to_primval(arg_vals[1], f32)?.to_f32()?;
|
|
|
|
self.write_primval(dest, PrimVal::from_f32(f.powf(f2)), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 06:35:38 -05:00
|
|
|
"powf64" => {
|
2016-12-17 00:01:01 -06:00
|
|
|
let f = self.value_to_primval(arg_vals[0], f64)?.to_f64()?;
|
2017-03-14 06:35:38 -05:00
|
|
|
let f2 = self.value_to_primval(arg_vals[1], f64)?.to_f64()?;
|
|
|
|
self.write_primval(dest, PrimVal::from_f64(f.powf(f2)), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 06:35:38 -05:00
|
|
|
"fmaf32" => {
|
|
|
|
let a = self.value_to_primval(arg_vals[0], f32)?.to_f32()?;
|
|
|
|
let b = self.value_to_primval(arg_vals[1], f32)?.to_f32()?;
|
|
|
|
let c = self.value_to_primval(arg_vals[2], f32)?.to_f32()?;
|
|
|
|
self.write_primval(dest, PrimVal::from_f32(a * b + c), dest_ty)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
"fmaf64" => {
|
|
|
|
let a = self.value_to_primval(arg_vals[0], f64)?.to_f64()?;
|
|
|
|
let b = self.value_to_primval(arg_vals[1], f64)?.to_f64()?;
|
|
|
|
let c = self.value_to_primval(arg_vals[2], f64)?.to_f64()?;
|
|
|
|
self.write_primval(dest, PrimVal::from_f64(a * b + c), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 06:35:38 -05:00
|
|
|
"powif32" => {
|
2016-12-17 00:01:01 -06:00
|
|
|
let f = self.value_to_primval(arg_vals[0], f32)?.to_f32()?;
|
2017-03-14 06:35:38 -05:00
|
|
|
let i = self.value_to_primval(arg_vals[1], i32)?.to_i128()?;
|
|
|
|
self.write_primval(dest, PrimVal::from_f32(f.powi(i as i32)), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-03-14 06:35:38 -05:00
|
|
|
"powif64" => {
|
2016-12-17 00:01:01 -06:00
|
|
|
let f = self.value_to_primval(arg_vals[0], f64)?.to_f64()?;
|
2017-03-14 06:35:38 -05:00
|
|
|
let i = self.value_to_primval(arg_vals[1], i32)?.to_i128()?;
|
|
|
|
self.write_primval(dest, PrimVal::from_f64(f.powi(i as i32)), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"size_of" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-06-01 19:24:21 -05:00
|
|
|
let size = self.type_size(ty)?.expect("size_of intrinsic called on unsized value") as u128;
|
2017-01-12 01:28:42 -06:00
|
|
|
self.write_primval(dest, PrimVal::from_u128(size), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"size_of_val" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2016-10-21 04:17:53 -05:00
|
|
|
let (size, _) = self.size_and_align_of_dst(ty, arg_vals[0])?;
|
2017-01-12 01:28:42 -06:00
|
|
|
self.write_primval(dest, PrimVal::from_u128(size as u128), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
2016-11-03 11:32:06 -05:00
|
|
|
|
|
|
|
"min_align_of_val" |
|
|
|
|
"align_of_val" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2016-11-03 11:32:06 -05:00
|
|
|
let (_, align) = self.size_and_align_of_dst(ty, arg_vals[0])?;
|
2017-01-12 01:28:42 -06:00
|
|
|
self.write_primval(dest, PrimVal::from_u128(align as u128), dest_ty)?;
|
2016-11-03 11:32:06 -05:00
|
|
|
}
|
|
|
|
|
2016-09-20 09:05:30 -05:00
|
|
|
"type_name" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2016-09-20 09:05:30 -05:00
|
|
|
let ty_name = ty.to_string();
|
2016-09-26 10:49:30 -05:00
|
|
|
let s = self.str_to_value(&ty_name)?;
|
|
|
|
self.write_value(s, dest, dest_ty)?;
|
2016-09-23 03:38:30 -05:00
|
|
|
}
|
2016-09-20 09:05:30 -05:00
|
|
|
"type_id" => {
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2016-09-20 09:05:30 -05:00
|
|
|
let n = self.tcx.type_id_hash(ty);
|
2017-01-12 01:28:42 -06:00
|
|
|
self.write_primval(dest, PrimVal::Bytes(n as u128), dest_ty)?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
"transmute" => {
|
2017-06-06 08:49:34 -05:00
|
|
|
let src_ty = substs.type_at(0);
|
2017-07-03 15:57:18 -05:00
|
|
|
let ptr = self.force_allocation(dest)?.to_ptr()?;
|
2017-07-27 11:14:04 -05:00
|
|
|
self.write_maybe_aligned_mut(/*aligned*/false, |ectx| {
|
2017-07-13 12:29:11 -05:00
|
|
|
ectx.write_value_to_ptr(arg_vals[0], ptr.into(), src_ty)
|
|
|
|
})?;
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2017-07-03 21:55:15 -05:00
|
|
|
"unchecked_shl" => {
|
2017-07-03 22:27:09 -05:00
|
|
|
let bits = self.type_size(dest_ty)?.expect("intrinsic can't be called on unsized type") as u128 * 8;
|
|
|
|
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
|
|
|
|
if rhs >= bits {
|
2017-08-02 09:59:01 -05:00
|
|
|
return err!(Intrinsic(format!("Overflowing shift by {} in unchecked_shl", rhs)));
|
2017-07-03 22:27:09 -05:00
|
|
|
}
|
2017-07-03 21:55:15 -05:00
|
|
|
self.intrinsic_overflowing(mir::BinOp::Shl, &args[0], &args[1], dest, dest_ty)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
"unchecked_shr" => {
|
2017-07-03 22:27:09 -05:00
|
|
|
let bits = self.type_size(dest_ty)?.expect("intrinsic can't be called on unsized type") as u128 * 8;
|
|
|
|
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
|
|
|
|
if rhs >= bits {
|
2017-08-02 09:59:01 -05:00
|
|
|
return err!(Intrinsic(format!("Overflowing shift by {} in unchecked_shr", rhs)));
|
2017-07-03 22:27:09 -05:00
|
|
|
}
|
2017-07-03 21:55:15 -05:00
|
|
|
self.intrinsic_overflowing(mir::BinOp::Shr, &args[0], &args[1], dest, dest_ty)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
"unchecked_div" => {
|
|
|
|
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
|
|
|
|
if rhs == 0 {
|
2017-08-02 09:59:01 -05:00
|
|
|
return err!(Intrinsic(format!("Division by 0 in unchecked_div")));
|
2017-07-03 21:55:15 -05:00
|
|
|
}
|
|
|
|
self.intrinsic_overflowing(mir::BinOp::Div, &args[0], &args[1], dest, dest_ty)?;
|
|
|
|
}
|
|
|
|
|
|
|
|
"unchecked_rem" => {
|
|
|
|
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
|
|
|
|
if rhs == 0 {
|
2017-08-02 09:59:01 -05:00
|
|
|
return err!(Intrinsic(format!("Division by 0 in unchecked_rem")));
|
2017-07-03 21:55:15 -05:00
|
|
|
}
|
|
|
|
self.intrinsic_overflowing(mir::BinOp::Rem, &args[0], &args[1], dest, dest_ty)?;
|
|
|
|
}
|
|
|
|
|
2016-10-14 04:31:45 -05:00
|
|
|
"uninit" => {
|
2016-11-18 05:55:14 -06:00
|
|
|
let size = dest_layout.size(&self.tcx.data_layout).bytes();
|
2016-12-18 22:59:01 -06:00
|
|
|
let uninit = |this: &mut Self, val: Value| {
|
2016-11-03 07:13:47 -05:00
|
|
|
match val {
|
2017-08-08 08:53:07 -05:00
|
|
|
Value::ByRef(PtrAndAlign { ptr, .. }) => {
|
2017-07-03 07:16:11 -05:00
|
|
|
this.memory.mark_definedness(ptr, size, false)?;
|
2017-08-08 08:53:07 -05:00
|
|
|
Ok(val)
|
2016-11-03 07:13:47 -05:00
|
|
|
},
|
2016-12-18 22:59:01 -06:00
|
|
|
_ => Ok(Value::ByVal(PrimVal::Undef)),
|
2016-11-03 07:13:47 -05:00
|
|
|
}
|
|
|
|
};
|
|
|
|
match dest {
|
2017-06-27 06:36:41 -05:00
|
|
|
Lvalue::Local { frame, local } => self.modify_local(frame, local, uninit)?,
|
2017-08-08 08:53:07 -05:00
|
|
|
Lvalue::Ptr { ptr: PtrAndAlign { ptr, aligned: true }, extra: LvalueExtra::None } =>
|
2017-06-20 07:26:50 -05:00
|
|
|
self.memory.mark_definedness(ptr, size, false)?,
|
2017-07-12 19:46:56 -05:00
|
|
|
Lvalue::Ptr { .. } => bug!("uninit intrinsic tried to write to fat or unaligned ptr target"),
|
2016-11-03 07:13:47 -05:00
|
|
|
}
|
2016-10-14 04:31:45 -05:00
|
|
|
}
|
2016-09-20 09:05:30 -05:00
|
|
|
|
2017-03-13 18:28:29 -05:00
|
|
|
"write_bytes" => {
|
|
|
|
let u8 = self.tcx.types.u8;
|
2017-03-29 02:10:05 -05:00
|
|
|
let ty = substs.type_at(0);
|
2017-03-13 19:47:08 -05:00
|
|
|
let ty_align = self.type_align(ty)?;
|
|
|
|
let val_byte = self.value_to_primval(arg_vals[1], u8)?.to_u128()? as u8;
|
2017-03-13 18:28:29 -05:00
|
|
|
let size = self.type_size(ty)?.expect("write_bytes() type must be sized");
|
2017-07-27 11:14:04 -05:00
|
|
|
let ptr = arg_vals[0].into_ptr(&self.memory)?;
|
2017-03-13 18:28:29 -05:00
|
|
|
let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
|
2017-06-02 20:35:33 -05:00
|
|
|
if count > 0 {
|
2017-07-20 15:20:33 -05:00
|
|
|
// HashMap relies on write_bytes on a NULL ptr with count == 0 to work
|
|
|
|
// TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic)
|
2017-07-12 19:46:56 -05:00
|
|
|
self.memory.check_align(ptr, ty_align)?;
|
2017-06-02 20:35:33 -05:00
|
|
|
self.memory.write_repeat(ptr, val_byte, size * count)?;
|
|
|
|
}
|
2017-03-13 18:28:29 -05:00
|
|
|
}
|
|
|
|
|
2017-08-02 09:59:01 -05:00
|
|
|
name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))),
|
2016-09-20 09:05:30 -05:00
|
|
|
}
|
|
|
|
|
2016-11-04 11:51:13 -05:00
|
|
|
self.goto_block(target);
|
|
|
|
|
2016-09-20 09:05:30 -05:00
|
|
|
// Since we pushed no stack frame, the main loop will act
|
|
|
|
// as if the call just completed and it's returning to the
|
|
|
|
// current frame.
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
2016-09-29 09:42:01 -05:00
|
|
|
|
2016-12-17 05:09:57 -06:00
|
|
|
fn numeric_intrinsic<'tcx>(
|
|
|
|
name: &str,
|
2017-06-22 02:08:19 -05:00
|
|
|
bytes: u128,
|
2016-12-17 05:09:57 -06:00
|
|
|
kind: PrimValKind
|
|
|
|
) -> EvalResult<'tcx, PrimVal> {
|
|
|
|
macro_rules! integer_intrinsic {
|
2017-06-21 02:06:35 -05:00
|
|
|
($method:ident) => ({
|
2017-07-28 06:08:27 -05:00
|
|
|
use rustc_miri::interpret::PrimValKind::*;
|
2017-06-21 02:06:35 -05:00
|
|
|
let result_bytes = match kind {
|
2017-01-12 01:28:42 -06:00
|
|
|
I8 => (bytes as i8).$method() as u128,
|
|
|
|
U8 => (bytes as u8).$method() as u128,
|
|
|
|
I16 => (bytes as i16).$method() as u128,
|
|
|
|
U16 => (bytes as u16).$method() as u128,
|
|
|
|
I32 => (bytes as i32).$method() as u128,
|
|
|
|
U32 => (bytes as u32).$method() as u128,
|
|
|
|
I64 => (bytes as i64).$method() as u128,
|
|
|
|
U64 => (bytes as u64).$method() as u128,
|
|
|
|
I128 => (bytes as i128).$method() as u128,
|
|
|
|
U128 => bytes.$method() as u128,
|
2017-06-22 02:08:19 -05:00
|
|
|
_ => bug!("invalid `{}` argument: {:?}", name, bytes),
|
2016-12-17 05:09:57 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
PrimVal::Bytes(result_bytes)
|
|
|
|
});
|
|
|
|
}
|
2016-10-20 05:42:19 -05:00
|
|
|
|
2016-12-17 05:09:57 -06:00
|
|
|
let result_val = match name {
|
2017-06-21 02:06:35 -05:00
|
|
|
"bswap" => integer_intrinsic!(swap_bytes),
|
|
|
|
"ctlz" => integer_intrinsic!(leading_zeros),
|
|
|
|
"ctpop" => integer_intrinsic!(count_ones),
|
|
|
|
"cttz" => integer_intrinsic!(trailing_zeros),
|
2016-10-20 05:42:19 -05:00
|
|
|
_ => bug!("not a numeric intrinsic: {}", name),
|
2016-12-17 05:09:57 -06:00
|
|
|
};
|
|
|
|
|
|
|
|
Ok(result_val)
|
2016-09-29 09:42:01 -05:00
|
|
|
}
|