Skip to main content

rustc_codegen_llvm/
intrinsic.rs

1use std::cmp::Ordering;
2use std::ffi::c_uint;
3use std::{assert_matches, iter, ptr};
4
5use rustc_abi::{
6    AddressSpace, Align, BackendRepr, CVariadicStatus, Float, HasDataLayout, Integer,
7    NumScalableVectors, Primitive, Size, WrappingRange,
8};
9use rustc_codegen_ssa::RetagInfo;
10use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh, wants_wasm_eh};
11use rustc_codegen_ssa::common::{IntPredicate, TypeKind};
12use rustc_codegen_ssa::errors::{ExpectedPointerMutability, InvalidMonomorphization};
13use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue};
14use rustc_codegen_ssa::mir::place::{PlaceRef, PlaceValue};
15use rustc_codegen_ssa::traits::*;
16use rustc_hir as hir;
17use rustc_hir::def_id::LOCAL_CRATE;
18use rustc_hir::find_attr;
19use rustc_middle::mir::BinOp;
20use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, HasTypingEnv, LayoutOf};
21use rustc_middle::ty::offload_meta::OffloadMetadata;
22use rustc_middle::ty::{self, GenericArgsRef, Instance, SimdAlign, Ty, TyCtxt, TypingEnv};
23use rustc_middle::{bug, span_bug};
24use rustc_session::config::CrateType;
25use rustc_session::errors::feature_err;
26use rustc_session::lint::builtin::DEPRECATED_LLVM_INTRINSIC;
27use rustc_span::{Span, Symbol, sym};
28use rustc_symbol_mangling::{mangle_internal_symbol, symbol_name_for_instance_in_crate};
29use rustc_target::callconv::PassMode;
30use rustc_target::spec::{Arch, Os};
31use tracing::debug;
32
33use crate::abi::FnAbiLlvmExt;
34use crate::builder::Builder;
35use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call};
36use crate::builder::gpu_offload::{
37    OffloadKernelDims, gen_call_handling, gen_define_handling, register_offload,
38};
39use crate::context::CodegenCx;
40use crate::declare::declare_raw_fn;
41use crate::errors::{
42    AutoDiffWithoutEnable, AutoDiffWithoutLto, IntrinsicSignatureMismatch, IntrinsicWrongArch,
43    OffloadWithoutEnable, OffloadWithoutFatLTO, UnknownIntrinsic,
44};
45use crate::llvm::{self, Type, Value};
46use crate::type_of::LayoutLlvmExt;
47use crate::va_arg::emit_va_arg;
48
49fn call_simple_intrinsic<'ll, 'tcx>(
50    bx: &mut Builder<'_, 'll, 'tcx>,
51    name: Symbol,
52    args: &[OperandRef<'tcx, &'ll Value>],
53) -> Option<&'ll Value> {
54    let (base_name, type_params): (&'static str, &[&'ll Type]) = match name {
55        sym::sqrtf16 => ("llvm.sqrt", &[bx.type_f16()]),
56        sym::sqrtf32 => ("llvm.sqrt", &[bx.type_f32()]),
57        sym::sqrtf64 => ("llvm.sqrt", &[bx.type_f64()]),
58        sym::sqrtf128 => ("llvm.sqrt", &[bx.type_f128()]),
59
60        sym::powif16 => ("llvm.powi", &[bx.type_f16(), bx.type_i32()]),
61        sym::powif32 => ("llvm.powi", &[bx.type_f32(), bx.type_i32()]),
62        sym::powif64 => ("llvm.powi", &[bx.type_f64(), bx.type_i32()]),
63        sym::powif128 => ("llvm.powi", &[bx.type_f128(), bx.type_i32()]),
64
65        sym::sinf16 => ("llvm.sin", &[bx.type_f16()]),
66        sym::sinf32 => ("llvm.sin", &[bx.type_f32()]),
67        sym::sinf64 => ("llvm.sin", &[bx.type_f64()]),
68        sym::sinf128 => ("llvm.sin", &[bx.type_f128()]),
69
70        sym::cosf16 => ("llvm.cos", &[bx.type_f16()]),
71        sym::cosf32 => ("llvm.cos", &[bx.type_f32()]),
72        sym::cosf64 => ("llvm.cos", &[bx.type_f64()]),
73        sym::cosf128 => ("llvm.cos", &[bx.type_f128()]),
74
75        sym::powf16 => ("llvm.pow", &[bx.type_f16()]),
76        sym::powf32 => ("llvm.pow", &[bx.type_f32()]),
77        sym::powf64 => ("llvm.pow", &[bx.type_f64()]),
78        sym::powf128 => ("llvm.pow", &[bx.type_f128()]),
79
80        sym::expf16 => ("llvm.exp", &[bx.type_f16()]),
81        sym::expf32 => ("llvm.exp", &[bx.type_f32()]),
82        sym::expf64 => ("llvm.exp", &[bx.type_f64()]),
83        sym::expf128 => ("llvm.exp", &[bx.type_f128()]),
84
85        sym::exp2f16 => ("llvm.exp2", &[bx.type_f16()]),
86        sym::exp2f32 => ("llvm.exp2", &[bx.type_f32()]),
87        sym::exp2f64 => ("llvm.exp2", &[bx.type_f64()]),
88        sym::exp2f128 => ("llvm.exp2", &[bx.type_f128()]),
89
90        sym::logf16 => ("llvm.log", &[bx.type_f16()]),
91        sym::logf32 => ("llvm.log", &[bx.type_f32()]),
92        sym::logf64 => ("llvm.log", &[bx.type_f64()]),
93        sym::logf128 => ("llvm.log", &[bx.type_f128()]),
94
95        sym::log10f16 => ("llvm.log10", &[bx.type_f16()]),
96        sym::log10f32 => ("llvm.log10", &[bx.type_f32()]),
97        sym::log10f64 => ("llvm.log10", &[bx.type_f64()]),
98        sym::log10f128 => ("llvm.log10", &[bx.type_f128()]),
99
100        sym::log2f16 => ("llvm.log2", &[bx.type_f16()]),
101        sym::log2f32 => ("llvm.log2", &[bx.type_f32()]),
102        sym::log2f64 => ("llvm.log2", &[bx.type_f64()]),
103        sym::log2f128 => ("llvm.log2", &[bx.type_f128()]),
104
105        sym::fmaf16 => ("llvm.fma", &[bx.type_f16()]),
106        sym::fmaf32 => ("llvm.fma", &[bx.type_f32()]),
107        sym::fmaf64 => ("llvm.fma", &[bx.type_f64()]),
108        sym::fmaf128 => ("llvm.fma", &[bx.type_f128()]),
109
110        sym::fmuladdf16 => ("llvm.fmuladd", &[bx.type_f16()]),
111        sym::fmuladdf32 => ("llvm.fmuladd", &[bx.type_f32()]),
112        sym::fmuladdf64 => ("llvm.fmuladd", &[bx.type_f64()]),
113        sym::fmuladdf128 => ("llvm.fmuladd", &[bx.type_f128()]),
114
115        // FIXME: LLVM currently mis-compile those intrinsics, re-enable them
116        // when llvm/llvm-project#{139380,139381,140445} are fixed.
117        //sym::minimumf16 => ("llvm.minimum", &[bx.type_f16()]),
118        //sym::minimumf32 => ("llvm.minimum", &[bx.type_f32()]),
119        //sym::minimumf64 => ("llvm.minimum", &[bx.type_f64()]),
120        //sym::minimumf128 => ("llvm.minimum", &[cx.type_f128()]),
121        //
122        // FIXME: LLVM currently mis-compile those intrinsics, re-enable them
123        // when llvm/llvm-project#{139380,139381,140445} are fixed.
124        //sym::maximumf16 => ("llvm.maximum", &[bx.type_f16()]),
125        //sym::maximumf32 => ("llvm.maximum", &[bx.type_f32()]),
126        //sym::maximumf64 => ("llvm.maximum", &[bx.type_f64()]),
127        //sym::maximumf128 => ("llvm.maximum", &[cx.type_f128()]),
128        //
129        sym::copysignf16 => ("llvm.copysign", &[bx.type_f16()]),
130        sym::copysignf32 => ("llvm.copysign", &[bx.type_f32()]),
131        sym::copysignf64 => ("llvm.copysign", &[bx.type_f64()]),
132        sym::copysignf128 => ("llvm.copysign", &[bx.type_f128()]),
133
134        sym::floorf16 => ("llvm.floor", &[bx.type_f16()]),
135        sym::floorf32 => ("llvm.floor", &[bx.type_f32()]),
136        sym::floorf64 => ("llvm.floor", &[bx.type_f64()]),
137        sym::floorf128 => ("llvm.floor", &[bx.type_f128()]),
138
139        sym::ceilf16 => ("llvm.ceil", &[bx.type_f16()]),
140        sym::ceilf32 => ("llvm.ceil", &[bx.type_f32()]),
141        sym::ceilf64 => ("llvm.ceil", &[bx.type_f64()]),
142        sym::ceilf128 => ("llvm.ceil", &[bx.type_f128()]),
143
144        sym::truncf16 => ("llvm.trunc", &[bx.type_f16()]),
145        sym::truncf32 => ("llvm.trunc", &[bx.type_f32()]),
146        sym::truncf64 => ("llvm.trunc", &[bx.type_f64()]),
147        sym::truncf128 => ("llvm.trunc", &[bx.type_f128()]),
148
149        // We could use any of `rint`, `nearbyint`, or `roundeven`
150        // for this -- they are all identical in semantics when
151        // assuming the default FP environment.
152        // `rint` is what we used for $forever.
153        sym::round_ties_even_f16 => ("llvm.rint", &[bx.type_f16()]),
154        sym::round_ties_even_f32 => ("llvm.rint", &[bx.type_f32()]),
155        sym::round_ties_even_f64 => ("llvm.rint", &[bx.type_f64()]),
156        sym::round_ties_even_f128 => ("llvm.rint", &[bx.type_f128()]),
157
158        sym::roundf16 => ("llvm.round", &[bx.type_f16()]),
159        sym::roundf32 => ("llvm.round", &[bx.type_f32()]),
160        sym::roundf64 => ("llvm.round", &[bx.type_f64()]),
161        sym::roundf128 => ("llvm.round", &[bx.type_f128()]),
162
163        _ => return None,
164    };
165    Some(bx.call_intrinsic(
166        base_name,
167        type_params,
168        &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
169    ))
170}
171
172impl<'ll, 'tcx> IntrinsicCallBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
173    fn codegen_intrinsic_call(
174        &mut self,
175        instance: ty::Instance<'tcx>,
176        args: &[OperandRef<'tcx, &'ll Value>],
177        result: PlaceRef<'tcx, &'ll Value>,
178        span: Span,
179    ) -> Result<(), ty::Instance<'tcx>> {
180        let tcx = self.tcx;
181        let llvm_version = crate::llvm_util::get_version();
182
183        let name = tcx.item_name(instance.def_id());
184        let fn_args = instance.args;
185
186        let simple = call_simple_intrinsic(self, name, args);
187        let llval = match name {
188            _ if simple.is_some() => simple.unwrap(),
189            sym::minimum_number_nsz_f16
190            | sym::minimum_number_nsz_f32
191            | sym::minimum_number_nsz_f64
192            | sym::minimum_number_nsz_f128
193            | sym::maximum_number_nsz_f16
194            | sym::maximum_number_nsz_f32
195            | sym::maximum_number_nsz_f64
196            | sym::maximum_number_nsz_f128
197                // Need at least LLVM 22 for `min/maximumnum` to not crash LLVM.
198                if llvm_version >= (22, 0, 0) =>
199            {
200                let intrinsic_name = if name.as_str().starts_with("min") {
201                    "llvm.minimumnum"
202                } else {
203                    "llvm.maximumnum"
204                };
205                let call = self.call_intrinsic(
206                    intrinsic_name,
207                    &[args[0].layout.immediate_llvm_type(self.cx)],
208                    &[args[0].immediate(), args[1].immediate()],
209                );
210                // `nsz` on minimumnum/maximumnum is special: its only effect is to make
211                // signed-zero ordering non-deterministic.
212                unsafe { llvm::LLVMRustSetNoSignedZeros(call) };
213                call
214            }
215            sym::ptr_mask => {
216                let ptr = args[0].immediate();
217                self.call_intrinsic(
218                    "llvm.ptrmask",
219                    &[self.val_ty(ptr), self.type_isize()],
220                    &[ptr, args[1].immediate()],
221                )
222            }
223            sym::autodiff => {
224                codegen_autodiff(self, tcx, instance, args, result);
225                return Ok(());
226            }
227            sym::offload => {
228                if tcx.sess.opts.unstable_opts.offload.is_empty() {
229                    let _ = tcx.dcx().emit_almost_fatal(OffloadWithoutEnable);
230                }
231
232                if tcx.sess.lto() != rustc_session::config::Lto::Fat {
233                    let _ = tcx.dcx().emit_almost_fatal(OffloadWithoutFatLTO);
234                }
235
236                codegen_offload(self, tcx, instance, args);
237                return Ok(());
238            }
239            sym::is_val_statically_known => {
240                if let OperandValue::Immediate(imm) = args[0].val {
241                    self.call_intrinsic(
242                        "llvm.is.constant",
243                        &[args[0].layout.immediate_llvm_type(self.cx)],
244                        &[imm],
245                    )
246                } else {
247                    self.const_bool(false)
248                }
249            }
250            sym::select_unpredictable => {
251                let cond = args[0].immediate();
252                match (&args[1].layout, &args[2].layout) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(args[1].layout, args[2].layout);
253                let select = |bx: &mut Self, true_val, false_val| {
254                    let result = bx.select(cond, true_val, false_val);
255                    bx.set_unpredictable(&result);
256                    result
257                };
258                match (args[1].val, args[2].val) {
259                    (OperandValue::Ref(true_val), OperandValue::Ref(false_val)) => {
260                        if !true_val.llextra.is_none() {
    ::core::panicking::panic("assertion failed: true_val.llextra.is_none()")
};assert!(true_val.llextra.is_none());
261                        if !false_val.llextra.is_none() {
    ::core::panicking::panic("assertion failed: false_val.llextra.is_none()")
};assert!(false_val.llextra.is_none());
262                        match (&true_val.align, &false_val.align) {
    (left_val, right_val) => {
        if !(*left_val == *right_val) {
            let kind = ::core::panicking::AssertKind::Eq;
            ::core::panicking::assert_failed(kind, &*left_val, &*right_val,
                ::core::option::Option::None);
        }
    }
};assert_eq!(true_val.align, false_val.align);
263                        let ptr = select(self, true_val.llval, false_val.llval);
264                        let selected =
265                            OperandValue::Ref(PlaceValue::new_sized(ptr, true_val.align));
266                        selected.store(self, result);
267                        return Ok(());
268                    }
269                    (OperandValue::Immediate(_), OperandValue::Immediate(_))
270                    | (OperandValue::Pair(_, _), OperandValue::Pair(_, _)) => {
271                        let true_val = args[1].immediate_or_packed_pair(self);
272                        let false_val = args[2].immediate_or_packed_pair(self);
273                        select(self, true_val, false_val)
274                    }
275                    (OperandValue::ZeroSized, OperandValue::ZeroSized) => return Ok(()),
276                    _ => ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("Incompatible OperandValue for select_unpredictable"))span_bug!(span, "Incompatible OperandValue for select_unpredictable"),
277                }
278            }
279            sym::catch_unwind => {
280                catch_unwind_intrinsic(
281                    self,
282                    args[0].immediate(),
283                    args[1].immediate(),
284                    args[2].immediate(),
285                    result,
286                );
287                return Ok(());
288            }
289            sym::breakpoint => self.call_intrinsic("llvm.debugtrap", &[], &[]),
290            sym::va_arg => {
291                let target = &self.cx.tcx.sess.target;
292                let stability = target.supports_c_variadic_definitions();
293                if let CVariadicStatus::Unstable { feature } = stability
294                    && !self.tcx.features().enabled(feature)
295                {
296                    let msg =
297                        ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("C-variadic function definitions on this target are unstable"))
    })format!("C-variadic function definitions on this target are unstable");
298                    feature_err(&*self.sess(), feature, span, msg).emit();
299                }
300
301                let BackendRepr::Scalar(scalar) = result.layout.backend_repr else {
302                    ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support non-scalar types"))bug!("the va_arg intrinsic does not support non-scalar types")
303                };
304
305                // We reject types that would never be passed as varargs in C because
306                // they get promoted to a larger type, specifically integers smaller than
307                // c_int and float type smaller than c_double.
308                match scalar.primitive() {
309                    Primitive::Pointer(_) => {
310                        // Pointers are always OK.
311                    }
312                    Primitive::Int(Integer::I128, _) => {
313                        // FIXME: maybe we should support these? At least on 32-bit powerpc
314                        // the logic in LLVM does not handle i128 correctly though.
315                        ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support `i128`/`u128`"))bug!("the va_arg intrinsic does not support `i128`/`u128`")
316                    }
317                    Primitive::Int(..) => {
318                        let int_width = self.cx().size_of(result.layout.ty).bits();
319                        let target_c_int_width = self.cx().sess().target.options.c_int_width;
320                        if int_width < u64::from(target_c_int_width) {
321                            // Smaller integer types are automatically promototed and `va_arg`
322                            // should not be called on them.
323                            ::rustc_middle::util::bug::bug_fmt(format_args!("va_arg got i{0} but needs at least c_int (an i{1})",
        int_width, target_c_int_width));bug!(
324                                "va_arg got i{} but needs at least c_int (an i{})",
325                                int_width,
326                                target_c_int_width
327                            );
328                        }
329                    }
330                    Primitive::Float(Float::F16) => {
331                        ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support `f16`"))bug!("the va_arg intrinsic does not support `f16`")
332                    }
333                    Primitive::Float(Float::F32) => {
334                        // c_double is actually f32 on avr.
335                        if self.cx().sess().target.arch != Arch::Avr {
336                            ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support `f32` on this target"))bug!("the va_arg intrinsic does not support `f32` on this target")
337                        }
338                    }
339                    Primitive::Float(Float::F64) => {
340                        // 64-bit floats are always OK.
341                    }
342                    Primitive::Float(Float::F128) => {
343                        // FIXME(f128) figure out whether we should support this.
344                        ::rustc_middle::util::bug::bug_fmt(format_args!("the va_arg intrinsic does not support `f128`"))bug!("the va_arg intrinsic does not support `f128`")
345                    }
346                }
347
348                emit_va_arg(self, args[0], result.layout.ty)
349            }
350
351            sym::volatile_load | sym::unaligned_volatile_load => {
352                let ptr = args[0].immediate();
353                let load = self.volatile_load(result.layout.llvm_type(self), ptr);
354                let align = if name == sym::unaligned_volatile_load {
355                    1
356                } else {
357                    result.layout.align.bytes() as u32
358                };
359                unsafe {
360                    llvm::LLVMSetAlignment(load, align);
361                }
362                if !result.layout.is_zst() {
363                    self.store_to_place(load, result.val);
364                }
365                return Ok(());
366            }
367            sym::volatile_store => {
368                let dst = args[0].deref(self.cx());
369                args[1].val.volatile_store(self, dst);
370                return Ok(());
371            }
372            sym::unaligned_volatile_store => {
373                let dst = args[0].deref(self.cx());
374                args[1].val.unaligned_volatile_store(self, dst);
375                return Ok(());
376            }
377            sym::prefetch_read_data
378            | sym::prefetch_write_data
379            | sym::prefetch_read_instruction
380            | sym::prefetch_write_instruction => {
381                let (rw, cache_type) = match name {
382                    sym::prefetch_read_data => (0, 1),
383                    sym::prefetch_write_data => (1, 1),
384                    sym::prefetch_read_instruction => (0, 0),
385                    sym::prefetch_write_instruction => (1, 0),
386                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
387                };
388                let ptr = args[0].immediate();
389                let locality = fn_args.const_at(1).to_leaf().to_i32();
390                self.call_intrinsic(
391                    "llvm.prefetch",
392                    &[self.val_ty(ptr)],
393                    &[
394                        ptr,
395                        self.const_i32(rw),
396                        self.const_i32(locality),
397                        self.const_i32(cache_type),
398                    ],
399                )
400            }
401            sym::carrying_mul_add => {
402                let (size, signed) = fn_args.type_at(0).int_size_and_signed(self.tcx);
403
404                let wide_llty = self.type_ix(size.bits() * 2);
405                let args = args.as_array().unwrap();
406                let [a, b, c, d] = args.map(|a| self.intcast(a.immediate(), wide_llty, signed));
407
408                let wide = if signed {
409                    let prod = self.unchecked_smul(a, b);
410                    let acc = self.unchecked_sadd(prod, c);
411                    self.unchecked_sadd(acc, d)
412                } else {
413                    let prod = self.unchecked_umul(a, b);
414                    let acc = self.unchecked_uadd(prod, c);
415                    self.unchecked_uadd(acc, d)
416                };
417
418                let narrow_llty = self.type_ix(size.bits());
419                let low = self.trunc(wide, narrow_llty);
420                let bits_const = self.const_uint(wide_llty, size.bits());
421                // No need for ashr when signed; LLVM changes it to lshr anyway.
422                let high = self.lshr(wide, bits_const);
423                // FIXME: could be `trunc nuw`, even for signed.
424                let high = self.trunc(high, narrow_llty);
425
426                let pair_llty = self.type_struct(&[narrow_llty, narrow_llty], false);
427                let pair = self.const_poison(pair_llty);
428                let pair = self.insert_value(pair, low, 0);
429                let pair = self.insert_value(pair, high, 1);
430                pair
431            }
432
433            // FIXME move into the branch below when LLVM 22 is the lowest version we support.
434            sym::carryless_mul if llvm_version >= (22, 0, 0) => {
435                let ty = args[0].layout.ty;
436                if !ty.is_integral() {
437                    tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
438                        span,
439                        name,
440                        ty,
441                    });
442                    return Ok(());
443                }
444                let (size, _) = ty.int_size_and_signed(self.tcx);
445                let width = size.bits();
446                let llty = self.type_ix(width);
447
448                let lhs = args[0].immediate();
449                let rhs = args[1].immediate();
450                self.call_intrinsic("llvm.clmul", &[llty], &[lhs, rhs])
451            }
452
453            sym::ctlz
454            | sym::ctlz_nonzero
455            | sym::cttz
456            | sym::cttz_nonzero
457            | sym::ctpop
458            | sym::bswap
459            | sym::bitreverse
460            | sym::saturating_add
461            | sym::saturating_sub
462            | sym::unchecked_funnel_shl
463            | sym::unchecked_funnel_shr => {
464                let ty = args[0].layout.ty;
465                if !ty.is_integral() {
466                    tcx.dcx().emit_err(InvalidMonomorphization::BasicIntegerType {
467                        span,
468                        name,
469                        ty,
470                    });
471                    return Ok(());
472                }
473                let (size, signed) = ty.int_size_and_signed(self.tcx);
474                let width = size.bits();
475                let llty = self.type_ix(width);
476                match name {
477                    sym::ctlz | sym::ctlz_nonzero | sym::cttz | sym::cttz_nonzero => {
478                        let y =
479                            self.const_bool(name == sym::ctlz_nonzero || name == sym::cttz_nonzero);
480                        let llvm_name = if name == sym::ctlz || name == sym::ctlz_nonzero {
481                            "llvm.ctlz"
482                        } else {
483                            "llvm.cttz"
484                        };
485                        let ret =
486                            self.call_intrinsic(llvm_name, &[llty], &[args[0].immediate(), y]);
487                        self.intcast(ret, result.layout.llvm_type(self), false)
488                    }
489                    sym::ctpop => {
490                        let ret =
491                            self.call_intrinsic("llvm.ctpop", &[llty], &[args[0].immediate()]);
492                        self.intcast(ret, result.layout.llvm_type(self), false)
493                    }
494                    sym::bswap => {
495                        if width == 8 {
496                            args[0].immediate() // byte swap a u8/i8 is just a no-op
497                        } else {
498                            self.call_intrinsic("llvm.bswap", &[llty], &[args[0].immediate()])
499                        }
500                    }
501                    sym::bitreverse => {
502                        self.call_intrinsic("llvm.bitreverse", &[llty], &[args[0].immediate()])
503                    }
504                    sym::unchecked_funnel_shl | sym::unchecked_funnel_shr => {
505                        let is_left = name == sym::unchecked_funnel_shl;
506                        let lhs = args[0].immediate();
507                        let rhs = args[1].immediate();
508                        let raw_shift = args[2].immediate();
509                        let llvm_name = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("llvm.fsh{0}",
                if is_left { 'l' } else { 'r' }))
    })format!("llvm.fsh{}", if is_left { 'l' } else { 'r' });
510
511                        // llvm expects shift to be the same type as the values, but rust
512                        // always uses `u32`.
513                        let raw_shift = self.intcast(raw_shift, self.val_ty(lhs), false);
514
515                        self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs, raw_shift])
516                    }
517                    sym::saturating_add | sym::saturating_sub => {
518                        let is_add = name == sym::saturating_add;
519                        let lhs = args[0].immediate();
520                        let rhs = args[1].immediate();
521                        let llvm_name = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("llvm.{0}{1}.sat",
                if signed { 's' } else { 'u' },
                if is_add { "add" } else { "sub" }))
    })format!(
522                            "llvm.{}{}.sat",
523                            if signed { 's' } else { 'u' },
524                            if is_add { "add" } else { "sub" },
525                        );
526                        self.call_intrinsic(llvm_name, &[llty], &[lhs, rhs])
527                    }
528                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
529                }
530            }
531
532            sym::fabs => {
533                let ty = args[0].layout.ty;
534                let ty::Float(f) = ty.kind() else {
535                    ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("the `fabs` intrinsic requires a floating-point argument, got {0:?}",
        ty));span_bug!(span, "the `fabs` intrinsic requires a floating-point argument, got {:?}", ty);
536                };
537                let llty = self.type_float_from_ty(*f);
538                let llvm_name = "llvm.fabs";
539                self.call_intrinsic(
540                    llvm_name,
541                    &[llty],
542                    &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
543                )
544            }
545
546            sym::raw_eq => {
547                use BackendRepr::*;
548                let tp_ty = fn_args.type_at(0);
549                let layout = self.layout_of(tp_ty).layout;
550                let use_integer_compare = match layout.backend_repr() {
551                    Scalar(_) | ScalarPair(_, _) => true,
552                    SimdVector { .. } => false,
553                    SimdScalableVector { .. } => {
554                        tcx.dcx().emit_err(InvalidMonomorphization::NonScalableType {
555                            span,
556                            name: sym::raw_eq,
557                            ty: tp_ty,
558                        });
559                        return Ok(());
560                    }
561                    Memory { .. } => {
562                        // For rusty ABIs, small aggregates are actually passed
563                        // as `RegKind::Integer` (see `FnAbi::adjust_for_abi`),
564                        // so we re-use that same threshold here.
565                        layout.size() <= self.data_layout().pointer_size() * 2
566                    }
567                };
568
569                let a = args[0].immediate();
570                let b = args[1].immediate();
571                if layout.size().bytes() == 0 {
572                    self.const_bool(true)
573                } else if use_integer_compare {
574                    let integer_ty = self.type_ix(layout.size().bits());
575                    let a_val = self.load(integer_ty, a, layout.align().abi);
576                    let b_val = self.load(integer_ty, b, layout.align().abi);
577                    self.icmp(IntPredicate::IntEQ, a_val, b_val)
578                } else {
579                    let n = self.const_usize(layout.size().bytes());
580                    let cmp = self.call_intrinsic("memcmp", &[], &[a, b, n]);
581                    self.icmp(IntPredicate::IntEQ, cmp, self.const_int(self.type_int(), 0))
582                }
583            }
584
585            sym::compare_bytes => {
586                // Here we assume that the `memcmp` provided by the target is a NOP for size 0.
587                let cmp = self.call_intrinsic(
588                    "memcmp",
589                    &[],
590                    &[args[0].immediate(), args[1].immediate(), args[2].immediate()],
591                );
592                // Some targets have `memcmp` returning `i16`, but the intrinsic is always `i32`.
593                self.sext(cmp, self.type_ix(32))
594            }
595
596            sym::black_box => {
597                args[0].val.store(self, result);
598                let result_val_span = [result.val.llval];
599                // We need to "use" the argument in some way LLVM can't introspect, and on
600                // targets that support it we can typically leverage inline assembly to do
601                // this. LLVM's interpretation of inline assembly is that it's, well, a black
602                // box. This isn't the greatest implementation since it probably deoptimizes
603                // more than we want, but it's so far good enough.
604                //
605                // For zero-sized types, the location pointed to by the result may be
606                // uninitialized. Do not "use" the result in this case; instead just clobber
607                // the memory.
608                let (constraint, inputs): (&str, &[_]) = if result.layout.is_zst() {
609                    ("~{memory}", &[])
610                } else {
611                    ("r,~{memory}", &result_val_span)
612                };
613                crate::asm::inline_asm_call(
614                    self,
615                    "",
616                    constraint,
617                    inputs,
618                    self.type_void(),
619                    &[],
620                    true,
621                    false,
622                    llvm::AsmDialect::Att,
623                    &[span],
624                    false,
625                    None,
626                    None,
627                )
628                .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("failed to generate inline asm call for `black_box`"))bug!("failed to generate inline asm call for `black_box`"));
629
630                // We have copied the value to `result` already.
631                return Ok(());
632            }
633
634            sym::gpu_launch_sized_workgroup_mem => {
635                // Generate an anonymous global per call, with these properties:
636                // 1. The global is in the address space for workgroup memory
637                // 2. It is an `external` global
638                // 3. It is correctly aligned for the pointee `T`
639                // All instances of extern addrspace(gpu_workgroup) globals are merged in the LLVM backend.
640                // The name is irrelevant.
641                // See https://docs.nvidia.com/cuda/cuda-c-programming-guide/#shared
642                let name = if llvm_version < (23, 0, 0) && tcx.sess.target.arch == Arch::Nvptx64 {
643                    // The auto-assigned name for extern shared globals in the nvptx backend does
644                    // not compile in ptxas. Workaround this issue by assigning a name.
645                    // Fixed in LLVM 23.
646                    "gpu_launch_sized_workgroup_mem"
647                } else {
648                    ""
649                };
650                let global = self.declare_global_in_addrspace(
651                    name,
652                    self.type_array(self.type_i8(), 0),
653                    AddressSpace::GPU_WORKGROUP,
654                );
655                let ty::RawPtr(inner_ty, _) = result.layout.ty.kind() else { ::core::panicking::panic("internal error: entered unreachable code")unreachable!() };
656                // The alignment of the global is used to specify the *minimum* alignment that
657                // must be obeyed by the GPU runtime.
658                // When multiple of these global variables are used by a kernel, the maximum alignment is taken.
659                // See https://github.com/llvm/llvm-project/blob/a271d07488a85ce677674bbe8101b10efff58c95/llvm/lib/Target/AMDGPU/AMDGPULowerModuleLDSPass.cpp#L821
660                let alignment = self.align_of(*inner_ty).bytes() as u32;
661                unsafe {
662                    // FIXME Workaround the above issue by taking maximum alignment if the global existed
663                    if tcx.sess.target.arch == Arch::Nvptx64 {
664                        if alignment > llvm::LLVMGetAlignment(global) {
665                            llvm::LLVMSetAlignment(global, alignment);
666                        }
667                    } else {
668                        llvm::LLVMSetAlignment(global, alignment);
669                    }
670                }
671                self.cx().const_pointercast(global, self.type_ptr())
672            }
673
674            sym::amdgpu_dispatch_ptr => {
675                let val = self.call_intrinsic("llvm.amdgcn.dispatch.ptr", &[], &[]);
676                // Relying on `LLVMBuildPointerCast` to produce an addrspacecast
677                self.pointercast(val, self.type_ptr())
678            }
679
680            sym::sve_tuple_create2 => {
681                {
    match self.layout_of(fn_args.type_at(0)).backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(1), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
682                    self.layout_of(fn_args.type_at(0)).backend_repr,
683                    BackendRepr::SimdScalableVector {
684                        number_of_vectors: NumScalableVectors(1),
685                        ..
686                    }
687                );
688                let tuple_ty = self.layout_of(fn_args.type_at(1));
689                {
    match tuple_ty.backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(2), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(2), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
690                    tuple_ty.backend_repr,
691                    BackendRepr::SimdScalableVector {
692                        number_of_vectors: NumScalableVectors(2),
693                        ..
694                    }
695                );
696                let ret = self.const_poison(self.backend_type(tuple_ty));
697                let ret = self.insert_value(ret, args[0].immediate(), 0);
698                self.insert_value(ret, args[1].immediate(), 1)
699            }
700
701            sym::sve_tuple_create3 => {
702                {
    match self.layout_of(fn_args.type_at(0)).backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(1), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
703                    self.layout_of(fn_args.type_at(0)).backend_repr,
704                    BackendRepr::SimdScalableVector {
705                        number_of_vectors: NumScalableVectors(1),
706                        ..
707                    }
708                );
709                let tuple_ty = self.layout_of(fn_args.type_at(1));
710                {
    match tuple_ty.backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(3), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(3), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
711                    tuple_ty.backend_repr,
712                    BackendRepr::SimdScalableVector {
713                        number_of_vectors: NumScalableVectors(3),
714                        ..
715                    }
716                );
717                let ret = self.const_poison(self.backend_type(tuple_ty));
718                let ret = self.insert_value(ret, args[0].immediate(), 0);
719                let ret = self.insert_value(ret, args[1].immediate(), 1);
720                self.insert_value(ret, args[2].immediate(), 2)
721            }
722
723            sym::sve_tuple_create4 => {
724                {
    match self.layout_of(fn_args.type_at(0)).backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(1), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
725                    self.layout_of(fn_args.type_at(0)).backend_repr,
726                    BackendRepr::SimdScalableVector {
727                        number_of_vectors: NumScalableVectors(1),
728                        ..
729                    }
730                );
731                let tuple_ty = self.layout_of(fn_args.type_at(1));
732                {
    match tuple_ty.backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(4), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(4), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
733                    tuple_ty.backend_repr,
734                    BackendRepr::SimdScalableVector {
735                        number_of_vectors: NumScalableVectors(4),
736                        ..
737                    }
738                );
739                let ret = self.const_poison(self.backend_type(tuple_ty));
740                let ret = self.insert_value(ret, args[0].immediate(), 0);
741                let ret = self.insert_value(ret, args[1].immediate(), 1);
742                let ret = self.insert_value(ret, args[2].immediate(), 2);
743                self.insert_value(ret, args[3].immediate(), 3)
744            }
745
746            sym::sve_tuple_get => {
747                {
    match self.layout_of(fn_args.type_at(0)).backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
            .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
748                    self.layout_of(fn_args.type_at(0)).backend_repr,
749                    BackendRepr::SimdScalableVector {
750                        number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
751                        ..
752                    }
753                );
754                {
    match self.layout_of(fn_args.type_at(1)).backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(1), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
755                    self.layout_of(fn_args.type_at(1)).backend_repr,
756                    BackendRepr::SimdScalableVector {
757                        number_of_vectors: NumScalableVectors(1),
758                        ..
759                    }
760                );
761                self.extract_value(
762                    args[0].immediate(),
763                    fn_args.const_at(2).to_leaf().to_i32() as u64,
764                )
765            }
766
767            sym::sve_tuple_set => {
768                {
    match self.layout_of(fn_args.type_at(0)).backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
            .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
769                    self.layout_of(fn_args.type_at(0)).backend_repr,
770                    BackendRepr::SimdScalableVector {
771                        number_of_vectors: NumScalableVectors(2 | 3 | 4 | 5 | 6 | 7 | 8),
772                        ..
773                    }
774                );
775                {
    match self.layout_of(fn_args.type_at(1)).backend_repr {
        BackendRepr::SimdScalableVector {
            number_of_vectors: NumScalableVectors(1), .. } => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "BackendRepr::SimdScalableVector\n{ number_of_vectors: NumScalableVectors(1), .. }",
                ::core::option::Option::None);
        }
    }
};assert_matches!(
776                    self.layout_of(fn_args.type_at(1)).backend_repr,
777                    BackendRepr::SimdScalableVector {
778                        number_of_vectors: NumScalableVectors(1),
779                        ..
780                    }
781                );
782                self.insert_value(
783                    args[0].immediate(),
784                    args[1].immediate(),
785                    fn_args.const_at(2).to_leaf().to_i32() as u64,
786                )
787            }
788
789            _ if name.as_str().starts_with("simd_") => {
790                // Unpack non-power-of-2 #[repr(packed, simd)] arguments.
791                // This gives them the expected layout of a regular #[repr(simd)] vector.
792                let mut loaded_args = Vec::new();
793                for arg in args {
794                    loaded_args.push(
795                        // #[repr(packed, simd)] vectors are passed like arrays (as references,
796                        // with reduced alignment and no padding) rather than as immediates.
797                        // We can use a vector load to fix the layout and turn the argument
798                        // into an immediate.
799                        if arg.layout.ty.is_simd()
800                            && let OperandValue::Ref(place) = arg.val
801                        {
802                            let (size, elem_ty) = arg.layout.ty.simd_size_and_type(self.tcx());
803                            let elem_ll_ty = match elem_ty.kind() {
804                                ty::Float(f) => self.type_float_from_ty(*f),
805                                ty::Int(i) => self.type_int_from_ty(*i),
806                                ty::Uint(u) => self.type_uint_from_ty(*u),
807                                ty::RawPtr(_, _) => self.type_ptr(),
808                                _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
809                            };
810                            let loaded =
811                                self.load_from_place(self.type_vector(elem_ll_ty, size), place);
812                            OperandRef::from_immediate_or_packed_pair(self, loaded, arg.layout)
813                        } else {
814                            *arg
815                        },
816                    );
817                }
818
819                let llret_ty = if result.layout.ty.is_simd()
820                    && let BackendRepr::Memory { .. } = result.layout.backend_repr
821                {
822                    let (size, elem_ty) = result.layout.ty.simd_size_and_type(self.tcx());
823                    let elem_ll_ty = match elem_ty.kind() {
824                        ty::Float(f) => self.type_float_from_ty(*f),
825                        ty::Int(i) => self.type_int_from_ty(*i),
826                        ty::Uint(u) => self.type_uint_from_ty(*u),
827                        ty::RawPtr(_, _) => self.type_ptr(),
828                        _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
829                    };
830                    self.type_vector(elem_ll_ty, size)
831                } else {
832                    result.layout.llvm_type(self)
833                };
834
835                match generic_simd_intrinsic(
836                    self,
837                    name,
838                    fn_args,
839                    &loaded_args,
840                    result.layout.ty,
841                    llret_ty,
842                    span,
843                ) {
844                    Ok(llval) => llval,
845                    // If there was an error, just skip this invocation... we'll abort compilation
846                    // anyway, but we can keep codegen'ing to find more errors.
847                    Err(()) => return Ok(()),
848                }
849            }
850
851            sym::return_address => {
852                match self.sess().target.arch {
853                    // Expand this list as needed
854                    | Arch::Wasm32
855                    | Arch::Wasm64 => {
856                        let ty = self.type_ptr();
857                        self.const_null(ty)
858                    }
859                    _ => {
860                        let ty = self.type_ix(32);
861                        let val = self.const_int(ty, 0);
862
863                        let type_params: &[&'ll Type] = if llvm_version < (23, 0, 0) {
864                            &[]
865                        } else {
866                            &[self.type_ptr()]
867                        };
868
869                        self.call_intrinsic("llvm.returnaddress", type_params, &[val])
870                    }
871                }
872            }
873
874            _ => {
875                {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/intrinsic.rs:875",
                        "rustc_codegen_llvm::intrinsic", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/intrinsic.rs"),
                        ::tracing_core::__macro_support::Option::Some(875u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::intrinsic"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("unknown intrinsic \'{0}\' -- falling back to default body",
                                                    name) as &dyn Value))])
            });
    } else { ; }
};debug!("unknown intrinsic '{}' -- falling back to default body", name);
876                // Call the fallback body instead of generating the intrinsic code
877                return Err(ty::Instance::new_raw(instance.def_id(), instance.args));
878            }
879        };
880
881        if result.layout.ty.is_bool() {
882            let val = self.from_immediate(llval);
883            self.store_to_place(val, result.val);
884        } else if !result.layout.ty.is_unit() {
885            self.store_to_place(llval, result.val);
886        }
887        Ok(())
888    }
889
890    fn codegen_llvm_intrinsic_call(
891        &mut self,
892        instance: ty::Instance<'tcx>,
893        args: &[OperandRef<'tcx, Self::Value>],
894        _is_cleanup: bool,
895    ) -> Self::Value {
896        let tcx = self.tcx();
897
898        let fn_ty = instance.ty(tcx, self.typing_env());
899        let fn_sig = match *fn_ty.kind() {
900            ty::FnDef(def_id, args) => tcx.instantiate_bound_regions_with_erased(
901                tcx.fn_sig(def_id).instantiate(tcx, args).skip_norm_wip(),
902            ),
903            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
904        };
905        if !!fn_sig.c_variadic() {
    ::core::panicking::panic("assertion failed: !fn_sig.c_variadic()")
};assert!(!fn_sig.c_variadic());
906
907        let ret_layout = self.layout_of(fn_sig.output());
908        let llreturn_ty = if ret_layout.is_zst() {
909            self.type_void()
910        } else {
911            ret_layout.immediate_llvm_type(self)
912        };
913
914        let mut llargument_tys = Vec::with_capacity(fn_sig.inputs().len());
915        for &arg in fn_sig.inputs() {
916            let arg_layout = self.layout_of(arg);
917            if arg_layout.is_zst() {
918                continue;
919            }
920            llargument_tys.push(arg_layout.immediate_llvm_type(self));
921        }
922
923        let fn_ptr = if let Some(&llfn) = self.intrinsic_instances.borrow().get(&instance) {
924            llfn
925        } else {
926            let sym = tcx.symbol_name(instance).name;
927
928            let llfn = if let Some(llfn) = self.get_declared_value(sym) {
929                llfn
930            } else {
931                intrinsic_fn(self, sym, llreturn_ty, llargument_tys, instance)
932            };
933
934            self.intrinsic_instances.borrow_mut().insert(instance, llfn);
935
936            llfn
937        };
938        let fn_ty = self.get_type_of_global(fn_ptr);
939
940        let mut llargs = ::alloc::vec::Vec::new()vec![];
941
942        for arg in args {
943            match arg.val {
944                OperandValue::ZeroSized => {}
945                OperandValue::Immediate(a) => llargs.push(a),
946                OperandValue::Pair(a, b) => {
947                    llargs.push(a);
948                    llargs.push(b);
949                }
950                OperandValue::Ref(op_place_val) => {
951                    let mut llval = op_place_val.llval;
952                    // We can't use `PlaceRef::load` here because the argument
953                    // may have a type we don't treat as immediate, but the ABI
954                    // used for this call is passing it by-value. In that case,
955                    // the load would just produce `OperandValue::Ref` instead
956                    // of the `OperandValue::Immediate` we need for the call.
957                    llval = self.load(self.backend_type(arg.layout), llval, op_place_val.align);
958                    if let BackendRepr::Scalar(scalar) = arg.layout.backend_repr {
959                        if scalar.is_bool() {
960                            self.range_metadata(llval, WrappingRange { start: 0, end: 1 });
961                        }
962                        // We store bools as `i8` so we need to truncate to `i1`.
963                        llval = self.to_immediate_scalar(llval, scalar);
964                    }
965                    llargs.push(llval);
966                }
967            }
968        }
969
970        {
    use ::tracing::__macro_support::Callsite as _;
    static __CALLSITE: ::tracing::callsite::DefaultCallsite =
        {
            static META: ::tracing::Metadata<'static> =
                {
                    ::tracing_core::metadata::Metadata::new("event compiler/rustc_codegen_llvm/src/intrinsic.rs:970",
                        "rustc_codegen_llvm::intrinsic", ::tracing::Level::DEBUG,
                        ::tracing_core::__macro_support::Option::Some("compiler/rustc_codegen_llvm/src/intrinsic.rs"),
                        ::tracing_core::__macro_support::Option::Some(970u32),
                        ::tracing_core::__macro_support::Option::Some("rustc_codegen_llvm::intrinsic"),
                        ::tracing_core::field::FieldSet::new(&["message"],
                            ::tracing_core::callsite::Identifier(&__CALLSITE)),
                        ::tracing::metadata::Kind::EVENT)
                };
            ::tracing::callsite::DefaultCallsite::new(&META)
        };
    let enabled =
        ::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
                &&
                ::tracing::Level::DEBUG <=
                    ::tracing::level_filters::LevelFilter::current() &&
            {
                let interest = __CALLSITE.interest();
                !interest.is_never() &&
                    ::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
                        interest)
            };
    if enabled {
        (|value_set: ::tracing::field::ValueSet|
                    {
                        let meta = __CALLSITE.metadata();
                        ::tracing::Event::dispatch(meta, &value_set);
                        ;
                    })({
                #[allow(unused_imports)]
                use ::tracing::field::{debug, display, Value};
                let mut iter = __CALLSITE.metadata().fields().iter();
                __CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
                                    ::tracing::__macro_support::Option::Some(&format_args!("call intrinsic {0:?} with args ({1:?})",
                                                    instance, llargs) as &dyn Value))])
            });
    } else { ; }
};debug!("call intrinsic {:?} with args ({:?})", instance, llargs);
971
972        for (dest_ty, arg) in iter::zip(self.func_params_types(fn_ty), &mut llargs) {
973            let src_ty = self.val_ty(arg);
974            if !can_autocast(self, src_ty, dest_ty) {
    {
        ::core::panicking::panic_fmt(format_args!("Cannot match `{0:?}` (expected) with {1:?} (found) in `{2:?}",
                dest_ty, src_ty, fn_ptr));
    }
};assert!(
975                can_autocast(self, src_ty, dest_ty),
976                "Cannot match `{dest_ty:?}` (expected) with {src_ty:?} (found) in `{fn_ptr:?}"
977            );
978
979            *arg = autocast(self, arg, src_ty, dest_ty);
980        }
981
982        let llret = unsafe {
983            llvm::LLVMBuildCallWithOperandBundles(
984                self.llbuilder,
985                fn_ty,
986                fn_ptr,
987                llargs.as_ptr(),
988                llargs.len() as c_uint,
989                ptr::dangling(),
990                0,
991                c"".as_ptr(),
992            )
993        };
994
995        let src_ty = self.val_ty(llret);
996        let dest_ty = llreturn_ty;
997        if !can_autocast(self, dest_ty, src_ty) {
    {
        ::core::panicking::panic_fmt(format_args!("Cannot match `{0:?}` (expected) with `{1:?}` (found) in `{2:?}`",
                src_ty, dest_ty, fn_ptr));
    }
};assert!(
998            can_autocast(self, dest_ty, src_ty),
999            "Cannot match `{src_ty:?}` (expected) with `{dest_ty:?}` (found) in `{fn_ptr:?}`"
1000        );
1001
1002        autocast(self, llret, src_ty, dest_ty)
1003    }
1004
1005    fn abort(&mut self) {
1006        self.call_intrinsic("llvm.trap", &[], &[]);
1007    }
1008
1009    fn assume(&mut self, val: Self::Value) {
1010        if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
1011            self.call_intrinsic("llvm.assume", &[], &[val]);
1012        }
1013    }
1014
1015    fn expect(&mut self, cond: Self::Value, expected: bool) -> Self::Value {
1016        if self.cx.sess().opts.optimize != rustc_session::config::OptLevel::No {
1017            self.call_intrinsic(
1018                "llvm.expect",
1019                &[self.type_i1()],
1020                &[cond, self.const_bool(expected)],
1021            )
1022        } else {
1023            cond
1024        }
1025    }
1026
1027    fn type_checked_load(
1028        &mut self,
1029        llvtable: &'ll Value,
1030        vtable_byte_offset: u64,
1031        typeid: &[u8],
1032    ) -> Self::Value {
1033        let typeid = self.create_metadata(typeid);
1034        let typeid = self.get_metadata_value(typeid);
1035        let vtable_byte_offset = self.const_i32(vtable_byte_offset as i32);
1036        let type_checked_load = self.call_intrinsic(
1037            "llvm.type.checked.load",
1038            &[],
1039            &[llvtable, vtable_byte_offset, typeid],
1040        );
1041        self.extract_value(type_checked_load, 0)
1042    }
1043
1044    fn va_start(&mut self, va_list: &'ll Value) -> &'ll Value {
1045        self.call_intrinsic("llvm.va_start", &[self.val_ty(va_list)], &[va_list])
1046    }
1047
1048    fn va_end(&mut self, va_list: &'ll Value) -> &'ll Value {
1049        self.call_intrinsic("llvm.va_end", &[self.val_ty(va_list)], &[va_list])
1050    }
1051
1052    fn retag_reg(&mut self, ptr: Self::Value, info: &RetagInfo<Self::Value>) -> Self::Value {
1053        codegen_retag_inner(self, "__rust_retag_reg", ptr, info)
1054    }
1055
1056    fn retag_mem(&mut self, ptr: Self::Value, info: &RetagInfo<Self::Value>) {
1057        codegen_retag_inner(self, "__rust_retag_mem", ptr, info);
1058    }
1059}
1060
1061fn llvm_arch_for(rust_arch: &Arch) -> Option<&'static str> {
1062    Some(match rust_arch {
1063        Arch::AArch64 | Arch::Arm64EC => "aarch64",
1064        Arch::AmdGpu => "amdgcn",
1065        Arch::Arm => "arm",
1066        Arch::Bpf => "bpf",
1067        Arch::Hexagon => "hexagon",
1068        Arch::LoongArch32 | Arch::LoongArch64 => "loongarch",
1069        Arch::Mips | Arch::Mips32r6 | Arch::Mips64 | Arch::Mips64r6 => "mips",
1070        Arch::Nvptx64 => "nvvm",
1071        Arch::PowerPC | Arch::PowerPC64 => "ppc",
1072        Arch::RiscV32 | Arch::RiscV64 => "riscv",
1073        Arch::S390x => "s390",
1074        Arch::SpirV => "spv",
1075        Arch::Wasm32 | Arch::Wasm64 => "wasm",
1076        Arch::X86 | Arch::X86_64 => "x86",
1077        _ => return None, // fallback for unknown archs
1078    })
1079}
1080
1081fn can_autocast<'ll>(cx: &CodegenCx<'ll, '_>, rust_ty: &'ll Type, llvm_ty: &'ll Type) -> bool {
1082    if rust_ty == llvm_ty {
1083        return true;
1084    }
1085
1086    match cx.type_kind(llvm_ty) {
1087        // Some LLVM intrinsics return **non-packed** structs, but they can't be mimicked from Rust
1088        // due to auto field-alignment in non-packed structs (packed structs are represented in LLVM
1089        // as, well, packed structs, so they won't match with those either)
1090        TypeKind::Struct if cx.type_kind(rust_ty) == TypeKind::Struct => {
1091            let rust_element_tys = cx.struct_element_types(rust_ty);
1092            let llvm_element_tys = cx.struct_element_types(llvm_ty);
1093
1094            if rust_element_tys.len() != llvm_element_tys.len() {
1095                return false;
1096            }
1097
1098            iter::zip(rust_element_tys, llvm_element_tys).all(
1099                |(rust_element_ty, llvm_element_ty)| {
1100                    can_autocast(cx, rust_element_ty, llvm_element_ty)
1101                },
1102            )
1103        }
1104        TypeKind::Vector => {
1105            let llvm_element_ty = cx.element_type(llvm_ty);
1106            let element_count = cx.vector_length(llvm_ty) as u64;
1107
1108            if llvm_element_ty == cx.type_bf16() {
1109                rust_ty == cx.type_vector(cx.type_i16(), element_count)
1110            } else if llvm_element_ty == cx.type_i1() {
1111                let int_width = element_count.next_power_of_two().max(8);
1112                rust_ty == cx.type_ix(int_width)
1113            } else {
1114                false
1115            }
1116        }
1117        TypeKind::BFloat => rust_ty == cx.type_i16(),
1118        TypeKind::X86_AMX if cx.type_kind(rust_ty) == TypeKind::Vector => {
1119            let element_ty = cx.element_type(rust_ty);
1120            let element_count = cx.vector_length(rust_ty) as u64;
1121
1122            let element_size_bits = match cx.type_kind(element_ty) {
1123                TypeKind::Half => 16,
1124                TypeKind::Float => 32,
1125                TypeKind::Double => 64,
1126                TypeKind::FP128 => 128,
1127                TypeKind::Integer => cx.int_width(element_ty),
1128                TypeKind::Pointer => cx.int_width(cx.isize_ty),
1129                _ => ::rustc_middle::util::bug::bug_fmt(format_args!("Vector element type `{0:?}` not one of integer, float or pointer",
        element_ty))bug!(
1130                    "Vector element type `{element_ty:?}` not one of integer, float or pointer"
1131                ),
1132            };
1133
1134            element_size_bits * element_count == 8192
1135        }
1136        _ => false,
1137    }
1138}
1139
1140fn autocast<'ll>(
1141    bx: &mut Builder<'_, 'll, '_>,
1142    val: &'ll Value,
1143    src_ty: &'ll Type,
1144    dest_ty: &'ll Type,
1145) -> &'ll Value {
1146    if src_ty == dest_ty {
1147        return val;
1148    }
1149    match (bx.type_kind(src_ty), bx.type_kind(dest_ty)) {
1150        // re-pack structs
1151        (TypeKind::Struct, TypeKind::Struct) => {
1152            let mut ret = bx.const_poison(dest_ty);
1153            for (idx, (src_element_ty, dest_element_ty)) in
1154                iter::zip(bx.struct_element_types(src_ty), bx.struct_element_types(dest_ty))
1155                    .enumerate()
1156            {
1157                let elt = bx.extract_value(val, idx as u64);
1158                let casted_elt = autocast(bx, elt, src_element_ty, dest_element_ty);
1159                ret = bx.insert_value(ret, casted_elt, idx as u64);
1160            }
1161            ret
1162        }
1163        // cast from the i1xN vector type to the primitive type
1164        (TypeKind::Vector, TypeKind::Integer) if bx.element_type(src_ty) == bx.type_i1() => {
1165            let vector_length = bx.vector_length(src_ty) as u64;
1166            let int_width = vector_length.next_power_of_two().max(8);
1167
1168            let val = if vector_length == int_width {
1169                val
1170            } else {
1171                // zero-extends vector
1172                let shuffle_indices = match vector_length {
1173                    0 => {
    ::core::panicking::panic_fmt(format_args!("internal error: entered unreachable code: {0}",
            format_args!("zero length vectors are not allowed")));
}unreachable!("zero length vectors are not allowed"),
1174                    1 => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [0, 1, 1, 1, 1, 1, 1, 1]))vec![0, 1, 1, 1, 1, 1, 1, 1],
1175                    2 => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [0, 1, 2, 2, 2, 2, 2, 2]))vec![0, 1, 2, 2, 2, 2, 2, 2],
1176                    3 => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [0, 1, 2, 3, 3, 3, 3, 3]))vec![0, 1, 2, 3, 3, 3, 3, 3],
1177                    4.. => (0..int_width as i32).collect(),
1178                };
1179                let shuffle_mask =
1180                    shuffle_indices.into_iter().map(|i| bx.const_i32(i)).collect::<Vec<_>>();
1181                bx.shuffle_vector(val, bx.const_null(src_ty), bx.const_vector(&shuffle_mask))
1182            };
1183            bx.bitcast(val, dest_ty)
1184        }
1185        // cast from the primitive type to the i1xN vector type
1186        (TypeKind::Integer, TypeKind::Vector) if bx.element_type(dest_ty) == bx.type_i1() => {
1187            let vector_length = bx.vector_length(dest_ty) as u64;
1188            let int_width = vector_length.next_power_of_two().max(8);
1189
1190            let intermediate_ty = bx.type_vector(bx.type_i1(), int_width);
1191            let intermediate = bx.bitcast(val, intermediate_ty);
1192
1193            if vector_length == int_width {
1194                intermediate
1195            } else {
1196                let shuffle_mask: Vec<_> =
1197                    (0..vector_length).map(|i| bx.const_i32(i as i32)).collect();
1198                bx.shuffle_vector(
1199                    intermediate,
1200                    bx.const_poison(intermediate_ty),
1201                    bx.const_vector(&shuffle_mask),
1202                )
1203            }
1204        }
1205        (TypeKind::Vector, TypeKind::X86_AMX) => {
1206            bx.call_intrinsic("llvm.x86.cast.vector.to.tile", &[src_ty], &[val])
1207        }
1208        (TypeKind::X86_AMX, TypeKind::Vector) => {
1209            bx.call_intrinsic("llvm.x86.cast.tile.to.vector", &[dest_ty], &[val])
1210        }
1211        _ => bx.bitcast(val, dest_ty), // for `bf16(xN)` <-> `u16(xN)`
1212    }
1213}
1214
1215fn intrinsic_fn<'ll, 'tcx>(
1216    bx: &Builder<'_, 'll, 'tcx>,
1217    name: &str,
1218    rust_return_ty: &'ll Type,
1219    rust_argument_tys: Vec<&'ll Type>,
1220    instance: ty::Instance<'tcx>,
1221) -> &'ll Value {
1222    let tcx = bx.tcx;
1223
1224    let rust_fn_ty = bx.type_func(&rust_argument_tys, rust_return_ty);
1225
1226    let intrinsic = llvm::Intrinsic::lookup(name.as_bytes());
1227
1228    if let Some(intrinsic) = intrinsic
1229        && intrinsic.is_target_specific()
1230    {
1231        let (llvm_arch, _) = name[5..].split_once('.').unwrap();
1232        let rust_arch = &tcx.sess.target.arch;
1233
1234        if let Some(correct_llvm_arch) = llvm_arch_for(rust_arch)
1235            && llvm_arch != correct_llvm_arch
1236        {
1237            tcx.dcx().emit_fatal(IntrinsicWrongArch {
1238                name,
1239                target_arch: rust_arch.desc(),
1240                span: tcx.def_span(instance.def_id()),
1241            });
1242        }
1243    }
1244
1245    if let Some(intrinsic) = intrinsic
1246        && !intrinsic.is_overloaded()
1247    {
1248        // FIXME: also do this for overloaded intrinsics
1249        let llfn = intrinsic.get_declaration(bx.llmod, &[]);
1250        let llvm_fn_ty = bx.get_type_of_global(llfn);
1251
1252        let llvm_return_ty = bx.get_return_type(llvm_fn_ty);
1253        let llvm_argument_tys = bx.func_params_types(llvm_fn_ty);
1254        let llvm_is_variadic = bx.func_is_variadic(llvm_fn_ty);
1255
1256        let is_correct_signature = !llvm_is_variadic
1257            && rust_argument_tys.len() == llvm_argument_tys.len()
1258            && iter::once((rust_return_ty, llvm_return_ty))
1259                .chain(iter::zip(rust_argument_tys, llvm_argument_tys))
1260                .all(|(rust_ty, llvm_ty)| can_autocast(bx, rust_ty, llvm_ty));
1261
1262        if !is_correct_signature {
1263            tcx.dcx().emit_fatal(IntrinsicSignatureMismatch {
1264                name,
1265                llvm_fn_ty: &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", llvm_fn_ty))
    })format!("{llvm_fn_ty:?}"),
1266                rust_fn_ty: &::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0:?}", rust_fn_ty))
    })format!("{rust_fn_ty:?}"),
1267                span: tcx.def_span(instance.def_id()),
1268            });
1269        }
1270
1271        return llfn;
1272    }
1273
1274    // Function addresses in Rust are never significant, allowing functions to be merged.
1275    let llfn = declare_raw_fn(
1276        bx,
1277        name,
1278        llvm::CCallConv,
1279        llvm::UnnamedAddr::Global,
1280        llvm::Visibility::Default,
1281        rust_fn_ty,
1282    );
1283
1284    if intrinsic.is_none() {
1285        let mut new_llfn = None;
1286        let can_upgrade = unsafe { llvm::LLVMRustUpgradeIntrinsicFunction(llfn, &mut new_llfn) };
1287
1288        if !can_upgrade {
1289            // This is either plain wrong, or this can be caused by incompatible LLVM versions
1290            tcx.dcx().emit_fatal(UnknownIntrinsic { name, span: tcx.def_span(instance.def_id()) });
1291        } else if let Some(def_id) = instance.def_id().as_local() {
1292            // we can emit diagnostics only for local crates
1293            let hir_id = tcx.local_def_id_to_hir_id(def_id);
1294
1295            // not all intrinsics are upgraded to some other intrinsics, most are upgraded to instruction sequences
1296            let msg = if let Some(new_llfn) = new_llfn {
1297                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("using deprecated intrinsic `{1}`, `{0}` can be used instead",
                str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap(),
                name))
    })format!(
1298                    "using deprecated intrinsic `{name}`, `{}` can be used instead",
1299                    str::from_utf8(&llvm::get_value_name(new_llfn)).unwrap()
1300                )
1301            } else {
1302                ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("using deprecated intrinsic `{0}`",
                name))
    })format!("using deprecated intrinsic `{name}`")
1303            };
1304
1305            tcx.emit_node_lint(
1306                DEPRECATED_LLVM_INTRINSIC,
1307                hir_id,
1308                rustc_errors::DiagDecorator(|d| {
1309                    d.primary_message(msg).span(tcx.hir_span(hir_id));
1310                }),
1311            );
1312        }
1313    }
1314
1315    llfn
1316}
1317
1318fn catch_unwind_intrinsic<'ll, 'tcx>(
1319    bx: &mut Builder<'_, 'll, 'tcx>,
1320    try_func: &'ll Value,
1321    data: &'ll Value,
1322    catch_func: &'ll Value,
1323    dest: PlaceRef<'tcx, &'ll Value>,
1324) {
1325    if !bx.sess().panic_strategy().unwinds() {
1326        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1327        bx.call(try_func_ty, None, None, try_func, &[data], None, None);
1328        // Return 0 unconditionally from the intrinsic call;
1329        // we can never unwind.
1330        OperandValue::Immediate(bx.const_i32(0)).store(bx, dest);
1331    } else if wants_msvc_seh(bx.sess()) {
1332        codegen_msvc_try(bx, try_func, data, catch_func, dest);
1333    } else if wants_wasm_eh(bx.sess()) {
1334        codegen_wasm_try(bx, try_func, data, catch_func, dest);
1335    } else if bx.sess().target.os == Os::Emscripten {
1336        codegen_emcc_try(bx, try_func, data, catch_func, dest);
1337    } else {
1338        codegen_gnu_try(bx, try_func, data, catch_func, dest);
1339    }
1340}
1341
1342// MSVC's definition of the `rust_try` function.
1343//
1344// This implementation uses the new exception handling instructions in LLVM
1345// which have support in LLVM for SEH on MSVC targets. Although these
1346// instructions are meant to work for all targets, as of the time of this
1347// writing, however, LLVM does not recommend the usage of these new instructions
1348// as the old ones are still more optimized.
1349fn codegen_msvc_try<'ll, 'tcx>(
1350    bx: &mut Builder<'_, 'll, 'tcx>,
1351    try_func: &'ll Value,
1352    data: &'ll Value,
1353    catch_func: &'ll Value,
1354    dest: PlaceRef<'tcx, &'ll Value>,
1355) {
1356    let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
1357        bx.set_personality_fn(bx.eh_personality());
1358
1359        let normal = bx.append_sibling_block("normal");
1360        let catchswitch = bx.append_sibling_block("catchswitch");
1361        let catchpad_rust = bx.append_sibling_block("catchpad_rust");
1362        let catchpad_foreign = bx.append_sibling_block("catchpad_foreign");
1363        let caught = bx.append_sibling_block("caught");
1364
1365        let try_func = llvm::get_param(bx.llfn(), 0);
1366        let data = llvm::get_param(bx.llfn(), 1);
1367        let catch_func = llvm::get_param(bx.llfn(), 2);
1368
1369        // We're generating an IR snippet that looks like:
1370        //
1371        //   declare i32 @rust_try(%try_func, %data, %catch_func) {
1372        //      %slot = alloca i8*
1373        //      invoke %try_func(%data) to label %normal unwind label %catchswitch
1374        //
1375        //   normal:
1376        //      ret i32 0
1377        //
1378        //   catchswitch:
1379        //      %cs = catchswitch within none [%catchpad_rust, %catchpad_foreign] unwind to caller
1380        //
1381        //   catchpad_rust:
1382        //      %tok = catchpad within %cs [%type_descriptor, 8, %slot]
1383        //      %ptr = load %slot
1384        //      call %catch_func(%data, %ptr)
1385        //      catchret from %tok to label %caught
1386        //
1387        //   catchpad_foreign:
1388        //      %tok = catchpad within %cs [null, 64, null]
1389        //      call %catch_func(%data, null)
1390        //      catchret from %tok to label %caught
1391        //
1392        //   caught:
1393        //      ret i32 1
1394        //   }
1395        //
1396        // This structure follows the basic usage of throw/try/catch in LLVM.
1397        // For example, compile this C++ snippet to see what LLVM generates:
1398        //
1399        //      struct rust_panic {
1400        //          rust_panic(const rust_panic&);
1401        //          ~rust_panic();
1402        //
1403        //          void* x[2];
1404        //      };
1405        //
1406        //      int __rust_try(
1407        //          void (*try_func)(void*),
1408        //          void *data,
1409        //          void (*catch_func)(void*, void*) noexcept
1410        //      ) {
1411        //          try {
1412        //              try_func(data);
1413        //              return 0;
1414        //          } catch(rust_panic& a) {
1415        //              catch_func(data, &a);
1416        //              return 1;
1417        //          } catch(...) {
1418        //              catch_func(data, NULL);
1419        //              return 1;
1420        //          }
1421        //      }
1422        //
1423        // More information can be found in libstd's seh.rs implementation.
1424        let ptr_size = bx.tcx().data_layout.pointer_size();
1425        let ptr_align = bx.tcx().data_layout.pointer_align().abi;
1426        let slot = bx.alloca(ptr_size, ptr_align);
1427        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1428        bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None);
1429
1430        bx.switch_to_block(normal);
1431        bx.ret(bx.const_i32(0));
1432
1433        bx.switch_to_block(catchswitch);
1434        let cs = bx.catch_switch(None, None, &[catchpad_rust, catchpad_foreign]);
1435
1436        // We can't use the TypeDescriptor defined in libpanic_unwind because it
1437        // might be in another DLL and the SEH encoding only supports specifying
1438        // a TypeDescriptor from the current module.
1439        //
1440        // However this isn't an issue since the MSVC runtime uses string
1441        // comparison on the type name to match TypeDescriptors rather than
1442        // pointer equality.
1443        //
1444        // So instead we generate a new TypeDescriptor in each module that uses
1445        // `try` and let the linker merge duplicate definitions in the same
1446        // module.
1447        //
1448        // When modifying, make sure that the type_name string exactly matches
1449        // the one used in library/panic_unwind/src/seh.rs.
1450        let type_info_vtable = bx.declare_global("??_7type_info@@6B@", bx.type_ptr());
1451        let type_name = bx.const_bytes(b"rust_panic\0");
1452        let type_info =
1453            bx.const_struct(&[type_info_vtable, bx.const_null(bx.type_ptr()), type_name], false);
1454        let tydesc = bx.declare_global(
1455            &mangle_internal_symbol(bx.tcx, "__rust_panic_type_info"),
1456            bx.val_ty(type_info),
1457        );
1458
1459        llvm::set_linkage(tydesc, llvm::Linkage::LinkOnceODRLinkage);
1460        if bx.cx.tcx.sess.target.supports_comdat() {
1461            llvm::SetUniqueComdat(bx.llmod, tydesc);
1462        }
1463        llvm::set_initializer(tydesc, type_info);
1464
1465        // The flag value of 8 indicates that we are catching the exception by
1466        // reference instead of by value. We can't use catch by value because
1467        // that requires copying the exception object, which we don't support
1468        // since our exception object effectively contains a Box.
1469        //
1470        // Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang
1471        bx.switch_to_block(catchpad_rust);
1472        let flags = bx.const_i32(8);
1473        let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
1474        let ptr = bx.load(bx.type_ptr(), slot, ptr_align);
1475        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
1476        bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None);
1477        bx.catch_ret(&funclet, caught);
1478
1479        // The flag value of 64 indicates a "catch-all".
1480        bx.switch_to_block(catchpad_foreign);
1481        let flags = bx.const_i32(64);
1482        let null = bx.const_null(bx.type_ptr());
1483        let funclet = bx.catch_pad(cs, &[null, flags, null]);
1484        bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet), None);
1485        bx.catch_ret(&funclet, caught);
1486
1487        bx.switch_to_block(caught);
1488        bx.ret(bx.const_i32(1));
1489    });
1490
1491    // Note that no invoke is used here because by definition this function
1492    // can't panic (that's what it's catching).
1493    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
1494    OperandValue::Immediate(ret).store(bx, dest);
1495}
1496
1497// WASM's definition of the `rust_try` function.
1498fn codegen_wasm_try<'ll, 'tcx>(
1499    bx: &mut Builder<'_, 'll, 'tcx>,
1500    try_func: &'ll Value,
1501    data: &'ll Value,
1502    catch_func: &'ll Value,
1503    dest: PlaceRef<'tcx, &'ll Value>,
1504) {
1505    let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
1506        bx.set_personality_fn(bx.eh_personality());
1507
1508        let normal = bx.append_sibling_block("normal");
1509        let catchswitch = bx.append_sibling_block("catchswitch");
1510        let catchpad = bx.append_sibling_block("catchpad");
1511        let caught = bx.append_sibling_block("caught");
1512
1513        let try_func = llvm::get_param(bx.llfn(), 0);
1514        let data = llvm::get_param(bx.llfn(), 1);
1515        let catch_func = llvm::get_param(bx.llfn(), 2);
1516
1517        // We're generating an IR snippet that looks like:
1518        //
1519        //   declare i32 @rust_try(%try_func, %data, %catch_func) {
1520        //      %slot = alloca i8*
1521        //      invoke %try_func(%data) to label %normal unwind label %catchswitch
1522        //
1523        //   normal:
1524        //      ret i32 0
1525        //
1526        //   catchswitch:
1527        //      %cs = catchswitch within none [%catchpad] unwind to caller
1528        //
1529        //   catchpad:
1530        //      %tok = catchpad within %cs [null]
1531        //      %ptr = call @llvm.wasm.get.exception(token %tok)
1532        //      %sel = call @llvm.wasm.get.ehselector(token %tok)
1533        //      call %catch_func(%data, %ptr)
1534        //      catchret from %tok to label %caught
1535        //
1536        //   caught:
1537        //      ret i32 1
1538        //   }
1539        //
1540        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1541        bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None, None);
1542
1543        bx.switch_to_block(normal);
1544        bx.ret(bx.const_i32(0));
1545
1546        bx.switch_to_block(catchswitch);
1547        let cs = bx.catch_switch(None, None, &[catchpad]);
1548
1549        bx.switch_to_block(catchpad);
1550        let null = bx.const_null(bx.type_ptr());
1551        let funclet = bx.catch_pad(cs, &[null]);
1552
1553        let ptr = bx.call_intrinsic("llvm.wasm.get.exception", &[], &[funclet.cleanuppad()]);
1554        let _sel = bx.call_intrinsic("llvm.wasm.get.ehselector", &[], &[funclet.cleanuppad()]);
1555
1556        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
1557        bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet), None);
1558        bx.catch_ret(&funclet, caught);
1559
1560        bx.switch_to_block(caught);
1561        bx.ret(bx.const_i32(1));
1562    });
1563
1564    // Note that no invoke is used here because by definition this function
1565    // can't panic (that's what it's catching).
1566    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
1567    OperandValue::Immediate(ret).store(bx, dest);
1568}
1569
1570// Definition of the standard `try` function for Rust using the GNU-like model
1571// of exceptions (e.g., the normal semantics of LLVM's `landingpad` and `invoke`
1572// instructions).
1573//
1574// This codegen is a little surprising because we always call a shim
1575// function instead of inlining the call to `invoke` manually here. This is done
1576// because in LLVM we're only allowed to have one personality per function
1577// definition. The call to the `try` intrinsic is being inlined into the
1578// function calling it, and that function may already have other personality
1579// functions in play. By calling a shim we're guaranteed that our shim will have
1580// the right personality function.
1581fn codegen_gnu_try<'ll, 'tcx>(
1582    bx: &mut Builder<'_, 'll, 'tcx>,
1583    try_func: &'ll Value,
1584    data: &'ll Value,
1585    catch_func: &'ll Value,
1586    dest: PlaceRef<'tcx, &'ll Value>,
1587) {
1588    let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
1589        // Codegens the shims described above:
1590        //
1591        //   bx:
1592        //      invoke %try_func(%data) normal %normal unwind %catch
1593        //
1594        //   normal:
1595        //      ret 0
1596        //
1597        //   catch:
1598        //      (%ptr, _) = landingpad
1599        //      call %catch_func(%data, %ptr)
1600        //      ret 1
1601        let then = bx.append_sibling_block("then");
1602        let catch = bx.append_sibling_block("catch");
1603
1604        let try_func = llvm::get_param(bx.llfn(), 0);
1605        let data = llvm::get_param(bx.llfn(), 1);
1606        let catch_func = llvm::get_param(bx.llfn(), 2);
1607        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1608        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None);
1609
1610        bx.switch_to_block(then);
1611        bx.ret(bx.const_i32(0));
1612
1613        // Type indicator for the exception being thrown.
1614        //
1615        // The first value in this tuple is a pointer to the exception object
1616        // being thrown. The second value is a "selector" indicating which of
1617        // the landing pad clauses the exception's type had been matched to.
1618        // rust_try ignores the selector.
1619        bx.switch_to_block(catch);
1620        let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()], false);
1621        let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 1);
1622        let tydesc = bx.const_null(bx.type_ptr());
1623        bx.add_clause(vals, tydesc);
1624        let ptr = bx.extract_value(vals, 0);
1625        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
1626        bx.call(catch_ty, None, None, catch_func, &[data, ptr], None, None);
1627        bx.ret(bx.const_i32(1));
1628    });
1629
1630    // Note that no invoke is used here because by definition this function
1631    // can't panic (that's what it's catching).
1632    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
1633    OperandValue::Immediate(ret).store(bx, dest);
1634}
1635
1636// Variant of codegen_gnu_try used for emscripten where Rust panics are
1637// implemented using C++ exceptions. Here we use exceptions of a specific type
1638// (`struct rust_panic`) to represent Rust panics.
1639fn codegen_emcc_try<'ll, 'tcx>(
1640    bx: &mut Builder<'_, 'll, 'tcx>,
1641    try_func: &'ll Value,
1642    data: &'ll Value,
1643    catch_func: &'ll Value,
1644    dest: PlaceRef<'tcx, &'ll Value>,
1645) {
1646    let (llty, llfn) = get_rust_try_fn(bx, &mut |mut bx| {
1647        // Codegens the shims described above:
1648        //
1649        //   bx:
1650        //      invoke %try_func(%data) normal %normal unwind %catch
1651        //
1652        //   normal:
1653        //      ret 0
1654        //
1655        //   catch:
1656        //      (%ptr, %selector) = landingpad
1657        //      %rust_typeid = @llvm.eh.typeid.for(@_ZTI10rust_panic)
1658        //      %is_rust_panic = %selector == %rust_typeid
1659        //      %catch_data = alloca { i8*, i8 }
1660        //      %catch_data[0] = %ptr
1661        //      %catch_data[1] = %is_rust_panic
1662        //      call %catch_func(%data, %catch_data)
1663        //      ret 1
1664        let then = bx.append_sibling_block("then");
1665        let catch = bx.append_sibling_block("catch");
1666
1667        let try_func = llvm::get_param(bx.llfn(), 0);
1668        let data = llvm::get_param(bx.llfn(), 1);
1669        let catch_func = llvm::get_param(bx.llfn(), 2);
1670        let try_func_ty = bx.type_func(&[bx.type_ptr()], bx.type_void());
1671        bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None, None);
1672
1673        bx.switch_to_block(then);
1674        bx.ret(bx.const_i32(0));
1675
1676        // Type indicator for the exception being thrown.
1677        //
1678        // The first value in this tuple is a pointer to the exception object
1679        // being thrown. The second value is a "selector" indicating which of
1680        // the landing pad clauses the exception's type had been matched to.
1681        bx.switch_to_block(catch);
1682        let tydesc = bx.eh_catch_typeinfo();
1683        let lpad_ty = bx.type_struct(&[bx.type_ptr(), bx.type_i32()], false);
1684        let vals = bx.landing_pad(lpad_ty, bx.eh_personality(), 2);
1685        bx.add_clause(vals, tydesc);
1686        bx.add_clause(vals, bx.const_null(bx.type_ptr()));
1687        let ptr = bx.extract_value(vals, 0);
1688        let selector = bx.extract_value(vals, 1);
1689
1690        // Check if the typeid we got is the one for a Rust panic.
1691        let rust_typeid = bx.call_intrinsic("llvm.eh.typeid.for", &[bx.val_ty(tydesc)], &[tydesc]);
1692        let is_rust_panic = bx.icmp(IntPredicate::IntEQ, selector, rust_typeid);
1693        let is_rust_panic = bx.zext(is_rust_panic, bx.type_bool());
1694
1695        // We need to pass two values to catch_func (ptr and is_rust_panic), so
1696        // create an alloca and pass a pointer to that.
1697        let ptr_size = bx.tcx().data_layout.pointer_size();
1698        let ptr_align = bx.tcx().data_layout.pointer_align().abi;
1699        let i8_align = bx.tcx().data_layout.i8_align;
1700        // Required in order for there to be no padding between the fields.
1701        if !(i8_align <= ptr_align) {
    ::core::panicking::panic("assertion failed: i8_align <= ptr_align")
};assert!(i8_align <= ptr_align);
1702        let catch_data = bx.alloca(2 * ptr_size, ptr_align);
1703        bx.store(ptr, catch_data, ptr_align);
1704        let catch_data_1 = bx.inbounds_ptradd(catch_data, bx.const_usize(ptr_size.bytes()));
1705        bx.store(is_rust_panic, catch_data_1, i8_align);
1706
1707        let catch_ty = bx.type_func(&[bx.type_ptr(), bx.type_ptr()], bx.type_void());
1708        bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None, None);
1709        bx.ret(bx.const_i32(1));
1710    });
1711
1712    // Note that no invoke is used here because by definition this function
1713    // can't panic (that's what it's catching).
1714    let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None, None);
1715    OperandValue::Immediate(ret).store(bx, dest);
1716}
1717
1718// Helper function to give a Block to a closure to codegen a shim function.
1719// This is currently primarily used for the `try` intrinsic functions above.
1720fn gen_fn<'a, 'll, 'tcx>(
1721    cx: &'a CodegenCx<'ll, 'tcx>,
1722    name: &str,
1723    rust_fn_sig: ty::PolyFnSig<'tcx>,
1724    codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
1725) -> (&'ll Type, &'ll Value) {
1726    let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
1727    let llty = fn_abi.llvm_type(cx);
1728    let llfn = cx.declare_fn(name, fn_abi, None);
1729    cx.set_frame_pointer_type(llfn);
1730    cx.apply_target_cpu_attr(llfn);
1731    // FIXME(eddyb) find a nicer way to do this.
1732    llvm::set_linkage(llfn, llvm::Linkage::InternalLinkage);
1733    let llbb = Builder::append_block(cx, llfn, "entry-block");
1734    let bx = Builder::build(cx, llbb);
1735    codegen(bx);
1736    (llty, llfn)
1737}
1738
1739// Helper function used to get a handle to the `__rust_try` function used to
1740// catch exceptions.
1741//
1742// This function is only generated once and is then cached.
1743fn get_rust_try_fn<'a, 'll, 'tcx>(
1744    cx: &'a CodegenCx<'ll, 'tcx>,
1745    codegen: &mut dyn FnMut(Builder<'a, 'll, 'tcx>),
1746) -> (&'ll Type, &'ll Value) {
1747    if let Some(llfn) = cx.rust_try_fn.get() {
1748        return llfn;
1749    }
1750
1751    // Define the type up front for the signature of the rust_try function.
1752    let tcx = cx.tcx;
1753    let i8p = Ty::new_mut_ptr(tcx, tcx.types.i8);
1754    // `unsafe fn(*mut i8) -> ()`
1755    let try_fn_ty = Ty::new_fn_ptr(
1756        tcx,
1757        ty::Binder::dummy(tcx.mk_fn_sig_rust_abi([i8p], tcx.types.unit, hir::Safety::Unsafe)),
1758    );
1759    // `unsafe fn(*mut i8, *mut i8) -> ()`
1760    let catch_fn_ty = Ty::new_fn_ptr(
1761        tcx,
1762        ty::Binder::dummy(tcx.mk_fn_sig_rust_abi([i8p, i8p], tcx.types.unit, hir::Safety::Unsafe)),
1763    );
1764    // `unsafe fn(unsafe fn(*mut i8) -> (), *mut i8, unsafe fn(*mut i8, *mut i8) -> ()) -> i32`
1765    let rust_fn_sig = ty::Binder::dummy(cx.tcx.mk_fn_sig_rust_abi(
1766        [try_fn_ty, i8p, catch_fn_ty],
1767        tcx.types.i32,
1768        hir::Safety::Unsafe,
1769    ));
1770    let rust_try = gen_fn(cx, "__rust_try", rust_fn_sig, codegen);
1771    cx.rust_try_fn.set(Some(rust_try));
1772    rust_try
1773}
1774
1775fn codegen_retag_inner<'ll, 'tcx>(
1776    bx: &mut Builder<'_, 'll, 'tcx>,
1777    name: &'static str,
1778    ptr: &'ll Value,
1779    info: &RetagInfo<&'ll Value>,
1780) -> &'ll Value {
1781    let size = bx.const_usize(info.size.bytes());
1782    let perms = bx.const_u8(info.flags.bits());
1783
1784    bx.call_intrinsic(
1785        name,
1786        // Retag intrinsics have special handling within `CodegenCx::declare_intrinsic`
1787        // to ensure that each form has the correct return type.
1788        &[bx.type_ptr(), bx.val_ty(size), bx.type_i8(), bx.type_ptr(), bx.type_ptr()],
1789        &[ptr, size, perms, info.im_layout, info.pin_layout],
1790    )
1791}
1792
1793fn codegen_autodiff<'ll, 'tcx>(
1794    bx: &mut Builder<'_, 'll, 'tcx>,
1795    tcx: TyCtxt<'tcx>,
1796    instance: ty::Instance<'tcx>,
1797    args: &[OperandRef<'tcx, &'ll Value>],
1798    result: PlaceRef<'tcx, &'ll Value>,
1799) {
1800    if !tcx.sess.opts.unstable_opts.autodiff.contains(&rustc_session::config::AutoDiff::Enable) {
1801        let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutEnable);
1802    }
1803
1804    let ct = tcx.crate_types();
1805    let lto = tcx.sess.lto();
1806    if ct.len() == 1 && ct.contains(&CrateType::Executable) {
1807        if lto != rustc_session::config::Lto::Fat {
1808            let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutLto);
1809        }
1810    } else {
1811        if lto != rustc_session::config::Lto::Fat && !tcx.sess.opts.cg.linker_plugin_lto.enabled() {
1812            let _ = tcx.dcx().emit_almost_fatal(AutoDiffWithoutLto);
1813        }
1814    }
1815
1816    let fn_args = instance.args;
1817    let callee_ty = instance.ty(tcx, bx.typing_env());
1818
1819    let sig = callee_ty.fn_sig(tcx).skip_binder();
1820
1821    let ret_ty = sig.output();
1822    let llret_ty = bx.layout_of(ret_ty).llvm_type(bx);
1823
1824    let source_fn_ptr_ty = fn_args.into_type_list(tcx)[0];
1825    let fn_to_diff = args[0].immediate();
1826
1827    let (diff_id, diff_args) = match fn_args.into_type_list(tcx)[1].kind() {
1828        ty::FnDef(def_id, diff_args) => (def_id, diff_args),
1829        _ => ::rustc_middle::util::bug::bug_fmt(format_args!("invalid args"))bug!("invalid args"),
1830    };
1831
1832    let fn_diff = match Instance::try_resolve(tcx, bx.cx.typing_env(), *diff_id, diff_args) {
1833        Ok(Some(instance)) => instance,
1834        Ok(None) => ::rustc_middle::util::bug::bug_fmt(format_args!("could not resolve ({0:?}, {1:?}) to a specific autodiff instance",
        diff_id, diff_args))bug!(
1835            "could not resolve ({:?}, {:?}) to a specific autodiff instance",
1836            diff_id,
1837            diff_args
1838        ),
1839        Err(_) => {
1840            // An error has already been emitted
1841            return;
1842        }
1843    };
1844
1845    let val_arr = get_args_from_tuple(bx, args[2], fn_diff);
1846    let diff_symbol = symbol_name_for_instance_in_crate(tcx, fn_diff.clone(), LOCAL_CRATE);
1847
1848    let Some(Some(mut diff_attrs)) =
1849        {
    {
        'done:
            {
            for i in
                ::rustc_hir::attrs::HasAttrs::get_attrs(fn_diff.def_id(),
                    &tcx) {
                #[allow(unused_imports)]
                use rustc_hir::attrs::AttributeKind::*;
                let i: &rustc_hir::Attribute = i;
                match i {
                    rustc_hir::Attribute::Parsed(RustcAutodiff(attr)) => {
                        break 'done Some(attr.clone());
                    }
                    rustc_hir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(tcx, fn_diff.def_id(), RustcAutodiff(attr) => attr.clone())
1850    else {
1851        ::rustc_middle::util::bug::bug_fmt(format_args!("could not find autodiff attrs"))bug!("could not find autodiff attrs")
1852    };
1853
1854    adjust_activity_to_abi(
1855        tcx,
1856        source_fn_ptr_ty,
1857        TypingEnv::fully_monomorphized(),
1858        &mut diff_attrs.input_activity,
1859    );
1860
1861    let fnc_tree = rustc_middle::ty::fnc_typetrees(tcx, source_fn_ptr_ty);
1862
1863    // Build body
1864    generate_enzyme_call(
1865        bx,
1866        bx.cx,
1867        fn_to_diff,
1868        &diff_symbol,
1869        llret_ty,
1870        &val_arr,
1871        &diff_attrs,
1872        result,
1873        fnc_tree,
1874    );
1875}
1876
1877// Generates the LLVM code to offload a Rust function to a target device (e.g., GPU).
1878// For each kernel call, it generates the necessary globals (including metadata such as
1879// size and pass mode), manages memory mapping to and from the device, handles all
1880// data transfers, and launches the kernel on the target device.
1881fn codegen_offload<'ll, 'tcx>(
1882    bx: &mut Builder<'_, 'll, 'tcx>,
1883    tcx: TyCtxt<'tcx>,
1884    instance: ty::Instance<'tcx>,
1885    args: &[OperandRef<'tcx, &'ll Value>],
1886) {
1887    let cx = bx.cx;
1888    let fn_args = instance.args;
1889
1890    let (target_id, target_args) = match fn_args.into_type_list(tcx)[0].kind() {
1891        ty::FnDef(def_id, params) => (def_id, params),
1892        _ => ::rustc_middle::util::bug::bug_fmt(format_args!("invalid offload intrinsic arg"))bug!("invalid offload intrinsic arg"),
1893    };
1894
1895    let fn_target = match Instance::try_resolve(tcx, cx.typing_env(), *target_id, target_args) {
1896        Ok(Some(instance)) => instance,
1897        Ok(None) => ::rustc_middle::util::bug::bug_fmt(format_args!("could not resolve ({0:?}, {1:?}) to a specific offload instance",
        target_id, target_args))bug!(
1898            "could not resolve ({:?}, {:?}) to a specific offload instance",
1899            target_id,
1900            target_args
1901        ),
1902        Err(_) => {
1903            // An error has already been emitted
1904            return;
1905        }
1906    };
1907
1908    let offload_dims = OffloadKernelDims::from_operands(bx, &args[1], &args[2]);
1909    let args = get_args_from_tuple(bx, args[3], fn_target);
1910    let target_symbol = symbol_name_for_instance_in_crate(tcx, fn_target, LOCAL_CRATE);
1911
1912    let sig = tcx.fn_sig(fn_target.def_id()).skip_binder();
1913    let sig = tcx.instantiate_bound_regions_with_erased(sig);
1914    let inputs = sig.inputs();
1915
1916    let fn_abi = cx.fn_abi_of_instance(fn_target, ty::List::empty());
1917
1918    let mut metadata = Vec::new();
1919    let mut types = Vec::new();
1920
1921    for (i, arg_abi) in fn_abi.args.iter().enumerate() {
1922        let ty = inputs[i];
1923        let decomposed = OffloadMetadata::handle_abi(cx, tcx, ty, arg_abi);
1924
1925        for (meta, entry_ty) in decomposed {
1926            metadata.push(meta);
1927            types.push(bx.cx.layout_of(entry_ty).llvm_type(bx.cx));
1928        }
1929    }
1930
1931    let offload_globals_ref = cx.offload_globals.borrow();
1932    let offload_globals = match offload_globals_ref.as_ref() {
1933        Some(globals) => globals,
1934        None => {
1935            // Offload is not initialized, cannot continue
1936            return;
1937        }
1938    };
1939    register_offload(cx);
1940    let offload_data = gen_define_handling(&cx, &metadata, target_symbol, offload_globals);
1941    gen_call_handling(bx, &offload_data, &args, &types, &metadata, offload_globals, &offload_dims);
1942}
1943
1944fn get_args_from_tuple<'ll, 'tcx>(
1945    bx: &mut Builder<'_, 'll, 'tcx>,
1946    tuple_op: OperandRef<'tcx, &'ll Value>,
1947    fn_instance: Instance<'tcx>,
1948) -> Vec<&'ll Value> {
1949    let cx = bx.cx;
1950    let fn_abi = cx.fn_abi_of_instance(fn_instance, ty::List::empty());
1951
1952    match tuple_op.val {
1953        OperandValue::Immediate(val) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [val]))vec![val],
1954        OperandValue::Pair(v1, v2) => ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
        [v1, v2]))vec![v1, v2],
1955        OperandValue::Ref(ptr) => {
1956            let tuple_place = PlaceRef { val: ptr, layout: tuple_op.layout };
1957
1958            let mut result = Vec::with_capacity(fn_abi.args.len());
1959            let mut tuple_index = 0;
1960
1961            for arg in &fn_abi.args {
1962                match arg.mode {
1963                    PassMode::Ignore => {}
1964                    PassMode::Direct(_) | PassMode::Cast { .. } => {
1965                        let field = tuple_place.project_field(bx, tuple_index);
1966                        let llvm_ty = field.layout.llvm_type(bx.cx);
1967                        let val = bx.load(llvm_ty, field.val.llval, field.val.align);
1968                        result.push(val);
1969                        tuple_index += 1;
1970                    }
1971                    PassMode::Pair(_, _) => {
1972                        let field = tuple_place.project_field(bx, tuple_index);
1973                        let llvm_ty = field.layout.llvm_type(bx.cx);
1974                        let pair_val = bx.load(llvm_ty, field.val.llval, field.val.align);
1975                        result.push(bx.extract_value(pair_val, 0));
1976                        result.push(bx.extract_value(pair_val, 1));
1977                        tuple_index += 1;
1978                    }
1979                    PassMode::Indirect { .. } => {
1980                        let field = tuple_place.project_field(bx, tuple_index);
1981                        result.push(field.val.llval);
1982                        tuple_index += 1;
1983                    }
1984                }
1985            }
1986
1987            result
1988        }
1989
1990        OperandValue::ZeroSized => ::alloc::vec::Vec::new()vec![],
1991    }
1992}
1993
1994fn generic_simd_intrinsic<'ll, 'tcx>(
1995    bx: &mut Builder<'_, 'll, 'tcx>,
1996    name: Symbol,
1997    fn_args: GenericArgsRef<'tcx>,
1998    args: &[OperandRef<'tcx, &'ll Value>],
1999    ret_ty: Ty<'tcx>,
2000    llret_ty: &'ll Type,
2001    span: Span,
2002) -> Result<&'ll Value, ()> {
2003    macro_rules! return_error {
2004        ($diag: expr) => {{
2005            bx.sess().dcx().emit_err($diag);
2006            return Err(());
2007        }};
2008    }
2009
2010    macro_rules! require {
2011        ($cond: expr, $diag: expr) => {
2012            if !$cond {
2013                return_error!($diag);
2014            }
2015        };
2016    }
2017
2018    macro_rules! require_simd {
2019        ($ty: expr, $variant:ident) => {{
2020            require!($ty.is_simd(), InvalidMonomorphization::$variant { span, name, ty: $ty });
2021            $ty.simd_size_and_type(bx.tcx())
2022        }};
2023    }
2024
2025    macro_rules! require_simd_or_scalable {
2026        ($ty: expr, $variant:ident) => {{
2027            require!(
2028                $ty.is_simd() || $ty.is_scalable_vector(),
2029                InvalidMonomorphization::$variant { span, name, ty: $ty }
2030            );
2031            if $ty.is_simd() {
2032                let (len, ty) = $ty.simd_size_and_type(bx.tcx());
2033                (len, ty, None)
2034            } else {
2035                let (count, ty, num_vecs) =
2036                    $ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
2037                (count as u64, ty, Some(num_vecs))
2038            }
2039        }};
2040    }
2041
2042    /// Returns the bitwidth of the `$ty` argument if it is an `Int` or `Uint` type.
2043    macro_rules! require_int_or_uint_ty {
2044        ($ty: expr, $diag: expr) => {
2045            match $ty {
2046                ty::Int(i) => {
2047                    i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
2048                }
2049                ty::Uint(i) => {
2050                    i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
2051                }
2052                _ => {
2053                    return_error!($diag);
2054                }
2055            }
2056        };
2057    }
2058
2059    let llvm_version = crate::llvm_util::get_version();
2060
2061    /// Converts a vector mask, where each element has a bit width equal to the data elements it is used with,
2062    /// down to an i1 based mask that can be used by llvm intrinsics.
2063    ///
2064    /// The rust simd semantics are that each element should either consist of all ones or all zeroes,
2065    /// but this information is not available to llvm. Truncating the vector effectively uses the lowest bit,
2066    /// but codegen for several targets is better if we consider the highest bit by shifting.
2067    ///
2068    /// For x86 SSE/AVX targets this is beneficial since most instructions with mask parameters only consider the highest bit.
2069    /// So even though on llvm level we have an additional shift, in the final assembly there is no shift or truncate and
2070    /// instead the mask can be used as is.
2071    ///
2072    /// For aarch64 and other targets there is a benefit because a mask from the sign bit can be more
2073    /// efficiently converted to an all ones / all zeroes mask by comparing whether each element is negative.
2074    fn vector_mask_to_bitmask<'a, 'll, 'tcx>(
2075        bx: &mut Builder<'a, 'll, 'tcx>,
2076        i_xn: &'ll Value,
2077        in_elem_bitwidth: u64,
2078        in_len: u64,
2079    ) -> &'ll Value {
2080        // Shift the MSB to the right by "in_elem_bitwidth - 1" into the first bit position.
2081        let shift_idx = bx.cx.const_int(bx.type_ix(in_elem_bitwidth), (in_elem_bitwidth - 1) as _);
2082        let shift_indices = ::alloc::vec::from_elem(shift_idx, in_len as _)vec![shift_idx; in_len as _];
2083        let i_xn_msb = bx.lshr(i_xn, bx.const_vector(shift_indices.as_slice()));
2084        // Truncate vector to an <i1 x N>
2085        bx.trunc(i_xn_msb, bx.type_vector(bx.type_i1(), in_len))
2086    }
2087
2088    // Sanity-check: all vector arguments must be immediates.
2089    if truecfg!(debug_assertions) {
2090        for arg in args {
2091            if arg.layout.ty.is_simd() {
2092                {
    match arg.val {
        OperandValue::Immediate(_) => {}
        ref left_val => {
            ::core::panicking::assert_matches_failed(left_val,
                "OperandValue::Immediate(_)", ::core::option::Option::None);
        }
    }
};assert_matches!(arg.val, OperandValue::Immediate(_));
2093            }
2094        }
2095    }
2096
2097    if name == sym::simd_select_bitmask {
2098        let (len, _) = {
    if !args[1].layout.ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdArgument {
                    span,
                    name,
                    ty: args[1].layout.ty,
                });
            return Err(());
        };
    };
    args[1].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[1].layout.ty, SimdArgument);
2099
2100        let expected_int_bits = len.max(8).next_power_of_two();
2101        let expected_bytes = len.div_ceil(8);
2102
2103        let mask_ty = args[0].layout.ty;
2104        let mask = match mask_ty.kind() {
2105            ty::Int(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
2106            ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => args[0].immediate(),
2107            ty::Array(elem, len)
2108                if #[allow(non_exhaustive_omitted_patterns)] match elem.kind() {
    ty::Uint(ty::UintTy::U8) => true,
    _ => false,
}matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
2109                    && len
2110                        .try_to_target_usize(bx.tcx)
2111                        .expect("expected monomorphic const in codegen")
2112                        == expected_bytes =>
2113            {
2114                let place = PlaceRef::alloca(bx, args[0].layout);
2115                args[0].val.store(bx, place);
2116                let int_ty = bx.type_ix(expected_bytes * 8);
2117                bx.load(int_ty, place.val.llval, Align::ONE)
2118            }
2119            _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::InvalidBitmask {
            span,
            name,
            mask_ty,
            expected_int_bits,
            expected_bytes,
        });
    return Err(());
}return_error!(InvalidMonomorphization::InvalidBitmask {
2120                span,
2121                name,
2122                mask_ty,
2123                expected_int_bits,
2124                expected_bytes
2125            }),
2126        };
2127
2128        let i1 = bx.type_i1();
2129        let im = bx.type_ix(len);
2130        let i1xn = bx.type_vector(i1, len);
2131        let m_im = bx.trunc(mask, im);
2132        let m_i1s = bx.bitcast(m_im, i1xn);
2133        return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
2134    }
2135
2136    if name == sym::simd_splat {
2137        let (out_len, out_ty) = {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2138
2139        if !(args[0].layout.ty == out_ty) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedVectorElementType {
                span,
                name,
                expected_element: out_ty,
                vector_type: ret_ty,
            });
        return Err(());
    };
};require!(
2140            args[0].layout.ty == out_ty,
2141            InvalidMonomorphization::ExpectedVectorElementType {
2142                span,
2143                name,
2144                expected_element: out_ty,
2145                vector_type: ret_ty,
2146            }
2147        );
2148
2149        // `insertelement <N x elem> poison, elem %x, i32 0`
2150        let poison_vec = bx.const_poison(llret_ty);
2151        let idx0 = bx.const_i32(0);
2152        let v0 = bx.insert_element(poison_vec, args[0].immediate(), idx0);
2153
2154        // `shufflevector <N x elem> v0, <N x elem> poison, <N x i32> zeroinitializer`
2155        // The masks is all zeros, so this splats lane 0 (which has our element in it).
2156        let mask_ty = bx.type_vector(bx.type_i32(), out_len);
2157        let splat = bx.shuffle_vector(v0, poison_vec, bx.const_null(mask_ty));
2158
2159        return Ok(splat);
2160    }
2161
2162    let supports_scalable = match name {
2163        sym::simd_cast | sym::simd_select => true,
2164        _ => false,
2165    };
2166
2167    // Every intrinsic below takes a SIMD vector as its first argument. Some intrinsics also accept
2168    // scalable vectors. `require_simd_or_scalable` is used regardless as it'll do the right thing
2169    // for non-scalable vectors, and an additional check to prohibit scalable vectors for those
2170    // intrinsics that do not support them is added.
2171    if !supports_scalable {
2172        let _ = {
    if !args[0].layout.ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdInput {
                    span,
                    name,
                    ty: args[0].layout.ty,
                });
            return Err(());
        };
    };
    args[0].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[0].layout.ty, SimdInput);
2173    }
2174    let (in_len, in_elem, in_num_vecs) = {
    if !(args[0].layout.ty.is_simd() ||
                args[0].layout.ty.is_scalable_vector()) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdInput {
                    span,
                    name,
                    ty: args[0].layout.ty,
                });
            return Err(());
        };
    };
    if args[0].layout.ty.is_simd() {
        let (len, ty) = args[0].layout.ty.simd_size_and_type(bx.tcx());
        (len, ty, None)
    } else {
        let (count, ty, num_vecs) =
            args[0].layout.ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
        (count as u64, ty, Some(num_vecs))
    }
}require_simd_or_scalable!(args[0].layout.ty, SimdInput);
2175    let in_ty = args[0].layout.ty;
2176
2177    let comparison = match name {
2178        sym::simd_eq => Some(BinOp::Eq),
2179        sym::simd_ne => Some(BinOp::Ne),
2180        sym::simd_lt => Some(BinOp::Lt),
2181        sym::simd_le => Some(BinOp::Le),
2182        sym::simd_gt => Some(BinOp::Gt),
2183        sym::simd_ge => Some(BinOp::Ge),
2184        _ => None,
2185    };
2186
2187    if let Some(cmp_op) = comparison {
2188        let (out_len, out_ty) = {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2189
2190        if !(in_len == out_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
                span,
                name,
                in_len,
                in_ty,
                ret_ty,
                out_len,
            });
        return Err(());
    };
};require!(
2191            in_len == out_len,
2192            InvalidMonomorphization::ReturnLengthInputType {
2193                span,
2194                name,
2195                in_len,
2196                in_ty,
2197                ret_ty,
2198                out_len
2199            }
2200        );
2201        if !(bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnIntegerType {
                span,
                name,
                ret_ty,
                out_ty,
            });
        return Err(());
    };
};require!(
2202            bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
2203            InvalidMonomorphization::ReturnIntegerType { span, name, ret_ty, out_ty }
2204        );
2205
2206        return Ok(compare_simd_types(
2207            bx,
2208            args[0].immediate(),
2209            args[1].immediate(),
2210            in_elem,
2211            llret_ty,
2212            cmp_op,
2213        ));
2214    }
2215
2216    if name == sym::simd_shuffle_const_generic {
2217        let idx = fn_args[2].expect_const().to_branch();
2218        let n = idx.len() as u64;
2219
2220        let (out_len, out_ty) = {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2221        if !(out_len == n) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLength {
                span,
                name,
                in_len: n,
                ret_ty,
                out_len,
            });
        return Err(());
    };
};require!(
2222            out_len == n,
2223            InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
2224        );
2225        if !(in_elem == out_ty) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnElement {
                span,
                name,
                in_elem,
                in_ty,
                ret_ty,
                out_ty,
            });
        return Err(());
    };
};require!(
2226            in_elem == out_ty,
2227            InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
2228        );
2229
2230        let total_len = in_len * 2;
2231
2232        let indices: Option<Vec<_>> = idx
2233            .iter()
2234            .enumerate()
2235            .map(|(arg_idx, val)| {
2236                let idx = val.to_leaf().to_i32();
2237                if idx >= i32::try_from(total_len).unwrap() {
2238                    bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
2239                        span,
2240                        name,
2241                        arg_idx: arg_idx as u64,
2242                        total_len: total_len.into(),
2243                    });
2244                    None
2245                } else {
2246                    Some(bx.const_i32(idx))
2247                }
2248            })
2249            .collect();
2250        let Some(indices) = indices else {
2251            return Ok(bx.const_null(llret_ty));
2252        };
2253
2254        return Ok(bx.shuffle_vector(
2255            args[0].immediate(),
2256            args[1].immediate(),
2257            bx.const_vector(&indices),
2258        ));
2259    }
2260
2261    if name == sym::simd_shuffle {
2262        // Make sure this is actually a SIMD vector.
2263        let idx_ty = args[2].layout.ty;
2264        let n: u64 = if idx_ty.is_simd()
2265            && #[allow(non_exhaustive_omitted_patterns)] match idx_ty.simd_size_and_type(bx.cx.tcx).1.kind()
    {
    ty::Uint(ty::UintTy::U32) => true,
    _ => false,
}matches!(idx_ty.simd_size_and_type(bx.cx.tcx).1.kind(), ty::Uint(ty::UintTy::U32))
2266        {
2267            idx_ty.simd_size_and_type(bx.cx.tcx).0
2268        } else {
2269            {
    bx.sess().dcx().emit_err(InvalidMonomorphization::SimdShuffle {
            span,
            name,
            ty: idx_ty,
        });
    return Err(());
}return_error!(InvalidMonomorphization::SimdShuffle { span, name, ty: idx_ty })
2270        };
2271
2272        let (out_len, out_ty) = {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
2273        if !(out_len == n) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLength {
                span,
                name,
                in_len: n,
                ret_ty,
                out_len,
            });
        return Err(());
    };
};require!(
2274            out_len == n,
2275            InvalidMonomorphization::ReturnLength { span, name, in_len: n, ret_ty, out_len }
2276        );
2277        if !(in_elem == out_ty) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnElement {
                span,
                name,
                in_elem,
                in_ty,
                ret_ty,
                out_ty,
            });
        return Err(());
    };
};require!(
2278            in_elem == out_ty,
2279            InvalidMonomorphization::ReturnElement { span, name, in_elem, in_ty, ret_ty, out_ty }
2280        );
2281
2282        let total_len = u128::from(in_len) * 2;
2283
2284        // Check that the indices are in-bounds.
2285        let indices = args[2].immediate();
2286        for i in 0..n {
2287            let val = bx.const_get_elt(indices, i as u64);
2288            let idx = bx
2289                .const_to_opt_u128(val, true)
2290                .unwrap_or_else(|| ::rustc_middle::util::bug::bug_fmt(format_args!("typeck should have already ensured that these are const"))bug!("typeck should have already ensured that these are const"));
2291            if idx >= total_len {
2292                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
            span,
            name,
            arg_idx: i,
            total_len,
        });
    return Err(());
};return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
2293                    span,
2294                    name,
2295                    arg_idx: i,
2296                    total_len,
2297                });
2298            }
2299        }
2300
2301        return Ok(bx.shuffle_vector(args[0].immediate(), args[1].immediate(), indices));
2302    }
2303
2304    if name == sym::simd_insert || name == sym::simd_insert_dyn {
2305        if !(in_elem == args[2].layout.ty) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::InsertedType {
                span,
                name,
                in_elem,
                in_ty,
                out_ty: args[2].layout.ty,
            });
        return Err(());
    };
};require!(
2306            in_elem == args[2].layout.ty,
2307            InvalidMonomorphization::InsertedType {
2308                span,
2309                name,
2310                in_elem,
2311                in_ty,
2312                out_ty: args[2].layout.ty
2313            }
2314        );
2315
2316        let index_imm = if name == sym::simd_insert {
2317            let idx = bx
2318                .const_to_opt_u128(args[1].immediate(), false)
2319                .expect("typeck should have ensure that this is a const");
2320            if idx >= in_len.into() {
2321                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
            span,
            name,
            arg_idx: 1,
            total_len: in_len.into(),
        });
    return Err(());
};return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
2322                    span,
2323                    name,
2324                    arg_idx: 1,
2325                    total_len: in_len.into(),
2326                });
2327            }
2328            bx.const_i32(idx as i32)
2329        } else {
2330            args[1].immediate()
2331        };
2332
2333        return Ok(bx.insert_element(args[0].immediate(), args[2].immediate(), index_imm));
2334    }
2335    if name == sym::simd_extract || name == sym::simd_extract_dyn {
2336        if !(ret_ty == in_elem) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                span,
                name,
                in_elem,
                in_ty,
                ret_ty,
            });
        return Err(());
    };
};require!(
2337            ret_ty == in_elem,
2338            InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
2339        );
2340        let index_imm = if name == sym::simd_extract {
2341            let idx = bx
2342                .const_to_opt_u128(args[1].immediate(), false)
2343                .expect("typeck should have ensure that this is a const");
2344            if idx >= in_len.into() {
2345                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::SimdIndexOutOfBounds {
            span,
            name,
            arg_idx: 1,
            total_len: in_len.into(),
        });
    return Err(());
};return_error!(InvalidMonomorphization::SimdIndexOutOfBounds {
2346                    span,
2347                    name,
2348                    arg_idx: 1,
2349                    total_len: in_len.into(),
2350                });
2351            }
2352            bx.const_i32(idx as i32)
2353        } else {
2354            args[1].immediate()
2355        };
2356
2357        return Ok(bx.extract_element(args[0].immediate(), index_imm));
2358    }
2359
2360    if name == sym::simd_select {
2361        let m_elem_ty = in_elem;
2362        let m_len = in_len;
2363        let (v_len, _, _) = {
    if !(args[1].layout.ty.is_simd() ||
                args[1].layout.ty.is_scalable_vector()) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdArgument {
                    span,
                    name,
                    ty: args[1].layout.ty,
                });
            return Err(());
        };
    };
    if args[1].layout.ty.is_simd() {
        let (len, ty) = args[1].layout.ty.simd_size_and_type(bx.tcx());
        (len, ty, None)
    } else {
        let (count, ty, num_vecs) =
            args[1].layout.ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
        (count as u64, ty, Some(num_vecs))
    }
}require_simd_or_scalable!(args[1].layout.ty, SimdArgument);
2364        if !(m_len == v_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::MismatchedLengths {
                span,
                name,
                m_len,
                v_len,
            });
        return Err(());
    };
};require!(
2365            m_len == v_len,
2366            InvalidMonomorphization::MismatchedLengths { span, name, m_len, v_len }
2367        );
2368
2369        let m_i1s = if args[1].layout.ty.is_scalable_vector() {
2370            match m_elem_ty.kind() {
2371                ty::Bool => {}
2372                _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
            span,
            name,
            ty: m_elem_ty,
        });
    return Err(());
}return_error!(InvalidMonomorphization::MaskWrongElementType {
2373                    span,
2374                    name,
2375                    ty: m_elem_ty
2376                }),
2377            };
2378            let i1 = bx.type_i1();
2379            let i1xn = bx.type_scalable_vector(i1, m_len as u64);
2380            bx.trunc(args[0].immediate(), i1xn)
2381        } else {
2382            let in_elem_bitwidth = match m_elem_ty.kind() {
    ty::Int(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    ty::Uint(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    _ => {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
                    span,
                    name,
                    ty: m_elem_ty,
                });
            return Err(());
        };
    }
}require_int_or_uint_ty!(
2383                m_elem_ty.kind(),
2384                InvalidMonomorphization::MaskWrongElementType { span, name, ty: m_elem_ty }
2385            );
2386            vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, m_len)
2387        };
2388
2389        return Ok(bx.select(m_i1s, args[1].immediate(), args[2].immediate()));
2390    }
2391
2392    if name == sym::simd_bitmask {
2393        // The `fn simd_bitmask(vector) -> unsigned integer` intrinsic takes a vector mask and
2394        // returns one bit for each lane (which must all be `0` or `!0`) in the form of either:
2395        // * an unsigned integer
2396        // * an array of `u8`
2397        // If the vector has less than 8 lanes, a u8 is returned with zeroed trailing bits.
2398        //
2399        // The bit order of the result depends on the byte endianness, LSB-first for little
2400        // endian and MSB-first for big endian.
2401        let expected_int_bits = in_len.max(8).next_power_of_two();
2402        let expected_bytes = in_len.div_ceil(8);
2403
2404        // Integer vector <i{in_bitwidth} x in_len>:
2405        let in_elem_bitwidth = match in_elem.kind() {
    ty::Int(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    ty::Uint(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    _ => {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
                    span,
                    name,
                    ty: in_elem,
                });
            return Err(());
        };
    }
}require_int_or_uint_ty!(
2406            in_elem.kind(),
2407            InvalidMonomorphization::MaskWrongElementType { span, name, ty: in_elem }
2408        );
2409
2410        let i1xn = vector_mask_to_bitmask(bx, args[0].immediate(), in_elem_bitwidth, in_len);
2411        // Bitcast <i1 x N> to iN:
2412        let i_ = bx.bitcast(i1xn, bx.type_ix(in_len));
2413
2414        match ret_ty.kind() {
2415            ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => {
2416                // Zero-extend iN to the bitmask type:
2417                return Ok(bx.zext(i_, bx.type_ix(expected_int_bits)));
2418            }
2419            ty::Array(elem, len)
2420                if #[allow(non_exhaustive_omitted_patterns)] match elem.kind() {
    ty::Uint(ty::UintTy::U8) => true,
    _ => false,
}matches!(elem.kind(), ty::Uint(ty::UintTy::U8))
2421                    && len
2422                        .try_to_target_usize(bx.tcx)
2423                        .expect("expected monomorphic const in codegen")
2424                        == expected_bytes =>
2425            {
2426                // Zero-extend iN to the array length:
2427                let ze = bx.zext(i_, bx.type_ix(expected_bytes * 8));
2428
2429                // Convert the integer to a byte array
2430                let ptr = bx.alloca(Size::from_bytes(expected_bytes), Align::ONE);
2431                bx.store(ze, ptr, Align::ONE);
2432                let array_ty = bx.type_array(bx.type_i8(), expected_bytes);
2433                return Ok(bx.load(array_ty, ptr, Align::ONE));
2434            }
2435            _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::CannotReturn {
            span,
            name,
            ret_ty,
            expected_int_bits,
            expected_bytes,
        });
    return Err(());
}return_error!(InvalidMonomorphization::CannotReturn {
2436                span,
2437                name,
2438                ret_ty,
2439                expected_int_bits,
2440                expected_bytes
2441            }),
2442        }
2443    }
2444
2445    fn simd_simple_float_intrinsic<'ll, 'tcx>(
2446        name: Symbol,
2447        in_elem: Ty<'_>,
2448        in_ty: Ty<'_>,
2449        in_len: u64,
2450        bx: &mut Builder<'_, 'll, 'tcx>,
2451        span: Span,
2452        args: &[OperandRef<'tcx, &'ll Value>],
2453    ) -> Result<&'ll Value, ()> {
2454        macro_rules! return_error {
2455            ($diag: expr) => {{
2456                bx.sess().dcx().emit_err($diag);
2457                return Err(());
2458            }};
2459        }
2460
2461        let ty::Float(f) = in_elem.kind() else {
2462            {
    bx.sess().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
            span,
            name,
            ty: in_ty,
        });
    return Err(());
};return_error!(InvalidMonomorphization::BasicFloatType { span, name, ty: in_ty });
2463        };
2464        let elem_ty = bx.cx.type_float_from_ty(*f);
2465
2466        let vec_ty = bx.type_vector(elem_ty, in_len);
2467
2468        let intr_name = match name {
2469            sym::simd_ceil => "llvm.ceil",
2470            sym::simd_fabs => "llvm.fabs",
2471            sym::simd_fcos => "llvm.cos",
2472            sym::simd_fexp2 => "llvm.exp2",
2473            sym::simd_fexp => "llvm.exp",
2474            sym::simd_flog10 => "llvm.log10",
2475            sym::simd_flog2 => "llvm.log2",
2476            sym::simd_flog => "llvm.log",
2477            sym::simd_floor => "llvm.floor",
2478            sym::simd_fma => "llvm.fma",
2479            sym::simd_relaxed_fma => "llvm.fmuladd",
2480            sym::simd_fsin => "llvm.sin",
2481            sym::simd_fsqrt => "llvm.sqrt",
2482            sym::simd_round => "llvm.round",
2483            sym::simd_round_ties_even => "llvm.rint",
2484            sym::simd_trunc => "llvm.trunc",
2485            _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::UnrecognizedIntrinsic {
            span,
            name,
        });
    return Err(());
}return_error!(InvalidMonomorphization::UnrecognizedIntrinsic { span, name }),
2486        };
2487        Ok(bx.call_intrinsic(
2488            intr_name,
2489            &[vec_ty],
2490            &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
2491        ))
2492    }
2493
2494    if #[allow(non_exhaustive_omitted_patterns)] match name {
    sym::simd_ceil | sym::simd_fabs | sym::simd_fcos | sym::simd_fexp2 |
        sym::simd_fexp | sym::simd_flog10 | sym::simd_flog2 | sym::simd_flog |
        sym::simd_floor | sym::simd_fma | sym::simd_fsin | sym::simd_fsqrt |
        sym::simd_relaxed_fma | sym::simd_round | sym::simd_round_ties_even |
        sym::simd_trunc => true,
    _ => false,
}std::matches!(
2495        name,
2496        sym::simd_ceil
2497            | sym::simd_fabs
2498            | sym::simd_fcos
2499            | sym::simd_fexp2
2500            | sym::simd_fexp
2501            | sym::simd_flog10
2502            | sym::simd_flog2
2503            | sym::simd_flog
2504            | sym::simd_floor
2505            | sym::simd_fma
2506            | sym::simd_fsin
2507            | sym::simd_fsqrt
2508            | sym::simd_relaxed_fma
2509            | sym::simd_round
2510            | sym::simd_round_ties_even
2511            | sym::simd_trunc
2512    ) {
2513        return simd_simple_float_intrinsic(name, in_elem, in_ty, in_len, bx, span, args);
2514    }
2515
2516    fn llvm_vector_ty<'ll>(cx: &CodegenCx<'ll, '_>, elem_ty: Ty<'_>, vec_len: u64) -> &'ll Type {
2517        let elem_ty = match *elem_ty.kind() {
2518            ty::Int(v) => cx.type_int_from_ty(v),
2519            ty::Uint(v) => cx.type_uint_from_ty(v),
2520            ty::Float(v) => cx.type_float_from_ty(v),
2521            ty::RawPtr(_, _) => cx.type_ptr(),
2522            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
2523        };
2524        cx.type_vector(elem_ty, vec_len)
2525    }
2526
2527    if name == sym::simd_gather {
2528        // simd_gather(values: <N x T>, pointers: <N x *_ T>,
2529        //             mask: <N x i{M}>) -> <N x T>
2530        // * N: number of elements in the input vectors
2531        // * T: type of the element to load
2532        // * M: any integer width is supported, will be truncated to i1
2533
2534        // All types must be simd vector types
2535
2536        // The second argument must be a simd vector with an element type that's a pointer
2537        // to the element type of the first argument
2538        let (_, element_ty0) = {
    if !in_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdFirst {
                    span,
                    name,
                    ty: in_ty,
                });
            return Err(());
        };
    };
    in_ty.simd_size_and_type(bx.tcx())
}require_simd!(in_ty, SimdFirst);
2539        let (out_len, element_ty1) = {
    if !args[1].layout.ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdSecond {
                    span,
                    name,
                    ty: args[1].layout.ty,
                });
            return Err(());
        };
    };
    args[1].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[1].layout.ty, SimdSecond);
2540        // The element type of the third argument must be a signed integer type of any width:
2541        let (out_len2, element_ty2) = {
    if !args[2].layout.ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
                    span,
                    name,
                    ty: args[2].layout.ty,
                });
            return Err(());
        };
    };
    args[2].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[2].layout.ty, SimdThird);
2542        {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
};require_simd!(ret_ty, SimdReturn);
2543
2544        // Of the same length:
2545        if !(in_len == out_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::SecondArgumentLength {
                span,
                name,
                in_len,
                in_ty,
                arg_ty: args[1].layout.ty,
                out_len,
            });
        return Err(());
    };
};require!(
2546            in_len == out_len,
2547            InvalidMonomorphization::SecondArgumentLength {
2548                span,
2549                name,
2550                in_len,
2551                in_ty,
2552                arg_ty: args[1].layout.ty,
2553                out_len
2554            }
2555        );
2556        if !(in_len == out_len2) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
                span,
                name,
                in_len,
                in_ty,
                arg_ty: args[2].layout.ty,
                out_len: out_len2,
            });
        return Err(());
    };
};require!(
2557            in_len == out_len2,
2558            InvalidMonomorphization::ThirdArgumentLength {
2559                span,
2560                name,
2561                in_len,
2562                in_ty,
2563                arg_ty: args[2].layout.ty,
2564                out_len: out_len2
2565            }
2566        );
2567
2568        // The return type must match the first argument type
2569        if !(ret_ty == in_ty) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedReturnType {
                span,
                name,
                in_ty,
                ret_ty,
            });
        return Err(());
    };
};require!(
2570            ret_ty == in_ty,
2571            InvalidMonomorphization::ExpectedReturnType { span, name, in_ty, ret_ty }
2572        );
2573
2574        if !#[allow(non_exhaustive_omitted_patterns)] match *element_ty1.kind() {
            ty::RawPtr(p_ty, _) if
                p_ty == in_elem && p_ty.kind() == element_ty0.kind() => true,
            _ => false,
        } {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
                span,
                name,
                expected_element: element_ty1,
                second_arg: args[1].layout.ty,
                in_elem,
                in_ty,
                mutability: ExpectedPointerMutability::Not,
            });
        return Err(());
    };
};require!(
2575            matches!(
2576                *element_ty1.kind(),
2577                ty::RawPtr(p_ty, _) if p_ty == in_elem && p_ty.kind() == element_ty0.kind()
2578            ),
2579            InvalidMonomorphization::ExpectedElementType {
2580                span,
2581                name,
2582                expected_element: element_ty1,
2583                second_arg: args[1].layout.ty,
2584                in_elem,
2585                in_ty,
2586                mutability: ExpectedPointerMutability::Not,
2587            }
2588        );
2589
2590        let mask_elem_bitwidth = match element_ty2.kind() {
    ty::Int(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    ty::Uint(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    _ => {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
                    span,
                    name,
                    ty: element_ty2,
                });
            return Err(());
        };
    }
}require_int_or_uint_ty!(
2591            element_ty2.kind(),
2592            InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
2593        );
2594
2595        // Alignment of T, must be a constant integer value:
2596        let alignment = bx.align_of(in_elem).bytes();
2597
2598        // Truncate the mask vector to a vector of i1s:
2599        let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
2600
2601        // Type of the vector of pointers:
2602        let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
2603
2604        // Type of the vector of elements:
2605        let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
2606
2607        let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2608            let alignment = bx.const_i32(alignment as i32);
2609            &[args[1].immediate(), alignment, mask, args[0].immediate()]
2610        } else {
2611            &[args[1].immediate(), mask, args[0].immediate()]
2612        };
2613
2614        let call =
2615            bx.call_intrinsic("llvm.masked.gather", &[llvm_elem_vec_ty, llvm_pointer_vec_ty], args);
2616        if llvm_version >= (22, 0, 0) {
2617            crate::attributes::apply_to_callsite(
2618                call,
2619                crate::llvm::AttributePlace::Argument(0),
2620                &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2621            )
2622        }
2623        return Ok(call);
2624    }
2625
2626    fn llvm_alignment<'ll, 'tcx>(
2627        bx: &mut Builder<'_, 'll, 'tcx>,
2628        alignment: SimdAlign,
2629        vector_ty: Ty<'tcx>,
2630        element_ty: Ty<'tcx>,
2631    ) -> u64 {
2632        match alignment {
2633            SimdAlign::Unaligned => 1,
2634            SimdAlign::Element => bx.align_of(element_ty).bytes(),
2635            SimdAlign::Vector => bx.align_of(vector_ty).bytes(),
2636        }
2637    }
2638
2639    if name == sym::simd_masked_load {
2640        // simd_masked_load<_, _, _, const ALIGN: SimdAlign>(mask: <N x i{M}>, pointer: *_ T, values: <N x T>) -> <N x T>
2641        // * N: number of elements in the input vectors
2642        // * T: type of the element to load
2643        // * M: any integer width is supported, will be truncated to i1
2644        // Loads contiguous elements from memory behind `pointer`, but only for
2645        // those lanes whose `mask` bit is enabled.
2646        // The memory addresses corresponding to the “off” lanes are not accessed.
2647
2648        let alignment = fn_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment();
2649
2650        // The element type of the "mask" argument must be a signed integer type of any width
2651        let mask_ty = in_ty;
2652        let (mask_len, mask_elem) = (in_len, in_elem);
2653
2654        // The second argument must be a pointer matching the element type
2655        let pointer_ty = args[1].layout.ty;
2656
2657        // The last argument is a passthrough vector providing values for disabled lanes
2658        let values_ty = args[2].layout.ty;
2659        let (values_len, values_elem) = {
    if !values_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
                    span,
                    name,
                    ty: values_ty,
                });
            return Err(());
        };
    };
    values_ty.simd_size_and_type(bx.tcx())
}require_simd!(values_ty, SimdThird);
2660
2661        {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
};require_simd!(ret_ty, SimdReturn);
2662
2663        // Of the same length:
2664        if !(values_len == mask_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
                span,
                name,
                in_len: mask_len,
                in_ty: mask_ty,
                arg_ty: values_ty,
                out_len: values_len,
            });
        return Err(());
    };
};require!(
2665            values_len == mask_len,
2666            InvalidMonomorphization::ThirdArgumentLength {
2667                span,
2668                name,
2669                in_len: mask_len,
2670                in_ty: mask_ty,
2671                arg_ty: values_ty,
2672                out_len: values_len
2673            }
2674        );
2675
2676        // The return type must match the last argument type
2677        if !(ret_ty == values_ty) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedReturnType {
                span,
                name,
                in_ty: values_ty,
                ret_ty,
            });
        return Err(());
    };
};require!(
2678            ret_ty == values_ty,
2679            InvalidMonomorphization::ExpectedReturnType { span, name, in_ty: values_ty, ret_ty }
2680        );
2681
2682        if !#[allow(non_exhaustive_omitted_patterns)] match *pointer_ty.kind() {
            ty::RawPtr(p_ty, _) if
                p_ty == values_elem && p_ty.kind() == values_elem.kind() =>
                true,
            _ => false,
        } {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
                span,
                name,
                expected_element: values_elem,
                second_arg: pointer_ty,
                in_elem: values_elem,
                in_ty: values_ty,
                mutability: ExpectedPointerMutability::Not,
            });
        return Err(());
    };
};require!(
2683            matches!(
2684                *pointer_ty.kind(),
2685                ty::RawPtr(p_ty, _) if p_ty == values_elem && p_ty.kind() == values_elem.kind()
2686            ),
2687            InvalidMonomorphization::ExpectedElementType {
2688                span,
2689                name,
2690                expected_element: values_elem,
2691                second_arg: pointer_ty,
2692                in_elem: values_elem,
2693                in_ty: values_ty,
2694                mutability: ExpectedPointerMutability::Not,
2695            }
2696        );
2697
2698        let m_elem_bitwidth = match mask_elem.kind() {
    ty::Int(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    ty::Uint(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    _ => {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
                    span,
                    name,
                    ty: mask_elem,
                });
            return Err(());
        };
    }
}require_int_or_uint_ty!(
2699            mask_elem.kind(),
2700            InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
2701        );
2702
2703        let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
2704
2705        // Alignment of T, must be a constant integer value:
2706        let alignment = llvm_alignment(bx, alignment, values_ty, values_elem);
2707
2708        let llvm_pointer = bx.type_ptr();
2709
2710        // Type of the vector of elements:
2711        let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
2712
2713        let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2714            let alignment = bx.const_i32(alignment as i32);
2715
2716            &[args[1].immediate(), alignment, mask, args[2].immediate()]
2717        } else {
2718            &[args[1].immediate(), mask, args[2].immediate()]
2719        };
2720
2721        let call = bx.call_intrinsic("llvm.masked.load", &[llvm_elem_vec_ty, llvm_pointer], args);
2722        if llvm_version >= (22, 0, 0) {
2723            crate::attributes::apply_to_callsite(
2724                call,
2725                crate::llvm::AttributePlace::Argument(0),
2726                &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2727            )
2728        }
2729        return Ok(call);
2730    }
2731
2732    if name == sym::simd_masked_store {
2733        // simd_masked_store<_, _, _, const ALIGN: SimdAlign>(mask: <N x i{M}>, pointer: *mut T, values: <N x T>) -> ()
2734        // * N: number of elements in the input vectors
2735        // * T: type of the element to load
2736        // * M: any integer width is supported, will be truncated to i1
2737        // Stores contiguous elements to memory behind `pointer`, but only for
2738        // those lanes whose `mask` bit is enabled.
2739        // The memory addresses corresponding to the “off” lanes are not accessed.
2740
2741        let alignment = fn_args[3].expect_const().to_branch()[0].to_leaf().to_simd_alignment();
2742
2743        // The element type of the "mask" argument must be a signed integer type of any width
2744        let mask_ty = in_ty;
2745        let (mask_len, mask_elem) = (in_len, in_elem);
2746
2747        // The second argument must be a pointer matching the element type
2748        let pointer_ty = args[1].layout.ty;
2749
2750        // The last argument specifies the values to store to memory
2751        let values_ty = args[2].layout.ty;
2752        let (values_len, values_elem) = {
    if !values_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
                    span,
                    name,
                    ty: values_ty,
                });
            return Err(());
        };
    };
    values_ty.simd_size_and_type(bx.tcx())
}require_simd!(values_ty, SimdThird);
2753
2754        // Of the same length:
2755        if !(values_len == mask_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
                span,
                name,
                in_len: mask_len,
                in_ty: mask_ty,
                arg_ty: values_ty,
                out_len: values_len,
            });
        return Err(());
    };
};require!(
2756            values_len == mask_len,
2757            InvalidMonomorphization::ThirdArgumentLength {
2758                span,
2759                name,
2760                in_len: mask_len,
2761                in_ty: mask_ty,
2762                arg_ty: values_ty,
2763                out_len: values_len
2764            }
2765        );
2766
2767        // The second argument must be a mutable pointer type matching the element type
2768        if !#[allow(non_exhaustive_omitted_patterns)] match *pointer_ty.kind() {
            ty::RawPtr(p_ty, p_mutbl) if
                p_ty == values_elem && p_ty.kind() == values_elem.kind() &&
                    p_mutbl.is_mut() => true,
            _ => false,
        } {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
                span,
                name,
                expected_element: values_elem,
                second_arg: pointer_ty,
                in_elem: values_elem,
                in_ty: values_ty,
                mutability: ExpectedPointerMutability::Mut,
            });
        return Err(());
    };
};require!(
2769            matches!(
2770                *pointer_ty.kind(),
2771                ty::RawPtr(p_ty, p_mutbl)
2772                    if p_ty == values_elem && p_ty.kind() == values_elem.kind() && p_mutbl.is_mut()
2773            ),
2774            InvalidMonomorphization::ExpectedElementType {
2775                span,
2776                name,
2777                expected_element: values_elem,
2778                second_arg: pointer_ty,
2779                in_elem: values_elem,
2780                in_ty: values_ty,
2781                mutability: ExpectedPointerMutability::Mut,
2782            }
2783        );
2784
2785        let m_elem_bitwidth = match mask_elem.kind() {
    ty::Int(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    ty::Uint(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    _ => {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
                    span,
                    name,
                    ty: mask_elem,
                });
            return Err(());
        };
    }
}require_int_or_uint_ty!(
2786            mask_elem.kind(),
2787            InvalidMonomorphization::MaskWrongElementType { span, name, ty: mask_elem }
2788        );
2789
2790        let mask = vector_mask_to_bitmask(bx, args[0].immediate(), m_elem_bitwidth, mask_len);
2791
2792        // Alignment of T, must be a constant integer value:
2793        let alignment = llvm_alignment(bx, alignment, values_ty, values_elem);
2794
2795        let llvm_pointer = bx.type_ptr();
2796
2797        // Type of the vector of elements:
2798        let llvm_elem_vec_ty = llvm_vector_ty(bx, values_elem, values_len);
2799
2800        let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2801            let alignment = bx.const_i32(alignment as i32);
2802            &[args[2].immediate(), args[1].immediate(), alignment, mask]
2803        } else {
2804            &[args[2].immediate(), args[1].immediate(), mask]
2805        };
2806
2807        let call = bx.call_intrinsic("llvm.masked.store", &[llvm_elem_vec_ty, llvm_pointer], args);
2808        if llvm_version >= (22, 0, 0) {
2809            crate::attributes::apply_to_callsite(
2810                call,
2811                crate::llvm::AttributePlace::Argument(1),
2812                &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2813            )
2814        }
2815        return Ok(call);
2816    }
2817
2818    if name == sym::simd_scatter {
2819        // simd_scatter(values: <N x T>, pointers: <N x *mut T>,
2820        //             mask: <N x i{M}>) -> ()
2821        // * N: number of elements in the input vectors
2822        // * T: type of the element to load
2823        // * M: any integer width is supported, will be truncated to i1
2824
2825        // All types must be simd vector types
2826        // The second argument must be a simd vector with an element type that's a pointer
2827        // to the element type of the first argument
2828        let (_, element_ty0) = {
    if !in_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdFirst {
                    span,
                    name,
                    ty: in_ty,
                });
            return Err(());
        };
    };
    in_ty.simd_size_and_type(bx.tcx())
}require_simd!(in_ty, SimdFirst);
2829        let (element_len1, element_ty1) = {
    if !args[1].layout.ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdSecond {
                    span,
                    name,
                    ty: args[1].layout.ty,
                });
            return Err(());
        };
    };
    args[1].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[1].layout.ty, SimdSecond);
2830        let (element_len2, element_ty2) = {
    if !args[2].layout.ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdThird {
                    span,
                    name,
                    ty: args[2].layout.ty,
                });
            return Err(());
        };
    };
    args[2].layout.ty.simd_size_and_type(bx.tcx())
}require_simd!(args[2].layout.ty, SimdThird);
2831
2832        // Of the same length:
2833        if !(in_len == element_len1) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::SecondArgumentLength {
                span,
                name,
                in_len,
                in_ty,
                arg_ty: args[1].layout.ty,
                out_len: element_len1,
            });
        return Err(());
    };
};require!(
2834            in_len == element_len1,
2835            InvalidMonomorphization::SecondArgumentLength {
2836                span,
2837                name,
2838                in_len,
2839                in_ty,
2840                arg_ty: args[1].layout.ty,
2841                out_len: element_len1
2842            }
2843        );
2844        if !(in_len == element_len2) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ThirdArgumentLength {
                span,
                name,
                in_len,
                in_ty,
                arg_ty: args[2].layout.ty,
                out_len: element_len2,
            });
        return Err(());
    };
};require!(
2845            in_len == element_len2,
2846            InvalidMonomorphization::ThirdArgumentLength {
2847                span,
2848                name,
2849                in_len,
2850                in_ty,
2851                arg_ty: args[2].layout.ty,
2852                out_len: element_len2
2853            }
2854        );
2855
2856        if !#[allow(non_exhaustive_omitted_patterns)] match *element_ty1.kind() {
            ty::RawPtr(p_ty, p_mutbl) if
                p_ty == in_elem && p_mutbl.is_mut() &&
                    p_ty.kind() == element_ty0.kind() => true,
            _ => false,
        } {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedElementType {
                span,
                name,
                expected_element: element_ty1,
                second_arg: args[1].layout.ty,
                in_elem,
                in_ty,
                mutability: ExpectedPointerMutability::Mut,
            });
        return Err(());
    };
};require!(
2857            matches!(
2858                *element_ty1.kind(),
2859                ty::RawPtr(p_ty, p_mutbl)
2860                    if p_ty == in_elem && p_mutbl.is_mut() && p_ty.kind() == element_ty0.kind()
2861            ),
2862            InvalidMonomorphization::ExpectedElementType {
2863                span,
2864                name,
2865                expected_element: element_ty1,
2866                second_arg: args[1].layout.ty,
2867                in_elem,
2868                in_ty,
2869                mutability: ExpectedPointerMutability::Mut,
2870            }
2871        );
2872
2873        // The element type of the third argument must be an integer type of any width:
2874        let mask_elem_bitwidth = match element_ty2.kind() {
    ty::Int(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    ty::Uint(i) => {
        i.bit_width().unwrap_or_else(||
                bx.data_layout().pointer_size().bits())
    }
    _ => {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::MaskWrongElementType {
                    span,
                    name,
                    ty: element_ty2,
                });
            return Err(());
        };
    }
}require_int_or_uint_ty!(
2875            element_ty2.kind(),
2876            InvalidMonomorphization::MaskWrongElementType { span, name, ty: element_ty2 }
2877        );
2878
2879        // Alignment of T, must be a constant integer value:
2880        let alignment = bx.align_of(in_elem).bytes();
2881
2882        // Truncate the mask vector to a vector of i1s:
2883        let mask = vector_mask_to_bitmask(bx, args[2].immediate(), mask_elem_bitwidth, in_len);
2884
2885        // Type of the vector of pointers:
2886        let llvm_pointer_vec_ty = llvm_vector_ty(bx, element_ty1, in_len);
2887
2888        // Type of the vector of elements:
2889        let llvm_elem_vec_ty = llvm_vector_ty(bx, element_ty0, in_len);
2890        let args: &[&'ll Value] = if llvm_version < (22, 0, 0) {
2891            let alignment = bx.const_i32(alignment as i32);
2892            &[args[0].immediate(), args[1].immediate(), alignment, mask]
2893        } else {
2894            &[args[0].immediate(), args[1].immediate(), mask]
2895        };
2896        let call = bx.call_intrinsic(
2897            "llvm.masked.scatter",
2898            &[llvm_elem_vec_ty, llvm_pointer_vec_ty],
2899            args,
2900        );
2901        if llvm_version >= (22, 0, 0) {
2902            crate::attributes::apply_to_callsite(
2903                call,
2904                crate::llvm::AttributePlace::Argument(1),
2905                &[crate::llvm::CreateAlignmentAttr(bx.llcx, alignment)],
2906            )
2907        }
2908        return Ok(call);
2909    }
2910
2911    macro_rules! arith_red {
2912        ($name:ident : $integer_reduce:ident, $float_reduce:ident, $ordered:expr, $op:ident,
2913         $identity:expr) => {
2914            if name == sym::$name {
2915                require!(
2916                    ret_ty == in_elem,
2917                    InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
2918                );
2919                return match in_elem.kind() {
2920                    ty::Int(_) | ty::Uint(_) => {
2921                        let r = bx.$integer_reduce(args[0].immediate());
2922                        if $ordered {
2923                            // if overflow occurs, the result is the
2924                            // mathematical result modulo 2^n:
2925                            Ok(bx.$op(args[1].immediate(), r))
2926                        } else {
2927                            Ok(bx.$integer_reduce(args[0].immediate()))
2928                        }
2929                    }
2930                    ty::Float(f) => {
2931                        let acc = if $ordered {
2932                            // ordered arithmetic reductions take an accumulator
2933                            args[1].immediate()
2934                        } else {
2935                            // unordered arithmetic reductions use the identity accumulator
2936                            match f.bit_width() {
2937                                32 => bx.const_real(bx.type_f32(), $identity),
2938                                64 => bx.const_real(bx.type_f64(), $identity),
2939                                v => return_error!(
2940                                    InvalidMonomorphization::UnsupportedSymbolOfSize {
2941                                        span,
2942                                        name,
2943                                        symbol: sym::$name,
2944                                        in_ty,
2945                                        in_elem,
2946                                        size: v,
2947                                        ret_ty
2948                                    }
2949                                ),
2950                            }
2951                        };
2952                        Ok(bx.$float_reduce(acc, args[0].immediate()))
2953                    }
2954                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
2955                        span,
2956                        name,
2957                        symbol: sym::$name,
2958                        in_ty,
2959                        in_elem,
2960                        ret_ty
2961                    }),
2962                };
2963            }
2964        };
2965    }
2966
2967    if name == sym::simd_reduce_add_ordered {
    if !(ret_ty == in_elem) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                    span,
                    name,
                    in_elem,
                    in_ty,
                    ret_ty,
                });
            return Err(());
        };
    };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_add(args[0].immediate());
                if true {
                    Ok(bx.add(args[1].immediate(), r))
                } else { Ok(bx.vector_reduce_add(args[0].immediate())) }
            }
            ty::Float(f) => {
                let acc =
                    if true {
                        args[1].immediate()
                    } else {
                        match f.bit_width() {
                            32 => bx.const_real(bx.type_f32(), -0.0),
                            64 => bx.const_real(bx.type_f64(), -0.0),
                            v => {
                                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
                                        span,
                                        name,
                                        symbol: sym::simd_reduce_add_ordered,
                                        in_ty,
                                        in_elem,
                                        size: v,
                                        ret_ty,
                                    });
                                return Err(());
                            }
                        }
                    };
                Ok(bx.vector_reduce_fadd(acc, args[0].immediate()))
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_add_ordered,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};arith_red!(simd_reduce_add_ordered: vector_reduce_add, vector_reduce_fadd, true, add, -0.0);
2968    if name == sym::simd_reduce_mul_ordered {
    if !(ret_ty == in_elem) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                    span,
                    name,
                    in_elem,
                    in_ty,
                    ret_ty,
                });
            return Err(());
        };
    };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_mul(args[0].immediate());
                if true {
                    Ok(bx.mul(args[1].immediate(), r))
                } else { Ok(bx.vector_reduce_mul(args[0].immediate())) }
            }
            ty::Float(f) => {
                let acc =
                    if true {
                        args[1].immediate()
                    } else {
                        match f.bit_width() {
                            32 => bx.const_real(bx.type_f32(), 1.0),
                            64 => bx.const_real(bx.type_f64(), 1.0),
                            v => {
                                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
                                        span,
                                        name,
                                        symbol: sym::simd_reduce_mul_ordered,
                                        in_ty,
                                        in_elem,
                                        size: v,
                                        ret_ty,
                                    });
                                return Err(());
                            }
                        }
                    };
                Ok(bx.vector_reduce_fmul(acc, args[0].immediate()))
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_mul_ordered,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};arith_red!(simd_reduce_mul_ordered: vector_reduce_mul, vector_reduce_fmul, true, mul, 1.0);
2969    if name == sym::simd_reduce_add_unordered {
    if !(ret_ty == in_elem) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                    span,
                    name,
                    in_elem,
                    in_ty,
                    ret_ty,
                });
            return Err(());
        };
    };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_add(args[0].immediate());
                if false {
                    Ok(bx.add(args[1].immediate(), r))
                } else { Ok(bx.vector_reduce_add(args[0].immediate())) }
            }
            ty::Float(f) => {
                let acc =
                    if false {
                        args[1].immediate()
                    } else {
                        match f.bit_width() {
                            32 => bx.const_real(bx.type_f32(), -0.0),
                            64 => bx.const_real(bx.type_f64(), -0.0),
                            v => {
                                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
                                        span,
                                        name,
                                        symbol: sym::simd_reduce_add_unordered,
                                        in_ty,
                                        in_elem,
                                        size: v,
                                        ret_ty,
                                    });
                                return Err(());
                            }
                        }
                    };
                Ok(bx.vector_reduce_fadd_reassoc(acc, args[0].immediate()))
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_add_unordered,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};arith_red!(
2970        simd_reduce_add_unordered: vector_reduce_add,
2971        vector_reduce_fadd_reassoc,
2972        false,
2973        add,
2974        -0.0
2975    );
2976    if name == sym::simd_reduce_mul_unordered {
    if !(ret_ty == in_elem) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                    span,
                    name,
                    in_elem,
                    in_ty,
                    ret_ty,
                });
            return Err(());
        };
    };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_mul(args[0].immediate());
                if false {
                    Ok(bx.mul(args[1].immediate(), r))
                } else { Ok(bx.vector_reduce_mul(args[0].immediate())) }
            }
            ty::Float(f) => {
                let acc =
                    if false {
                        args[1].immediate()
                    } else {
                        match f.bit_width() {
                            32 => bx.const_real(bx.type_f32(), 1.0),
                            64 => bx.const_real(bx.type_f64(), 1.0),
                            v => {
                                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbolOfSize {
                                        span,
                                        name,
                                        symbol: sym::simd_reduce_mul_unordered,
                                        in_ty,
                                        in_elem,
                                        size: v,
                                        ret_ty,
                                    });
                                return Err(());
                            }
                        }
                    };
                Ok(bx.vector_reduce_fmul_reassoc(acc, args[0].immediate()))
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_mul_unordered,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};arith_red!(
2977        simd_reduce_mul_unordered: vector_reduce_mul,
2978        vector_reduce_fmul_reassoc,
2979        false,
2980        mul,
2981        1.0
2982    );
2983
2984    macro_rules! minmax_red {
2985        ($name:ident: $int_red:ident) => {
2986            if name == sym::$name {
2987                require!(
2988                    ret_ty == in_elem,
2989                    InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
2990                );
2991                return match in_elem.kind() {
2992                    ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)),
2993                    ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)),
2994                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
2995                        span,
2996                        name,
2997                        symbol: sym::$name,
2998                        in_ty,
2999                        in_elem,
3000                        ret_ty
3001                    }),
3002                };
3003            }
3004        };
3005    }
3006
3007    // Currently no support for float due to <https://github.com/llvm/llvm-project/issues/185827>.
3008    if name == sym::simd_reduce_min {
    if !(ret_ty == in_elem) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                    span,
                    name,
                    in_elem,
                    in_ty,
                    ret_ty,
                });
            return Err(());
        };
    };
    return match in_elem.kind() {
            ty::Int(_i) =>
                Ok(bx.vector_reduce_min(args[0].immediate(), true)),
            ty::Uint(_u) =>
                Ok(bx.vector_reduce_min(args[0].immediate(), false)),
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_min,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};minmax_red!(simd_reduce_min: vector_reduce_min);
3009    if name == sym::simd_reduce_max {
    if !(ret_ty == in_elem) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                    span,
                    name,
                    in_elem,
                    in_ty,
                    ret_ty,
                });
            return Err(());
        };
    };
    return match in_elem.kind() {
            ty::Int(_i) =>
                Ok(bx.vector_reduce_max(args[0].immediate(), true)),
            ty::Uint(_u) =>
                Ok(bx.vector_reduce_max(args[0].immediate(), false)),
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_max,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};minmax_red!(simd_reduce_max: vector_reduce_max);
3010
3011    macro_rules! bitwise_red {
3012        ($name:ident : $red:ident, $boolean:expr) => {
3013            if name == sym::$name {
3014                let input = if !$boolean {
3015                    require!(
3016                        ret_ty == in_elem,
3017                        InvalidMonomorphization::ReturnType { span, name, in_elem, in_ty, ret_ty }
3018                    );
3019                    args[0].immediate()
3020                } else {
3021                    let bitwidth = match in_elem.kind() {
3022                        ty::Int(i) => {
3023                            i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
3024                        }
3025                        ty::Uint(i) => {
3026                            i.bit_width().unwrap_or_else(|| bx.data_layout().pointer_size().bits())
3027                        }
3028                        _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
3029                            span,
3030                            name,
3031                            symbol: sym::$name,
3032                            in_ty,
3033                            in_elem,
3034                            ret_ty
3035                        }),
3036                    };
3037
3038                    vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth, in_len as _)
3039                };
3040                return match in_elem.kind() {
3041                    ty::Int(_) | ty::Uint(_) => {
3042                        let r = bx.$red(input);
3043                        Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) })
3044                    }
3045                    _ => return_error!(InvalidMonomorphization::UnsupportedSymbol {
3046                        span,
3047                        name,
3048                        symbol: sym::$name,
3049                        in_ty,
3050                        in_elem,
3051                        ret_ty
3052                    }),
3053                };
3054            }
3055        };
3056    }
3057
3058    if name == sym::simd_reduce_and {
    let input =
        if !false {
            if !(ret_ty == in_elem) {
                {
                    bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                            span,
                            name,
                            in_elem,
                            in_ty,
                            ret_ty,
                        });
                    return Err(());
                };
            };
            args[0].immediate()
        } else {
            let bitwidth =
                match in_elem.kind() {
                    ty::Int(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    ty::Uint(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    _ => {
                        bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                                span,
                                name,
                                symbol: sym::simd_reduce_and,
                                in_ty,
                                in_elem,
                                ret_ty,
                            });
                        return Err(());
                    }
                };
            vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
                in_len as _)
        };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_and(input);
                Ok(if !false { r } else { bx.zext(r, bx.type_bool()) })
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_and,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};bitwise_red!(simd_reduce_and: vector_reduce_and, false);
3059    if name == sym::simd_reduce_or {
    let input =
        if !false {
            if !(ret_ty == in_elem) {
                {
                    bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                            span,
                            name,
                            in_elem,
                            in_ty,
                            ret_ty,
                        });
                    return Err(());
                };
            };
            args[0].immediate()
        } else {
            let bitwidth =
                match in_elem.kind() {
                    ty::Int(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    ty::Uint(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    _ => {
                        bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                                span,
                                name,
                                symbol: sym::simd_reduce_or,
                                in_ty,
                                in_elem,
                                ret_ty,
                            });
                        return Err(());
                    }
                };
            vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
                in_len as _)
        };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_or(input);
                Ok(if !false { r } else { bx.zext(r, bx.type_bool()) })
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_or,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};bitwise_red!(simd_reduce_or: vector_reduce_or, false);
3060    if name == sym::simd_reduce_xor {
    let input =
        if !false {
            if !(ret_ty == in_elem) {
                {
                    bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                            span,
                            name,
                            in_elem,
                            in_ty,
                            ret_ty,
                        });
                    return Err(());
                };
            };
            args[0].immediate()
        } else {
            let bitwidth =
                match in_elem.kind() {
                    ty::Int(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    ty::Uint(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    _ => {
                        bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                                span,
                                name,
                                symbol: sym::simd_reduce_xor,
                                in_ty,
                                in_elem,
                                ret_ty,
                            });
                        return Err(());
                    }
                };
            vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
                in_len as _)
        };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_xor(input);
                Ok(if !false { r } else { bx.zext(r, bx.type_bool()) })
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_xor,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};bitwise_red!(simd_reduce_xor: vector_reduce_xor, false);
3061    if name == sym::simd_reduce_all {
    let input =
        if !true {
            if !(ret_ty == in_elem) {
                {
                    bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                            span,
                            name,
                            in_elem,
                            in_ty,
                            ret_ty,
                        });
                    return Err(());
                };
            };
            args[0].immediate()
        } else {
            let bitwidth =
                match in_elem.kind() {
                    ty::Int(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    ty::Uint(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    _ => {
                        bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                                span,
                                name,
                                symbol: sym::simd_reduce_all,
                                in_ty,
                                in_elem,
                                ret_ty,
                            });
                        return Err(());
                    }
                };
            vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
                in_len as _)
        };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_and(input);
                Ok(if !true { r } else { bx.zext(r, bx.type_bool()) })
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_all,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};bitwise_red!(simd_reduce_all: vector_reduce_and, true);
3062    if name == sym::simd_reduce_any {
    let input =
        if !true {
            if !(ret_ty == in_elem) {
                {
                    bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnType {
                            span,
                            name,
                            in_elem,
                            in_ty,
                            ret_ty,
                        });
                    return Err(());
                };
            };
            args[0].immediate()
        } else {
            let bitwidth =
                match in_elem.kind() {
                    ty::Int(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    ty::Uint(i) => {
                        i.bit_width().unwrap_or_else(||
                                bx.data_layout().pointer_size().bits())
                    }
                    _ => {
                        bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                                span,
                                name,
                                symbol: sym::simd_reduce_any,
                                in_ty,
                                in_elem,
                                ret_ty,
                            });
                        return Err(());
                    }
                };
            vector_mask_to_bitmask(bx, args[0].immediate(), bitwidth,
                in_len as _)
        };
    return match in_elem.kind() {
            ty::Int(_) | ty::Uint(_) => {
                let r = bx.vector_reduce_or(input);
                Ok(if !true { r } else { bx.zext(r, bx.type_bool()) })
            }
            _ => {
                bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedSymbol {
                        span,
                        name,
                        symbol: sym::simd_reduce_any,
                        in_ty,
                        in_elem,
                        ret_ty,
                    });
                return Err(());
            }
        };
};bitwise_red!(simd_reduce_any: vector_reduce_or, true);
3063
3064    if name == sym::simd_cast_ptr {
3065        let (out_len, out_elem) = {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
3066        if !(in_len == out_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
                span,
                name,
                in_len,
                in_ty,
                ret_ty,
                out_len,
            });
        return Err(());
    };
};require!(
3067            in_len == out_len,
3068            InvalidMonomorphization::ReturnLengthInputType {
3069                span,
3070                name,
3071                in_len,
3072                in_ty,
3073                ret_ty,
3074                out_len
3075            }
3076        );
3077
3078        match in_elem.kind() {
3079            ty::RawPtr(p_ty, _) => {
3080                let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
3081                    bx.tcx.normalize_erasing_regions(bx.typing_env(), ty)
3082                });
3083                if !metadata.is_unit() {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::CastWidePointer {
                span,
                name,
                ty: in_elem,
            });
        return Err(());
    };
};require!(
3084                    metadata.is_unit(),
3085                    InvalidMonomorphization::CastWidePointer { span, name, ty: in_elem }
3086                );
3087            }
3088            _ => {
3089                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
            span,
            name,
            ty: in_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
3090            }
3091        }
3092        match out_elem.kind() {
3093            ty::RawPtr(p_ty, _) => {
3094                let metadata = p_ty.ptr_metadata_ty(bx.tcx, |ty| {
3095                    bx.tcx.normalize_erasing_regions(bx.typing_env(), ty)
3096                });
3097                if !metadata.is_unit() {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::CastWidePointer {
                span,
                name,
                ty: out_elem,
            });
        return Err(());
    };
};require!(
3098                    metadata.is_unit(),
3099                    InvalidMonomorphization::CastWidePointer { span, name, ty: out_elem }
3100                );
3101            }
3102            _ => {
3103                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
            span,
            name,
            ty: out_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
3104            }
3105        }
3106
3107        return Ok(args[0].immediate());
3108    }
3109
3110    if name == sym::simd_expose_provenance {
3111        let (out_len, out_elem) = {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
3112        if !(in_len == out_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
                span,
                name,
                in_len,
                in_ty,
                ret_ty,
                out_len,
            });
        return Err(());
    };
};require!(
3113            in_len == out_len,
3114            InvalidMonomorphization::ReturnLengthInputType {
3115                span,
3116                name,
3117                in_len,
3118                in_ty,
3119                ret_ty,
3120                out_len
3121            }
3122        );
3123
3124        match in_elem.kind() {
3125            ty::RawPtr(_, _) => {}
3126            _ => {
3127                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
            span,
            name,
            ty: in_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: in_elem })
3128            }
3129        }
3130        match out_elem.kind() {
3131            ty::Uint(ty::UintTy::Usize) => {}
3132            _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedUsize {
            span,
            name,
            ty: out_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: out_elem }),
3133        }
3134
3135        return Ok(bx.ptrtoint(args[0].immediate(), llret_ty));
3136    }
3137
3138    if name == sym::simd_with_exposed_provenance {
3139        let (out_len, out_elem) = {
    if !ret_ty.is_simd() {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    ret_ty.simd_size_and_type(bx.tcx())
}require_simd!(ret_ty, SimdReturn);
3140        if !(in_len == out_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
                span,
                name,
                in_len,
                in_ty,
                ret_ty,
                out_len,
            });
        return Err(());
    };
};require!(
3141            in_len == out_len,
3142            InvalidMonomorphization::ReturnLengthInputType {
3143                span,
3144                name,
3145                in_len,
3146                in_ty,
3147                ret_ty,
3148                out_len
3149            }
3150        );
3151
3152        match in_elem.kind() {
3153            ty::Uint(ty::UintTy::Usize) => {}
3154            _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedUsize {
            span,
            name,
            ty: in_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::ExpectedUsize { span, name, ty: in_elem }),
3155        }
3156        match out_elem.kind() {
3157            ty::RawPtr(_, _) => {}
3158            _ => {
3159                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedPointer {
            span,
            name,
            ty: out_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::ExpectedPointer { span, name, ty: out_elem })
3160            }
3161        }
3162
3163        return Ok(bx.inttoptr(args[0].immediate(), llret_ty));
3164    }
3165
3166    if name == sym::simd_cast || name == sym::simd_as {
3167        let (out_len, out_elem, out_num_vecs) = {
    if !(ret_ty.is_simd() || ret_ty.is_scalable_vector()) {
        {
            bx.sess().dcx().emit_err(InvalidMonomorphization::SimdReturn {
                    span,
                    name,
                    ty: ret_ty,
                });
            return Err(());
        };
    };
    if ret_ty.is_simd() {
        let (len, ty) = ret_ty.simd_size_and_type(bx.tcx());
        (len, ty, None)
    } else {
        let (count, ty, num_vecs) =
            ret_ty.scalable_vector_parts(bx.tcx()).expect("`is_scalable_vector` was wrong");
        (count as u64, ty, Some(num_vecs))
    }
}require_simd_or_scalable!(ret_ty, SimdReturn);
3168        if !(in_len == out_len) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnLengthInputType {
                span,
                name,
                in_len,
                in_ty,
                ret_ty,
                out_len,
            });
        return Err(());
    };
};require!(
3169            in_len == out_len,
3170            InvalidMonomorphization::ReturnLengthInputType {
3171                span,
3172                name,
3173                in_len,
3174                in_ty,
3175                ret_ty,
3176                out_len
3177            }
3178        );
3179        if !(in_num_vecs == out_num_vecs) {
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::ReturnNumVecsInputType {
                span,
                name,
                in_num_vecs: in_num_vecs.unwrap_or(NumScalableVectors(1)),
                in_ty,
                ret_ty,
                out_num_vecs: out_num_vecs.unwrap_or(NumScalableVectors(1)),
            });
        return Err(());
    };
};require!(
3180            in_num_vecs == out_num_vecs,
3181            InvalidMonomorphization::ReturnNumVecsInputType {
3182                span,
3183                name,
3184                in_num_vecs: in_num_vecs.unwrap_or(NumScalableVectors(1)),
3185                in_ty,
3186                ret_ty,
3187                out_num_vecs: out_num_vecs.unwrap_or(NumScalableVectors(1))
3188            }
3189        );
3190
3191        // Casting cares about nominal type, not just structural type
3192        if in_elem == out_elem {
3193            return Ok(args[0].immediate());
3194        }
3195
3196        #[derive(#[automatically_derived]
impl ::core::marker::Copy for Sign { }Copy, #[automatically_derived]
impl ::core::clone::Clone for Sign {
    #[inline]
    fn clone(&self) -> Sign { *self }
}Clone)]
3197        enum Sign {
3198            Unsigned,
3199            Signed,
3200        }
3201        use Sign::*;
3202
3203        enum Style {
3204            Float,
3205            Int(Sign),
3206            Unsupported,
3207        }
3208
3209        let (in_style, in_width) = match in_elem.kind() {
3210            // vectors of pointer-sized integers should've been
3211            // disallowed before here, so this unwrap is safe.
3212            ty::Int(i) => (
3213                Style::Int(Signed),
3214                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3215            ),
3216            ty::Uint(u) => (
3217                Style::Int(Unsigned),
3218                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3219            ),
3220            ty::Float(f) => (Style::Float, f.bit_width()),
3221            _ => (Style::Unsupported, 0),
3222        };
3223        let (out_style, out_width) = match out_elem.kind() {
3224            ty::Int(i) => (
3225                Style::Int(Signed),
3226                i.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3227            ),
3228            ty::Uint(u) => (
3229                Style::Int(Unsigned),
3230                u.normalize(bx.tcx().sess.target.pointer_width).bit_width().unwrap(),
3231            ),
3232            ty::Float(f) => (Style::Float, f.bit_width()),
3233            _ => (Style::Unsupported, 0),
3234        };
3235
3236        match (in_style, out_style) {
3237            (Style::Int(sign), Style::Int(_)) => {
3238                return Ok(match in_width.cmp(&out_width) {
3239                    Ordering::Greater => bx.trunc(args[0].immediate(), llret_ty),
3240                    Ordering::Equal => args[0].immediate(),
3241                    Ordering::Less => match sign {
3242                        Sign::Signed => bx.sext(args[0].immediate(), llret_ty),
3243                        Sign::Unsigned => bx.zext(args[0].immediate(), llret_ty),
3244                    },
3245                });
3246            }
3247            (Style::Int(Sign::Signed), Style::Float) => {
3248                return Ok(bx.sitofp(args[0].immediate(), llret_ty));
3249            }
3250            (Style::Int(Sign::Unsigned), Style::Float) => {
3251                return Ok(bx.uitofp(args[0].immediate(), llret_ty));
3252            }
3253            (Style::Float, Style::Int(sign)) => {
3254                return Ok(match (sign, name == sym::simd_as) {
3255                    (Sign::Unsigned, false) => bx.fptoui(args[0].immediate(), llret_ty),
3256                    (Sign::Signed, false) => bx.fptosi(args[0].immediate(), llret_ty),
3257                    (_, true) => bx.cast_float_to_int(
3258                        #[allow(non_exhaustive_omitted_patterns)] match sign {
    Sign::Signed => true,
    _ => false,
}matches!(sign, Sign::Signed),
3259                        args[0].immediate(),
3260                        llret_ty,
3261                    ),
3262                });
3263            }
3264            (Style::Float, Style::Float) => {
3265                return Ok(match in_width.cmp(&out_width) {
3266                    Ordering::Greater => bx.fptrunc(args[0].immediate(), llret_ty),
3267                    Ordering::Equal => args[0].immediate(),
3268                    Ordering::Less => bx.fpext(args[0].immediate(), llret_ty),
3269                });
3270            }
3271            _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedCast {
            span,
            name,
            in_ty,
            in_elem,
            ret_ty,
            out_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::UnsupportedCast {
3272                span,
3273                name,
3274                in_ty,
3275                in_elem,
3276                ret_ty,
3277                out_elem
3278            }),
3279        }
3280    }
3281    macro_rules! arith_binary {
3282        ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
3283            $(if name == sym::$name {
3284                match in_elem.kind() {
3285                    $($(ty::$p(_))|* => {
3286                        return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
3287                    })*
3288                    _ => {},
3289                }
3290                return_error!(
3291                    InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
3292                );
3293            })*
3294        }
3295    }
3296    if name == sym::simd_minimum_number_nsz {
    match in_elem.kind() {
        ty::Float(_) => {
            return Ok(bx.minimum_number_nsz(args[0].immediate(),
                        args[1].immediate()))
        }
        _ => {}
    }
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedOperation {
                span,
                name,
                in_ty,
                in_elem,
            });
        return Err(());
    };
}arith_binary! {
3297        simd_add: Uint, Int => add, Float => fadd;
3298        simd_sub: Uint, Int => sub, Float => fsub;
3299        simd_mul: Uint, Int => mul, Float => fmul;
3300        simd_div: Uint => udiv, Int => sdiv, Float => fdiv;
3301        simd_rem: Uint => urem, Int => srem, Float => frem;
3302        simd_shl: Uint, Int => shl;
3303        simd_shr: Uint => lshr, Int => ashr;
3304        simd_and: Uint, Int => and;
3305        simd_or: Uint, Int => or;
3306        simd_xor: Uint, Int => xor;
3307        simd_maximum_number_nsz: Float => maximum_number_nsz;
3308        simd_minimum_number_nsz: Float => minimum_number_nsz;
3309
3310    }
3311    macro_rules! arith_unary {
3312        ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
3313            $(if name == sym::$name {
3314                match in_elem.kind() {
3315                    $($(ty::$p(_))|* => {
3316                        return Ok(bx.$call(args[0].immediate()))
3317                    })*
3318                    _ => {},
3319                }
3320                return_error!(
3321                    InvalidMonomorphization::UnsupportedOperation { span, name, in_ty, in_elem }
3322                );
3323            })*
3324        }
3325    }
3326    if name == sym::simd_neg {
    match in_elem.kind() {
        ty::Int(_) => { return Ok(bx.neg(args[0].immediate())) }
        ty::Float(_) => { return Ok(bx.fneg(args[0].immediate())) }
        _ => {}
    }
    {
        bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedOperation {
                span,
                name,
                in_ty,
                in_elem,
            });
        return Err(());
    };
}arith_unary! {
3327        simd_neg: Int => neg, Float => fneg;
3328    }
3329
3330    // Unary integer intrinsics
3331    if #[allow(non_exhaustive_omitted_patterns)] match name {
    sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctlz | sym::simd_ctpop
        | sym::simd_cttz | sym::simd_carryless_mul | sym::simd_funnel_shl |
        sym::simd_funnel_shr => true,
    _ => false,
}matches!(
3332        name,
3333        sym::simd_bswap
3334            | sym::simd_bitreverse
3335            | sym::simd_ctlz
3336            | sym::simd_ctpop
3337            | sym::simd_cttz
3338            | sym::simd_carryless_mul
3339            | sym::simd_funnel_shl
3340            | sym::simd_funnel_shr
3341    ) {
3342        let vec_ty = bx.cx.type_vector(
3343            match *in_elem.kind() {
3344                ty::Int(i) => bx.cx.type_int_from_ty(i),
3345                ty::Uint(i) => bx.cx.type_uint_from_ty(i),
3346                _ => {
    bx.sess().dcx().emit_err(InvalidMonomorphization::UnsupportedOperation {
            span,
            name,
            in_ty,
            in_elem,
        });
    return Err(());
}return_error!(InvalidMonomorphization::UnsupportedOperation {
3347                    span,
3348                    name,
3349                    in_ty,
3350                    in_elem
3351                }),
3352            },
3353            in_len as u64,
3354        );
3355        let llvm_intrinsic = match name {
3356            sym::simd_bswap => "llvm.bswap",
3357            sym::simd_bitreverse => "llvm.bitreverse",
3358            sym::simd_ctlz => "llvm.ctlz",
3359            sym::simd_ctpop => "llvm.ctpop",
3360            sym::simd_cttz => "llvm.cttz",
3361            sym::simd_funnel_shl => "llvm.fshl",
3362            sym::simd_funnel_shr => "llvm.fshr",
3363            sym::simd_carryless_mul => "llvm.clmul",
3364            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
3365        };
3366        let int_size = in_elem.int_size_and_signed(bx.tcx()).0.bits();
3367
3368        return match name {
3369            // byte swap is no-op for i8/u8
3370            sym::simd_bswap if int_size == 8 => Ok(args[0].immediate()),
3371            sym::simd_ctlz | sym::simd_cttz => {
3372                // for the (int, i1 immediate) pair, the second arg adds `(0, true) => poison`
3373                let dont_poison_on_zero = bx.const_int(bx.type_i1(), 0);
3374                Ok(bx.call_intrinsic(
3375                    llvm_intrinsic,
3376                    &[vec_ty],
3377                    &[args[0].immediate(), dont_poison_on_zero],
3378                ))
3379            }
3380            sym::simd_bswap | sym::simd_bitreverse | sym::simd_ctpop => {
3381                // simple unary argument cases
3382                Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[args[0].immediate()]))
3383            }
3384            sym::simd_funnel_shl | sym::simd_funnel_shr => Ok(bx.call_intrinsic(
3385                llvm_intrinsic,
3386                &[vec_ty],
3387                &[args[0].immediate(), args[1].immediate(), args[2].immediate()],
3388            )),
3389            sym::simd_carryless_mul => {
3390                if crate::llvm_util::get_version() >= (22, 0, 0) {
3391                    Ok(bx.call_intrinsic(
3392                        llvm_intrinsic,
3393                        &[vec_ty],
3394                        &[args[0].immediate(), args[1].immediate()],
3395                    ))
3396                } else {
3397                    ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("`simd_carryless_mul` needs LLVM 22 or higher"));span_bug!(span, "`simd_carryless_mul` needs LLVM 22 or higher");
3398                }
3399            }
3400            _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
3401        };
3402    }
3403
3404    if name == sym::simd_arith_offset {
3405        // This also checks that the first operand is a ptr type.
3406        let pointee = in_elem.builtin_deref(true).unwrap_or_else(|| {
3407            ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("must be called with a vector of pointer types as first argument"))span_bug!(span, "must be called with a vector of pointer types as first argument")
3408        });
3409        let layout = bx.layout_of(pointee);
3410        let ptrs = args[0].immediate();
3411        // The second argument must be a ptr-sized integer.
3412        // (We don't care about the signedness, this is wrapping anyway.)
3413        let (_offsets_len, offsets_elem) = args[1].layout.ty.simd_size_and_type(bx.tcx());
3414        if !#[allow(non_exhaustive_omitted_patterns)] match offsets_elem.kind() {
    ty::Int(ty::IntTy::Isize) | ty::Uint(ty::UintTy::Usize) => true,
    _ => false,
}matches!(offsets_elem.kind(), ty::Int(ty::IntTy::Isize) | ty::Uint(ty::UintTy::Usize)) {
3415            ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("must be called with a vector of pointer-sized integers as second argument"));span_bug!(
3416                span,
3417                "must be called with a vector of pointer-sized integers as second argument"
3418            );
3419        }
3420        let offsets = args[1].immediate();
3421
3422        return Ok(bx.gep(bx.backend_type(layout), ptrs, &[offsets]));
3423    }
3424
3425    if name == sym::simd_saturating_add || name == sym::simd_saturating_sub {
3426        let lhs = args[0].immediate();
3427        let rhs = args[1].immediate();
3428        let is_add = name == sym::simd_saturating_add;
3429        let (signed, elem_ty) = match *in_elem.kind() {
3430            ty::Int(i) => (true, bx.cx.type_int_from_ty(i)),
3431            ty::Uint(i) => (false, bx.cx.type_uint_from_ty(i)),
3432            _ => {
3433                {
    bx.sess().dcx().emit_err(InvalidMonomorphization::ExpectedVectorElementType {
            span,
            name,
            expected_element: args[0].layout.ty.simd_size_and_type(bx.tcx()).1,
            vector_type: args[0].layout.ty,
        });
    return Err(());
};return_error!(InvalidMonomorphization::ExpectedVectorElementType {
3434                    span,
3435                    name,
3436                    expected_element: args[0].layout.ty.simd_size_and_type(bx.tcx()).1,
3437                    vector_type: args[0].layout.ty
3438                });
3439            }
3440        };
3441        let llvm_intrinsic = ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("llvm.{0}{1}.sat",
                if signed { 's' } else { 'u' },
                if is_add { "add" } else { "sub" }))
    })format!(
3442            "llvm.{}{}.sat",
3443            if signed { 's' } else { 'u' },
3444            if is_add { "add" } else { "sub" },
3445        );
3446        let vec_ty = bx.cx.type_vector(elem_ty, in_len as u64);
3447
3448        return Ok(bx.call_intrinsic(llvm_intrinsic, &[vec_ty], &[lhs, rhs]));
3449    }
3450
3451    ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("unknown SIMD intrinsic"));span_bug!(span, "unknown SIMD intrinsic");
3452}