]> git.lizzy.rs Git - rust.git/blob - miri/intrinsic.rs
Use correct alignment
[rust.git] / miri / intrinsic.rs
1 use rustc::mir;
2 use rustc::traits::Reveal;
3 use rustc::ty::layout::TyLayout;
4 use rustc::ty;
5
6 use rustc::mir::interpret::{EvalResult, Lvalue, LvalueExtra, PrimVal, PrimValKind, Value, Pointer,
7                             HasMemory, AccessKind, EvalContext, PtrAndAlign, ValTy};
8
9 use helpers::EvalContextExt as HelperEvalContextExt;
10
11 pub trait EvalContextExt<'tcx> {
12     fn call_intrinsic(
13         &mut self,
14         instance: ty::Instance<'tcx>,
15         args: &[ValTy<'tcx>],
16         dest: Lvalue,
17         dest_layout: TyLayout<'tcx>,
18         target: mir::BasicBlock,
19     ) -> EvalResult<'tcx>;
20 }
21
22 impl<'a, 'tcx> EvalContextExt<'tcx> for EvalContext<'a, 'tcx, super::Evaluator> {
23     fn call_intrinsic(
24         &mut self,
25         instance: ty::Instance<'tcx>,
26         args: &[ValTy<'tcx>],
27         dest: Lvalue,
28         dest_layout: TyLayout<'tcx>,
29         target: mir::BasicBlock,
30     ) -> EvalResult<'tcx> {
31         let substs = instance.substs;
32
33         let intrinsic_name = &self.tcx.item_name(instance.def_id())[..];
34         match intrinsic_name {
35             "align_offset" => {
36                 // FIXME: return a real value in case the target allocation has an
37                 // alignment bigger than the one requested
38                 self.write_primval(dest, PrimVal::Bytes(u128::max_value()), dest_layout.ty)?;
39             },
40
41             "add_with_overflow" => {
42                 self.intrinsic_with_overflow(
43                     mir::BinOp::Add,
44                     args[0],
45                     args[1],
46                     dest,
47                     dest_layout.ty,
48                 )?
49             }
50
51             "sub_with_overflow" => {
52                 self.intrinsic_with_overflow(
53                     mir::BinOp::Sub,
54                     args[0],
55                     args[1],
56                     dest,
57                     dest_layout.ty,
58                 )?
59             }
60
61             "mul_with_overflow" => {
62                 self.intrinsic_with_overflow(
63                     mir::BinOp::Mul,
64                     args[0],
65                     args[1],
66                     dest,
67                     dest_layout.ty,
68                 )?
69             }
70
71             "arith_offset" => {
72                 let offset = self.value_to_primval(args[1])?.to_i128()? as i64;
73                 let ptr = args[0].into_ptr(&self.memory)?;
74                 let result_ptr = self.wrapping_pointer_offset(ptr, substs.type_at(0), offset)?;
75                 self.write_ptr(dest, result_ptr, dest_layout.ty)?;
76             }
77
78             "assume" => {
79                 let cond = self.value_to_primval(args[0])?.to_bool()?;
80                 if !cond {
81                     return err!(AssumptionNotHeld);
82                 }
83             }
84
85             "atomic_load" |
86             "atomic_load_relaxed" |
87             "atomic_load_acq" |
88             "volatile_load" => {
89                 let ptr = args[0].into_ptr(&self.memory)?;
90                 let valty = ValTy {
91                     value: Value::by_ref(ptr),
92                     ty: substs.type_at(0),
93                 };
94                 self.write_value(valty, dest)?;
95             }
96
97             "atomic_store" |
98             "atomic_store_relaxed" |
99             "atomic_store_rel" |
100             "volatile_store" => {
101                 let ty = substs.type_at(0);
102                 let dest = args[0].into_ptr(&self.memory)?;
103                 self.write_value_to_ptr(args[1].value, dest, ty)?;
104             }
105
106             "atomic_fence_acq" => {
107                 // we are inherently singlethreaded and singlecored, this is a nop
108             }
109
110             _ if intrinsic_name.starts_with("atomic_xchg") => {
111                 let ty = substs.type_at(0);
112                 let ptr = args[0].into_ptr(&self.memory)?;
113                 let change = self.value_to_primval(args[1])?;
114                 let old = self.read_value(ptr, ty)?;
115                 let old = match old {
116                     Value::ByVal(val) => val,
117                     Value::ByRef { .. } => bug!("just read the value, can't be byref"),
118                     Value::ByValPair(..) => bug!("atomic_xchg doesn't work with nonprimitives"),
119                 };
120                 self.write_primval(dest, old, ty)?;
121                 self.write_primval(
122                     Lvalue::from_primval_ptr(ptr),
123                     change,
124                     ty,
125                 )?;
126             }
127
128             _ if intrinsic_name.starts_with("atomic_cxchg") => {
129                 let ty = substs.type_at(0);
130                 let ptr = args[0].into_ptr(&self.memory)?;
131                 let expect_old = self.value_to_primval(args[1])?;
132                 let change = self.value_to_primval(args[2])?;
133                 let old = self.read_value(ptr, ty)?;
134                 let old = match old {
135                     Value::ByVal(val) => val,
136                     Value::ByRef { .. } => bug!("just read the value, can't be byref"),
137                     Value::ByValPair(..) => bug!("atomic_cxchg doesn't work with nonprimitives"),
138                 };
139                 let (val, _) = self.binary_op(mir::BinOp::Eq, old, ty, expect_old, ty)?;
140                 let valty = ValTy {
141                     value: Value::ByValPair(old, val),
142                     ty: dest_layout.ty,
143                 };
144                 self.write_value(valty, dest)?;
145                 self.write_primval(
146                     Lvalue::from_primval_ptr(ptr),
147                     change,
148                     ty,
149                 )?;
150             }
151
152             "atomic_or" |
153             "atomic_or_acq" |
154             "atomic_or_rel" |
155             "atomic_or_acqrel" |
156             "atomic_or_relaxed" |
157             "atomic_xor" |
158             "atomic_xor_acq" |
159             "atomic_xor_rel" |
160             "atomic_xor_acqrel" |
161             "atomic_xor_relaxed" |
162             "atomic_and" |
163             "atomic_and_acq" |
164             "atomic_and_rel" |
165             "atomic_and_acqrel" |
166             "atomic_and_relaxed" |
167             "atomic_xadd" |
168             "atomic_xadd_acq" |
169             "atomic_xadd_rel" |
170             "atomic_xadd_acqrel" |
171             "atomic_xadd_relaxed" |
172             "atomic_xsub" |
173             "atomic_xsub_acq" |
174             "atomic_xsub_rel" |
175             "atomic_xsub_acqrel" |
176             "atomic_xsub_relaxed" => {
177                 let ty = substs.type_at(0);
178                 let ptr = args[0].into_ptr(&self.memory)?;
179                 let change = self.value_to_primval(args[1])?;
180                 let old = self.read_value(ptr, ty)?;
181                 let old = match old {
182                     Value::ByVal(val) => val,
183                     Value::ByRef { .. } => bug!("just read the value, can't be byref"),
184                     Value::ByValPair(..) => {
185                         bug!("atomic_xadd_relaxed doesn't work with nonprimitives")
186                     }
187                 };
188                 self.write_primval(dest, old, ty)?;
189                 let op = match intrinsic_name.split('_').nth(1).unwrap() {
190                     "or" => mir::BinOp::BitOr,
191                     "xor" => mir::BinOp::BitXor,
192                     "and" => mir::BinOp::BitAnd,
193                     "xadd" => mir::BinOp::Add,
194                     "xsub" => mir::BinOp::Sub,
195                     _ => bug!(),
196                 };
197                 // FIXME: what do atomics do on overflow?
198                 let (val, _) = self.binary_op(op, old, ty, change, ty)?;
199                 self.write_primval(Lvalue::from_primval_ptr(ptr), val, ty)?;
200             }
201
202             "breakpoint" => unimplemented!(), // halt miri
203
204             "copy" |
205             "copy_nonoverlapping" => {
206                 let elem_ty = substs.type_at(0);
207                 let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value");
208                 let count = self.value_to_primval(args[2])?.to_u64()?;
209                 if count * elem_size != 0 {
210                     // TODO: We do not even validate alignment for the 0-bytes case.  libstd relies on this in vec::IntoIter::next.
211                     // Also see the write_bytes intrinsic.
212                     let elem_align = self.type_align(elem_ty)?;
213                     let src = args[0].into_ptr(&self.memory)?;
214                     let dest = args[1].into_ptr(&self.memory)?;
215                     self.memory.copy(
216                         src,
217                         dest,
218                         count * elem_size,
219                         elem_align,
220                         intrinsic_name.ends_with("_nonoverlapping"),
221                     )?;
222                 }
223             }
224
225             "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
226                 let ty = substs.type_at(0);
227                 let num = self.value_to_primval(args[0])?.to_bytes()?;
228                 let kind = self.ty_to_primval_kind(ty)?;
229                 let num = if intrinsic_name.ends_with("_nonzero") {
230                     if num == 0 {
231                         return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
232                     }
233                     numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), num, kind)?
234                 } else {
235                     numeric_intrinsic(intrinsic_name, num, kind)?
236                 };
237                 self.write_primval(dest, num, ty)?;
238             }
239
240             "discriminant_value" => {
241                 let ty = substs.type_at(0);
242                 let adt_ptr = args[0].into_ptr(&self.memory)?;
243                 let lval = Lvalue::from_primval_ptr(adt_ptr);
244                 let discr_val = self.read_discriminant_value(lval, ty)?;
245                 self.write_primval(dest, PrimVal::Bytes(discr_val), dest_layout.ty)?;
246             }
247
248             "sinf32" | "fabsf32" | "cosf32" | "sqrtf32" | "expf32" | "exp2f32" | "logf32" |
249             "log10f32" | "log2f32" | "floorf32" | "ceilf32" | "truncf32" => {
250                 let f = self.value_to_primval(args[0])?.to_bytes()?;
251                 let f = f32::from_bits(f as u32);
252                 let f = match intrinsic_name {
253                     "sinf32" => f.sin(),
254                     "fabsf32" => f.abs(),
255                     "cosf32" => f.cos(),
256                     "sqrtf32" => f.sqrt(),
257                     "expf32" => f.exp(),
258                     "exp2f32" => f.exp2(),
259                     "logf32" => f.ln(),
260                     "log10f32" => f.log10(),
261                     "log2f32" => f.log2(),
262                     "floorf32" => f.floor(),
263                     "ceilf32" => f.ceil(),
264                     "truncf32" => f.trunc(),
265                     _ => bug!(),
266                 };
267                 self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?;
268             }
269
270             "sinf64" | "fabsf64" | "cosf64" | "sqrtf64" | "expf64" | "exp2f64" | "logf64" |
271             "log10f64" | "log2f64" | "floorf64" | "ceilf64" | "truncf64" => {
272                 let f = self.value_to_primval(args[0])?.to_bytes()?;
273                 let f = f64::from_bits(f as u64);
274                 let f = match intrinsic_name {
275                     "sinf64" => f.sin(),
276                     "fabsf64" => f.abs(),
277                     "cosf64" => f.cos(),
278                     "sqrtf64" => f.sqrt(),
279                     "expf64" => f.exp(),
280                     "exp2f64" => f.exp2(),
281                     "logf64" => f.ln(),
282                     "log10f64" => f.log10(),
283                     "log2f64" => f.log2(),
284                     "floorf64" => f.floor(),
285                     "ceilf64" => f.ceil(),
286                     "truncf64" => f.trunc(),
287                     _ => bug!(),
288                 };
289                 self.write_primval(dest, PrimVal::Bytes(f.to_bits() as u128), dest_layout.ty)?;
290             }
291
292             "fadd_fast" | "fsub_fast" | "fmul_fast" | "fdiv_fast" | "frem_fast" => {
293                 let ty = substs.type_at(0);
294                 let a = self.value_to_primval(args[0])?;
295                 let b = self.value_to_primval(args[1])?;
296                 let op = match intrinsic_name {
297                     "fadd_fast" => mir::BinOp::Add,
298                     "fsub_fast" => mir::BinOp::Sub,
299                     "fmul_fast" => mir::BinOp::Mul,
300                     "fdiv_fast" => mir::BinOp::Div,
301                     "frem_fast" => mir::BinOp::Rem,
302                     _ => bug!(),
303                 };
304                 let result = self.binary_op(op, a, ty, b, ty)?;
305                 self.write_primval(dest, result.0, dest_layout.ty)?;
306             }
307
308             "likely" | "unlikely" | "forget" => {}
309
310             "init" => {
311                 let size = self.type_size(dest_layout.ty)?.expect("cannot zero unsized value");
312                 let init = |this: &mut Self, val: Value| {
313                     let zero_val = match val {
314                         Value::ByRef(PtrAndAlign { ptr, .. }) => {
315                             // These writes have no alignment restriction anyway.
316                             this.memory.write_repeat(ptr, 0, size)?;
317                             val
318                         }
319                         // TODO(solson): Revisit this, it's fishy to check for Undef here.
320                         Value::ByVal(PrimVal::Undef) => {
321                             match this.ty_to_primval_kind(dest_layout.ty) {
322                                 Ok(_) => Value::ByVal(PrimVal::Bytes(0)),
323                                 Err(_) => {
324                                     let ptr = this.alloc_ptr_with_substs(dest_layout.ty, substs)?;
325                                     let ptr = Pointer::from(PrimVal::Ptr(ptr));
326                                     this.memory.write_repeat(ptr, 0, size)?;
327                                     Value::by_ref(ptr)
328                                 }
329                             }
330                         }
331                         Value::ByVal(_) => Value::ByVal(PrimVal::Bytes(0)),
332                         Value::ByValPair(..) => {
333                             Value::ByValPair(PrimVal::Bytes(0), PrimVal::Bytes(0))
334                         }
335                     };
336                     Ok(zero_val)
337                 };
338                 match dest {
339                     Lvalue::Local { frame, local } => self.modify_local(frame, local, init)?,
340                     Lvalue::Ptr {
341                         ptr: PtrAndAlign { ptr, aligned: true },
342                         extra: LvalueExtra::None,
343                     } => self.memory.write_repeat(ptr, 0, size)?,
344                     Lvalue::Ptr { .. } => {
345                         bug!("init intrinsic tried to write to fat or unaligned ptr target")
346                     }
347                 }
348             }
349
350             "min_align_of" => {
351                 let elem_ty = substs.type_at(0);
352                 let elem_align = self.type_align(elem_ty)?;
353                 let align_val = PrimVal::from_u128(elem_align as u128);
354                 self.write_primval(dest, align_val, dest_layout.ty)?;
355             }
356
357             "pref_align_of" => {
358                 let ty = substs.type_at(0);
359                 let layout = self.type_layout(ty)?;
360                 let align = layout.align.pref();
361                 let align_val = PrimVal::from_u128(align as u128);
362                 self.write_primval(dest, align_val, dest_layout.ty)?;
363             }
364
365             "move_val_init" => {
366                 let ty = substs.type_at(0);
367                 let ptr = args[0].into_ptr(&self.memory)?;
368                 self.write_value_to_ptr(args[1].value, ptr, ty)?;
369             }
370
371             "needs_drop" => {
372                 let ty = substs.type_at(0);
373                 let env = ty::ParamEnv::empty(Reveal::All);
374                 let needs_drop = ty.needs_drop(self.tcx, env);
375                 self.write_primval(
376                     dest,
377                     PrimVal::from_bool(needs_drop),
378                     dest_layout.ty,
379                 )?;
380             }
381
382             "offset" => {
383                 let offset = self.value_to_primval(args[1])?.to_i128()? as i64;
384                 let ptr = args[0].into_ptr(&self.memory)?;
385                 let result_ptr = self.pointer_offset(ptr, substs.type_at(0), offset)?;
386                 self.write_ptr(dest, result_ptr, dest_layout.ty)?;
387             }
388
389             "overflowing_sub" => {
390                 self.intrinsic_overflowing(
391                     mir::BinOp::Sub,
392                     args[0],
393                     args[1],
394                     dest,
395                     dest_layout.ty,
396                 )?;
397             }
398
399             "overflowing_mul" => {
400                 self.intrinsic_overflowing(
401                     mir::BinOp::Mul,
402                     args[0],
403                     args[1],
404                     dest,
405                     dest_layout.ty,
406                 )?;
407             }
408
409             "overflowing_add" => {
410                 self.intrinsic_overflowing(
411                     mir::BinOp::Add,
412                     args[0],
413                     args[1],
414                     dest,
415                     dest_layout.ty,
416                 )?;
417             }
418
419             "powf32" => {
420                 let f = self.value_to_primval(args[0])?.to_bytes()?;
421                 let f = f32::from_bits(f as u32);
422                 let f2 = self.value_to_primval(args[1])?.to_bytes()?;
423                 let f2 = f32::from_bits(f2 as u32);
424                 self.write_primval(
425                     dest,
426                     PrimVal::Bytes(f.powf(f2).to_bits() as u128),
427                     dest_layout.ty,
428                 )?;
429             }
430
431             "powf64" => {
432                 let f = self.value_to_primval(args[0])?.to_bytes()?;
433                 let f = f64::from_bits(f as u64);
434                 let f2 = self.value_to_primval(args[1])?.to_bytes()?;
435                 let f2 = f64::from_bits(f2 as u64);
436                 self.write_primval(
437                     dest,
438                     PrimVal::Bytes(f.powf(f2).to_bits() as u128),
439                     dest_layout.ty,
440                 )?;
441             }
442
443             "fmaf32" => {
444                 let a = self.value_to_primval(args[0])?.to_bytes()?;
445                 let a = f32::from_bits(a as u32);
446                 let b = self.value_to_primval(args[1])?.to_bytes()?;
447                 let b = f32::from_bits(b as u32);
448                 let c = self.value_to_primval(args[2])?.to_bytes()?;
449                 let c = f32::from_bits(c as u32);
450                 self.write_primval(
451                     dest,
452                     PrimVal::Bytes((a * b + c).to_bits() as u128),
453                     dest_layout.ty,
454                 )?;
455             }
456
457             "fmaf64" => {
458                 let a = self.value_to_primval(args[0])?.to_bytes()?;
459                 let a = f64::from_bits(a as u64);
460                 let b = self.value_to_primval(args[1])?.to_bytes()?;
461                 let b = f64::from_bits(b as u64);
462                 let c = self.value_to_primval(args[2])?.to_bytes()?;
463                 let c = f64::from_bits(c as u64);
464                 self.write_primval(
465                     dest,
466                     PrimVal::Bytes((a * b + c).to_bits() as u128),
467                     dest_layout.ty,
468                 )?;
469             }
470
471             "powif32" => {
472                 let f = self.value_to_primval(args[0])?.to_bytes()?;
473                 let f = f32::from_bits(f as u32);
474                 let i = self.value_to_primval(args[1])?.to_i128()?;
475                 self.write_primval(
476                     dest,
477                     PrimVal::Bytes(f.powi(i as i32).to_bits() as u128),
478                     dest_layout.ty,
479                 )?;
480             }
481
482             "powif64" => {
483                 let f = self.value_to_primval(args[0])?.to_bytes()?;
484                 let f = f64::from_bits(f as u64);
485                 let i = self.value_to_primval(args[1])?.to_i128()?;
486                 self.write_primval(
487                     dest,
488                     PrimVal::Bytes(f.powi(i as i32).to_bits() as u128),
489                     dest_layout.ty,
490                 )?;
491             }
492
493             "size_of" => {
494                 let ty = substs.type_at(0);
495                 let size = self.type_size(ty)?.expect(
496                     "size_of intrinsic called on unsized value",
497                 ) as u128;
498                 self.write_primval(dest, PrimVal::from_u128(size), dest_layout.ty)?;
499             }
500
501             "size_of_val" => {
502                 let ty = substs.type_at(0);
503                 let (size, _) = self.size_and_align_of_dst(ty, args[0].value)?;
504                 self.write_primval(
505                     dest,
506                     PrimVal::from_u128(size.bytes() as u128),
507                     dest_layout.ty,
508                 )?;
509             }
510
511             "min_align_of_val" |
512             "align_of_val" => {
513                 let ty = substs.type_at(0);
514                 let (_, align) = self.size_and_align_of_dst(ty, args[0].value)?;
515                 self.write_primval(
516                     dest,
517                     PrimVal::from_u128(align.abi() as u128),
518                     dest_layout.ty,
519                 )?;
520             }
521
522             "type_name" => {
523                 let ty = substs.type_at(0);
524                 let ty_name = ty.to_string();
525                 let value = self.str_to_value(&ty_name)?;
526                 self.write_value(ValTy { value, ty: dest_layout.ty }, dest)?;
527             }
528             "type_id" => {
529                 let ty = substs.type_at(0);
530                 let n = self.tcx.type_id_hash(ty);
531                 self.write_primval(dest, PrimVal::Bytes(n as u128), dest_layout.ty)?;
532             }
533
534             "transmute" => {
535                 let src_ty = substs.type_at(0);
536                 let ptr = self.force_allocation(dest)?.to_ptr()?;
537                 self.write_maybe_aligned_mut(
538                     /*aligned*/
539                     false,
540                     |ectx| {
541                         ectx.write_value_to_ptr(args[0].value, ptr.into(), src_ty)
542                     },
543                 )?;
544             }
545
546             "unchecked_shl" => {
547                 let bits = self.type_size(dest_layout.ty)?.expect(
548                     "intrinsic can't be called on unsized type",
549                 ) as u128 * 8;
550                 let rhs = self.value_to_primval(args[1])?
551                     .to_bytes()?;
552                 if rhs >= bits {
553                     return err!(Intrinsic(
554                         format!("Overflowing shift by {} in unchecked_shl", rhs),
555                     ));
556                 }
557                 self.intrinsic_overflowing(
558                     mir::BinOp::Shl,
559                     args[0],
560                     args[1],
561                     dest,
562                     dest_layout.ty,
563                 )?;
564             }
565
566             "unchecked_shr" => {
567                 let bits = self.type_size(dest_layout.ty)?.expect(
568                     "intrinsic can't be called on unsized type",
569                 ) as u128 * 8;
570                 let rhs = self.value_to_primval(args[1])?
571                     .to_bytes()?;
572                 if rhs >= bits {
573                     return err!(Intrinsic(
574                         format!("Overflowing shift by {} in unchecked_shr", rhs),
575                     ));
576                 }
577                 self.intrinsic_overflowing(
578                     mir::BinOp::Shr,
579                     args[0],
580                     args[1],
581                     dest,
582                     dest_layout.ty,
583                 )?;
584             }
585
586             "unchecked_div" => {
587                 let rhs = self.value_to_primval(args[1])?
588                     .to_bytes()?;
589                 if rhs == 0 {
590                     return err!(Intrinsic(format!("Division by 0 in unchecked_div")));
591                 }
592                 self.intrinsic_overflowing(
593                     mir::BinOp::Div,
594                     args[0],
595                     args[1],
596                     dest,
597                     dest_layout.ty,
598                 )?;
599             }
600
601             "unchecked_rem" => {
602                 let rhs = self.value_to_primval(args[1])?
603                     .to_bytes()?;
604                 if rhs == 0 {
605                     return err!(Intrinsic(format!("Division by 0 in unchecked_rem")));
606                 }
607                 self.intrinsic_overflowing(
608                     mir::BinOp::Rem,
609                     args[0],
610                     args[1],
611                     dest,
612                     dest_layout.ty,
613                 )?;
614             }
615
616             "uninit" => {
617                 let size = dest_layout.size.bytes();
618                 let uninit = |this: &mut Self, val: Value| match val {
619                     Value::ByRef(PtrAndAlign { ptr, .. }) => {
620                         this.memory.mark_definedness(ptr, size, false)?;
621                         Ok(val)
622                     }
623                     _ => Ok(Value::ByVal(PrimVal::Undef)),
624                 };
625                 match dest {
626                     Lvalue::Local { frame, local } => self.modify_local(frame, local, uninit)?,
627                     Lvalue::Ptr {
628                         ptr: PtrAndAlign { ptr, aligned: true },
629                         extra: LvalueExtra::None,
630                     } => self.memory.mark_definedness(ptr, size, false)?,
631                     Lvalue::Ptr { .. } => {
632                         bug!("uninit intrinsic tried to write to fat or unaligned ptr target")
633                     }
634                 }
635             }
636
637             "write_bytes" => {
638                 let ty = substs.type_at(0);
639                 let ty_align = self.type_align(ty)?;
640                 let val_byte = self.value_to_primval(args[1])?.to_u128()? as u8;
641                 let size = self.type_size(ty)?.expect(
642                     "write_bytes() type must be sized",
643                 );
644                 let ptr = args[0].into_ptr(&self.memory)?;
645                 let count = self.value_to_primval(args[2])?.to_u64()?;
646                 if count > 0 {
647                     // HashMap relies on write_bytes on a NULL ptr with count == 0 to work
648                     // TODO: Should we, at least, validate the alignment? (Also see the copy intrinsic)
649                     self.memory.check_align(ptr, ty_align, Some(AccessKind::Write))?;
650                     self.memory.write_repeat(ptr, val_byte, size * count)?;
651                 }
652             }
653
654             name => return err!(Unimplemented(format!("unimplemented intrinsic: {}", name))),
655         }
656
657         self.goto_block(target);
658
659         // Since we pushed no stack frame, the main loop will act
660         // as if the call just completed and it's returning to the
661         // current frame.
662         Ok(())
663     }
664 }
665
666 fn numeric_intrinsic<'tcx>(
667     name: &str,
668     bytes: u128,
669     kind: PrimValKind,
670 ) -> EvalResult<'tcx, PrimVal> {
671     macro_rules! integer_intrinsic {
672         ($method:ident) => ({
673             use rustc::mir::interpret::PrimValKind::*;
674             let result_bytes = match kind {
675                 I8 => (bytes as i8).$method() as u128,
676                 U8 => (bytes as u8).$method() as u128,
677                 I16 => (bytes as i16).$method() as u128,
678                 U16 => (bytes as u16).$method() as u128,
679                 I32 => (bytes as i32).$method() as u128,
680                 U32 => (bytes as u32).$method() as u128,
681                 I64 => (bytes as i64).$method() as u128,
682                 U64 => (bytes as u64).$method() as u128,
683                 I128 => (bytes as i128).$method() as u128,
684                 U128 => bytes.$method() as u128,
685                 _ => bug!("invalid `{}` argument: {:?}", name, bytes),
686             };
687
688             PrimVal::Bytes(result_bytes)
689         });
690     }
691
692     let result_val = match name {
693         "bswap" => integer_intrinsic!(swap_bytes),
694         "ctlz" => integer_intrinsic!(leading_zeros),
695         "ctpop" => integer_intrinsic!(count_ones),
696         "cttz" => integer_intrinsic!(trailing_zeros),
697         _ => bug!("not a numeric intrinsic: {}", name),
698     };
699
700     Ok(result_val)
701 }