]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/interpret/const_eval.rs
9ea33b24d129eddb2fe2154b08a392e48524151f
[rust.git] / src / librustc_mir / interpret / const_eval.rs
1 use std::fmt;
2 use std::error::Error;
3
4 use rustc::hir;
5 use rustc::mir::interpret::{ConstEvalErr, ScalarMaybeUndef};
6 use rustc::mir;
7 use rustc::ty::{self, TyCtxt, Ty, Instance};
8 use rustc::ty::layout::{self, LayoutOf, Primitive, TyLayout};
9 use rustc::ty::subst::Subst;
10 use rustc_data_structures::indexed_vec::IndexVec;
11
12 use syntax::ast::Mutability;
13 use syntax::codemap::Span;
14 use syntax::codemap::DUMMY_SP;
15
16 use rustc::mir::interpret::{
17     EvalResult, EvalError, EvalErrorKind, GlobalId,
18     Value, Scalar, AllocId, Allocation, ConstValue,
19 };
20 use super::{Place, EvalContext, StackPopCleanup, ValTy, Memory, MemoryKind};
21
22 pub fn mk_borrowck_eval_cx<'a, 'mir, 'tcx>(
23     tcx: TyCtxt<'a, 'tcx, 'tcx>,
24     instance: Instance<'tcx>,
25     mir: &'mir mir::Mir<'tcx>,
26     span: Span,
27 ) -> EvalResult<'tcx, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>> {
28     debug!("mk_borrowck_eval_cx: {:?}", instance);
29     let param_env = tcx.param_env(instance.def_id());
30     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
31     // insert a stack frame so any queries have the correct substs
32     ecx.stack.push(super::eval_context::Frame {
33         block: mir::START_BLOCK,
34         locals: IndexVec::new(),
35         instance,
36         span,
37         mir,
38         return_place: Place::undef(),
39         return_to_block: StackPopCleanup::None,
40         stmt: 0,
41     });
42     Ok(ecx)
43 }
44
45 pub fn mk_eval_cx<'a, 'tcx>(
46     tcx: TyCtxt<'a, 'tcx, 'tcx>,
47     instance: Instance<'tcx>,
48     param_env: ty::ParamEnv<'tcx>,
49 ) -> EvalResult<'tcx, EvalContext<'a, 'tcx, 'tcx, CompileTimeEvaluator>> {
50     debug!("mk_eval_cx: {:?}, {:?}", instance, param_env);
51     let span = tcx.def_span(instance.def_id());
52     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
53     let mir = ecx.load_mir(instance.def)?;
54     // insert a stack frame so any queries have the correct substs
55     ecx.push_stack_frame(
56         instance,
57         mir.span,
58         mir,
59         Place::undef(),
60         StackPopCleanup::None,
61     )?;
62     Ok(ecx)
63 }
64
65 pub fn eval_promoted<'a, 'mir, 'tcx>(
66     ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
67     cid: GlobalId<'tcx>,
68     mir: &'mir mir::Mir<'tcx>,
69     param_env: ty::ParamEnv<'tcx>,
70 ) -> EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)> {
71     ecx.with_fresh_body(|ecx| {
72         eval_body_using_ecx(ecx, cid, Some(mir), param_env)
73     })
74 }
75
76 pub fn value_to_const_value<'tcx>(
77     ecx: &EvalContext<'_, '_, 'tcx, CompileTimeEvaluator>,
78     val: Value,
79     ty: Ty<'tcx>,
80 ) -> &'tcx ty::Const<'tcx> {
81     let layout = ecx.layout_of(ty).unwrap();
82     match (val, &layout.abi) {
83         (Value::Scalar(ScalarMaybeUndef::Scalar(Scalar::Bits { size: 0, ..})), _) if layout.is_zst() => {},
84         (Value::ByRef(..), _) |
85         (Value::Scalar(_), &layout::Abi::Scalar(_)) |
86         (Value::ScalarPair(..), &layout::Abi::ScalarPair(..)) => {},
87         _ => bug!("bad value/layout combo: {:#?}, {:#?}", val, layout),
88     }
89     let val = (|| {
90         match val {
91             Value::Scalar(val) => Ok(ConstValue::Scalar(val.read()?)),
92             Value::ScalarPair(a, b) => Ok(ConstValue::ScalarPair(a.read()?, b.read()?)),
93             Value::ByRef(ptr, align) => {
94                 let ptr = ptr.to_ptr().unwrap();
95                 let alloc = ecx.memory.get(ptr.alloc_id)?;
96                 assert!(alloc.align.abi() >= align.abi());
97                 assert!(alloc.bytes.len() as u64 - ptr.offset.bytes() >= layout.size.bytes());
98                 let mut alloc = alloc.clone();
99                 alloc.align = align;
100                 let alloc = ecx.tcx.intern_const_alloc(alloc);
101                 Ok(ConstValue::ByRef(alloc, ptr.offset))
102             }
103         }
104     })();
105     match val {
106         Ok(val) => ty::Const::from_const_value(ecx.tcx.tcx, val, ty),
107         Err(err) => {
108             let (frames, span) = ecx.generate_stacktrace(None);
109             let err = ConstEvalErr {
110                 span,
111                 error: err,
112                 stacktrace: frames,
113             };
114             err.report_as_error(
115                 ecx.tcx,
116                 "failed to convert Value to ConstValue, this is a bug",
117             );
118             span_bug!(span, "miri error occured when converting Value to ConstValue")
119         }
120     }
121 }
122
123 fn eval_body_and_ecx<'a, 'mir, 'tcx>(
124     tcx: TyCtxt<'a, 'tcx, 'tcx>,
125     cid: GlobalId<'tcx>,
126     mir: Option<&'mir mir::Mir<'tcx>>,
127     param_env: ty::ParamEnv<'tcx>,
128 ) -> (EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)>, EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>) {
129     debug!("eval_body_and_ecx: {:?}, {:?}", cid, param_env);
130     // we start out with the best span we have
131     // and try improving it down the road when more information is available
132     let span = tcx.def_span(cid.instance.def_id());
133     let span = mir.map(|mir| mir.span).unwrap_or(span);
134     let mut ecx = EvalContext::new(tcx.at(span), param_env, CompileTimeEvaluator, ());
135     let r = eval_body_using_ecx(&mut ecx, cid, mir, param_env);
136     (r, ecx)
137 }
138
139 fn eval_body_using_ecx<'a, 'mir, 'tcx>(
140     ecx: &mut EvalContext<'a, 'mir, 'tcx, CompileTimeEvaluator>,
141     cid: GlobalId<'tcx>,
142     mir: Option<&'mir mir::Mir<'tcx>>,
143     param_env: ty::ParamEnv<'tcx>,
144 ) -> EvalResult<'tcx, (Value, Scalar, TyLayout<'tcx>)> {
145     debug!("eval_body: {:?}, {:?}", cid, param_env);
146     let tcx = ecx.tcx.tcx;
147     let mut mir = match mir {
148         Some(mir) => mir,
149         None => ecx.load_mir(cid.instance.def)?,
150     };
151     if let Some(index) = cid.promoted {
152         mir = &mir.promoted[index];
153     }
154     let layout = ecx.layout_of(mir.return_ty().subst(tcx, cid.instance.substs))?;
155     assert!(!layout.is_unsized());
156     let ptr = ecx.memory.allocate(
157         layout.size,
158         layout.align,
159         MemoryKind::Stack,
160     )?;
161     let internally_mutable = !layout.ty.is_freeze(tcx, param_env, mir.span);
162     let is_static = tcx.is_static(cid.instance.def_id());
163     let mutability = if is_static == Some(hir::Mutability::MutMutable) || internally_mutable {
164         Mutability::Mutable
165     } else {
166         Mutability::Immutable
167     };
168     let cleanup = StackPopCleanup::MarkStatic(mutability);
169     let name = ty::tls::with(|tcx| tcx.item_path_str(cid.instance.def_id()));
170     let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p));
171     trace!("const_eval: pushing stack frame for global: {}{}", name, prom);
172     assert!(mir.arg_count == 0);
173     ecx.push_stack_frame(
174         cid.instance,
175         mir.span,
176         mir,
177         Place::from_ptr(ptr, layout.align),
178         cleanup,
179     )?;
180
181     while ecx.step()? {}
182     let ptr = ptr.into();
183     // always try to read the value and report errors
184     let value = match ecx.try_read_value(ptr, layout.align, layout.ty)? {
185         Some(val) if is_static.is_none() && cid.promoted.is_none() => val,
186         // point at the allocation
187         _ => Value::ByRef(ptr, layout.align),
188     };
189     Ok((value, ptr, layout))
190 }
191
192 #[derive(Debug, Clone, Eq, PartialEq, Hash)]
193 pub struct CompileTimeEvaluator;
194
195 impl<'tcx> Into<EvalError<'tcx>> for ConstEvalError {
196     fn into(self) -> EvalError<'tcx> {
197         EvalErrorKind::MachineError(self.to_string()).into()
198     }
199 }
200
201 #[derive(Clone, Debug)]
202 enum ConstEvalError {
203     NeedsRfc(String),
204     NotConst(String),
205 }
206
207 impl fmt::Display for ConstEvalError {
208     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
209         use self::ConstEvalError::*;
210         match *self {
211             NeedsRfc(ref msg) => {
212                 write!(
213                     f,
214                     "\"{}\" needs an rfc before being allowed inside constants",
215                     msg
216                 )
217             }
218             NotConst(ref msg) => write!(f, "{}", msg),
219         }
220     }
221 }
222
223 impl Error for ConstEvalError {
224     fn description(&self) -> &str {
225         use self::ConstEvalError::*;
226         match *self {
227             NeedsRfc(_) => "this feature needs an rfc before being allowed inside constants",
228             NotConst(_) => "this feature is not compatible with constant evaluation",
229         }
230     }
231
232     fn cause(&self) -> Option<&dyn Error> {
233         None
234     }
235 }
236
237 impl<'mir, 'tcx> super::Machine<'mir, 'tcx> for CompileTimeEvaluator {
238     type MemoryData = ();
239     type MemoryKinds = !;
240     fn eval_fn_call<'a>(
241         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
242         instance: ty::Instance<'tcx>,
243         destination: Option<(Place, mir::BasicBlock)>,
244         args: &[ValTy<'tcx>],
245         span: Span,
246         sig: ty::FnSig<'tcx>,
247     ) -> EvalResult<'tcx, bool> {
248         debug!("eval_fn_call: {:?}", instance);
249         if !ecx.tcx.is_const_fn(instance.def_id()) {
250             let def_id = instance.def_id();
251             let (op, oflo) = if let Some(op) = ecx.tcx.is_binop_lang_item(def_id) {
252                 op
253             } else {
254                 return Err(
255                     ConstEvalError::NotConst(format!("calling non-const fn `{}`", instance)).into(),
256                 );
257             };
258             let (dest, bb) = destination.expect("128 lowerings can't diverge");
259             let dest_ty = sig.output();
260             if oflo {
261                 ecx.intrinsic_with_overflow(op, args[0], args[1], dest, dest_ty)?;
262             } else {
263                 ecx.intrinsic_overflowing(op, args[0], args[1], dest, dest_ty)?;
264             }
265             ecx.goto_block(bb);
266             return Ok(true);
267         }
268         let mir = match ecx.load_mir(instance.def) {
269             Ok(mir) => mir,
270             Err(err) => {
271                 if let EvalErrorKind::NoMirFor(ref path) = err.kind {
272                     return Err(
273                         ConstEvalError::NeedsRfc(format!("calling extern function `{}`", path))
274                             .into(),
275                     );
276                 }
277                 return Err(err);
278             }
279         };
280         let (return_place, return_to_block) = match destination {
281             Some((place, block)) => (place, StackPopCleanup::Goto(block)),
282             None => (Place::undef(), StackPopCleanup::None),
283         };
284
285         ecx.push_stack_frame(
286             instance,
287             span,
288             mir,
289             return_place,
290             return_to_block,
291         )?;
292
293         Ok(false)
294     }
295
296
297     fn call_intrinsic<'a>(
298         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
299         instance: ty::Instance<'tcx>,
300         args: &[ValTy<'tcx>],
301         dest: Place,
302         dest_layout: layout::TyLayout<'tcx>,
303         target: mir::BasicBlock,
304     ) -> EvalResult<'tcx> {
305         let substs = instance.substs;
306
307         let intrinsic_name = &ecx.tcx.item_name(instance.def_id()).as_str()[..];
308         match intrinsic_name {
309             "min_align_of" => {
310                 let elem_ty = substs.type_at(0);
311                 let elem_align = ecx.layout_of(elem_ty)?.align.abi();
312                 let align_val = Scalar::Bits {
313                     bits: elem_align as u128,
314                     size: dest_layout.size.bytes() as u8,
315                 };
316                 ecx.write_scalar(dest, align_val, dest_layout.ty)?;
317             }
318
319             "size_of" => {
320                 let ty = substs.type_at(0);
321                 let size = ecx.layout_of(ty)?.size.bytes() as u128;
322                 let size_val = Scalar::Bits {
323                     bits: size,
324                     size: dest_layout.size.bytes() as u8,
325                 };
326                 ecx.write_scalar(dest, size_val, dest_layout.ty)?;
327             }
328
329             "type_id" => {
330                 let ty = substs.type_at(0);
331                 let type_id = ecx.tcx.type_id_hash(ty) as u128;
332                 let id_val = Scalar::Bits {
333                     bits: type_id,
334                     size: dest_layout.size.bytes() as u8,
335                 };
336                 ecx.write_scalar(dest, id_val, dest_layout.ty)?;
337             }
338             "ctpop" | "cttz" | "cttz_nonzero" | "ctlz" | "ctlz_nonzero" | "bswap" => {
339                 let ty = substs.type_at(0);
340                 let layout_of = ecx.layout_of(ty)?;
341                 let bits = ecx.value_to_scalar(args[0])?.to_bits(layout_of.size)?;
342                 let kind = match layout_of.abi {
343                     ty::layout::Abi::Scalar(ref scalar) => scalar.value,
344                     _ => Err(::rustc::mir::interpret::EvalErrorKind::TypeNotPrimitive(ty))?,
345                 };
346                 let out_val = if intrinsic_name.ends_with("_nonzero") {
347                     if bits == 0 {
348                         return err!(Intrinsic(format!("{} called on 0", intrinsic_name)));
349                     }
350                     numeric_intrinsic(intrinsic_name.trim_right_matches("_nonzero"), bits, kind)?
351                 } else {
352                     numeric_intrinsic(intrinsic_name, bits, kind)?
353                 };
354                 ecx.write_scalar(dest, out_val, ty)?;
355             }
356
357             name => return Err(
358                 ConstEvalError::NeedsRfc(format!("calling intrinsic `{}`", name)).into()
359             ),
360         }
361
362         ecx.goto_block(target);
363
364         // Since we pushed no stack frame, the main loop will act
365         // as if the call just completed and it's returning to the
366         // current frame.
367         Ok(())
368     }
369
370     fn try_ptr_op<'a>(
371         _ecx: &EvalContext<'a, 'mir, 'tcx, Self>,
372         _bin_op: mir::BinOp,
373         left: Scalar,
374         _left_ty: Ty<'tcx>,
375         right: Scalar,
376         _right_ty: Ty<'tcx>,
377     ) -> EvalResult<'tcx, Option<(Scalar, bool)>> {
378         if left.is_bits() && right.is_bits() {
379             Ok(None)
380         } else {
381             Err(
382                 ConstEvalError::NeedsRfc("pointer arithmetic or comparison".to_string()).into(),
383             )
384         }
385     }
386
387     fn mark_static_initialized<'a>(
388         _mem: &mut Memory<'a, 'mir, 'tcx, Self>,
389         _id: AllocId,
390         _mutability: Mutability,
391     ) -> EvalResult<'tcx, bool> {
392         Ok(false)
393     }
394
395     fn init_static<'a>(
396         ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
397         cid: GlobalId<'tcx>,
398     ) -> EvalResult<'tcx, AllocId> {
399         Ok(ecx
400             .tcx
401             .alloc_map
402             .lock()
403             .intern_static(cid.instance.def_id()))
404     }
405
406     fn box_alloc<'a>(
407         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
408         _ty: Ty<'tcx>,
409         _dest: Place,
410     ) -> EvalResult<'tcx> {
411         Err(
412             ConstEvalError::NeedsRfc("heap allocations via `box` keyword".to_string()).into(),
413         )
414     }
415
416     fn global_item_with_linkage<'a>(
417         _ecx: &mut EvalContext<'a, 'mir, 'tcx, Self>,
418         _instance: ty::Instance<'tcx>,
419         _mutability: Mutability,
420     ) -> EvalResult<'tcx> {
421         Err(
422             ConstEvalError::NotConst("statics with `linkage` attribute".to_string()).into(),
423         )
424     }
425 }
426
427 pub fn const_val_field<'a, 'tcx>(
428     tcx: TyCtxt<'a, 'tcx, 'tcx>,
429     param_env: ty::ParamEnv<'tcx>,
430     instance: ty::Instance<'tcx>,
431     variant: Option<usize>,
432     field: mir::Field,
433     value: &'tcx ty::Const<'tcx>,
434 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
435     trace!("const_val_field: {:?}, {:?}, {:?}", instance, field, value);
436     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
437     let result = (|| {
438         let ty = value.ty;
439         let value = ecx.const_to_value(value.val)?;
440         let layout = ecx.layout_of(ty)?;
441         let place = ecx.allocate_place_for_value(value, layout, variant)?;
442         let (place, layout) = ecx.place_field(place, field, layout)?;
443         let (ptr, align) = place.to_ptr_align();
444         let mut new_value = Value::ByRef(ptr.read()?, align);
445         new_value = ecx.try_read_by_ref(new_value, layout.ty)?;
446         use rustc_data_structures::indexed_vec::Idx;
447         match (value, new_value) {
448             (Value::Scalar(_), Value::ByRef(..)) |
449             (Value::ScalarPair(..), Value::ByRef(..)) |
450             (Value::Scalar(_), Value::ScalarPair(..)) => bug!(
451                 "field {} of {:?} yielded {:?}",
452                 field.index(),
453                 value,
454                 new_value,
455             ),
456             _ => {},
457         }
458         Ok(value_to_const_value(&ecx, new_value, layout.ty))
459     })();
460     result.map_err(|err| {
461         let (trace, span) = ecx.generate_stacktrace(None);
462         ConstEvalErr {
463             error: err,
464             stacktrace: trace,
465             span,
466         }.into()
467     })
468 }
469
470 pub fn const_variant_index<'a, 'tcx>(
471     tcx: TyCtxt<'a, 'tcx, 'tcx>,
472     param_env: ty::ParamEnv<'tcx>,
473     instance: ty::Instance<'tcx>,
474     val: &'tcx ty::Const<'tcx>,
475 ) -> EvalResult<'tcx, usize> {
476     trace!("const_variant_index: {:?}, {:?}", instance, val);
477     let mut ecx = mk_eval_cx(tcx, instance, param_env).unwrap();
478     let value = ecx.const_to_value(val.val)?;
479     let layout = ecx.layout_of(val.ty)?;
480     let (ptr, align) = match value {
481         Value::ScalarPair(..) | Value::Scalar(_) => {
482             let ptr = ecx.memory.allocate(layout.size, layout.align, MemoryKind::Stack)?.into();
483             ecx.write_value_to_ptr(value, ptr, layout.align, val.ty)?;
484             (ptr, layout.align)
485         },
486         Value::ByRef(ptr, align) => (ptr, align),
487     };
488     let place = Place::from_scalar_ptr(ptr, align);
489     ecx.read_discriminant_as_variant_index(place, layout)
490 }
491
492 pub fn const_value_to_allocation_provider<'a, 'tcx>(
493     tcx: TyCtxt<'a, 'tcx, 'tcx>,
494     val: &'tcx ty::Const<'tcx>,
495 ) -> &'tcx Allocation {
496     match val.val {
497         ConstValue::ByRef(alloc, offset) => {
498             assert_eq!(offset.bytes(), 0);
499             return alloc;
500         },
501         _ => ()
502     }
503     let result = || -> EvalResult<'tcx, &'tcx Allocation> {
504         let mut ecx = EvalContext::new(
505             tcx.at(DUMMY_SP),
506             ty::ParamEnv::reveal_all(),
507             CompileTimeEvaluator,
508             ());
509         let value = ecx.const_to_value(val.val)?;
510         let layout = ecx.layout_of(val.ty)?;
511         let ptr = ecx.memory.allocate(layout.size, layout.align, MemoryKind::Stack)?;
512         ecx.write_value_to_ptr(value, ptr.into(), layout.align, val.ty)?;
513         let alloc = ecx.memory.get(ptr.alloc_id)?;
514         Ok(tcx.intern_const_alloc(alloc.clone()))
515     };
516     result().expect("unable to convert ConstValue to Allocation")
517 }
518
519 pub fn const_eval_provider<'a, 'tcx>(
520     tcx: TyCtxt<'a, 'tcx, 'tcx>,
521     key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>,
522 ) -> ::rustc::mir::interpret::ConstEvalResult<'tcx> {
523     trace!("const eval: {:?}", key);
524     let cid = key.value;
525     let def_id = cid.instance.def.def_id();
526
527     if let Some(id) = tcx.hir.as_local_node_id(def_id) {
528         let tables = tcx.typeck_tables_of(def_id);
529         let span = tcx.def_span(def_id);
530
531         // Do match-check before building MIR
532         if tcx.check_match(def_id).is_err() {
533             return Err(ConstEvalErr {
534                 error: EvalErrorKind::CheckMatchError.into(),
535                 stacktrace: vec![],
536                 span,
537             }.into());
538         }
539
540         if let hir::BodyOwnerKind::Const = tcx.hir.body_owner_kind(id) {
541             tcx.mir_const_qualif(def_id);
542         }
543
544         // Do not continue into miri if typeck errors occurred; it will fail horribly
545         if tables.tainted_by_errors {
546             return Err(ConstEvalErr {
547                 error: EvalErrorKind::CheckMatchError.into(),
548                 stacktrace: vec![],
549                 span,
550             }.into());
551         }
552     };
553
554     let (res, ecx) = eval_body_and_ecx(tcx, cid, None, key.param_env);
555     res.and_then(|(mut val, _, layout)| {
556         if tcx.is_static(def_id).is_none() && cid.promoted.is_none() {
557             val = ecx.try_read_by_ref(val, layout.ty)?;
558         }
559         Ok(value_to_const_value(&ecx, val, layout.ty))
560     }).map_err(|err| {
561         let (trace, span) = ecx.generate_stacktrace(None);
562         let err = ConstEvalErr {
563             error: err,
564             stacktrace: trace,
565             span,
566         };
567         if tcx.is_static(def_id).is_some() {
568             err.report_as_error(ecx.tcx, "could not evaluate static initializer");
569             if tcx.sess.err_count() == 0 {
570                 span_bug!(span, "static eval failure didn't emit an error: {:#?}", err);
571             }
572         }
573         err.into()
574     })
575 }
576
577 fn numeric_intrinsic<'tcx>(
578     name: &str,
579     bits: u128,
580     kind: Primitive,
581 ) -> EvalResult<'tcx, Scalar> {
582     let size = match kind {
583         Primitive::Int(integer, _) => integer.size(),
584         _ => bug!("invalid `{}` argument: {:?}", name, bits),
585     };
586     let extra = 128 - size.bits() as u128;
587     let bits_out = match name {
588         "ctpop" => bits.count_ones() as u128,
589         "ctlz" => bits.leading_zeros() as u128 - extra,
590         "cttz" => (bits << extra).trailing_zeros() as u128 - extra,
591         "bswap" => (bits << extra).swap_bytes(),
592         _ => bug!("not a numeric intrinsic: {}", name),
593     };
594     Ok(Scalar::Bits { bits: bits_out, size: size.bytes() as u8 })
595 }