2 use rustc::ty::layout::{TyLayout, LayoutOf};
5 use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer};
6 use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy};
8 use helpers::EvalContextExt as HelperEvalContextExt;
10 pub trait EvalContextExt<'tcx> {
13 instance: ty::Instance<'tcx>,
16 dest_layout: TyLayout<'tcx>,
17 target: mir::BasicBlock,
18 ) -> EvalResult<'tcx>;
21 impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
24 instance: ty::Instance<'tcx>,
27 dest_layout: TyLayout<'tcx>,
28 target: mir::BasicBlock,
29 ) -> EvalResult<'tcx> {
30 let substs = instance.substs;
32 let intrinsic_name = &self.tcx.item_name(instance.def_id())[..];
33 match intrinsic_name {
35 // FIXME: return a real value in case the target allocation has an
36 // alignment bigger than the one requested
37 self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_layout.ty)?;
40 "add_with_overflow" => {
41 self.intrinsic_with_overflow(
50 "sub_with_overflow" => {
51 self.intrinsic_with_overflow(
60 "mul_with_overflow" => {
61 self.intrinsic_with_overflow(
71 let offset = self.value_to_primval(args[1])?.to_i128()? as i64;
72 let ptr = self.into_ptr(args[0].value)?;
73 let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
74 self.write_ptr(dest, result_ptr, dest_layout.ty)?;
78 let cond = self.value_to_primval(args[0])?.to_bool()?;
80 return err!(AssumptionNotHeld);
85 "atomic_load_relaxed" |
88 let ptr = self.into_ptr(args[0].value)?;
89 let align = self.layout_of(args[0].ty)?.align;
92 value: Value::ByRef(ptr, align),
93 ty: substs.type_at(0),
95 self.write_value(valty, dest)?;
99 "atomic_store_relaxed" |
101 "volatile_store" => {
102 let ty = substs.type_at(0);
103 let align = self.layout_of(ty)?.align;
104 let dest = self.into_ptr(args[0].value)?;
105 self.write_value_to_ptr(args[1].value, dest, align, ty)?;
108 "atomic_fence_acq" => {
109 // we are inherently singlethreaded and singlecored, this is a nop
112 _ if intrinsic_name.starts_with("atomic_xchg") => {
113 let ty = substs.type_at(0);
114 let align = self.layout_of(ty)?.align;
115 let ptr = self.into_ptr(args[0].value)?;
116 let change = self.value_to_primval(args[1])?;
117 let old = self.read_value(ptr, align, ty)?;
118 let old = match old {
119 Value::ByVal(val) => val,
120 Value::ByRef { .. } => bug!("just read the value, can't be byref"),
121 Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"),
123 self.write_primval(dest, old, ty)?;
125 Place::from_primval_ptr(ptr, align),
131 _ if intrinsic_name.starts_with("atomic_cxchg") => {
132 let ty = substs.type_at(0);
133 let align = self.layout_of(ty)?.align;
134 let ptr = self.into_ptr(args[0].value)?;
135 let expect_old = self.value_to_primval(args[1])?;
136 let change = self.value_to_primval(args[2])?;
137 let old = self.read_value(ptr, align, ty)?;
138 let old = match old {
139 Value::ByVal(val) => val,
140 Value::ByRef { .. } => bug!("just read the value, can't be byref"),
141 Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
143 let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
145 value: Value::ByValPair(old, val),
148 self.write_value(valty, dest)?;
150 Place::from_primval_ptr(ptr, dest_layout.align),
160 "atomic_or_relaxed" |
164 "atomic_xor_acqrel" |
165 "atomic_xor_relaxed" |
169 "atomic_and_acqrel" |
170 "atomic_and_relaxed" |
174 "atomic_xadd_acqrel" |
175 "atomic_xadd_relaxed" |
179 "atomic_xsub_acqrel" |
180 "atomic_xsub_relaxed" => {
181 let ty = substs.type_at(0);
182 let align = self.layout_of(ty)?.align;
183 let ptr = self.into_ptr(args[0].value)?;
184 let change = self.value_to_primval(args[1])?;
185 let old = self.read_value(ptr, align, ty)?;
186 let old = match old {
187 Value::ByVal(val) => val,
188 Value::ByRef { .. } => bug!("just read the value, can't be byref"),
189 Value::ByValPair(..) => {
190 bug!("atomic_xadd_relaxed doesn't work with nonprimitives")
193 self.write_primval(dest, old, ty)?;
194 let op = match intrinsic_name.split('_').nth(1).unwrap() {
195 "or" => mir::BinOp::BitOr,
196 "xor" => mir::BinOp::BitXor,
197 "and" => mir::BinOp::BitAnd,
198 "xadd" => mir::BinOp::Add,
199 "xsub" => mir::BinOp::Sub,
202 // FIXME: what do atomics do on overflow?
203 let (val, _) = self.binary_op(op, old, ty, change, ty)?;
204 self.write_primval(Place::from_primval_ptr(ptr, dest_layout.align), val, ty)?;
207 "breakpoint" => unimplemented!(), // halt miri
210 "copy_nonoverlapping" => {
211 let elem_ty = substs.type_at(0);
212 let elem_layout = self.layout_of(elem_ty)?;
213 let elem_size = elem_layout.size.bytes();
214 let count = self.value_to_primval(args[2])?.to_u64()?;
215 if count * elem_size != 0 {
216 // TODO: We do not even validate alignment for the 0-bytes case. libstd relies on this in vec::IntoIter::next.
217 // Also see the write_bytes intrinsic.
218 let elem_align = elem_layout.align;
219 let src = self.into_ptr(args[0].value)?;
220 //let src_align = self.layout_of(args[0].ty)?.align;
221 //let src_align = ty::layout::Align::from_bytes(1, 1).unwrap();
222 let dest = self.into_ptr(args[1].value)?;
223 /*self.tcx.sess.warn(&format!("src_ty: {:?} src_align: {} elem_align: {} src_aligned: {:?} dst_aligned: {:?}",
227 self.memory.check_align(src, src_align),
228 self.memory.check_align(dest, elem_align)
236 intrinsic_name.ends_with("_nonoverlapping"),
241 "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
242 let ty = substs.type_at(0);
243 let num = self.value_to_primval(args[0])?.to_bytes()?;
244 let kind = self.ty_to_primval_kind(ty)?;
245 let num = if intrinsic_name.ends_with("_nonzero") {
247 return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
249 numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), num, kind)?
251 numeric_intrinsic(intrinsic_name, num, kind)?
253 self.write_primval(dest, num, ty)?;
256 "discriminant_value" => {
257 let ty = substs.type_at(0);
258 let adt_ptr = self.into_ptr(args[0].value)?;
259 let adt_align = self.layout_of(args[0].ty)?.align;
260 let place = Place::from_primval_ptr(adt_ptr, adt_align);
261 let discr_val = self.read_discriminant_value(place, ty)?;
262 self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?;
265 "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" |
266 "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => {
267 let f = self.value_to_primval(args[0])?.to_bytes()?;
268 let f = f32::from_bits(f as u32);
269 let f = match intrinsic_name {
271 "fabsf32" => f.abs(),
273 "sqrtf32" => f.sqrt(),
275 "exp2f32" => f.exp2(),
277 "log10f32" => f.log10(),
278 "log2f32" => f.log2(),
279 "floorf32" => f.floor(),
280 "ceilf32" => f.ceil(),
281 "truncf32" => f.trunc(),
284 self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?;
287 "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" |
288 "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => {
289 let f = self.value_to_primval(args[0])?.to_bytes()?;
290 let f = f64::from_bits(f as u64);
291 let f = match intrinsic_name {
293 "fabsf64" => f.abs(),
295 "sqrtf64" => f.sqrt(),
297 "exp2f64" => f.exp2(),
299 "log10f64" => f.log10(),
300 "log2f64" => f.log2(),
301 "floorf64" => f.floor(),
302 "ceilf64" => f.ceil(),
303 "truncf64" => f.trunc(),
306 self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?;
309 "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
310 let ty = substs.type_at(0);
311 let a = self.value_to_primval(args[0])?;
312 let b = self.value_to_primval(args[1])?;
313 let op = match intrinsic_name {
314 "fadd_fast" => mir::BinOp::Add,
315 "fsub_fast" => mir::BinOp::Sub,
316 "fmul_fast" => mir::BinOp::Mul,
317 "fdiv_fast" => mir::BinOp::Div,
318 "frem_fast" => mir::BinOp::Rem,
321 let result = self.binary_op(op, a, ty, b, ty)?;
322 self.write_primval(dest, result.0, dest_layout.ty)?;
325 "likely" | "unlikely" | "forget" => {}
328 let size = dest_layout.size.bytes();
329 let init = |this: &mut Self, val: Value| {
330 let zero_val = match val {
331 Value::ByRef(ptr, _) => {
332 // These writes have no alignment restriction anyway.
333 this.memory.write_repeat(ptr, 0, size)?;
336 // TODO(solson): Revisit this, it's fishy to check for Undef here.
337 Value::ByVal(PrimVal::Undef) => {
338 match this.ty_to_primval_kind(dest_layout.ty) {
339 Ok(_) => Value::ByVal(PrimVal::Bytes(0)),
341 // FIXME(oli-obk): pass TyLayout to alloc_ptr instead of Ty
342 let ptr = this.alloc_ptr(dest_layout.ty)?;
343 let ptr = Pointer::from(PrimVal::Ptr(ptr));
344 this.memory.write_repeat(ptr, 0, size)?;
345 Value::ByRef(ptr, dest_layout.align)
349 Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)),
350 Value::ByValPair(..) => {
351 Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0))
357 Place::Local { frame, local } => self.modify_local(frame, local, init)?,
361 extra: PlaceExtra::None,
362 } => self.memory.write_repeat(ptr, 0, size)?,
368 let elem_ty = substs.type_at(0);
369 let elem_align = self.layout_of(elem_ty)?.align.abi();
370 let align_val = PrimVal::from_u128(elem_align as u128);
371 self.write_primval(dest, align_val, dest_layout.ty)?;
375 let ty = substs.type_at(0);
376 let layout = self.layout_of(ty)?;
377 let align = layout.align.pref();
378 let align_val = PrimVal::from_u128(align as u128);
379 self.write_primval(dest, align_val, dest_layout.ty)?;
383 let ty = substs.type_at(0);
384 let ptr = self.into_ptr(args[0].value)?;
385 let align = self.layout_of(args[0].ty)?.align;
386 self.write_value_to_ptr(args[1].value, ptr, align, ty)?;
390 let ty = substs.type_at(0);
391 let env = ty::ParamEnv::reveal_all();
392 let needs_drop = ty.needs_drop(self.tcx.tcx, env);
395 PrimVal::from_bool(needs_drop),
401 let offset = self.value_to_primval(args[1])?.to_i128()? as i64;
402 let ptr = self.into_ptr(args[0].value)?;
403 let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
404 self.write_ptr(dest, result_ptr, dest_layout.ty)?;
407 "overflowing_sub" => {
408 self.intrinsic_overflowing(
417 "overflowing_mul" => {
418 self.intrinsic_overflowing(
427 "overflowing_add" => {
428 self.intrinsic_overflowing(
438 let f = self.value_to_primval(args[0])?.to_bytes()?;
439 let f = f32::from_bits(f as u32);
440 let f2 = self.value_to_primval(args[1])?.to_bytes()?;
441 let f2 = f32::from_bits(f2 as u32);
444 PrimVal::Bytes(f.powf(f2).to_bits() as u128),
450 let f = self.value_to_primval(args[0])?.to_bytes()?;
451 let f = f64::from_bits(f as u64);
452 let f2 = self.value_to_primval(args[1])?.to_bytes()?;
453 let f2 = f64::from_bits(f2 as u64);
456 PrimVal::Bytes(f.powf(f2).to_bits() as u128),
462 let a = self.value_to_primval(args[0])?.to_bytes()?;
463 let a = f32::from_bits(a as u32);
464 let b = self.value_to_primval(args[1])?.to_bytes()?;
465 let b = f32::from_bits(b as u32);
466 let c = self.value_to_primval(args[2])?.to_bytes()?;
467 let c = f32::from_bits(c as u32);
470 PrimVal::Bytes((a * b + c).to_bits() as u128),
476 let a = self.value_to_primval(args[0])?.to_bytes()?;
477 let a = f64::from_bits(a as u64);
478 let b = self.value_to_primval(args[1])?.to_bytes()?;
479 let b = f64::from_bits(b as u64);
480 let c = self.value_to_primval(args[2])?.to_bytes()?;
481 let c = f64::from_bits(c as u64);
484 PrimVal::Bytes((a * b + c).to_bits() as u128),
490 let f = self.value_to_primval(args[0])?.to_bytes()?;
491 let f = f32::from_bits(f as u32);
492 let i = self.value_to_primval(args[1])?.to_i128()?;
495 PrimVal::Bytes(f.powi(i as i32).to_bits() as u128),
501 let f = self.value_to_primval(args[0])?.to_bytes()?;
502 let f = f64::from_bits(f as u64);
503 let i = self.value_to_primval(args[1])?.to_i128()?;
506 PrimVal::Bytes(f.powi(i as i32).to_bits() as u128),
512 let ty = substs.type_at(0);
513 let size = self.layout_of(ty)?.size.bytes().into();
514 self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?;
518 let ty = substs.type_at(0);
519 let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?;
522 PrimVal::from_u128(size.bytes() as u128),
529 let ty = substs.type_at(0);
530 let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?;
533 PrimVal::from_u128(align.abi() as u128),
539 let ty = substs.type_at(0);
540 let ty_name = ty.to_string();
541 let value = self.str_to_value(&ty_name)?;
542 self.write_value(ValTy { value, ty: dest_layout.ty }, dest)?;
545 let ty = substs.type_at(0);
546 let n = self.tcx.type_id_hash(ty);
547 self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?;
551 let src_ty = substs.type_at(0);
552 let _src_align = self.layout_of(src_ty)?.align;
553 let ptr = self.force_allocation(dest)?.to_ptr()?;
554 let dest_align = self.layout_of(substs.type_at(1))?.align;
555 self.write_value_to_ptr(args[0].value, ptr.into(), dest_align, src_ty).unwrap();
559 let bits = dest_layout.size.bytes() as u128 * 8;
560 let rhs = self.value_to_primval(args[1])?
563 return err!(Intrinsic(
564 format!("Overflowing shift by {} in unchecked_shl", rhs),
567 self.intrinsic_overflowing(
577 let bits = dest_layout.size.bytes() as u128 * 8;
578 let rhs = self.value_to_primval(args[1])?
581 return err!(Intrinsic(
582 format!("Overflowing shift by {} in unchecked_shr", rhs),
585 self.intrinsic_overflowing(
595 let rhs = self.value_to_primval(args[1])?
598 return err!(Intrinsic(format!("Division by 0 in unchecked_div")));
600 self.intrinsic_overflowing(
610 let rhs = self.value_to_primval(args[1])?
613 return err!(Intrinsic(format!("Division by 0 in unchecked_rem")));
615 self.intrinsic_overflowing(
625 let size = dest_layout.size.bytes();
626 let uninit = |this: &mut Self, val: Value| match val {
627 Value::ByRef(ptr, _) => {
628 this.memory.mark_definedness(ptr, size, false)?;
631 _ => Ok(Value::ByVal(PrimVal::Undef)),
634 Place::Local { frame, local } => self.modify_local(frame, local, uninit)?,
638 extra: PlaceExtra::None,
639 } => self.memory.mark_definedness(ptr, size, false)?,
645 let ty = substs.type_at(0);
646 let ty_layout = self.layout_of(ty)?;
647 let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8;
648 let ptr = self.into_ptr(args[0].value)?;
649 let count = self.value_to_primval(args[2])?.to_u64()?;
651 // HashMap relies on write_bytes on a NULL ptr with count == 0 to work
652 // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic)
653 self.memory.check_align(ptr, ty_layout.align)?;
654 self.memory.write_repeat(ptr, val_byte, ty_layout.size.bytes() * count)?;
658 name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))),
661 self.goto_block(target);
663 // Since we pushed no stack frame, the main loop will act
664 // as if the call just completed and it's returning to the
670 fn numeric_intrinsic<'tcx>(
674 ) -> EvalResult<'tcx, PrimVal> {
675 macro_rules! integer_intrinsic {
676 ($method:ident) => ({
677 use rustc::mir::interpret::PrimValKind::*;
678 let result_bytes = match kind {
679 I8 => (bytes as i8).$method() as u128,
680 U8 => (bytes as u8).$method() as u128,
681 I16 => (bytes as i16).$method() as u128,
682 U16 => (bytes as u16).$method() as u128,
683 I32 => (bytes as i32).$method() as u128,
684 U32 => (bytes as u32).$method() as u128,
685 I64 => (bytes as i64).$method() as u128,
686 U64 => (bytes as u64).$method() as u128,
687 I128 => (bytes as i128).$method() as u128,
688 U128 => bytes.$method() as u128,
689 _ => bug!("invalid `{}` argument: {:?}", name, bytes),
692 PrimVal::Bytes(result_bytes)
696 let result_val = match name {
697 "bswap" => integer_intrinsic!(swap_bytes),
698 "ctlz" => integer_intrinsic!(leading_zeros),
699 "ctpop" => integer_intrinsic!(count_ones),
700 "cttz" => integer_intrinsic!(trailing_zeros),
701 _ => bug!("not a numeric intrinsic: {}", name),