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