]> git.lizzy.rs Git - rust.git/blob - miri/intrinsic.rs
Fix it
[rust.git] / miri / intrinsic.rs
1 use rustc::mir;
2 use rustc::ty::layout::{TyLayout, LayoutOf};
3 use rustc::ty;
4
5 use rustc::mir::interpret::{EvalResult, PrimVal, PrimValKind, Value, Pointer};
6 use rustc_mir::interpret::{Place, PlaceExtra, HasMemory, EvalContext, ValTy};
7
8 use helpers::EvalContextExt as HelperEvalContextExt;
9
10 pub trait EvalContextExt<'tcx> {
11     fn call_intrinsic(
12         &mut self,
13         instance: ty::Instance<'tcx>,
14         args: &[ValTy<'tcx>],
15         dest: Place,
16         dest_layout: TyLayout<'tcx>,
17         target: mir::BasicBlock,
18     ) -> EvalResult<'tcx>;
19 }
20
21 impl<'a, 'mir, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'mir, 'tcx, super::Evaluator<'tcx>> {
22     fn call_intrinsic(
23         &mut self,
24         instance: ty::Instance<'tcx>,
25         args: &[ValTy<'tcx>],
26         dest: Place,
27         dest_layout: TyLayout<'tcx>,
28         target: mir::BasicBlock,
29     ) -> EvalResult<'tcx> {
30         let substs = instance.substs;
31
32         let intrinsic_name = &self.tcx.item_name(instance.def_id())[..];
33         match intrinsic_name {
34             "align_offset" => {
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)?;
38             },
39
40             "add_with_overflow" => {
41                 self.intrinsic_with_overflow(
42                     mir::BinOp::Add,
43                     args[0],
44                     args[1],
45                     dest,
46                     dest_layout.ty,
47                 )?
48             }
49
50             "sub_with_overflow" => {
51                 self.intrinsic_with_overflow(
52                     mir::BinOp::Sub,
53                     args[0],
54                     args[1],
55                     dest,
56                     dest_layout.ty,
57                 )?
58             }
59
60             "mul_with_overflow" => {
61                 self.intrinsic_with_overflow(
62                     mir::BinOp::Mul,
63                     args[0],
64                     args[1],
65                     dest,
66                     dest_layout.ty,
67                 )?
68             }
69
70             "arith_offset" => {
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)?;
75             }
76
77             "assume" => {
78                 let cond = self.value_to_primval(args[0])?.to_bool()?;
79                 if !cond {
80                     return err!(AssumptionNotHeld);
81                 }
82             }
83
84             "atomic_load" |
85             "atomic_load_relaxed" |
86             "atomic_load_acq" |
87             "volatile_load" => {
88                 let ptr = self.into_ptr(args[0].value)?;
89                 let align = self.layout_of(args[0].ty)?.align;
90
91                 let valty = ValTy {
92                     value: Value::ByRef(ptr, align),
93                     ty: substs.type_at(0),
94                 };
95                 self.write_value(valty, dest)?;
96             }
97
98             "atomic_store" |
99             "atomic_store_relaxed" |
100             "atomic_store_rel" |
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)?;
106             }
107
108             "atomic_fence_acq" => {
109                 // we are inherently singlethreaded and singlecored, this is a nop
110             }
111
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"),
122                 };
123                 self.write_primval(dest, old, ty)?;
124                 self.write_primval(
125                     Place::from_primval_ptr(ptr, align),
126                     change,
127                     ty,
128                 )?;
129             }
130
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"),
142                 };
143                 let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
144                 let valty = ValTy {
145                     value: Value::ByValPair(old, val),
146                     ty: dest_layout.ty,
147                 };
148                 self.write_value(valty, dest)?;
149                 self.write_primval(
150                     Place::from_primval_ptr(ptr, dest_layout.align),
151                     change,
152                     ty,
153                 )?;
154             }
155
156             "atomic_or" |
157             "atomic_or_acq" |
158             "atomic_or_rel" |
159             "atomic_or_acqrel" |
160             "atomic_or_relaxed" |
161             "atomic_xor" |
162             "atomic_xor_acq" |
163             "atomic_xor_rel" |
164             "atomic_xor_acqrel" |
165             "atomic_xor_relaxed" |
166             "atomic_and" |
167             "atomic_and_acq" |
168             "atomic_and_rel" |
169             "atomic_and_acqrel" |
170             "atomic_and_relaxed" |
171             "atomic_xadd" |
172             "atomic_xadd_acq" |
173             "atomic_xadd_rel" |
174             "atomic_xadd_acqrel" |
175             "atomic_xadd_relaxed" |
176             "atomic_xsub" |
177             "atomic_xsub_acq" |
178             "atomic_xsub_rel" |
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")
191                     }
192                 };
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,
200                     _ => bug!(),
201                 };
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)?;
205             }
206
207             "breakpoint" => unimplemented!(), // halt miri
208
209             "copy" |
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: {:?}",
224                         args[0].ty,
225                         src_align.abi(),
226                         elem_align.abi(),
227                         self.memory.check_align(src, src_align),
228                         self.memory.check_align(dest, elem_align)
229                     ));*/
230                     self.memory.copy(
231                         src,
232                         elem_align,
233                         dest,
234                         elem_align,
235                         count * elem_size,
236                         intrinsic_name.ends_with("_nonoverlapping"),
237                     )?;
238                 }
239             }
240
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") {
246                     if num == 0 {
247                         return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
248                     }
249                     numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), num, kind)?
250                 } else {
251                     numeric_intrinsic(intrinsic_name, num, kind)?
252                 };
253                 self.write_primval(dest, num, ty)?;
254             }
255
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)?;
263             }
264
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 {
270                     "sinf32" => f.sin(),
271                     "fabsf32" => f.abs(),
272                     "cosf32" => f.cos(),
273                     "sqrtf32" => f.sqrt(),
274                     "expf32" => f.exp(),
275                     "exp2f32" => f.exp2(),
276                     "logf32" => f.ln(),
277                     "log10f32" => f.log10(),
278                     "log2f32" => f.log2(),
279                     "floorf32" => f.floor(),
280                     "ceilf32" => f.ceil(),
281                     "truncf32" => f.trunc(),
282                     _ => bug!(),
283                 };
284                 self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?;
285             }
286
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 {
292                     "sinf64" => f.sin(),
293                     "fabsf64" => f.abs(),
294                     "cosf64" => f.cos(),
295                     "sqrtf64" => f.sqrt(),
296                     "expf64" => f.exp(),
297                     "exp2f64" => f.exp2(),
298                     "logf64" => f.ln(),
299                     "log10f64" => f.log10(),
300                     "log2f64" => f.log2(),
301                     "floorf64" => f.floor(),
302                     "ceilf64" => f.ceil(),
303                     "truncf64" => f.trunc(),
304                     _ => bug!(),
305                 };
306                 self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?;
307             }
308
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,
319                     _ => bug!(),
320                 };
321                 let result = self.binary_op(op, a, ty, b, ty)?;
322                 self.write_primval(dest, result.0, dest_layout.ty)?;
323             }
324
325             "likely" | "unlikely" | "forget" => {}
326
327             "init" => {
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)?;
334                             val
335                         }
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)),
340                                 Err(_) => {
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)
346                                 }
347                             }
348                         }
349                         Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)),
350                         Value::ByValPair(..) => {
351                             Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0))
352                         }
353                     };
354                     Ok(zero_val)
355                 };
356                 match dest {
357                     Place::Local { frame, local } => self.modify_local(frame, local, init)?,
358                     Place::Ptr {
359                         ptr,
360                         align: _align,
361                         extra: PlaceExtra::None,
362                     } => self.memory.write_repeat(ptr, 0, size)?,
363                     _ => bug!("TODO"),
364                 }
365             }
366
367             "min_align_of" => {
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)?;
372             }
373
374             "pref_align_of" => {
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)?;
380             }
381
382             "move_val_init" => {
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)?;
387             }
388
389             "needs_drop" => {
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);
393                 self.write_primval(
394                     dest,
395                     PrimVal::from_bool(needs_drop),
396                     dest_layout.ty,
397                 )?;
398             }
399
400             "offset" => {
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)?;
405             }
406
407             "overflowing_sub" => {
408                 self.intrinsic_overflowing(
409                     mir::BinOp::Sub,
410                     args[0],
411                     args[1],
412                     dest,
413                     dest_layout.ty,
414                 )?;
415             }
416
417             "overflowing_mul" => {
418                 self.intrinsic_overflowing(
419                     mir::BinOp::Mul,
420                     args[0],
421                     args[1],
422                     dest,
423                     dest_layout.ty,
424                 )?;
425             }
426
427             "overflowing_add" => {
428                 self.intrinsic_overflowing(
429                     mir::BinOp::Add,
430                     args[0],
431                     args[1],
432                     dest,
433                     dest_layout.ty,
434                 )?;
435             }
436
437             "powf32" => {
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);
442                 self.write_primval(
443                     dest,
444                     PrimVal::Bytes(f.powf(f2).to_bits() as u128),
445                     dest_layout.ty,
446                 )?;
447             }
448
449             "powf64" => {
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);
454                 self.write_primval(
455                     dest,
456                     PrimVal::Bytes(f.powf(f2).to_bits() as u128),
457                     dest_layout.ty,
458                 )?;
459             }
460
461             "fmaf32" => {
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);
468                 self.write_primval(
469                     dest,
470                     PrimVal::Bytes((a * b + c).to_bits() as u128),
471                     dest_layout.ty,
472                 )?;
473             }
474
475             "fmaf64" => {
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);
482                 self.write_primval(
483                     dest,
484                     PrimVal::Bytes((a * b + c).to_bits() as u128),
485                     dest_layout.ty,
486                 )?;
487             }
488
489             "powif32" => {
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()?;
493                 self.write_primval(
494                     dest,
495                     PrimVal::Bytes(f.powi(i as i32).to_bits() as u128),
496                     dest_layout.ty,
497                 )?;
498             }
499
500             "powif64" => {
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()?;
504                 self.write_primval(
505                     dest,
506                     PrimVal::Bytes(f.powi(i as i32).to_bits() as u128),
507                     dest_layout.ty,
508                 )?;
509             }
510
511             "size_of" => {
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)?;
515             }
516
517             "size_of_val" => {
518                 let ty = substs.type_at(0);
519                 let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?;
520                 self.write_primval(
521                     dest,
522                     PrimVal::from_u128(size.bytes() as u128),
523                     dest_layout.ty,
524                 )?;
525             }
526
527             "min_align_of_val" |
528             "align_of_val" => {
529                 let ty = substs.type_at(0);
530                 let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?;
531                 self.write_primval(
532                     dest,
533                     PrimVal::from_u128(align.abi() as u128),
534                     dest_layout.ty,
535                 )?;
536             }
537
538             "type_name" => {
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)?;
543             }
544             "type_id" => {
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)?;
548             }
549
550             "transmute" => {
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();
556             }
557
558             "unchecked_shl" => {
559                 let bits = dest_layout.size.bytes() as u128 * 8;
560                 let rhs = self.value_to_primval(args[1])?
561                     .to_bytes()?;
562                 if rhs >= bits {
563                     return err!(Intrinsic(
564                         format!("Overflowing shift by {} in unchecked_shl", rhs),
565                     ));
566                 }
567                 self.intrinsic_overflowing(
568                     mir::BinOp::Shl,
569                     args[0],
570                     args[1],
571                     dest,
572                     dest_layout.ty,
573                 )?;
574             }
575
576             "unchecked_shr" => {
577                 let bits = dest_layout.size.bytes() as u128 * 8;
578                 let rhs = self.value_to_primval(args[1])?
579                     .to_bytes()?;
580                 if rhs >= bits {
581                     return err!(Intrinsic(
582                         format!("Overflowing shift by {} in unchecked_shr", rhs),
583                     ));
584                 }
585                 self.intrinsic_overflowing(
586                     mir::BinOp::Shr,
587                     args[0],
588                     args[1],
589                     dest,
590                     dest_layout.ty,
591                 )?;
592             }
593
594             "unchecked_div" => {
595                 let rhs = self.value_to_primval(args[1])?
596                     .to_bytes()?;
597                 if rhs == 0 {
598                     return err!(Intrinsic(format!("Division by 0 in unchecked_div")));
599                 }
600                 self.intrinsic_overflowing(
601                     mir::BinOp::Div,
602                     args[0],
603                     args[1],
604                     dest,
605                     dest_layout.ty,
606                 )?;
607             }
608
609             "unchecked_rem" => {
610                 let rhs = self.value_to_primval(args[1])?
611                     .to_bytes()?;
612                 if rhs == 0 {
613                     return err!(Intrinsic(format!("Division by 0 in unchecked_rem")));
614                 }
615                 self.intrinsic_overflowing(
616                     mir::BinOp::Rem,
617                     args[0],
618                     args[1],
619                     dest,
620                     dest_layout.ty,
621                 )?;
622             }
623
624             "uninit" => {
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)?;
629                         Ok(val)
630                     }
631                     _ => Ok(Value::ByVal(PrimVal::Undef)),
632                 };
633                 match dest {
634                     Place::Local { frame, local } => self.modify_local(frame, local, uninit)?,
635                     Place::Ptr {
636                         ptr,
637                         align: _align,
638                         extra: PlaceExtra::None,
639                     } => self.memory.mark_definedness(ptr, size, false)?,
640                     _ => bug!("todo"),
641                 }
642             }
643
644             "write_bytes" => {
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()?;
650                 if count > 0 {
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)?;
655                 }
656             }
657
658             name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))),
659         }
660
661         self.goto_block(target);
662
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
665         // current frame.
666         Ok(())
667     }
668 }
669
670 fn numeric_intrinsic<'tcx>(
671     name: &str,
672     bytes: u128,
673     kind: PrimValKind,
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),
690             };
691
692             PrimVal::Bytes(result_bytes)
693         });
694     }
695
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),
702     };
703
704     Ok(result_val)
705 }