]> git.lizzy.rs Git - rust.git/blob - src/intrinsics/mod.rs
Sync from rust bafe8d06e015eb00724d3d497516191d6681943f
[rust.git] / src / intrinsics / mod.rs
1 //! Codegen of intrinsics. This includes `extern "rust-intrinsic"`, `extern "platform-intrinsic"`
2 //! and LLVM intrinsics that have symbol names starting with `llvm.`.
3
4 mod cpuid;
5 mod llvm;
6 mod simd;
7
8 pub(crate) use cpuid::codegen_cpuid_call;
9 pub(crate) use llvm::codegen_llvm_intrinsic_call;
10
11 use rustc_middle::ty::print::with_no_trimmed_paths;
12 use rustc_middle::ty::subst::SubstsRef;
13 use rustc_span::symbol::{kw, sym, Symbol};
14
15 use crate::prelude::*;
16 use cranelift_codegen::ir::AtomicRmwOp;
17
18 macro intrinsic_pat {
19     (_) => {
20         _
21     },
22     ($name:ident) => {
23         sym::$name
24     },
25     (kw.$name:ident) => {
26         kw::$name
27     },
28     ($name:literal) => {
29         $name
30     },
31 }
32
33 macro intrinsic_arg {
34     (o $fx:expr, $arg:ident) => {},
35     (c $fx:expr, $arg:ident) => {
36         let $arg = codegen_operand($fx, $arg);
37     },
38     (v $fx:expr, $arg:ident) => {
39         let $arg = codegen_operand($fx, $arg).load_scalar($fx);
40     }
41 }
42
43 macro intrinsic_match {
44     ($fx:expr, $intrinsic:expr, $args:expr,
45     _ => $unknown:block;
46     $(
47         $($($name:tt).*)|+ $(if $cond:expr)?, ($($a:ident $arg:ident),*) $content:block;
48     )*) => {
49         match $intrinsic {
50             $(
51                 $(intrinsic_pat!($($name).*))|* $(if $cond)? => {
52                     if let [$($arg),*] = $args {
53                         $(intrinsic_arg!($a $fx, $arg);)*
54                         $content
55                     } else {
56                         bug!("wrong number of args for intrinsic {:?}", $intrinsic);
57                     }
58                 }
59             )*
60             _ => $unknown,
61         }
62     }
63 }
64
65 fn report_atomic_type_validation_error<'tcx>(
66     fx: &mut FunctionCx<'_, '_, 'tcx>,
67     intrinsic: Symbol,
68     span: Span,
69     ty: Ty<'tcx>,
70 ) {
71     fx.tcx.sess.span_err(
72         span,
73         &format!(
74             "`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`",
75             intrinsic, ty
76         ),
77     );
78     // Prevent verifier error
79     crate::trap::trap_unreachable(fx, "compilation should not have succeeded");
80 }
81
82 pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
83     let (element, count) = match layout.abi {
84         Abi::Vector { element, count } => (element, count),
85         _ => unreachable!(),
86     };
87
88     match scalar_to_clif_type(tcx, element).by(u16::try_from(count).unwrap()) {
89         // Cranelift currently only implements icmp for 128bit vectors.
90         Some(vector_ty) if vector_ty.bits() == 128 => Some(vector_ty),
91         _ => None,
92     }
93 }
94
95 fn simd_for_each_lane<'tcx>(
96     fx: &mut FunctionCx<'_, '_, 'tcx>,
97     val: CValue<'tcx>,
98     ret: CPlace<'tcx>,
99     f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Ty<'tcx>, Ty<'tcx>, Value) -> Value,
100 ) {
101     let layout = val.layout();
102
103     let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
104     let lane_layout = fx.layout_of(lane_ty);
105     let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
106     let ret_lane_layout = fx.layout_of(ret_lane_ty);
107     assert_eq!(lane_count, ret_lane_count);
108
109     for lane_idx in 0..lane_count {
110         let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
111
112         let res_lane = f(fx, lane_layout.ty, ret_lane_layout.ty, lane);
113         let res_lane = CValue::by_val(res_lane, ret_lane_layout);
114
115         ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
116     }
117 }
118
119 fn simd_pair_for_each_lane<'tcx>(
120     fx: &mut FunctionCx<'_, '_, 'tcx>,
121     x: CValue<'tcx>,
122     y: CValue<'tcx>,
123     ret: CPlace<'tcx>,
124     f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Ty<'tcx>, Ty<'tcx>, Value, Value) -> Value,
125 ) {
126     assert_eq!(x.layout(), y.layout());
127     let layout = x.layout();
128
129     let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx);
130     let lane_layout = fx.layout_of(lane_ty);
131     let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx);
132     let ret_lane_layout = fx.layout_of(ret_lane_ty);
133     assert_eq!(lane_count, ret_lane_count);
134
135     for lane_idx in 0..lane_count {
136         let x_lane = x.value_lane(fx, lane_idx).load_scalar(fx);
137         let y_lane = y.value_lane(fx, lane_idx).load_scalar(fx);
138
139         let res_lane = f(fx, lane_layout.ty, ret_lane_layout.ty, x_lane, y_lane);
140         let res_lane = CValue::by_val(res_lane, ret_lane_layout);
141
142         ret.place_lane(fx, lane_idx).write_cvalue(fx, res_lane);
143     }
144 }
145
146 fn simd_reduce<'tcx>(
147     fx: &mut FunctionCx<'_, '_, 'tcx>,
148     val: CValue<'tcx>,
149     acc: Option<Value>,
150     ret: CPlace<'tcx>,
151     f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Ty<'tcx>, Value, Value) -> Value,
152 ) {
153     let (lane_count, lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
154     let lane_layout = fx.layout_of(lane_ty);
155     assert_eq!(lane_layout, ret.layout());
156
157     let (mut res_val, start_lane) =
158         if let Some(acc) = acc { (acc, 0) } else { (val.value_lane(fx, 0).load_scalar(fx), 1) };
159     for lane_idx in start_lane..lane_count {
160         let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
161         res_val = f(fx, lane_layout.ty, res_val, lane);
162     }
163     let res = CValue::by_val(res_val, lane_layout);
164     ret.write_cvalue(fx, res);
165 }
166
167 // FIXME move all uses to `simd_reduce`
168 fn simd_reduce_bool<'tcx>(
169     fx: &mut FunctionCx<'_, '_, 'tcx>,
170     val: CValue<'tcx>,
171     ret: CPlace<'tcx>,
172     f: &dyn Fn(&mut FunctionCx<'_, '_, 'tcx>, Value, Value) -> Value,
173 ) {
174     let (lane_count, _lane_ty) = val.layout().ty.simd_size_and_type(fx.tcx);
175     assert!(ret.layout().ty.is_bool());
176
177     let res_val = val.value_lane(fx, 0).load_scalar(fx);
178     let mut res_val = fx.bcx.ins().band_imm(res_val, 1); // mask to boolean
179     for lane_idx in 1..lane_count {
180         let lane = val.value_lane(fx, lane_idx).load_scalar(fx);
181         let lane = fx.bcx.ins().band_imm(lane, 1); // mask to boolean
182         res_val = f(fx, res_val, lane);
183     }
184     let res_val = if fx.bcx.func.dfg.value_type(res_val) != types::I8 {
185         fx.bcx.ins().ireduce(types::I8, res_val)
186     } else {
187         res_val
188     };
189     let res = CValue::by_val(res_val, ret.layout());
190     ret.write_cvalue(fx, res);
191 }
192
193 fn bool_to_zero_or_max_uint<'tcx>(
194     fx: &mut FunctionCx<'_, '_, 'tcx>,
195     ty: Ty<'tcx>,
196     val: Value,
197 ) -> Value {
198     let ty = fx.clif_type(ty).unwrap();
199
200     let int_ty = match ty {
201         types::F32 => types::I32,
202         types::F64 => types::I64,
203         ty => ty,
204     };
205
206     let val = fx.bcx.ins().bint(int_ty, val);
207     let mut res = fx.bcx.ins().ineg(val);
208
209     if ty.is_float() {
210         res = fx.bcx.ins().bitcast(ty, res);
211     }
212
213     res
214 }
215
216 pub(crate) fn codegen_intrinsic_call<'tcx>(
217     fx: &mut FunctionCx<'_, '_, 'tcx>,
218     instance: Instance<'tcx>,
219     args: &[mir::Operand<'tcx>],
220     destination: Option<(CPlace<'tcx>, BasicBlock)>,
221     span: Span,
222 ) {
223     let intrinsic = fx.tcx.item_name(instance.def_id());
224     let substs = instance.substs;
225
226     let ret = match destination {
227         Some((place, _)) => place,
228         None => {
229             // Insert non returning intrinsics here
230             match intrinsic {
231                 sym::abort => {
232                     trap_abort(fx, "Called intrinsic::abort.");
233                 }
234                 sym::transmute => {
235                     crate::base::codegen_panic(fx, "Transmuting to uninhabited type.", span);
236                 }
237                 _ => unimplemented!("unsupported instrinsic {}", intrinsic),
238             }
239             return;
240         }
241     };
242
243     if intrinsic.as_str().starts_with("simd_") {
244         self::simd::codegen_simd_intrinsic_call(fx, intrinsic, substs, args, ret, span);
245         let ret_block = fx.get_block(destination.expect("SIMD intrinsics don't diverge").1);
246         fx.bcx.ins().jump(ret_block, &[]);
247     } else if codegen_float_intrinsic_call(fx, intrinsic, args, ret) {
248         let ret_block = fx.get_block(destination.expect("Float intrinsics don't diverge").1);
249         fx.bcx.ins().jump(ret_block, &[]);
250     } else {
251         codegen_regular_intrinsic_call(
252             fx,
253             instance,
254             intrinsic,
255             substs,
256             args,
257             ret,
258             span,
259             destination,
260         );
261     }
262 }
263
264 fn codegen_float_intrinsic_call<'tcx>(
265     fx: &mut FunctionCx<'_, '_, 'tcx>,
266     intrinsic: Symbol,
267     args: &[mir::Operand<'tcx>],
268     ret: CPlace<'tcx>,
269 ) -> bool {
270     let (name, arg_count, ty) = match intrinsic {
271         sym::expf32 => ("expf", 1, fx.tcx.types.f32),
272         sym::expf64 => ("exp", 1, fx.tcx.types.f64),
273         sym::exp2f32 => ("exp2f", 1, fx.tcx.types.f32),
274         sym::exp2f64 => ("exp2", 1, fx.tcx.types.f64),
275         sym::sqrtf32 => ("sqrtf", 1, fx.tcx.types.f32),
276         sym::sqrtf64 => ("sqrt", 1, fx.tcx.types.f64),
277         sym::powif32 => ("__powisf2", 2, fx.tcx.types.f32), // compiler-builtins
278         sym::powif64 => ("__powidf2", 2, fx.tcx.types.f64), // compiler-builtins
279         sym::powf32 => ("powf", 2, fx.tcx.types.f32),
280         sym::powf64 => ("pow", 2, fx.tcx.types.f64),
281         sym::logf32 => ("logf", 1, fx.tcx.types.f32),
282         sym::logf64 => ("log", 1, fx.tcx.types.f64),
283         sym::log2f32 => ("log2f", 1, fx.tcx.types.f32),
284         sym::log2f64 => ("log2", 1, fx.tcx.types.f64),
285         sym::log10f32 => ("log10f", 1, fx.tcx.types.f32),
286         sym::log10f64 => ("log10", 1, fx.tcx.types.f64),
287         sym::fabsf32 => ("fabsf", 1, fx.tcx.types.f32),
288         sym::fabsf64 => ("fabs", 1, fx.tcx.types.f64),
289         sym::fmaf32 => ("fmaf", 3, fx.tcx.types.f32),
290         sym::fmaf64 => ("fma", 3, fx.tcx.types.f64),
291         sym::copysignf32 => ("copysignf", 2, fx.tcx.types.f32),
292         sym::copysignf64 => ("copysign", 2, fx.tcx.types.f64),
293         sym::floorf32 => ("floorf", 1, fx.tcx.types.f32),
294         sym::floorf64 => ("floor", 1, fx.tcx.types.f64),
295         sym::ceilf32 => ("ceilf", 1, fx.tcx.types.f32),
296         sym::ceilf64 => ("ceil", 1, fx.tcx.types.f64),
297         sym::truncf32 => ("truncf", 1, fx.tcx.types.f32),
298         sym::truncf64 => ("trunc", 1, fx.tcx.types.f64),
299         sym::roundf32 => ("roundf", 1, fx.tcx.types.f32),
300         sym::roundf64 => ("round", 1, fx.tcx.types.f64),
301         sym::sinf32 => ("sinf", 1, fx.tcx.types.f32),
302         sym::sinf64 => ("sin", 1, fx.tcx.types.f64),
303         sym::cosf32 => ("cosf", 1, fx.tcx.types.f32),
304         sym::cosf64 => ("cos", 1, fx.tcx.types.f64),
305         _ => return false,
306     };
307
308     if args.len() != arg_count {
309         bug!("wrong number of args for intrinsic {:?}", intrinsic);
310     }
311
312     let (a, b, c);
313     let args = match args {
314         [x] => {
315             a = [codegen_operand(fx, x)];
316             &a as &[_]
317         }
318         [x, y] => {
319             b = [codegen_operand(fx, x), codegen_operand(fx, y)];
320             &b
321         }
322         [x, y, z] => {
323             c = [codegen_operand(fx, x), codegen_operand(fx, y), codegen_operand(fx, z)];
324             &c
325         }
326         _ => unreachable!(),
327     };
328
329     let res = fx.easy_call(name, &args, ty);
330     ret.write_cvalue(fx, res);
331
332     true
333 }
334
335 fn codegen_regular_intrinsic_call<'tcx>(
336     fx: &mut FunctionCx<'_, '_, 'tcx>,
337     instance: Instance<'tcx>,
338     intrinsic: Symbol,
339     substs: SubstsRef<'tcx>,
340     args: &[mir::Operand<'tcx>],
341     ret: CPlace<'tcx>,
342     span: Span,
343     destination: Option<(CPlace<'tcx>, BasicBlock)>,
344 ) {
345     let usize_layout = fx.layout_of(fx.tcx.types.usize);
346
347     intrinsic_match! {
348         fx, intrinsic, args,
349         _ => {
350             fx.tcx.sess.span_fatal(span, &format!("unsupported intrinsic {}", intrinsic));
351         };
352
353         assume, (c _a) {};
354         likely | unlikely, (c a) {
355             ret.write_cvalue(fx, a);
356         };
357         breakpoint, () {
358             fx.bcx.ins().debugtrap();
359         };
360         copy | copy_nonoverlapping, (v src, v dst, v count) {
361             let elem_ty = substs.type_at(0);
362             let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
363             assert_eq!(args.len(), 3);
364             let byte_amount = if elem_size != 1 {
365                 fx.bcx.ins().imul_imm(count, elem_size as i64)
366             } else {
367                 count
368             };
369
370             if intrinsic == sym::copy_nonoverlapping {
371                 // FIXME emit_small_memcpy
372                 fx.bcx.call_memcpy(fx.target_config, dst, src, byte_amount);
373             } else {
374                 // FIXME emit_small_memmove
375                 fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
376             }
377         };
378         // NOTE: the volatile variants have src and dst swapped
379         volatile_copy_memory | volatile_copy_nonoverlapping_memory, (v dst, v src, v count) {
380             let elem_ty = substs.type_at(0);
381             let elem_size: u64 = fx.layout_of(elem_ty).size.bytes();
382             assert_eq!(args.len(), 3);
383             let byte_amount = if elem_size != 1 {
384                 fx.bcx.ins().imul_imm(count, elem_size as i64)
385             } else {
386                 count
387             };
388
389             // FIXME make the copy actually volatile when using emit_small_mem{cpy,move}
390             if intrinsic == sym::volatile_copy_nonoverlapping_memory {
391                 // FIXME emit_small_memcpy
392                 fx.bcx.call_memcpy(fx.target_config, dst, src, byte_amount);
393             } else {
394                 // FIXME emit_small_memmove
395                 fx.bcx.call_memmove(fx.target_config, dst, src, byte_amount);
396             }
397         };
398         size_of_val, (c ptr) {
399             let layout = fx.layout_of(substs.type_at(0));
400             let size = if layout.is_unsized() {
401                 let (_ptr, info) = ptr.load_scalar_pair(fx);
402                 let (size, _align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
403                 size
404             } else {
405                 fx
406                     .bcx
407                     .ins()
408                     .iconst(fx.pointer_type, layout.size.bytes() as i64)
409             };
410             ret.write_cvalue(fx, CValue::by_val(size, usize_layout));
411         };
412         min_align_of_val, (c ptr) {
413             let layout = fx.layout_of(substs.type_at(0));
414             let align = if layout.is_unsized() {
415                 let (_ptr, info) = ptr.load_scalar_pair(fx);
416                 let (_size, align) = crate::unsize::size_and_align_of_dst(fx, layout, info);
417                 align
418             } else {
419                 fx
420                     .bcx
421                     .ins()
422                     .iconst(fx.pointer_type, layout.align.abi.bytes() as i64)
423             };
424             ret.write_cvalue(fx, CValue::by_val(align, usize_layout));
425         };
426
427         unchecked_add | unchecked_sub | unchecked_mul | unchecked_div | exact_div | unchecked_rem
428         | unchecked_shl | unchecked_shr, (c x, c y) {
429             // FIXME trap on overflow
430             let bin_op = match intrinsic {
431                 sym::unchecked_add => BinOp::Add,
432                 sym::unchecked_sub => BinOp::Sub,
433                 sym::unchecked_mul => BinOp::Mul,
434                 sym::unchecked_div | sym::exact_div => BinOp::Div,
435                 sym::unchecked_rem => BinOp::Rem,
436                 sym::unchecked_shl => BinOp::Shl,
437                 sym::unchecked_shr => BinOp::Shr,
438                 _ => unreachable!(),
439             };
440             let res = crate::num::codegen_int_binop(fx, bin_op, x, y);
441             ret.write_cvalue(fx, res);
442         };
443         add_with_overflow | sub_with_overflow | mul_with_overflow, (c x, c y) {
444             assert_eq!(x.layout().ty, y.layout().ty);
445             let bin_op = match intrinsic {
446                 sym::add_with_overflow => BinOp::Add,
447                 sym::sub_with_overflow => BinOp::Sub,
448                 sym::mul_with_overflow => BinOp::Mul,
449                 _ => unreachable!(),
450             };
451
452             let res = crate::num::codegen_checked_int_binop(
453                 fx,
454                 bin_op,
455                 x,
456                 y,
457             );
458             ret.write_cvalue(fx, res);
459         };
460         saturating_add | saturating_sub, (c lhs, c rhs) {
461             assert_eq!(lhs.layout().ty, rhs.layout().ty);
462             let bin_op = match intrinsic {
463                 sym::saturating_add => BinOp::Add,
464                 sym::saturating_sub => BinOp::Sub,
465                 _ => unreachable!(),
466             };
467
468             let signed = type_sign(lhs.layout().ty);
469
470             let checked_res = crate::num::codegen_checked_int_binop(
471                 fx,
472                 bin_op,
473                 lhs,
474                 rhs,
475             );
476
477             let (val, has_overflow) = checked_res.load_scalar_pair(fx);
478             let clif_ty = fx.clif_type(lhs.layout().ty).unwrap();
479
480             let (min, max) = type_min_max_value(&mut fx.bcx, clif_ty, signed);
481
482             let val = match (intrinsic, signed) {
483                 (sym::saturating_add, false) => fx.bcx.ins().select(has_overflow, max, val),
484                 (sym::saturating_sub, false) => fx.bcx.ins().select(has_overflow, min, val),
485                 (sym::saturating_add, true) => {
486                     let rhs = rhs.load_scalar(fx);
487                     let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
488                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, max, min);
489                     fx.bcx.ins().select(has_overflow, sat_val, val)
490                 }
491                 (sym::saturating_sub, true) => {
492                     let rhs = rhs.load_scalar(fx);
493                     let rhs_ge_zero = fx.bcx.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, rhs, 0);
494                     let sat_val = fx.bcx.ins().select(rhs_ge_zero, min, max);
495                     fx.bcx.ins().select(has_overflow, sat_val, val)
496                 }
497                 _ => unreachable!(),
498             };
499
500             let res = CValue::by_val(val, lhs.layout());
501
502             ret.write_cvalue(fx, res);
503         };
504         rotate_left, (c x, v y) {
505             let layout = x.layout();
506             let x = x.load_scalar(fx);
507             let res = fx.bcx.ins().rotl(x, y);
508             ret.write_cvalue(fx, CValue::by_val(res, layout));
509         };
510         rotate_right, (c x, v y) {
511             let layout = x.layout();
512             let x = x.load_scalar(fx);
513             let res = fx.bcx.ins().rotr(x, y);
514             ret.write_cvalue(fx, CValue::by_val(res, layout));
515         };
516
517         // The only difference between offset and arith_offset is regarding UB. Because Cranelift
518         // doesn't have UB both are codegen'ed the same way
519         offset | arith_offset, (c base, v offset) {
520             let pointee_ty = base.layout().ty.builtin_deref(true).unwrap().ty;
521             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
522             let ptr_diff = if pointee_size != 1 {
523                 fx.bcx.ins().imul_imm(offset, pointee_size as i64)
524             } else {
525                 offset
526             };
527             let base_val = base.load_scalar(fx);
528             let res = fx.bcx.ins().iadd(base_val, ptr_diff);
529             ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
530         };
531
532         transmute, (c from) {
533             ret.write_cvalue_transmute(fx, from);
534         };
535         write_bytes | volatile_set_memory, (c dst, v val, v count) {
536             let pointee_ty = dst.layout().ty.builtin_deref(true).unwrap().ty;
537             let pointee_size = fx.layout_of(pointee_ty).size.bytes();
538             let count = if pointee_size != 1 {
539                 fx.bcx.ins().imul_imm(count, pointee_size as i64)
540             } else {
541                 count
542             };
543             let dst_ptr = dst.load_scalar(fx);
544             // FIXME make the memset actually volatile when switching to emit_small_memset
545             // FIXME use emit_small_memset
546             fx.bcx.call_memset(fx.target_config, dst_ptr, val, count);
547         };
548         ctlz | ctlz_nonzero, (c arg) {
549             let val = arg.load_scalar(fx);
550             // FIXME trap on `ctlz_nonzero` with zero arg.
551             let res = fx.bcx.ins().clz(val);
552             let res = CValue::by_val(res, arg.layout());
553             ret.write_cvalue(fx, res);
554         };
555         cttz | cttz_nonzero, (c arg) {
556             let val = arg.load_scalar(fx);
557             // FIXME trap on `cttz_nonzero` with zero arg.
558             let res = fx.bcx.ins().ctz(val);
559             let res = CValue::by_val(res, arg.layout());
560             ret.write_cvalue(fx, res);
561         };
562         ctpop, (c arg) {
563             let val = arg.load_scalar(fx);
564             let res = fx.bcx.ins().popcnt(val);
565             let res = CValue::by_val(res, arg.layout());
566             ret.write_cvalue(fx, res);
567         };
568         bitreverse, (c arg) {
569             let val = arg.load_scalar(fx);
570             let res = fx.bcx.ins().bitrev(val);
571             let res = CValue::by_val(res, arg.layout());
572             ret.write_cvalue(fx, res);
573         };
574         bswap, (c arg) {
575             // FIXME(CraneStation/cranelift#794) add bswap instruction to cranelift
576             fn swap(bcx: &mut FunctionBuilder<'_>, v: Value) -> Value {
577                 match bcx.func.dfg.value_type(v) {
578                     types::I8 => v,
579
580                     // https://code.woboq.org/gcc/include/bits/byteswap.h.html
581                     types::I16 => {
582                         let tmp1 = bcx.ins().ishl_imm(v, 8);
583                         let n1 = bcx.ins().band_imm(tmp1, 0xFF00);
584
585                         let tmp2 = bcx.ins().ushr_imm(v, 8);
586                         let n2 = bcx.ins().band_imm(tmp2, 0x00FF);
587
588                         bcx.ins().bor(n1, n2)
589                     }
590                     types::I32 => {
591                         let tmp1 = bcx.ins().ishl_imm(v, 24);
592                         let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000);
593
594                         let tmp2 = bcx.ins().ishl_imm(v, 8);
595                         let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000);
596
597                         let tmp3 = bcx.ins().ushr_imm(v, 8);
598                         let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00);
599
600                         let tmp4 = bcx.ins().ushr_imm(v, 24);
601                         let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF);
602
603                         let or_tmp1 = bcx.ins().bor(n1, n2);
604                         let or_tmp2 = bcx.ins().bor(n3, n4);
605                         bcx.ins().bor(or_tmp1, or_tmp2)
606                     }
607                     types::I64 => {
608                         let tmp1 = bcx.ins().ishl_imm(v, 56);
609                         let n1 = bcx.ins().band_imm(tmp1, 0xFF00_0000_0000_0000u64 as i64);
610
611                         let tmp2 = bcx.ins().ishl_imm(v, 40);
612                         let n2 = bcx.ins().band_imm(tmp2, 0x00FF_0000_0000_0000u64 as i64);
613
614                         let tmp3 = bcx.ins().ishl_imm(v, 24);
615                         let n3 = bcx.ins().band_imm(tmp3, 0x0000_FF00_0000_0000u64 as i64);
616
617                         let tmp4 = bcx.ins().ishl_imm(v, 8);
618                         let n4 = bcx.ins().band_imm(tmp4, 0x0000_00FF_0000_0000u64 as i64);
619
620                         let tmp5 = bcx.ins().ushr_imm(v, 8);
621                         let n5 = bcx.ins().band_imm(tmp5, 0x0000_0000_FF00_0000u64 as i64);
622
623                         let tmp6 = bcx.ins().ushr_imm(v, 24);
624                         let n6 = bcx.ins().band_imm(tmp6, 0x0000_0000_00FF_0000u64 as i64);
625
626                         let tmp7 = bcx.ins().ushr_imm(v, 40);
627                         let n7 = bcx.ins().band_imm(tmp7, 0x0000_0000_0000_FF00u64 as i64);
628
629                         let tmp8 = bcx.ins().ushr_imm(v, 56);
630                         let n8 = bcx.ins().band_imm(tmp8, 0x0000_0000_0000_00FFu64 as i64);
631
632                         let or_tmp1 = bcx.ins().bor(n1, n2);
633                         let or_tmp2 = bcx.ins().bor(n3, n4);
634                         let or_tmp3 = bcx.ins().bor(n5, n6);
635                         let or_tmp4 = bcx.ins().bor(n7, n8);
636
637                         let or_tmp5 = bcx.ins().bor(or_tmp1, or_tmp2);
638                         let or_tmp6 = bcx.ins().bor(or_tmp3, or_tmp4);
639                         bcx.ins().bor(or_tmp5, or_tmp6)
640                     }
641                     types::I128 => {
642                         let (lo, hi) = bcx.ins().isplit(v);
643                         let lo = swap(bcx, lo);
644                         let hi = swap(bcx, hi);
645                         bcx.ins().iconcat(hi, lo)
646                     }
647                     ty => unreachable!("bswap {}", ty),
648                 }
649             }
650             let val = arg.load_scalar(fx);
651             let res = CValue::by_val(swap(&mut fx.bcx, val), arg.layout());
652             ret.write_cvalue(fx, res);
653         };
654         assert_inhabited | assert_zero_valid | assert_uninit_valid, () {
655             let layout = fx.layout_of(substs.type_at(0));
656             if layout.abi.is_uninhabited() {
657                 with_no_trimmed_paths!({
658                     crate::base::codegen_panic(
659                         fx,
660                         &format!("attempted to instantiate uninhabited type `{}`", layout.ty),
661                         span,
662                     )
663                 });
664                 return;
665             }
666
667             if intrinsic == sym::assert_zero_valid && !layout.might_permit_raw_init(fx, /*zero:*/ true) {
668                 with_no_trimmed_paths!({
669                     crate::base::codegen_panic(
670                         fx,
671                         &format!("attempted to zero-initialize type `{}`, which is invalid", layout.ty),
672                         span,
673                     );
674                 });
675                 return;
676             }
677
678             if intrinsic == sym::assert_uninit_valid && !layout.might_permit_raw_init(fx, /*zero:*/ false) {
679                 with_no_trimmed_paths!({
680                     crate::base::codegen_panic(
681                         fx,
682                         &format!("attempted to leave type `{}` uninitialized, which is invalid", layout.ty),
683                         span,
684                     )
685                 });
686                 return;
687             }
688         };
689
690         volatile_load | unaligned_volatile_load, (c ptr) {
691             // Cranelift treats loads as volatile by default
692             // FIXME correctly handle unaligned_volatile_load
693             let inner_layout =
694                 fx.layout_of(ptr.layout().ty.builtin_deref(true).unwrap().ty);
695             let val = CValue::by_ref(Pointer::new(ptr.load_scalar(fx)), inner_layout);
696             ret.write_cvalue(fx, val);
697         };
698         volatile_store | unaligned_volatile_store, (v ptr, c val) {
699             // Cranelift treats stores as volatile by default
700             // FIXME correctly handle unaligned_volatile_store
701             let dest = CPlace::for_ptr(Pointer::new(ptr), val.layout());
702             dest.write_cvalue(fx, val);
703         };
704
705         pref_align_of | needs_drop | type_id | type_name | variant_count, () {
706             let const_val =
707                 fx.tcx.const_eval_instance(ParamEnv::reveal_all(), instance, None).unwrap();
708             let val = crate::constant::codegen_const_value(
709                 fx,
710                 const_val,
711                 ret.layout().ty,
712             );
713             ret.write_cvalue(fx, val);
714         };
715
716         ptr_offset_from, (v ptr, v base) {
717             let ty = substs.type_at(0);
718             let isize_layout = fx.layout_of(fx.tcx.types.isize);
719
720             let pointee_size: u64 = fx.layout_of(ty).size.bytes();
721             let diff = fx.bcx.ins().isub(ptr, base);
722             // FIXME this can be an exact division.
723             let val = CValue::by_val(fx.bcx.ins().sdiv_imm(diff, pointee_size as i64), isize_layout);
724             ret.write_cvalue(fx, val);
725         };
726
727         ptr_guaranteed_eq, (c a, c b) {
728             let val = crate::num::codegen_ptr_binop(fx, BinOp::Eq, a, b);
729             ret.write_cvalue(fx, val);
730         };
731
732         ptr_guaranteed_ne, (c a, c b) {
733             let val = crate::num::codegen_ptr_binop(fx, BinOp::Ne, a, b);
734             ret.write_cvalue(fx, val);
735         };
736
737         caller_location, () {
738             let caller_location = fx.get_caller_location(span);
739             ret.write_cvalue(fx, caller_location);
740         };
741
742         _ if intrinsic.as_str().starts_with("atomic_fence"), () {
743             fx.bcx.ins().fence();
744         };
745         _ if intrinsic.as_str().starts_with("atomic_singlethreadfence"), () {
746             // FIXME use a compiler fence once Cranelift supports it
747             fx.bcx.ins().fence();
748         };
749         _ if intrinsic.as_str().starts_with("atomic_load"), (v ptr) {
750             let ty = substs.type_at(0);
751             match ty.kind() {
752                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
753                 _ => {
754                     report_atomic_type_validation_error(fx, intrinsic, span, ty);
755                     return;
756                 }
757             }
758             let clif_ty = fx.clif_type(ty).unwrap();
759
760             let val = fx.bcx.ins().atomic_load(clif_ty, MemFlags::trusted(), ptr);
761
762             let val = CValue::by_val(val, fx.layout_of(ty));
763             ret.write_cvalue(fx, val);
764         };
765         _ if intrinsic.as_str().starts_with("atomic_store"), (v ptr, c val) {
766             let ty = substs.type_at(0);
767             match ty.kind() {
768                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
769                 _ => {
770                     report_atomic_type_validation_error(fx, intrinsic, span, ty);
771                     return;
772                 }
773             }
774
775             let val = val.load_scalar(fx);
776
777             fx.bcx.ins().atomic_store(MemFlags::trusted(), val, ptr);
778         };
779         _ if intrinsic.as_str().starts_with("atomic_xchg"), (v ptr, c new) {
780             let layout = new.layout();
781             match layout.ty.kind() {
782                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
783                 _ => {
784                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
785                     return;
786                 }
787             }
788             let ty = fx.clif_type(layout.ty).unwrap();
789
790             let new = new.load_scalar(fx);
791
792             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Xchg, ptr, new);
793
794             let old = CValue::by_val(old, layout);
795             ret.write_cvalue(fx, old);
796         };
797         _ if intrinsic.as_str().starts_with("atomic_cxchg"), (v ptr, c test_old, c new) { // both atomic_cxchg_* and atomic_cxchgweak_*
798             let layout = new.layout();
799             match layout.ty.kind() {
800                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
801                 _ => {
802                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
803                     return;
804                 }
805             }
806
807             let test_old = test_old.load_scalar(fx);
808             let new = new.load_scalar(fx);
809
810             let old = fx.bcx.ins().atomic_cas(MemFlags::trusted(), ptr, test_old, new);
811             let is_eq = fx.bcx.ins().icmp(IntCC::Equal, old, test_old);
812
813             let ret_val = CValue::by_val_pair(old, fx.bcx.ins().bint(types::I8, is_eq), ret.layout());
814             ret.write_cvalue(fx, ret_val)
815         };
816
817         _ if intrinsic.as_str().starts_with("atomic_xadd"), (v ptr, c amount) {
818             let layout = amount.layout();
819             match layout.ty.kind() {
820                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
821                 _ => {
822                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
823                     return;
824                 }
825             }
826             let ty = fx.clif_type(layout.ty).unwrap();
827
828             let amount = amount.load_scalar(fx);
829
830             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Add, ptr, amount);
831
832             let old = CValue::by_val(old, layout);
833             ret.write_cvalue(fx, old);
834         };
835         _ if intrinsic.as_str().starts_with("atomic_xsub"), (v ptr, c amount) {
836             let layout = amount.layout();
837             match layout.ty.kind() {
838                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
839                 _ => {
840                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
841                     return;
842                 }
843             }
844             let ty = fx.clif_type(layout.ty).unwrap();
845
846             let amount = amount.load_scalar(fx);
847
848             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Sub, ptr, amount);
849
850             let old = CValue::by_val(old, layout);
851             ret.write_cvalue(fx, old);
852         };
853         _ if intrinsic.as_str().starts_with("atomic_and"), (v ptr, c src) {
854             let layout = src.layout();
855             match layout.ty.kind() {
856                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
857                 _ => {
858                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
859                     return;
860                 }
861             }
862             let ty = fx.clif_type(layout.ty).unwrap();
863
864             let src = src.load_scalar(fx);
865
866             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::And, ptr, src);
867
868             let old = CValue::by_val(old, layout);
869             ret.write_cvalue(fx, old);
870         };
871         _ if intrinsic.as_str().starts_with("atomic_or"), (v ptr, c src) {
872             let layout = src.layout();
873             match layout.ty.kind() {
874                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
875                 _ => {
876                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
877                     return;
878                 }
879             }
880             let ty = fx.clif_type(layout.ty).unwrap();
881
882             let src = src.load_scalar(fx);
883
884             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Or, ptr, src);
885
886             let old = CValue::by_val(old, layout);
887             ret.write_cvalue(fx, old);
888         };
889         _ if intrinsic.as_str().starts_with("atomic_xor"), (v ptr, c src) {
890             let layout = src.layout();
891             match layout.ty.kind() {
892                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
893                 _ => {
894                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
895                     return;
896                 }
897             }
898             let ty = fx.clif_type(layout.ty).unwrap();
899
900             let src = src.load_scalar(fx);
901
902             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Xor, ptr, src);
903
904             let old = CValue::by_val(old, layout);
905             ret.write_cvalue(fx, old);
906         };
907         _ if intrinsic.as_str().starts_with("atomic_nand"), (v ptr, c src) {
908             let layout = src.layout();
909             match layout.ty.kind() {
910                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
911                 _ => {
912                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
913                     return;
914                 }
915             }
916             let ty = fx.clif_type(layout.ty).unwrap();
917
918             let src = src.load_scalar(fx);
919
920             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Nand, ptr, src);
921
922             let old = CValue::by_val(old, layout);
923             ret.write_cvalue(fx, old);
924         };
925         _ if intrinsic.as_str().starts_with("atomic_max"), (v ptr, c src) {
926             let layout = src.layout();
927             match layout.ty.kind() {
928                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
929                 _ => {
930                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
931                     return;
932                 }
933             }
934             let ty = fx.clif_type(layout.ty).unwrap();
935
936             let src = src.load_scalar(fx);
937
938             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Smax, ptr, src);
939
940             let old = CValue::by_val(old, layout);
941             ret.write_cvalue(fx, old);
942         };
943         _ if intrinsic.as_str().starts_with("atomic_umax"), (v ptr, c src) {
944             let layout = src.layout();
945             match layout.ty.kind() {
946                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
947                 _ => {
948                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
949                     return;
950                 }
951             }
952             let ty = fx.clif_type(layout.ty).unwrap();
953
954             let src = src.load_scalar(fx);
955
956             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Umax, ptr, src);
957
958             let old = CValue::by_val(old, layout);
959             ret.write_cvalue(fx, old);
960         };
961         _ if intrinsic.as_str().starts_with("atomic_min"), (v ptr, c src) {
962             let layout = src.layout();
963             match layout.ty.kind() {
964                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
965                 _ => {
966                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
967                     return;
968                 }
969             }
970             let ty = fx.clif_type(layout.ty).unwrap();
971
972             let src = src.load_scalar(fx);
973
974             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Smin, ptr, src);
975
976             let old = CValue::by_val(old, layout);
977             ret.write_cvalue(fx, old);
978         };
979         _ if intrinsic.as_str().starts_with("atomic_umin"), (v ptr, c src) {
980             let layout = src.layout();
981             match layout.ty.kind() {
982                 ty::Uint(_) | ty::Int(_) | ty::RawPtr(..) => {}
983                 _ => {
984                     report_atomic_type_validation_error(fx, intrinsic, span, layout.ty);
985                     return;
986                 }
987             }
988             let ty = fx.clif_type(layout.ty).unwrap();
989
990             let src = src.load_scalar(fx);
991
992             let old = fx.bcx.ins().atomic_rmw(ty, MemFlags::trusted(), AtomicRmwOp::Umin, ptr, src);
993
994             let old = CValue::by_val(old, layout);
995             ret.write_cvalue(fx, old);
996         };
997
998         // In Rust floating point min and max don't propagate NaN. In Cranelift they do however.
999         // For this reason it is necessary to use `a.is_nan() ? b : (a >= b ? b : a)` for `minnumf*`
1000         // and `a.is_nan() ? b : (a <= b ? b : a)` for `maxnumf*`. NaN checks are done by comparing
1001         // a float against itself. Only in case of NaN is it not equal to itself.
1002         minnumf32, (v a, v b) {
1003             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
1004             let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
1005             let temp = fx.bcx.ins().select(a_ge_b, b, a);
1006             let val = fx.bcx.ins().select(a_is_nan, b, temp);
1007             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
1008             ret.write_cvalue(fx, val);
1009         };
1010         minnumf64, (v a, v b) {
1011             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
1012             let a_ge_b = fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, a, b);
1013             let temp = fx.bcx.ins().select(a_ge_b, b, a);
1014             let val = fx.bcx.ins().select(a_is_nan, b, temp);
1015             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
1016             ret.write_cvalue(fx, val);
1017         };
1018         maxnumf32, (v a, v b) {
1019             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
1020             let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
1021             let temp = fx.bcx.ins().select(a_le_b, b, a);
1022             let val = fx.bcx.ins().select(a_is_nan, b, temp);
1023             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f32));
1024             ret.write_cvalue(fx, val);
1025         };
1026         maxnumf64, (v a, v b) {
1027             let a_is_nan = fx.bcx.ins().fcmp(FloatCC::NotEqual, a, a);
1028             let a_le_b = fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, a, b);
1029             let temp = fx.bcx.ins().select(a_le_b, b, a);
1030             let val = fx.bcx.ins().select(a_is_nan, b, temp);
1031             let val = CValue::by_val(val, fx.layout_of(fx.tcx.types.f64));
1032             ret.write_cvalue(fx, val);
1033         };
1034
1035         kw.Try, (v f, v data, v _catch_fn) {
1036             // FIXME once unwinding is supported, change this to actually catch panics
1037             let f_sig = fx.bcx.func.import_signature(Signature {
1038                 call_conv: fx.target_config.default_call_conv,
1039                 params: vec![AbiParam::new(fx.bcx.func.dfg.value_type(data))],
1040                 returns: vec![],
1041             });
1042
1043             fx.bcx.ins().call_indirect(f_sig, f, &[data]);
1044
1045             let layout = ret.layout();
1046             let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
1047             ret.write_cvalue(fx, ret_val);
1048         };
1049
1050         fadd_fast | fsub_fast | fmul_fast | fdiv_fast | frem_fast, (c x, c y) {
1051             let res = crate::num::codegen_float_binop(fx, match intrinsic {
1052                 sym::fadd_fast => BinOp::Add,
1053                 sym::fsub_fast => BinOp::Sub,
1054                 sym::fmul_fast => BinOp::Mul,
1055                 sym::fdiv_fast => BinOp::Div,
1056                 sym::frem_fast => BinOp::Rem,
1057                 _ => unreachable!(),
1058             }, x, y);
1059             ret.write_cvalue(fx, res);
1060         };
1061         float_to_int_unchecked, (v f) {
1062             let res = crate::cast::clif_int_or_float_cast(
1063                 fx,
1064                 f,
1065                 false,
1066                 fx.clif_type(ret.layout().ty).unwrap(),
1067                 type_sign(ret.layout().ty),
1068             );
1069             ret.write_cvalue(fx, CValue::by_val(res, ret.layout()));
1070         };
1071
1072         raw_eq, (v lhs_ref, v rhs_ref) {
1073             let size = fx.layout_of(substs.type_at(0)).layout.size;
1074             // FIXME add and use emit_small_memcmp
1075             let is_eq_value =
1076                 if size == Size::ZERO {
1077                     // No bytes means they're trivially equal
1078                     fx.bcx.ins().iconst(types::I8, 1)
1079                 } else if let Some(clty) = size.bits().try_into().ok().and_then(Type::int) {
1080                     // Can't use `trusted` for these loads; they could be unaligned.
1081                     let mut flags = MemFlags::new();
1082                     flags.set_notrap();
1083                     let lhs_val = fx.bcx.ins().load(clty, flags, lhs_ref, 0);
1084                     let rhs_val = fx.bcx.ins().load(clty, flags, rhs_ref, 0);
1085                     let eq = fx.bcx.ins().icmp(IntCC::Equal, lhs_val, rhs_val);
1086                     fx.bcx.ins().bint(types::I8, eq)
1087                 } else {
1088                     // Just call `memcmp` (like slices do in core) when the
1089                     // size is too large or it's not a power-of-two.
1090                     let signed_bytes = i64::try_from(size.bytes()).unwrap();
1091                     let bytes_val = fx.bcx.ins().iconst(fx.pointer_type, signed_bytes);
1092                     let params = vec![AbiParam::new(fx.pointer_type); 3];
1093                     let returns = vec![AbiParam::new(types::I32)];
1094                     let args = &[lhs_ref, rhs_ref, bytes_val];
1095                     let cmp = fx.lib_call("memcmp", params, returns, args)[0];
1096                     let eq = fx.bcx.ins().icmp_imm(IntCC::Equal, cmp, 0);
1097                     fx.bcx.ins().bint(types::I8, eq)
1098                 };
1099             ret.write_cvalue(fx, CValue::by_val(is_eq_value, ret.layout()));
1100         };
1101
1102         const_allocate, (c _size, c _align) {
1103             // returns a null pointer at runtime.
1104             let null = fx.bcx.ins().iconst(fx.pointer_type, 0);
1105             ret.write_cvalue(fx, CValue::by_val(null, ret.layout()));
1106         };
1107
1108         const_deallocate, (c _ptr, c _size, c _align) {
1109             // nop at runtime.
1110         };
1111
1112         black_box, (c a) {
1113             // FIXME implement black_box semantics
1114             ret.write_cvalue(fx, a);
1115         };
1116     }
1117
1118     if let Some((_, dest)) = destination {
1119         let ret_block = fx.get_block(dest);
1120         fx.bcx.ins().jump(ret_block, &[]);
1121     } else {
1122         trap_unreachable(fx, "[corruption] Diverging intrinsic returned.");
1123     }
1124 }