]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_llvm/src/intrinsic.rs
Rollup merge of #105859 - compiler-errors:hr-lifetime-add, r=davidtwco
[rust.git] / compiler / rustc_codegen_llvm / src / intrinsic.rs
1 use crate::abi::{Abi, FnAbi, FnAbiLlvmExt, LlvmType, PassMode};
2 use crate::builder::Builder;
3 use crate::context::CodegenCx;
4 use crate::llvm;
5 use crate::type_::Type;
6 use crate::type_of::LayoutLlvmExt;
7 use crate::va_arg::emit_va_arg;
8 use crate::value::Value;
9
10 use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh};
11 use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
12 use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
13 use rustc_codegen_ssa::mir::operand::OperandRef;
14 use rustc_codegen_ssa::mir::place::PlaceRef;
15 use rustc_codegen_ssa::traits::*;
16 use rustc_hir as hir;
17 use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf};
18 use rustc_middle::ty::{self, Ty};
19 use rustc_middle::{bug, span_bug};
20 use rustc_span::{sym, symbol::kw, Span, Symbol};
21 use rustc_target::abi::{self, Align, HasDataLayout, Primitive};
22 use rustc_target::spec::{HasTargetSpec, PanicStrategy};
23
24 use std::cmp::Ordering;
25 use std::iter;
26
27 fn get_simple_intrinsic<'ll>(
28     cx: &CodegenCx<'ll, '_>,
29     name: Symbol,
30 ) -> Option<(&'ll Type, &'ll Value)> {
31     let llvm_name = match name {
32         sym::sqrtf32 => "llvm.sqrt.f32",
33         sym::sqrtf64 => "llvm.sqrt.f64",
34         sym::powif32 => "llvm.powi.f32",
35         sym::powif64 => "llvm.powi.f64",
36         sym::sinf32 => "llvm.sin.f32",
37         sym::sinf64 => "llvm.sin.f64",
38         sym::cosf32 => "llvm.cos.f32",
39         sym::cosf64 => "llvm.cos.f64",
40         sym::powf32 => "llvm.pow.f32",
41         sym::powf64 => "llvm.pow.f64",
42         sym::expf32 => "llvm.exp.f32",
43         sym::expf64 => "llvm.exp.f64",
44         sym::exp2f32 => "llvm.exp2.f32",
45         sym::exp2f64 => "llvm.exp2.f64",
46         sym::logf32 => "llvm.log.f32",
47         sym::logf64 => "llvm.log.f64",
48         sym::log10f32 => "llvm.log10.f32",
49         sym::log10f64 => "llvm.log10.f64",
50         sym::log2f32 => "llvm.log2.f32",
51         sym::log2f64 => "llvm.log2.f64",
52         sym::fmaf32 => "llvm.fma.f32",
53         sym::fmaf64 => "llvm.fma.f64",
54         sym::fabsf32 => "llvm.fabs.f32",
55         sym::fabsf64 => "llvm.fabs.f64",
56         sym::minnumf32 => "llvm.minnum.f32",
57         sym::minnumf64 => "llvm.minnum.f64",
58         sym::maxnumf32 => "llvm.maxnum.f32",
59         sym::maxnumf64 => "llvm.maxnum.f64",
60         sym::copysignf32 => "llvm.copysign.f32",
61         sym::copysignf64 => "llvm.copysign.f64",
62         sym::floorf32 => "llvm.floor.f32",
63         sym::floorf64 => "llvm.floor.f64",
64         sym::ceilf32 => "llvm.ceil.f32",
65         sym::ceilf64 => "llvm.ceil.f64",
66         sym::truncf32 => "llvm.trunc.f32",
67         sym::truncf64 => "llvm.trunc.f64",
68         sym::rintf32 => "llvm.rint.f32",
69         sym::rintf64 => "llvm.rint.f64",
70         sym::nearbyintf32 => "llvm.nearbyint.f32",
71         sym::nearbyintf64 => "llvm.nearbyint.f64",
72         sym::roundf32 => "llvm.round.f32",
73         sym::roundf64 => "llvm.round.f64",
74         sym::ptr_mask => "llvm.ptrmask",
75         _ => return None,
76     };
77     Some(cx.get_intrinsic(llvm_name))
78 }
79
80 impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
81     fn codegen_intrinsic_call(
82         &mut self,
83         instance: ty::Instance<'tcx>,
84         fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
85         args: &[OperandRef<'tcx, &'ll Value>],
86         llresult: &'ll Value,
87         span: Span,
88     ) {
89         let tcx = self.tcx;
90         let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all());
91
92         let ty::FnDef(def_id, substs) = *callee_ty.kind() else {
93             bug!("expected fn item type, found {}", callee_ty);
94         };
95
96         let sig = callee_ty.fn_sig(tcx);
97         let sig = tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), sig);
98         let arg_tys = sig.inputs();
99         let ret_ty = sig.output();
100         let name = tcx.item_name(def_id);
101
102         let llret_ty = self.layout_of(ret_ty).llvm_type(self);
103         let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout);
104
105         let simple = get_simple_intrinsic(self, name);
106         let llval = match name {
107             _ if simple.is_some() => {
108                 let (simple_ty, simple_fn) = simple.unwrap();
109                 self.call(
110                     simple_ty,
111                     None,
112                     simple_fn,
113                     &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
114                     None,
115                 )
116             }
117             sym::likely => {
118                 self.call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(true)])
119             }
120             sym::unlikely => self
121                 .call_intrinsic("llvm.expect.i1", &[args[0].immediate(), self.const_bool(false)]),
122             kw::Try => {
123                 try_intrinsic(
124                     self,
125                     args[0].immediate(),
126                     args[1].immediate(),
127                     args[2].immediate(),
128                     llresult,
129                 );
130                 return;
131             }
132             sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[]),
133             sym::va_copy => {
134                 self.call_intrinsic("llvm.va_copy", &[args[0].immediate(), args[1].immediate()])
135             }
136             sym::va_arg => {
137                 match fn_abi.ret.layout.abi {
138                     abi::Abi::Scalar(scalar) => {
139                         match scalar.primitive() {
140                             Primitive::Int(..) => {
141                                 if self.cx().size_of(ret_ty).bytes() < 4 {
142                                     // `va_arg` should not be called on an integer type
143                                     // less than 4 bytes in length. If it is, promote
144                                     // the integer to an `i32` and truncate the result
145                                     // back to the smaller type.
146                                     let promoted_result = emit_va_arg(self, args[0], tcx.types.i32);
147                                     self.trunc(promoted_result, llret_ty)
148                                 } else {
149                                     emit_va_arg(self, args[0], ret_ty)
150                                 }
151                             }
152                             Primitive::F64 | Primitive::Pointer => {
153                                 emit_va_arg(self, args[0], ret_ty)
154                             }
155                             // `va_arg` should never be used with the return type f32.
156                             Primitive::F32 => bug!("the va_arg intrinsic does not work with `f32`"),
157                         }
158                     }
159                     _ => bug!("the va_arg intrinsic does not work with non-scalar types"),
160                 }
161             }
162
163             sym::volatile_load | sym::unaligned_volatile_load => {
164                 let tp_ty = substs.type_at(0);
165                 let ptr = args[0].immediate();
166                 let load = if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
167                     let llty = ty.llvm_type(self);
168                     let ptr = self.pointercast(ptr, self.type_ptr_to(llty));
169                     self.volatile_load(llty, ptr)
170                 } else {
171                     self.volatile_load(self.layout_of(tp_ty).llvm_type(self), ptr)
172                 };
173                 let align = if name == sym::unaligned_volatile_load {
174                     1
175                 } else {
176                     self.align_of(tp_ty).bytes() as u32
177                 };
178                 unsafe {
179                     llvm::LLVMSetAlignment(load, align);
180                 }
181                 self.to_immediate(load, self.layout_of(tp_ty))
182             }
183             sym::volatile_store => {
184                 let dst = args[0].deref(self.cx());
185                 args[1].val.volatile_store(self, dst);
186                 return;
187             }
188             sym::unaligned_volatile_store => {
189                 let dst = args[0].deref(self.cx());
190                 args[1].val.unaligned_volatile_store(self, dst);
191                 return;
192             }
193             sym::prefetch_read_data
194             | sym::prefetch_write_data
195             | sym::prefetch_read_instruction
196             | sym::prefetch_write_instruction => {
197                 let (rw, cache_type) = match name {
198                     sym::prefetch_read_data => (0, 1),
199                     sym::prefetch_write_data => (1, 1),
200                     sym::prefetch_read_instruction => (0, 0),
201                     sym::prefetch_write_instruction => (1, 0),
202                     _ => bug!(),
203                 };
204                 self.call_intrinsic(
205                     "llvm.prefetch",
206                     &[
207                         args[0].immediate(),
208                         self.const_i32(rw),
209                         args[1].immediate(),
210                         self.const_i32(cache_type),
211                     ],
212                 )
213             }
214             sym::ctlz
215             | sym::ctlz_nonzero
216             | sym::cttz
217             | sym::cttz_nonzero
218             | sym::ctpop
219             | sym::bswap
220             | sym::bitreverse
221             | sym::rotate_left
222             | sym::rotate_right
223             | sym::saturating_add
224             | sym::saturating_sub => {
225                 let ty = arg_tys[0];
226                 match int_type_width_signed(ty, self) {
227                     Some((width, signed)) => match name {
228                         sym::ctlz | sym::cttz => {
229                             let y = self.const_bool(false);
230                             self.call_intrinsic(
231                                 &format!("llvm.{}.i{}", name, width),
232                                 &[args[0].immediate(), y],
233                             )
234                         }
235                         sym::ctlz_nonzero => {
236                             let y = self.const_bool(true);
237                             let llvm_name = &format!("llvm.ctlz.i{}", width);
238                             self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
239                         }
240                         sym::cttz_nonzero => {
241                             let y = self.const_bool(true);
242                             let llvm_name = &format!("llvm.cttz.i{}", width);
243                             self.call_intrinsic(llvm_name, &[args[0].immediate(), y])
244                         }
245                         sym::ctpop => self.call_intrinsic(
246                             &format!("llvm.ctpop.i{}", width),
247                             &[args[0].immediate()],
248                         ),
249                         sym::bswap => {
250                             if width == 8 {
251                                 args[0].immediate() // byte swap a u8/i8 is just a no-op
252                             } else {
253                                 self.call_intrinsic(
254                                     &format!("llvm.bswap.i{}", width),
255                                     &[args[0].immediate()],
256                                 )
257                             }
258                         }
259                         sym::bitreverse => self.call_intrinsic(
260                             &format!("llvm.bitreverse.i{}", width),
261                             &[args[0].immediate()],
262                         ),
263                         sym::rotate_left | sym::rotate_right => {
264                             let is_left = name == sym::rotate_left;
265                             let val = args[0].immediate();
266                             let raw_shift = args[1].immediate();
267                             // rotate = funnel shift with first two args the same
268                             let llvm_name =
269                                 &format!("llvm.fsh{}.i{}", if is_left { 'l' } else { 'r' }, width);
270                             self.call_intrinsic(llvm_name, &[val, val, raw_shift])
271                         }
272                         sym::saturating_add | sym::saturating_sub => {
273                             let is_add = name == sym::saturating_add;
274                             let lhs = args[0].immediate();
275                             let rhs = args[1].immediate();
276                             let llvm_name = &format!(
277                                 "llvm.{}{}.sat.i{}",
278                                 if signed { 's' } else { 'u' },
279                                 if is_add { "add" } else { "sub" },
280                                 width
281                             );
282                             self.call_intrinsic(llvm_name, &[lhs, rhs])
283                         }
284                         _ => bug!(),
285                     },
286                     None => {
287                         tcx.sess.emit_err(InvalidMonomorphization::BasicIntegerType {
288                             span,
289                             name,
290                             ty,
291                         });
292                         return;
293                     }
294                 }
295             }
296
297             sym::raw_eq => {
298                 use abi::Abi::*;
299                 let tp_ty = substs.type_at(0);
300                 let layout = self.layout_of(tp_ty).layout;
301                 let use_integer_compare = match layout.abi() {
302                     Scalar(_) | ScalarPair(_, _) => true,
303                     Uninhabited | Vector { .. } => false,
304                     Aggregate { .. } => {
305                         // For rusty ABIs, small aggregates are actually passed
306                         // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
307                         // so we re-use that same threshold here.
308                         layout.size() <= self.data_layout().pointer_size * 2
309                     }
310                 };
311
312                 let a = args[0].immediate();
313                 let b = args[1].immediate();
314                 if layout.size().bytes() == 0 {
315                     self.const_bool(true)
316                 } else if use_integer_compare {
317                     let integer_ty = self.type_ix(layout.size().bits());
318                     let ptr_ty = self.type_ptr_to(integer_ty);
319                     let a_ptr = self.bitcast(a, ptr_ty);
320                     let a_val = self.load(integer_ty, a_ptr, layout.align().abi);
321                     let b_ptr = self.bitcast(b, ptr_ty);
322                     let b_val = self.load(integer_ty, b_ptr, layout.align().abi);
323                     self.icmp(IntPredicate::IntEQ, a_val, b_val)
324                 } else {
325                     let i8p_ty = self.type_i8p();
326                     let a_ptr = self.bitcast(a, i8p_ty);
327                     let b_ptr = self.bitcast(b, i8p_ty);
328                     let n = self.const_usize(layout.size().bytes());
329                     let cmp = self.call_intrinsic("memcmp", &[a_ptr, b_ptr, n]);
330                     match self.cx.sess().target.arch.as_ref() {
331                         "avr" | "msp430" => self.icmp(IntPredicate::IntEQ, cmp, self.const_i16(0)),
332                         _ => self.icmp(IntPredicate::IntEQ, cmp, self.const_i32(0)),
333                     }
334                 }
335             }
336
337             sym::black_box => {
338                 args[0].val.store(self, result);
339                 let result_val_span = [result.llval];
340                 // We need to "use" the argument in some way LLVM can't introspect, and on
341                 // targets that support it we can typically leverage inline assembly to do
342                 // this. LLVM's interpretation of inline assembly is that it's, well, a black
343                 // box. This isn't the greatest implementation since it probably deoptimizes
344                 // more than we want, but it's so far good enough.
345                 //
346                 // For zero-sized types, the location pointed to by the result may be
347                 // uninitialized. Do not "use" the result in this case; instead just clobber
348                 // the memory.
349                 let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() {
350                     ("~{memory}", &[])
351                 } else {
352                     ("r,~{memory}", &result_val_span)
353                 };
354                 crate::asm::inline_asm_call(
355                     self,
356                     "",
357                     constraint,
358                     inputs,
359                     self.type_void(),
360                     true,
361                     false,
362                     llvm::AsmDialect::Att,
363                     &[span],
364                     false,
365                     None,
366                 )
367                 .unwrap_or_else(|| bug!("failed to generate inline asm call for `black_box`"));
368
369                 // We have copied the value to `result` already.
370                 return;
371             }
372
373             _ if name.as_str().starts_with("simd_") => {
374                 match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
375                     Ok(llval) => llval,
376                     Err(()) => return,
377                 }
378             }
379
380             _ => bug!("unknown intrinsic '{}'", name),
381         };
382
383         if !fn_abi.ret.is_ignore() {
384             if let PassMode::Cast(ty, _) = &fn_abi.ret.mode {
385                 let ptr_llty = self.type_ptr_to(ty.llvm_type(self));
386                 let ptr = self.pointercast(result.llval, ptr_llty);
387                 self.store(llval, ptr, result.align);
388             } else {
389                 OperandRef::from_immediate_or_packed_pair(self, llval, result.layout)
390                     .val
391                     .store(self, result);
392             }
393         }
394     }
395
396     fn abort(&mut self) {
397         self.call_intrinsic("llvm.trap", &[]);
398     }
399
400     fn assume(&mut self, val: Self::Value) {
401         self.call_intrinsic("llvm.assume", &[val]);
402     }
403
404     fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
405         self.call_intrinsic("llvm.expect.i1", &[cond, self.const_bool(expected)])
406     }
407
408     fn type_test(&mut self, pointer: Self::Value, typeid: Self::Value) -> Self::Value {
409         // Test the called operand using llvm.type.test intrinsic. The LowerTypeTests link-time
410         // optimization pass replaces calls to this intrinsic with code to test type membership.
411         let i8p_ty = self.type_i8p();
412         let bitcast = self.bitcast(pointer, i8p_ty);
413         self.call_intrinsic("llvm.type.test", &[bitcast, typeid])
414     }
415
416     fn type_checked_load(
417         &mut self,
418         llvtable: &'ll Value,
419         vtable_byte_offset: u64,
420         typeid: &'ll Value,
421     ) -> Self::Value {
422         let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
423         let type_checked_load =
424             self.call_intrinsic("llvm.type.checked.load", &[llvtable, vtable_byte_offset, typeid]);
425         self.extract_value(type_checked_load, 0)
426     }
427
428     fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
429         self.call_intrinsic("llvm.va_start", &[va_list])
430     }
431
432     fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
433         self.call_intrinsic("llvm.va_end", &[va_list])
434     }
435 }
436
437 fn try_intrinsic<'ll>(
438     bx: &mut Builder<'_, 'll, '_>,
439     try_func: &'ll Value,
440     data: &'ll Value,
441     catch_func: &'ll Value,
442     dest: &'ll Value,
443 ) {
444     if bx.sess().panic_strategy() == PanicStrategy::Abort {
445         let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
446         bx.call(try_func_ty, None, try_func, &[data], None);
447         // Return 0 unconditionally from the intrinsic call;
448         // we can never unwind.
449         let ret_align = bx.tcx().data_layout.i32_align.abi;
450         bx.store(bx.const_i32(0), dest, ret_align);
451     } else if wants_msvc_seh(bx.sess()) {
452         codegen_msvc_try(bx, try_func, data, catch_func, dest);
453     } else if bx.sess().target.os == "emscripten" {
454         codegen_emcc_try(bx, try_func, data, catch_func, dest);
455     } else {
456         codegen_gnu_try(bx, try_func, data, catch_func, dest);
457     }
458 }
459
460 // MSVC's definition of the `rust_try` function.
461 //
462 // This implementation uses the new exception handling instructions in LLVM
463 // which have support in LLVM for SEH on MSVC targets. Although these
464 // instructions are meant to work for all targets, as of the time of this
465 // writing, however, LLVM does not recommend the usage of these new instructions
466 // as the old ones are still more optimized.
467 fn codegen_msvc_try<'ll>(
468     bx: &mut Builder<'_, 'll, '_>,
469     try_func: &'ll Value,
470     data: &'ll Value,
471     catch_func: &'ll Value,
472     dest: &'ll Value,
473 ) {
474     let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
475         bx.set_personality_fn(bx.eh_personality());
476
477         let normal = bx.append_sibling_block("normal");
478         let catchswitch = bx.append_sibling_block("catchswitch");
479         let catchpad_rust = bx.append_sibling_block("catchpad_rust");
480         let catchpad_foreign = bx.append_sibling_block("catchpad_foreign");
481         let caught = bx.append_sibling_block("caught");
482
483         let try_func = llvm::get_param(bx.llfn(), 0);
484         let data = llvm::get_param(bx.llfn(), 1);
485         let catch_func = llvm::get_param(bx.llfn(), 2);
486
487         // We're generating an IR snippet that looks like:
488         //
489         //   declare i32 @rust_try(%try_func, %data, %catch_func) {
490         //      %slot = alloca i8*
491         //      invoke %try_func(%data) to label %normal unwind label %catchswitch
492         //
493         //   normal:
494         //      ret i32 0
495         //
496         //   catchswitch:
497         //      %cs = catchswitch within none [%catchpad_rust, %catchpad_foreign] unwind to caller
498         //
499         //   catchpad_rust:
500         //      %tok = catchpad within %cs [%type_descriptor, 8, %slot]
501         //      %ptr = load %slot
502         //      call %catch_func(%data, %ptr)
503         //      catchret from %tok to label %caught
504         //
505         //   catchpad_foreign:
506         //      %tok = catchpad within %cs [null, 64, null]
507         //      call %catch_func(%data, null)
508         //      catchret from %tok to label %caught
509         //
510         //   caught:
511         //      ret i32 1
512         //   }
513         //
514         // This structure follows the basic usage of throw/try/catch in LLVM.
515         // For example, compile this C++ snippet to see what LLVM generates:
516         //
517         //      struct rust_panic {
518         //          rust_panic(const rust_panic&);
519         //          ~rust_panic();
520         //
521         //          void* x[2];
522         //      };
523         //
524         //      int __rust_try(
525         //          void (*try_func)(void*),
526         //          void *data,
527         //          void (*catch_func)(void*, void*) noexcept
528         //      ) {
529         //          try {
530         //              try_func(data);
531         //              return 0;
532         //          } catch(rust_panic& a) {
533         //              catch_func(data, &a);
534         //              return 1;
535         //          } catch(...) {
536         //              catch_func(data, NULL);
537         //              return 1;
538         //          }
539         //      }
540         //
541         // More information can be found in libstd's seh.rs implementation.
542         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
543         let slot = bx.alloca(bx.type_i8p(), ptr_align);
544         let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
545         bx.invoke(try_func_ty, None, try_func, &[data], normal, catchswitch, None);
546
547         bx.switch_to_block(normal);
548         bx.ret(bx.const_i32(0));
549
550         bx.switch_to_block(catchswitch);
551         let cs = bx.catch_switch(None, None, &[catchpad_rust, catchpad_foreign]);
552
553         // We can't use the TypeDescriptor defined in libpanic_unwind because it
554         // might be in another DLL and the SEH encoding only supports specifying
555         // a TypeDescriptor from the current module.
556         //
557         // However this isn't an issue since the MSVC runtime uses string
558         // comparison on the type name to match TypeDescriptors rather than
559         // pointer equality.
560         //
561         // So instead we generate a new TypeDescriptor in each module that uses
562         // `try` and let the linker merge duplicate definitions in the same
563         // module.
564         //
565         // When modifying, make sure that the type_name string exactly matches
566         // the one used in library/panic_unwind/src/seh.rs.
567         let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_i8p());
568         let type_name = bx.const_bytes(b"rust_panic\0");
569         let type_info =
570             bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_i8p()), type_name], false);
571         let tydesc = bx.declare_global("__rust_panic_type_info", bx.val_ty(type_info));
572         unsafe {
573             llvm::LLVMRustSetLinkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
574             llvm::SetUniqueComdat(bx.llmod, tydesc);
575             llvm::LLVMSetInitializer(tydesc, type_info);
576         }
577
578         // The flag value of 8 indicates that we are catching the exception by
579         // reference instead of by value. We can't use catch by value because
580         // that requires copying the exception object, which we don't support
581         // since our exception object effectively contains a Box.
582         //
583         // Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
584         bx.switch_to_block(catchpad_rust);
585         let flags = bx.const_i32(8);
586         let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
587         let ptr = bx.load(bx.type_i8p(), slot, ptr_align);
588         let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
589         bx.call(catch_ty, None, catch_func, &[data, ptr], Some(&funclet));
590         bx.catch_ret(&funclet, caught);
591
592         // The flag value of 64 indicates a "catch-all".
593         bx.switch_to_block(catchpad_foreign);
594         let flags = bx.const_i32(64);
595         let null = bx.const_null(bx.type_i8p());
596         let funclet = bx.catch_pad(cs, &[null, flags, null]);
597         bx.call(catch_ty, None, catch_func, &[data, null], Some(&funclet));
598         bx.catch_ret(&funclet, caught);
599
600         bx.switch_to_block(caught);
601         bx.ret(bx.const_i32(1));
602     });
603
604     // Note that no invoke is used here because by definition this function
605     // can't panic (that's what it's catching).
606     let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
607     let i32_align = bx.tcx().data_layout.i32_align.abi;
608     bx.store(ret, dest, i32_align);
609 }
610
611 // Definition of the standard `try` function for Rust using the GNU-like model
612 // of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
613 // instructions).
614 //
615 // This codegen is a little surprising because we always call a shim
616 // function instead of inlining the call to `invoke` manually here. This is done
617 // because in LLVM we're only allowed to have one personality per function
618 // definition. The call to the `try` intrinsic is being inlined into the
619 // function calling it, and that function may already have other personality
620 // functions in play. By calling a shim we're guaranteed that our shim will have
621 // the right personality function.
622 fn codegen_gnu_try<'ll>(
623     bx: &mut Builder<'_, 'll, '_>,
624     try_func: &'ll Value,
625     data: &'ll Value,
626     catch_func: &'ll Value,
627     dest: &'ll Value,
628 ) {
629     let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
630         // Codegens the shims described above:
631         //
632         //   bx:
633         //      invoke %try_func(%data) normal %normal unwind %catch
634         //
635         //   normal:
636         //      ret 0
637         //
638         //   catch:
639         //      (%ptr, _) = landingpad
640         //      call %catch_func(%data, %ptr)
641         //      ret 1
642         let then = bx.append_sibling_block("then");
643         let catch = bx.append_sibling_block("catch");
644
645         let try_func = llvm::get_param(bx.llfn(), 0);
646         let data = llvm::get_param(bx.llfn(), 1);
647         let catch_func = llvm::get_param(bx.llfn(), 2);
648         let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
649         bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
650
651         bx.switch_to_block(then);
652         bx.ret(bx.const_i32(0));
653
654         // Type indicator for the exception being thrown.
655         //
656         // The first value in this tuple is a pointer to the exception object
657         // being thrown.  The second value is a "selector" indicating which of
658         // the landing pad clauses the exception's type had been matched to.
659         // rust_try ignores the selector.
660         bx.switch_to_block(catch);
661         let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
662         let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1);
663         let tydesc = bx.const_null(bx.type_i8p());
664         bx.add_clause(vals, tydesc);
665         let ptr = bx.extract_value(vals, 0);
666         let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
667         bx.call(catch_ty, None, catch_func, &[data, ptr], None);
668         bx.ret(bx.const_i32(1));
669     });
670
671     // Note that no invoke is used here because by definition this function
672     // can't panic (that's what it's catching).
673     let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
674     let i32_align = bx.tcx().data_layout.i32_align.abi;
675     bx.store(ret, dest, i32_align);
676 }
677
678 // Variant of codegen_gnu_try used for emscripten where Rust panics are
679 // implemented using C++ exceptions. Here we use exceptions of a specific type
680 // (`struct rust_panic`) to represent Rust panics.
681 fn codegen_emcc_try<'ll>(
682     bx: &mut Builder<'_, 'll, '_>,
683     try_func: &'ll Value,
684     data: &'ll Value,
685     catch_func: &'ll Value,
686     dest: &'ll Value,
687 ) {
688     let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
689         // Codegens the shims described above:
690         //
691         //   bx:
692         //      invoke %try_func(%data) normal %normal unwind %catch
693         //
694         //   normal:
695         //      ret 0
696         //
697         //   catch:
698         //      (%ptr, %selector) = landingpad
699         //      %rust_typeid = @llvm.eh.typeid.for(@_ZTI10rust_panic)
700         //      %is_rust_panic = %selector == %rust_typeid
701         //      %catch_data = alloca { i8*, i8 }
702         //      %catch_data[0] = %ptr
703         //      %catch_data[1] = %is_rust_panic
704         //      call %catch_func(%data, %catch_data)
705         //      ret 1
706         let then = bx.append_sibling_block("then");
707         let catch = bx.append_sibling_block("catch");
708
709         let try_func = llvm::get_param(bx.llfn(), 0);
710         let data = llvm::get_param(bx.llfn(), 1);
711         let catch_func = llvm::get_param(bx.llfn(), 2);
712         let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
713         bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
714
715         bx.switch_to_block(then);
716         bx.ret(bx.const_i32(0));
717
718         // Type indicator for the exception being thrown.
719         //
720         // The first value in this tuple is a pointer to the exception object
721         // being thrown.  The second value is a "selector" indicating which of
722         // the landing pad clauses the exception's type had been matched to.
723         bx.switch_to_block(catch);
724         let tydesc = bx.eh_catch_typeinfo();
725         let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false);
726         let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 2);
727         bx.add_clause(vals, tydesc);
728         bx.add_clause(vals, bx.const_null(bx.type_i8p()));
729         let ptr = bx.extract_value(vals, 0);
730         let selector = bx.extract_value(vals, 1);
731
732         // Check if the typeid we got is the one for a Rust panic.
733         let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[tydesc]);
734         let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid);
735         let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool());
736
737         // We need to pass two values to catch_func (ptr and is_rust_panic), so
738         // create an alloca and pass a pointer to that.
739         let ptr_align = bx.tcx().data_layout.pointer_align.abi;
740         let i8_align = bx.tcx().data_layout.i8_align.abi;
741         let catch_data_type = bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false);
742         let catch_data = bx.alloca(catch_data_type, ptr_align);
743         let catch_data_0 =
744             bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(0)]);
745         bx.store(ptr, catch_data_0, ptr_align);
746         let catch_data_1 =
747             bx.inbounds_gep(catch_data_type, catch_data, &[bx.const_usize(0), bx.const_usize(1)]);
748         bx.store(is_rust_panic, catch_data_1, i8_align);
749         let catch_data = bx.bitcast(catch_data, bx.type_i8p());
750
751         let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
752         bx.call(catch_ty, None, catch_func, &[data, catch_data], None);
753         bx.ret(bx.const_i32(1));
754     });
755
756     // Note that no invoke is used here because by definition this function
757     // can't panic (that's what it's catching).
758     let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
759     let i32_align = bx.tcx().data_layout.i32_align.abi;
760     bx.store(ret, dest, i32_align);
761 }
762
763 // Helper function to give a Block to a closure to codegen a shim function.
764 // This is currently primarily used for the `try` intrinsic functions above.
765 fn gen_fn<'ll, 'tcx>(
766     cx: &CodegenCx<'ll, 'tcx>,
767     name: &str,
768     rust_fn_sig: ty::PolyFnSig<'tcx>,
769     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
770 ) -> (&'ll Type, &'ll Value) {
771     let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
772     let llty = fn_abi.llvm_type(cx);
773     let llfn = cx.declare_fn(name, fn_abi);
774     cx.set_frame_pointer_type(llfn);
775     cx.apply_target_cpu_attr(llfn);
776     // FIXME(eddyb) find a nicer way to do this.
777     unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
778     let llbb = Builder::append_block(cx, llfn, "entry-block");
779     let bx = Builder::build(cx, llbb);
780     codegen(bx);
781     (llty, llfn)
782 }
783
784 // Helper function used to get a handle to the `__rust_try` function used to
785 // catch exceptions.
786 //
787 // This function is only generated once and is then cached.
788 fn get_rust_try_fn<'ll, 'tcx>(
789     cx: &CodegenCx<'ll, 'tcx>,
790     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
791 ) -> (&'ll Type, &'ll Value) {
792     if let Some(llfn) = cx.rust_try_fn.get() {
793         return llfn;
794     }
795
796     // Define the type up front for the signature of the rust_try function.
797     let tcx = cx.tcx;
798     let i8p = tcx.mk_mut_ptr(tcx.types.i8);
799     // `unsafe fn(*mut i8) -> ()`
800     let try_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
801         iter::once(i8p),
802         tcx.mk_unit(),
803         false,
804         hir::Unsafety::Unsafe,
805         Abi::Rust,
806     )));
807     // `unsafe fn(*mut i8, *mut i8) -> ()`
808     let catch_fn_ty = tcx.mk_fn_ptr(ty::Binder::dummy(tcx.mk_fn_sig(
809         [i8p, i8p].iter().cloned(),
810         tcx.mk_unit(),
811         false,
812         hir::Unsafety::Unsafe,
813         Abi::Rust,
814     )));
815     // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
816     let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig(
817         [try_fn_ty, i8p, catch_fn_ty].into_iter(),
818         tcx.types.i32,
819         false,
820         hir::Unsafety::Unsafe,
821         Abi::Rust,
822     ));
823     let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
824     cx.rust_try_fn.set(Some(rust_try));
825     rust_try
826 }
827
828 fn generic_simd_intrinsic<'ll, 'tcx>(
829     bx: &mut Builder<'_, 'll, 'tcx>,
830     name: Symbol,
831     callee_ty: Ty<'tcx>,
832     args: &[OperandRef<'tcx, &'ll Value>],
833     ret_ty: Ty<'tcx>,
834     llret_ty: &'ll Type,
835     span: Span,
836 ) -> Result<&'ll Value, ()> {
837     macro_rules! return_error {
838         ($diag: expr) => {{
839             bx.sess().emit_err($diag);
840             return Err(());
841         }};
842     }
843
844     macro_rules! require {
845         ($cond: expr, $diag: expr) => {
846             if !$cond {
847                 return_error!($diag);
848             }
849         };
850     }
851
852     macro_rules! require_simd {
853         ($ty: expr, $diag: expr) => {
854             require!($ty.is_simd(), $diag)
855         };
856     }
857
858     let tcx = bx.tcx();
859     let sig =
860         tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
861     let arg_tys = sig.inputs();
862
863     if name == sym::simd_select_bitmask {
864         require_simd!(
865             arg_tys[1],
866             InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
867         );
868
869         let (len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
870
871         let expected_int_bits = (len.max(8) - 1).next_power_of_two();
872         let expected_bytes = len / 8 + ((len % 8 > 0) as u64);
873
874         let mask_ty = arg_tys[0];
875         let mask = match mask_ty.kind() {
876             ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
877             ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
878             ty::Array(elem, len)
879                 if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
880                     && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
881                         == Some(expected_bytes) =>
882             {
883                 let place = PlaceRef::alloca(bx, args[0].layout);
884                 args[0].val.store(bx, place);
885                 let int_ty = bx.type_ix(expected_bytes * 8);
886                 let ptr = bx.pointercast(place.llval, bx.cx.type_ptr_to(int_ty));
887                 bx.load(int_ty, ptr, Align::ONE)
888             }
889             _ => return_error!(InvalidMonomorphization::InvalidBitmask {
890                 span,
891                 name,
892                 mask_ty,
893                 expected_int_bits,
894                 expected_bytes
895             }),
896         };
897
898         let i1 = bx.type_i1();
899         let im = bx.type_ix(len);
900         let i1xn = bx.type_vector(i1, len);
901         let m_im = bx.trunc(mask, im);
902         let m_i1s = bx.bitcast(m_im, i1xn);
903         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
904     }
905
906     // every intrinsic below takes a SIMD vector as its first argument
907     require_simd!(arg_tys[0], InvalidMonomorphization::SimdInput { span, name, ty: arg_tys[0] });
908     let in_ty = arg_tys[0];
909
910     let comparison = match name {
911         sym::simd_eq => Some(hir::BinOpKind::Eq),
912         sym::simd_ne => Some(hir::BinOpKind::Ne),
913         sym::simd_lt => Some(hir::BinOpKind::Lt),
914         sym::simd_le => Some(hir::BinOpKind::Le),
915         sym::simd_gt => Some(hir::BinOpKind::Gt),
916         sym::simd_ge => Some(hir::BinOpKind::Ge),
917         _ => None,
918     };
919
920     let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
921     if let Some(cmp_op) = comparison {
922         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
923
924         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
925
926         require!(
927             in_len == out_len,
928             InvalidMonomorphization::ReturnLengthInputType {
929                 span,
930                 name,
931                 in_len,
932                 in_ty,
933                 ret_ty,
934                 out_len
935             }
936         );
937         require!(
938             bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
939             InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty }
940         );
941
942         return Ok(compare_simd_types(
943             bx,
944             args[0].immediate(),
945             args[1].immediate(),
946             in_elem,
947             llret_ty,
948             cmp_op,
949         ));
950     }
951
952     if let Some(stripped) = name.as_str().strip_prefix("simd_shuffle") {
953         // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer.
954         // If there is no suffix, use the index array length.
955         let n: u64 = if stripped.is_empty() {
956             // Make sure this is actually an array, since typeck only checks the length-suffixed
957             // version of this intrinsic.
958             match args[2].layout.ty.kind() {
959                 ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => {
960                     len.try_eval_usize(bx.cx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| {
961                         span_bug!(span, "could not evaluate shuffle index array length")
962                     })
963                 }
964                 _ => return_error!(InvalidMonomorphization::SimdShuffle {
965                     span,
966                     name,
967                     ty: args[2].layout.ty
968                 }),
969             }
970         } else {
971             stripped.parse().unwrap_or_else(|_| {
972                 span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
973             })
974         };
975
976         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
977         let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
978         require!(
979             out_len == n,
980             InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
981         );
982         require!(
983             in_elem == out_ty,
984             InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
985         );
986
987         let total_len = u128::from(in_len) * 2;
988
989         let vector = args[2].immediate();
990
991         let indices: Option<Vec<_>> = (0..n)
992             .map(|i| {
993                 let arg_idx = i;
994                 let val = bx.const_get_elt(vector, i as u64);
995                 match bx.const_to_opt_u128(val, true) {
996                     None => {
997                         bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexNotConstant {
998                             span,
999                             name,
1000                             arg_idx,
1001                         });
1002                         None
1003                     }
1004                     Some(idx) if idx >= total_len => {
1005                         bx.sess().emit_err(InvalidMonomorphization::ShuffleIndexOutOfBounds {
1006                             span,
1007                             name,
1008                             arg_idx,
1009                             total_len,
1010                         });
1011                         None
1012                     }
1013                     Some(idx) => Some(bx.const_i32(idx as i32)),
1014                 }
1015             })
1016             .collect();
1017         let Some(indices) = indices else {
1018             return Ok(bx.const_null(llret_ty));
1019         };
1020
1021         return Ok(bx.shuffle_vector(
1022             args[0].immediate(),
1023             args[1].immediate(),
1024             bx.const_vector(&indices),
1025         ));
1026     }
1027
1028     if name == sym::simd_insert {
1029         require!(
1030             in_elem == arg_tys[2],
1031             InvalidMonomorphization::InsertedType {
1032                 span,
1033                 name,
1034                 in_elem,
1035                 in_ty,
1036                 out_ty: arg_tys[2]
1037             }
1038         );
1039         return Ok(bx.insert_element(
1040             args[0].immediate(),
1041             args[2].immediate(),
1042             args[1].immediate(),
1043         ));
1044     }
1045     if name == sym::simd_extract {
1046         require!(
1047             ret_ty == in_elem,
1048             InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
1049         );
1050         return Ok(bx.extract_element(args[0].immediate(), args[1].immediate()));
1051     }
1052
1053     if name == sym::simd_select {
1054         let m_elem_ty = in_elem;
1055         let m_len = in_len;
1056         require_simd!(
1057             arg_tys[1],
1058             InvalidMonomorphization::SimdArgument { span, name, ty: arg_tys[1] }
1059         );
1060         let (v_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
1061         require!(
1062             m_len == v_len,
1063             InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
1064         );
1065         match m_elem_ty.kind() {
1066             ty::Int(_) => {}
1067             _ => return_error!(InvalidMonomorphization::MaskType { span, name, ty: m_elem_ty }),
1068         }
1069         // truncate the mask to a vector of i1s
1070         let i1 = bx.type_i1();
1071         let i1xn = bx.type_vector(i1, m_len as u64);
1072         let m_i1s = bx.trunc(args[0].immediate(), i1xn);
1073         return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
1074     }
1075
1076     if name == sym::simd_bitmask {
1077         // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a
1078         // vector mask and returns the most significant bit (MSB) of each lane in the form
1079         // of either:
1080         // * an unsigned integer
1081         // * an array of `u8`
1082         // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
1083         //
1084         // The bit order of the result depends on the byte endianness, LSB-first for little
1085         // endian and MSB-first for big endian.
1086         let expected_int_bits = in_len.max(8);
1087         let expected_bytes = expected_int_bits / 8 + ((expected_int_bits % 8 > 0) as u64);
1088
1089         // Integer vector <i{in_bitwidth} x in_len>:
1090         let (i_xn, in_elem_bitwidth) = match in_elem.kind() {
1091             ty::Int(i) => (
1092                 args[0].immediate(),
1093                 i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
1094             ),
1095             ty::Uint(i) => (
1096                 args[0].immediate(),
1097                 i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size.bits()),
1098             ),
1099             _ => return_error!(InvalidMonomorphization::VectorArgument {
1100                 span,
1101                 name,
1102                 in_ty,
1103                 in_elem
1104             }),
1105         };
1106
1107         // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
1108         let shift_indices =
1109             vec![
1110                 bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _);
1111                 in_len as _
1112             ];
1113         let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice()));
1114         // Truncate vector to an <i1 x N>
1115         let i1xn = bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len));
1116         // Bitcast <i1 x N> to iN:
1117         let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
1118
1119         match ret_ty.kind() {
1120             ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
1121                 // Zero-extend iN to the bitmask type:
1122                 return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
1123             }
1124             ty::Array(elem, len)
1125                 if matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
1126                     && len.try_eval_usize(bx.tcx, ty::ParamEnv::reveal_all())
1127                         == Some(expected_bytes) =>
1128             {
1129                 // Zero-extend iN to the array length:
1130                 let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
1131
1132                 // Convert the integer to a byte array
1133                 let ptr = bx.alloca(bx.type_ix(expected_bytes * 8), Align::ONE);
1134                 bx.store(ze, ptr, Align::ONE);
1135                 let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
1136                 let ptr = bx.pointercast(ptr, bx.cx.type_ptr_to(array_ty));
1137                 return Ok(bx.load(array_ty, ptr, Align::ONE));
1138             }
1139             _ => return_error!(InvalidMonomorphization::CannotReturn {
1140                 span,
1141                 name,
1142                 ret_ty,
1143                 expected_int_bits,
1144                 expected_bytes
1145             }),
1146         }
1147     }
1148
1149     fn simd_simple_float_intrinsic<'ll, 'tcx>(
1150         name: Symbol,
1151         in_elem: Ty<'_>,
1152         in_ty: Ty<'_>,
1153         in_len: u64,
1154         bx: &mut Builder<'_, 'll, 'tcx>,
1155         span: Span,
1156         args: &[OperandRef<'tcx, &'ll Value>],
1157     ) -> Result<&'ll Value, ()> {
1158         macro_rules! return_error {
1159             ($diag: expr) => {{
1160                 bx.sess().emit_err($diag);
1161                 return Err(());
1162             }};
1163         }
1164
1165         let (elem_ty_str, elem_ty) = if let ty::Float(f) = in_elem.kind() {
1166             let elem_ty = bx.cx.type_float_from_ty(*f);
1167             match f.bit_width() {
1168                 32 => ("f32", elem_ty),
1169                 64 => ("f64", elem_ty),
1170                 _ => return_error!(InvalidMonomorphization::FloatingPointVector {
1171                     span,
1172                     name,
1173                     f_ty: *f,
1174                     in_ty,
1175                 }),
1176             }
1177         } else {
1178             return_error!(InvalidMonomorphization::FloatingPointType { span, name, in_ty });
1179         };
1180
1181         let vec_ty = bx.type_vector(elem_ty, in_len);
1182
1183         let (intr_name, fn_ty) = match name {
1184             sym::simd_ceil => ("ceil", bx.type_func(&[vec_ty], vec_ty)),
1185             sym::simd_fabs => ("fabs", bx.type_func(&[vec_ty], vec_ty)),
1186             sym::simd_fcos => ("cos", bx.type_func(&[vec_ty], vec_ty)),
1187             sym::simd_fexp2 => ("exp2", bx.type_func(&[vec_ty], vec_ty)),
1188             sym::simd_fexp => ("exp", bx.type_func(&[vec_ty], vec_ty)),
1189             sym::simd_flog10 => ("log10", bx.type_func(&[vec_ty], vec_ty)),
1190             sym::simd_flog2 => ("log2", bx.type_func(&[vec_ty], vec_ty)),
1191             sym::simd_flog => ("log", bx.type_func(&[vec_ty], vec_ty)),
1192             sym::simd_floor => ("floor", bx.type_func(&[vec_ty], vec_ty)),
1193             sym::simd_fma => ("fma", bx.type_func(&[vec_ty, vec_ty, vec_ty], vec_ty)),
1194             sym::simd_fpowi => ("powi", bx.type_func(&[vec_ty, bx.type_i32()], vec_ty)),
1195             sym::simd_fpow => ("pow", bx.type_func(&[vec_ty, vec_ty], vec_ty)),
1196             sym::simd_fsin => ("sin", bx.type_func(&[vec_ty], vec_ty)),
1197             sym::simd_fsqrt => ("sqrt", bx.type_func(&[vec_ty], vec_ty)),
1198             sym::simd_round => ("round", bx.type_func(&[vec_ty], vec_ty)),
1199             sym::simd_trunc => ("trunc", bx.type_func(&[vec_ty], vec_ty)),
1200             _ => return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
1201         };
1202         let llvm_name = &format!("llvm.{0}.v{1}{2}", intr_name, in_len, elem_ty_str);
1203         let f = bx.declare_cfn(llvm_name, llvm::UnnamedAddr::No, fn_ty);
1204         let c = bx.call(
1205             fn_ty,
1206             None,
1207             f,
1208             &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
1209             None,
1210         );
1211         Ok(c)
1212     }
1213
1214     if std::matches!(
1215         name,
1216         sym::simd_ceil
1217             | sym::simd_fabs
1218             | sym::simd_fcos
1219             | sym::simd_fexp2
1220             | sym::simd_fexp
1221             | sym::simd_flog10
1222             | sym::simd_flog2
1223             | sym::simd_flog
1224             | sym::simd_floor
1225             | sym::simd_fma
1226             | sym::simd_fpow
1227             | sym::simd_fpowi
1228             | sym::simd_fsin
1229             | sym::simd_fsqrt
1230             | sym::simd_round
1231             | sym::simd_trunc
1232     ) {
1233         return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
1234     }
1235
1236     // FIXME: use:
1237     //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Function.h#L182
1238     //  https://github.com/llvm-mirror/llvm/blob/master/include/llvm/IR/Intrinsics.h#L81
1239     fn llvm_vector_str(
1240         elem_ty: Ty<'_>,
1241         vec_len: u64,
1242         no_pointers: usize,
1243         bx: &Builder<'_, '_, '_>,
1244     ) -> String {
1245         let p0s: String = "p0".repeat(no_pointers);
1246         match *elem_ty.kind() {
1247             ty::Int(v) => format!(
1248                 "v{}{}i{}",
1249                 vec_len,
1250                 p0s,
1251                 // Normalize to prevent crash if v: IntTy::Isize
1252                 v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
1253             ),
1254             ty::Uint(v) => format!(
1255                 "v{}{}i{}",
1256                 vec_len,
1257                 p0s,
1258                 // Normalize to prevent crash if v: UIntTy::Usize
1259                 v.normalize(bx.target_spec().pointer_width).bit_width().unwrap()
1260             ),
1261             ty::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()),
1262             _ => unreachable!(),
1263         }
1264     }
1265
1266     fn llvm_vector_ty<'ll>(
1267         cx: &CodegenCx<'ll, '_>,
1268         elem_ty: Ty<'_>,
1269         vec_len: u64,
1270         mut no_pointers: usize,
1271     ) -> &'ll Type {
1272         // FIXME: use cx.layout_of(ty).llvm_type() ?
1273         let mut elem_ty = match *elem_ty.kind() {
1274             ty::Int(v) => cx.type_int_from_ty(v),
1275             ty::Uint(v) => cx.type_uint_from_ty(v),
1276             ty::Float(v) => cx.type_float_from_ty(v),
1277             _ => unreachable!(),
1278         };
1279         while no_pointers > 0 {
1280             elem_ty = cx.type_ptr_to(elem_ty);
1281             no_pointers -= 1;
1282         }
1283         cx.type_vector(elem_ty, vec_len)
1284     }
1285
1286     if name == sym::simd_gather {
1287         // simd_gather(values: <N x T>, pointers: <N x *_ T>,
1288         //             mask: <N x i{M}>) -> <N x T>
1289         // * N: number of elements in the input vectors
1290         // * T: type of the element to load
1291         // * M: any integer width is supported, will be truncated to i1
1292
1293         // All types must be simd vector types
1294         require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
1295         require_simd!(
1296             arg_tys[1],
1297             InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
1298         );
1299         require_simd!(
1300             arg_tys[2],
1301             InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
1302         );
1303         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
1304
1305         // Of the same length:
1306         let (out_len, _) = arg_tys[1].simd_size_and_type(bx.tcx());
1307         let (out_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
1308         require!(
1309             in_len == out_len,
1310             InvalidMonomorphization::SecondArgumentLength {
1311                 span,
1312                 name,
1313                 in_len,
1314                 in_ty,
1315                 arg_ty: arg_tys[1],
1316                 out_len
1317             }
1318         );
1319         require!(
1320             in_len == out_len2,
1321             InvalidMonomorphization::ThirdArgumentLength {
1322                 span,
1323                 name,
1324                 in_len,
1325                 in_ty,
1326                 arg_ty: arg_tys[2],
1327                 out_len: out_len2
1328             }
1329         );
1330
1331         // The return type must match the first argument type
1332         require!(
1333             ret_ty == in_ty,
1334             InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
1335         );
1336
1337         // This counts how many pointers
1338         fn ptr_count(t: Ty<'_>) -> usize {
1339             match t.kind() {
1340                 ty::RawPtr(p) => 1 + ptr_count(p.ty),
1341                 _ => 0,
1342             }
1343         }
1344
1345         // Non-ptr type
1346         fn non_ptr(t: Ty<'_>) -> Ty<'_> {
1347             match t.kind() {
1348                 ty::RawPtr(p) => non_ptr(p.ty),
1349                 _ => t,
1350             }
1351         }
1352
1353         // The second argument must be a simd vector with an element type that's a pointer
1354         // to the element type of the first argument
1355         let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
1356         let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
1357         let (pointer_count, underlying_ty) = match element_ty1.kind() {
1358             ty::RawPtr(p) if p.ty == in_elem => (ptr_count(element_ty1), non_ptr(element_ty1)),
1359             _ => {
1360                 require!(
1361                     false,
1362                     InvalidMonomorphization::ExpectedElementType {
1363                         span,
1364                         name,
1365                         expected_element: element_ty1,
1366                         second_arg: arg_tys[1],
1367                         in_elem,
1368                         in_ty,
1369                         mutability: ExpectedPointerMutability::Not,
1370                     }
1371                 );
1372                 unreachable!();
1373             }
1374         };
1375         assert!(pointer_count > 0);
1376         assert_eq!(pointer_count - 1, ptr_count(element_ty0));
1377         assert_eq!(underlying_ty, non_ptr(element_ty0));
1378
1379         // The element type of the third argument must be a signed integer type of any width:
1380         let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
1381         match element_ty2.kind() {
1382             ty::Int(_) => (),
1383             _ => {
1384                 require!(
1385                     false,
1386                     InvalidMonomorphization::ThirdArgElementType {
1387                         span,
1388                         name,
1389                         expected_element: element_ty2,
1390                         third_arg: arg_tys[2]
1391                     }
1392                 );
1393             }
1394         }
1395
1396         // Alignment of T, must be a constant integer value:
1397         let alignment_ty = bx.type_i32();
1398         let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32);
1399
1400         // Truncate the mask vector to a vector of i1s:
1401         let (mask, mask_ty) = {
1402             let i1 = bx.type_i1();
1403             let i1xn = bx.type_vector(i1, in_len);
1404             (bx.trunc(args[2].immediate(), i1xn), i1xn)
1405         };
1406
1407         // Type of the vector of pointers:
1408         let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
1409         let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx);
1410
1411         // Type of the vector of elements:
1412         let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1);
1413         let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx);
1414
1415         let llvm_intrinsic =
1416             format!("llvm.masked.gather.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
1417         let fn_ty = bx.type_func(
1418             &[llvm_pointer_vec_ty, alignment_ty, mask_ty, llvm_elem_vec_ty],
1419             llvm_elem_vec_ty,
1420         );
1421         let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
1422         let v = bx.call(
1423             fn_ty,
1424             None,
1425             f,
1426             &[args[1].immediate(), alignment, mask, args[0].immediate()],
1427             None,
1428         );
1429         return Ok(v);
1430     }
1431
1432     if name == sym::simd_scatter {
1433         // simd_scatter(values: <N x T>, pointers: <N x *mut T>,
1434         //             mask: <N x i{M}>) -> ()
1435         // * N: number of elements in the input vectors
1436         // * T: type of the element to load
1437         // * M: any integer width is supported, will be truncated to i1
1438
1439         // All types must be simd vector types
1440         require_simd!(in_ty, InvalidMonomorphization::SimdFirst { span, name, ty: in_ty });
1441         require_simd!(
1442             arg_tys[1],
1443             InvalidMonomorphization::SimdSecond { span, name, ty: arg_tys[1] }
1444         );
1445         require_simd!(
1446             arg_tys[2],
1447             InvalidMonomorphization::SimdThird { span, name, ty: arg_tys[2] }
1448         );
1449
1450         // Of the same length:
1451         let (element_len1, _) = arg_tys[1].simd_size_and_type(bx.tcx());
1452         let (element_len2, _) = arg_tys[2].simd_size_and_type(bx.tcx());
1453         require!(
1454             in_len == element_len1,
1455             InvalidMonomorphization::SecondArgumentLength {
1456                 span,
1457                 name,
1458                 in_len,
1459                 in_ty,
1460                 arg_ty: arg_tys[1],
1461                 out_len: element_len1
1462             }
1463         );
1464         require!(
1465             in_len == element_len2,
1466             InvalidMonomorphization::ThirdArgumentLength {
1467                 span,
1468                 name,
1469                 in_len,
1470                 in_ty,
1471                 arg_ty: arg_tys[2],
1472                 out_len: element_len2
1473             }
1474         );
1475
1476         // This counts how many pointers
1477         fn ptr_count(t: Ty<'_>) -> usize {
1478             match t.kind() {
1479                 ty::RawPtr(p) => 1 + ptr_count(p.ty),
1480                 _ => 0,
1481             }
1482         }
1483
1484         // Non-ptr type
1485         fn non_ptr(t: Ty<'_>) -> Ty<'_> {
1486             match t.kind() {
1487                 ty::RawPtr(p) => non_ptr(p.ty),
1488                 _ => t,
1489             }
1490         }
1491
1492         // The second argument must be a simd vector with an element type that's a pointer
1493         // to the element type of the first argument
1494         let (_, element_ty0) = arg_tys[0].simd_size_and_type(bx.tcx());
1495         let (_, element_ty1) = arg_tys[1].simd_size_and_type(bx.tcx());
1496         let (_, element_ty2) = arg_tys[2].simd_size_and_type(bx.tcx());
1497         let (pointer_count, underlying_ty) = match element_ty1.kind() {
1498             ty::RawPtr(p) if p.ty == in_elem && p.mutbl.is_mut() => {
1499                 (ptr_count(element_ty1), non_ptr(element_ty1))
1500             }
1501             _ => {
1502                 require!(
1503                     false,
1504                     InvalidMonomorphization::ExpectedElementType {
1505                         span,
1506                         name,
1507                         expected_element: element_ty1,
1508                         second_arg: arg_tys[1],
1509                         in_elem,
1510                         in_ty,
1511                         mutability: ExpectedPointerMutability::Mut,
1512                     }
1513                 );
1514                 unreachable!();
1515             }
1516         };
1517         assert!(pointer_count > 0);
1518         assert_eq!(pointer_count - 1, ptr_count(element_ty0));
1519         assert_eq!(underlying_ty, non_ptr(element_ty0));
1520
1521         // The element type of the third argument must be a signed integer type of any width:
1522         match element_ty2.kind() {
1523             ty::Int(_) => (),
1524             _ => {
1525                 require!(
1526                     false,
1527                     InvalidMonomorphization::ThirdArgElementType {
1528                         span,
1529                         name,
1530                         expected_element: element_ty2,
1531                         third_arg: arg_tys[2]
1532                     }
1533                 );
1534             }
1535         }
1536
1537         // Alignment of T, must be a constant integer value:
1538         let alignment_ty = bx.type_i32();
1539         let alignment = bx.const_i32(bx.align_of(in_elem).bytes() as i32);
1540
1541         // Truncate the mask vector to a vector of i1s:
1542         let (mask, mask_ty) = {
1543             let i1 = bx.type_i1();
1544             let i1xn = bx.type_vector(i1, in_len);
1545             (bx.trunc(args[2].immediate(), i1xn), i1xn)
1546         };
1547
1548         let ret_t = bx.type_void();
1549
1550         // Type of the vector of pointers:
1551         let llvm_pointer_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count);
1552         let llvm_pointer_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count, bx);
1553
1554         // Type of the vector of elements:
1555         let llvm_elem_vec_ty = llvm_vector_ty(bx, underlying_ty, in_len, pointer_count - 1);
1556         let llvm_elem_vec_str = llvm_vector_str(underlying_ty, in_len, pointer_count - 1, bx);
1557
1558         let llvm_intrinsic =
1559             format!("llvm.masked.scatter.{}.{}", llvm_elem_vec_str, llvm_pointer_vec_str);
1560         let fn_ty =
1561             bx.type_func(&[llvm_elem_vec_ty, llvm_pointer_vec_ty, alignment_ty, mask_ty], ret_t);
1562         let f = bx.declare_cfn(&llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
1563         let v = bx.call(
1564             fn_ty,
1565             None,
1566             f,
1567             &[args[0].immediate(), args[1].immediate(), alignment, mask],
1568             None,
1569         );
1570         return Ok(v);
1571     }
1572
1573     macro_rules! arith_red {
1574         ($name:ident : $integer_reduce:ident, $float_reduce:ident, $ordered:expr, $op:ident,
1575          $identity:expr) => {
1576             if name == sym::$name {
1577                 require!(
1578                     ret_ty == in_elem,
1579                     InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
1580                 );
1581                 return match in_elem.kind() {
1582                     ty::Int(_) | ty::Uint(_) => {
1583                         let r = bx.$integer_reduce(args[0].immediate());
1584                         if $ordered {
1585                             // if overflow occurs, the result is the
1586                             // mathematical result modulo 2^n:
1587                             Ok(bx.$op(args[1].immediate(), r))
1588                         } else {
1589                             Ok(bx.$integer_reduce(args[0].immediate()))
1590                         }
1591                     }
1592                     ty::Float(f) => {
1593                         let acc = if $ordered {
1594                             // ordered arithmetic reductions take an accumulator
1595                             args[1].immediate()
1596                         } else {
1597                             // unordered arithmetic reductions use the identity accumulator
1598                             match f.bit_width() {
1599                                 32 => bx.const_real(bx.type_f32(), $identity),
1600                                 64 => bx.const_real(bx.type_f64(), $identity),
1601                                 v => return_error!(
1602                                     InvalidMonomorphization::UnsupportedSymbolOfSize {
1603                                         span,
1604                                         name,
1605                                         symbol: sym::$name,
1606                                         in_ty,
1607                                         in_elem,
1608                                         size: v,
1609                                         ret_ty
1610                                     }
1611                                 ),
1612                             }
1613                         };
1614                         Ok(bx.$float_reduce(acc, args[0].immediate()))
1615                     }
1616                     _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
1617                         span,
1618                         name,
1619                         symbol: sym::$name,
1620                         in_ty,
1621                         in_elem,
1622                         ret_ty
1623                     }),
1624                 };
1625             }
1626         };
1627     }
1628
1629     arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, 0.0);
1630     arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0);
1631     arith_red!(
1632         simd_reduce_add_unordered: vector_reduce_add,
1633         vector_reduce_fadd_fast,
1634         false,
1635         add,
1636         0.0
1637     );
1638     arith_red!(
1639         simd_reduce_mul_unordered: vector_reduce_mul,
1640         vector_reduce_fmul_fast,
1641         false,
1642         mul,
1643         1.0
1644     );
1645
1646     macro_rules! minmax_red {
1647         ($name:ident: $int_red:ident, $float_red:ident) => {
1648             if name == sym::$name {
1649                 require!(
1650                     ret_ty == in_elem,
1651                     InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
1652                 );
1653                 return match in_elem.kind() {
1654                     ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)),
1655                     ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)),
1656                     ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())),
1657                     _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
1658                         span,
1659                         name,
1660                         symbol: sym::$name,
1661                         in_ty,
1662                         in_elem,
1663                         ret_ty
1664                     }),
1665                 };
1666             }
1667         };
1668     }
1669
1670     minmax_red!(simd_reduce_min: vector_reduce_min, vector_reduce_fmin);
1671     minmax_red!(simd_reduce_max: vector_reduce_max, vector_reduce_fmax);
1672
1673     minmax_red!(simd_reduce_min_nanless: vector_reduce_min, vector_reduce_fmin_fast);
1674     minmax_red!(simd_reduce_max_nanless: vector_reduce_max, vector_reduce_fmax_fast);
1675
1676     macro_rules! bitwise_red {
1677         ($name:ident : $red:ident, $boolean:expr) => {
1678             if name == sym::$name {
1679                 let input = if !$boolean {
1680                     require!(
1681                         ret_ty == in_elem,
1682                         InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
1683                     );
1684                     args[0].immediate()
1685                 } else {
1686                     match in_elem.kind() {
1687                         ty::Int(_) | ty::Uint(_) => {}
1688                         _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
1689                             span,
1690                             name,
1691                             symbol: sym::$name,
1692                             in_ty,
1693                             in_elem,
1694                             ret_ty
1695                         }),
1696                     }
1697
1698                     // boolean reductions operate on vectors of i1s:
1699                     let i1 = bx.type_i1();
1700                     let i1xn = bx.type_vector(i1, in_len as u64);
1701                     bx.trunc(args[0].immediate(), i1xn)
1702                 };
1703                 return match in_elem.kind() {
1704                     ty::Int(_) | ty::Uint(_) => {
1705                         let r = bx.$red(input);
1706                         Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
1707                     }
1708                     _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
1709                         span,
1710                         name,
1711                         symbol: sym::$name,
1712                         in_ty,
1713                         in_elem,
1714                         ret_ty
1715                     }),
1716                 };
1717             }
1718         };
1719     }
1720
1721     bitwise_red!(simd_reduce_and: vector_reduce_and, false);
1722     bitwise_red!(simd_reduce_or: vector_reduce_or, false);
1723     bitwise_red!(simd_reduce_xor: vector_reduce_xor, false);
1724     bitwise_red!(simd_reduce_all: vector_reduce_and, true);
1725     bitwise_red!(simd_reduce_any: vector_reduce_or, true);
1726
1727     if name == sym::simd_cast_ptr {
1728         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
1729         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
1730         require!(
1731             in_len == out_len,
1732             InvalidMonomorphization::ReturnLengthInputType {
1733                 span,
1734                 name,
1735                 in_len,
1736                 in_ty,
1737                 ret_ty,
1738                 out_len
1739             }
1740         );
1741
1742         match in_elem.kind() {
1743             ty::RawPtr(p) => {
1744                 let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
1745                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
1746                 });
1747                 assert!(!check_sized); // we are in codegen, so we shouldn't see these types
1748                 require!(
1749                     metadata.is_unit(),
1750                     InvalidMonomorphization::CastFatPointer { span, name, ty: in_elem }
1751                 );
1752             }
1753             _ => {
1754                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
1755             }
1756         }
1757         match out_elem.kind() {
1758             ty::RawPtr(p) => {
1759                 let (metadata, check_sized) = p.ty.ptr_metadata_ty(bx.tcx, |ty| {
1760                     bx.tcx.normalize_erasing_regions(ty::ParamEnv::reveal_all(), ty)
1761                 });
1762                 assert!(!check_sized); // we are in codegen, so we shouldn't see these types
1763                 require!(
1764                     metadata.is_unit(),
1765                     InvalidMonomorphization::CastFatPointer { span, name, ty: out_elem }
1766                 );
1767             }
1768             _ => {
1769                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
1770             }
1771         }
1772
1773         if in_elem == out_elem {
1774             return Ok(args[0].immediate());
1775         } else {
1776             return Ok(bx.pointercast(args[0].immediate(), llret_ty));
1777         }
1778     }
1779
1780     if name == sym::simd_expose_addr {
1781         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
1782         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
1783         require!(
1784             in_len == out_len,
1785             InvalidMonomorphization::ReturnLengthInputType {
1786                 span,
1787                 name,
1788                 in_len,
1789                 in_ty,
1790                 ret_ty,
1791                 out_len
1792             }
1793         );
1794
1795         match in_elem.kind() {
1796             ty::RawPtr(_) => {}
1797             _ => {
1798                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
1799             }
1800         }
1801         match out_elem.kind() {
1802             ty::Uint(ty::UintTy::Usize) => {}
1803             _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: out_elem }),
1804         }
1805
1806         return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
1807     }
1808
1809     if name == sym::simd_from_exposed_addr {
1810         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
1811         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
1812         require!(
1813             in_len == out_len,
1814             InvalidMonomorphization::ReturnLengthInputType {
1815                 span,
1816                 name,
1817                 in_len,
1818                 in_ty,
1819                 ret_ty,
1820                 out_len
1821             }
1822         );
1823
1824         match in_elem.kind() {
1825             ty::Uint(ty::UintTy::Usize) => {}
1826             _ => return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: in_elem }),
1827         }
1828         match out_elem.kind() {
1829             ty::RawPtr(_) => {}
1830             _ => {
1831                 return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
1832             }
1833         }
1834
1835         return Ok(bx.inttoptr(args[0].immediate(), llret_ty));
1836     }
1837
1838     if name == sym::simd_cast || name == sym::simd_as {
1839         require_simd!(ret_ty, InvalidMonomorphization::SimdReturn { span, name, ty: ret_ty });
1840         let (out_len, out_elem) = ret_ty.simd_size_and_type(bx.tcx());
1841         require!(
1842             in_len == out_len,
1843             InvalidMonomorphization::ReturnLengthInputType {
1844                 span,
1845                 name,
1846                 in_len,
1847                 in_ty,
1848                 ret_ty,
1849                 out_len
1850             }
1851         );
1852         // casting cares about nominal type, not just structural type
1853         if in_elem == out_elem {
1854             return Ok(args[0].immediate());
1855         }
1856
1857         enum Style {
1858             Float,
1859             Int(/* is signed? */ bool),
1860             Unsupported,
1861         }
1862
1863         let (in_style, in_width) = match in_elem.kind() {
1864             // vectors of pointer-sized integers should've been
1865             // disallowed before here, so this unwrap is safe.
1866             ty::Int(i) => (
1867                 Style::Int(true),
1868                 i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
1869             ),
1870             ty::Uint(u) => (
1871                 Style::Int(false),
1872                 u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
1873             ),
1874             ty::Float(f) => (Style::Float, f.bit_width()),
1875             _ => (Style::Unsupported, 0),
1876         };
1877         let (out_style, out_width) = match out_elem.kind() {
1878             ty::Int(i) => (
1879                 Style::Int(true),
1880                 i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
1881             ),
1882             ty::Uint(u) => (
1883                 Style::Int(false),
1884                 u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
1885             ),
1886             ty::Float(f) => (Style::Float, f.bit_width()),
1887             _ => (Style::Unsupported, 0),
1888         };
1889
1890         match (in_style, out_style) {
1891             (Style::Int(in_is_signed), Style::Int(_)) => {
1892                 return Ok(match in_width.cmp(&out_width) {
1893                     Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
1894                     Ordering::Equal => args[0].immediate(),
1895                     Ordering::Less => {
1896                         if in_is_signed {
1897                             bx.sext(args[0].immediate(), llret_ty)
1898                         } else {
1899                             bx.zext(args[0].immediate(), llret_ty)
1900                         }
1901                     }
1902                 });
1903             }
1904             (Style::Int(in_is_signed), Style::Float) => {
1905                 return Ok(if in_is_signed {
1906                     bx.sitofp(args[0].immediate(), llret_ty)
1907                 } else {
1908                     bx.uitofp(args[0].immediate(), llret_ty)
1909                 });
1910             }
1911             (Style::Float, Style::Int(out_is_signed)) => {
1912                 return Ok(match (out_is_signed, name == sym::simd_as) {
1913                     (false, false) => bx.fptoui(args[0].immediate(), llret_ty),
1914                     (true, false) => bx.fptosi(args[0].immediate(), llret_ty),
1915                     (_, true) => bx.cast_float_to_int(out_is_signed, args[0].immediate(), llret_ty),
1916                 });
1917             }
1918             (Style::Float, Style::Float) => {
1919                 return Ok(match in_width.cmp(&out_width) {
1920                     Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty),
1921                     Ordering::Equal => args[0].immediate(),
1922                     Ordering::Less => bx.fpext(args[0].immediate(), llret_ty),
1923                 });
1924             }
1925             _ => { /* Unsupported. Fallthrough. */ }
1926         }
1927         require!(
1928             false,
1929             InvalidMonomorphization::UnsupportedCast {
1930                 span,
1931                 name,
1932                 in_ty,
1933                 in_elem,
1934                 ret_ty,
1935                 out_elem
1936             }
1937         );
1938     }
1939     macro_rules! arith_binary {
1940         ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
1941             $(if name == sym::$name {
1942                 match in_elem.kind() {
1943                     $($(ty::$p(_))|* => {
1944                         return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
1945                     })*
1946                     _ => {},
1947                 }
1948                 require!(
1949                     false,
1950                     InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
1951                 );
1952             })*
1953         }
1954     }
1955     arith_binary! {
1956         simd_add: Uint, Int => add, Float => fadd;
1957         simd_sub: Uint, Int => sub, Float => fsub;
1958         simd_mul: Uint, Int => mul, Float => fmul;
1959         simd_div: Uint => udiv, Int => sdiv, Float => fdiv;
1960         simd_rem: Uint => urem, Int => srem, Float => frem;
1961         simd_shl: Uint, Int => shl;
1962         simd_shr: Uint => lshr, Int => ashr;
1963         simd_and: Uint, Int => and;
1964         simd_or: Uint, Int => or;
1965         simd_xor: Uint, Int => xor;
1966         simd_fmax: Float => maxnum;
1967         simd_fmin: Float => minnum;
1968
1969     }
1970     macro_rules! arith_unary {
1971         ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
1972             $(if name == sym::$name {
1973                 match in_elem.kind() {
1974                     $($(ty::$p(_))|* => {
1975                         return Ok(bx.$call(args[0].immediate()))
1976                     })*
1977                     _ => {},
1978                 }
1979                 require!(
1980                     false,
1981                     InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
1982                 );
1983             })*
1984         }
1985     }
1986     arith_unary! {
1987         simd_neg: Int => neg, Float => fneg;
1988     }
1989
1990     if name == sym::simd_arith_offset {
1991         // This also checks that the first operand is a ptr type.
1992         let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| {
1993             span_bug!(span, "must be called with a vector of pointer types as first argument")
1994         });
1995         let layout = bx.layout_of(pointee.ty);
1996         let ptrs = args[0].immediate();
1997         // The second argument must be a ptr-sized integer.
1998         // (We don't care about the signedness, this is wrapping anyway.)
1999         let (_offsets_len, offsets_elem) = arg_tys[1].simd_size_and_type(bx.tcx());
2000         if !matches!(offsets_elem.kind(), ty::Int(ty::IntTy::Isize) | ty::Uint(ty::UintTy::Usize)) {
2001             span_bug!(
2002                 span,
2003                 "must be called with a vector of pointer-sized integers as second argument"
2004             );
2005         }
2006         let offsets = args[1].immediate();
2007
2008         return Ok(bx.gep(bx.backend_type(layout), ptrs, &[offsets]));
2009     }
2010
2011     if name == sym::simd_saturating_add || name == sym::simd_saturating_sub {
2012         let lhs = args[0].immediate();
2013         let rhs = args[1].immediate();
2014         let is_add = name == sym::simd_saturating_add;
2015         let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _;
2016         let (signed, elem_width, elem_ty) = match *in_elem.kind() {
2017             ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)),
2018             ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)),
2019             _ => {
2020                 return_error!(InvalidMonomorphization::ExpectedVectorElementType {
2021                     span,
2022                     name,
2023                     expected_element: arg_tys[0].simd_size_and_type(bx.tcx()).1,
2024                     vector_type: arg_tys[0]
2025                 });
2026             }
2027         };
2028         let llvm_intrinsic = &format!(
2029             "llvm.{}{}.sat.v{}i{}",
2030             if signed { 's' } else { 'u' },
2031             if is_add { "add" } else { "sub" },
2032             in_len,
2033             elem_width
2034         );
2035         let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
2036
2037         let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
2038         let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
2039         let v = bx.call(fn_ty, None, f, &[lhs, rhs], None);
2040         return Ok(v);
2041     }
2042
2043     span_bug!(span, "unknown SIMD intrinsic");
2044 }
2045
2046 // Returns the width of an int Ty, and if it's signed or not
2047 // Returns None if the type is not an integer
2048 // FIXME: there’s multiple of this functions, investigate using some of the already existing
2049 // stuffs.
2050 fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> {
2051     match ty.kind() {
2052         ty::Int(t) => {
2053             Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), true))
2054         }
2055         ty::Uint(t) => {
2056             Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.pointer_width)), false))
2057         }
2058         _ => None,
2059     }
2060 }