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