Skip to main content

rustc_codegen_ssa/mir/
intrinsic.rs

1use rustc_abi::{Align, FieldIdx, WrappingRange};
2use rustc_middle::mir::SourceInfo;
3use rustc_middle::ty::{self, Ty, TyCtxt};
4use rustc_middle::{bug, span_bug};
5use rustc_session::config::OptLevel;
6use rustc_span::{ErrorGuaranteed, sym};
7use rustc_target::spec::Arch;
8
9use super::operand::{OperandRef, OperandValue};
10use super::place::PlaceValue;
11use super::{FunctionCx, IntrinsicResult};
12use crate::common::{AtomicRmwBinOp, SynchronizationScope};
13use crate::errors::InvalidMonomorphization;
14use crate::mir::operand::OperandRefBuilder;
15use crate::traits::*;
16use crate::{MemFlags, meth, size_of_val};
17
18fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
19    bx: &mut Bx,
20    allow_overlap: bool,
21    volatile: bool,
22    ty: Ty<'tcx>,
23    dst: Bx::Value,
24    src: Bx::Value,
25    count: Bx::Value,
26) {
27    let layout = bx.layout_of(ty);
28    let size = layout.size;
29    let align = layout.align.abi;
30    let size = bx.unchecked_sumul(bx.const_usize(size.bytes()), count);
31    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
32    if allow_overlap {
33        bx.memmove(dst, align, src, align, size, flags);
34    } else {
35        bx.memcpy(dst, align, src, align, size, flags, None);
36    }
37}
38
39fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
40    bx: &mut Bx,
41    volatile: bool,
42    ty: Ty<'tcx>,
43    dst: Bx::Value,
44    val: Bx::Value,
45    count: Bx::Value,
46) {
47    let layout = bx.layout_of(ty);
48    let size = layout.size;
49    let align = layout.align.abi;
50    let size = bx.mul(bx.const_usize(size.bytes()), count);
51    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
52    bx.memset(dst, val, size, align, flags);
53}
54
55impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
56    /// In the `Fallback` case, returns the instance that should be called instead.
57    pub fn codegen_intrinsic_call(
58        &mut self,
59        bx: &mut Bx,
60        instance: ty::Instance<'tcx>,
61        args: &[OperandRef<'tcx, Bx::Value>],
62        result_layout: ty::layout::TyAndLayout<'tcx>,
63        result_place: Option<PlaceValue<Bx::Value>>,
64        source_info: SourceInfo,
65    ) -> IntrinsicResult<'tcx, Bx::Value> {
66        // When `-Zforce-intrinsic-fallback` is enabled, always use the fallback body if it exists,
67        if bx.tcx().sess.opts.unstable_opts.force_intrinsic_fallback
68            && let Some(def) = bx.tcx().intrinsic(instance.def_id())
69            && !def.must_be_overridden
70        {
71            return IntrinsicResult::Fallback(ty::Instance::new_raw(
72                instance.def_id(),
73                instance.args,
74            ));
75        }
76
77        let span = source_info.span;
78
79        let name = bx.tcx().item_name(instance.def_id());
80        let fn_args = instance.args;
81
82        // If we're swapping something that's *not* an `OperandValue::Ref`,
83        // then we can do it directly and avoid the alloca.
84        // Otherwise, we'll let the fallback MIR body take care of it.
85        if let sym::typed_swap_nonoverlapping = name {
86            let pointee_ty = fn_args.type_at(0);
87            let pointee_layout = bx.layout_of(pointee_ty);
88            if !bx.is_backend_ref(pointee_layout)
89                // But if we're not going to optimize, trying to use the fallback
90                // body just makes things worse, so don't bother.
91                || bx.sess().opts.optimize == OptLevel::No
92                // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
93                // reinterpretation of values as (chunkable) byte arrays, and the loop in the
94                // block optimization in `ptr::swap_nonoverlapping` is hard to rewrite back
95                // into the (unoptimized) direct swapping implementation, so we disable it.
96                || bx.sess().target.arch == Arch::SpirV
97            {
98                let align = pointee_layout.align.abi;
99                let x_place = args[0].val.deref(align);
100                let y_place = args[1].val.deref(align);
101                bx.typed_place_swap(x_place, y_place, pointee_layout);
102                return IntrinsicResult::Operand(OperandValue::ZeroSized);
103            }
104        }
105
106        let invalid_monomorphization_int_type = |ty| -> ErrorGuaranteed {
107            bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty })
108        };
109        let invalid_monomorphization_int_or_ptr_type = |ty| -> ErrorGuaranteed {
110            bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerOrPtrType {
111                span,
112                name,
113                ty,
114            })
115        };
116
117        let parse_atomic_ordering = |ord: ty::Value<'tcx>| {
118            let discr = ord.to_branch()[0].to_leaf();
119            discr.to_atomic_ordering()
120        };
121
122        if args.is_empty() {
123            match name {
124                sym::abort
125                | sym::unreachable
126                | sym::cold_path
127                | sym::gpu_launch_sized_workgroup_mem
128                | sym::breakpoint
129                | sym::amdgpu_dispatch_ptr
130                | sym::assert_zero_valid
131                | sym::assert_mem_uninitialized_valid
132                | sym::assert_inhabited
133                | sym::ub_checks
134                | sym::contract_checks
135                | sym::atomic_fence
136                | sym::atomic_singlethreadfence
137                | sym::caller_location
138                | sym::return_address => {}
139                _ => {
140                    ::rustc_middle::util::bug::span_bug_fmt(span,
    format_args!("Nullary intrinsic {0} must be called in a const block. If you are seeing this message from code outside the standard library, the unstable implementation details of the relevant intrinsic may have changed. Consider using stable APIs instead. If you are adding a new nullary intrinsic that is inherently a runtime intrinsic, update this check.",
        name));span_bug!(
141                        span,
142                        "Nullary intrinsic {name} must be called in a const block. \
143                        If you are seeing this message from code outside the standard library, the \
144                        unstable implementation details of the relevant intrinsic may have changed. \
145                        Consider using stable APIs instead. \
146                        If you are adding a new nullary intrinsic that is inherently a runtime \
147                        intrinsic, update this check."
148                    );
149                }
150            }
151        }
152
153        let op_val: OperandValue<_> = match name {
154            sym::abort => {
155                bx.abort();
156                OperandValue::ZeroSized
157            }
158
159            sym::caller_location => {
160                let location = self.get_caller_location(bx, source_info);
161                location.val
162            }
163
164            // va_end uses the fallback body (a no-op).
165            sym::va_start => {
166                bx.va_start(args[0].immediate());
167                OperandValue::ZeroSized
168            }
169
170            sym::size_of_val => {
171                let tp_ty = fn_args.type_at(0);
172                let (_, meta) = args[0].val.pointer_parts();
173                let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
174                OperandValue::Immediate(llsize)
175            }
176            sym::align_of_val => {
177                let tp_ty = fn_args.type_at(0);
178                let (_, meta) = args[0].val.pointer_parts();
179                let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta);
180                OperandValue::Immediate(llalign)
181            }
182            sym::vtable_size | sym::vtable_align => {
183                let vtable = args[0].immediate();
184                let idx = match name {
185                    sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE,
186                    sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN,
187                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
188                };
189                let value = meth::VirtualIndex::from_index(idx).get_usize(
190                    bx,
191                    vtable,
192                    instance.ty(bx.tcx(), bx.typing_env()),
193                );
194                match name {
195                    // Size is always <= isize::MAX.
196                    sym::vtable_size => {
197                        let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
198                        bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
199                    }
200                    // Alignment is always a power of two, thus 1..=0x800…000,
201                    // but also bounded by the maximum we support in type layout.
202                    sym::vtable_align => {
203                        let align_bound = Align::max_for_target(bx.data_layout()).bytes().into();
204                        bx.range_metadata(value, WrappingRange { start: 1, end: align_bound })
205                    }
206                    _ => {}
207                }
208                OperandValue::Immediate(value)
209            }
210            sym::arith_offset => {
211                let ty = fn_args.type_at(0);
212                let layout = bx.layout_of(ty);
213                let ptr = args[0].immediate();
214                let offset = args[1].immediate();
215                OperandValue::Immediate(bx.gep(bx.backend_type(layout), ptr, &[offset]))
216            }
217            sym::copy => {
218                copy_intrinsic(
219                    bx,
220                    true,
221                    false,
222                    fn_args.type_at(0),
223                    args[1].immediate(),
224                    args[0].immediate(),
225                    args[2].immediate(),
226                );
227                OperandValue::ZeroSized
228            }
229            sym::write_bytes => {
230                memset_intrinsic(
231                    bx,
232                    false,
233                    fn_args.type_at(0),
234                    args[0].immediate(),
235                    args[1].immediate(),
236                    args[2].immediate(),
237                );
238                OperandValue::ZeroSized
239            }
240
241            sym::volatile_copy_nonoverlapping_memory => {
242                copy_intrinsic(
243                    bx,
244                    false,
245                    true,
246                    fn_args.type_at(0),
247                    args[0].immediate(),
248                    args[1].immediate(),
249                    args[2].immediate(),
250                );
251                OperandValue::ZeroSized
252            }
253            sym::volatile_copy_memory => {
254                copy_intrinsic(
255                    bx,
256                    true,
257                    true,
258                    fn_args.type_at(0),
259                    args[0].immediate(),
260                    args[1].immediate(),
261                    args[2].immediate(),
262                );
263                OperandValue::ZeroSized
264            }
265            sym::volatile_set_memory => {
266                memset_intrinsic(
267                    bx,
268                    true,
269                    fn_args.type_at(0),
270                    args[0].immediate(),
271                    args[1].immediate(),
272                    args[2].immediate(),
273                );
274                OperandValue::ZeroSized
275            }
276            sym::volatile_store => {
277                let dst = args[0].deref(bx.cx());
278                args[1].val.volatile_store(bx, dst);
279                OperandValue::ZeroSized
280            }
281            sym::unaligned_volatile_store => {
282                let dst = args[0].deref(bx.cx());
283                args[1].val.unaligned_volatile_store(bx, dst);
284                OperandValue::ZeroSized
285            }
286            sym::disjoint_bitor => {
287                let a = args[0].immediate();
288                let b = args[1].immediate();
289                OperandValue::Immediate(bx.or_disjoint(a, b))
290            }
291            sym::exact_div => {
292                let ty = args[0].layout.ty;
293                match int_type_width_signed(ty, bx.tcx()) {
294                    Some((_width, signed)) => OperandValue::Immediate(if signed {
295                        bx.exactsdiv(args[0].immediate(), args[1].immediate())
296                    } else {
297                        bx.exactudiv(args[0].immediate(), args[1].immediate())
298                    }),
299                    None => {
300                        let err = bx
301                            .tcx()
302                            .dcx()
303                            .emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
304                        return IntrinsicResult::Err(err);
305                    }
306                }
307            }
308            sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
309                match float_type_width(args[0].layout.ty) {
310                    Some(_width) => OperandValue::Immediate(match name {
311                        sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()),
312                        sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()),
313                        sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()),
314                        sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()),
315                        sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()),
316                        _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
317                    }),
318                    None => {
319                        let err =
320                            bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
321                                span,
322                                name,
323                                ty: args[0].layout.ty,
324                            });
325                        return IntrinsicResult::Err(err);
326                    }
327                }
328            }
329            sym::fadd_algebraic
330            | sym::fsub_algebraic
331            | sym::fmul_algebraic
332            | sym::fdiv_algebraic
333            | sym::frem_algebraic => match float_type_width(args[0].layout.ty) {
334                Some(_width) => OperandValue::Immediate(match name {
335                    sym::fadd_algebraic => {
336                        bx.fadd_algebraic(args[0].immediate(), args[1].immediate())
337                    }
338                    sym::fsub_algebraic => {
339                        bx.fsub_algebraic(args[0].immediate(), args[1].immediate())
340                    }
341                    sym::fmul_algebraic => {
342                        bx.fmul_algebraic(args[0].immediate(), args[1].immediate())
343                    }
344                    sym::fdiv_algebraic => {
345                        bx.fdiv_algebraic(args[0].immediate(), args[1].immediate())
346                    }
347                    sym::frem_algebraic => {
348                        bx.frem_algebraic(args[0].immediate(), args[1].immediate())
349                    }
350                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
351                }),
352                None => {
353                    let err = bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
354                        span,
355                        name,
356                        ty: args[0].layout.ty,
357                    });
358                    return IntrinsicResult::Err(err);
359                }
360            },
361
362            sym::float_to_int_unchecked => {
363                if float_type_width(args[0].layout.ty).is_none() {
364                    let err =
365                        bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
366                            span,
367                            ty: args[0].layout.ty,
368                        });
369                    return IntrinsicResult::Err(err);
370                }
371                let Some((_width, signed)) = int_type_width_signed(result_layout.ty, bx.tcx())
372                else {
373                    let err =
374                        bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
375                            span,
376                            ty: result_layout.ty,
377                        });
378                    return IntrinsicResult::Err(err);
379                };
380                OperandValue::Immediate(if signed {
381                    bx.fptosi(args[0].immediate(), bx.backend_type(result_layout))
382                } else {
383                    bx.fptoui(args[0].immediate(), bx.backend_type(result_layout))
384                })
385            }
386
387            sym::atomic_load => {
388                let ty = fn_args.type_at(0);
389                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
390                    let err = invalid_monomorphization_int_or_ptr_type(ty);
391                    return IntrinsicResult::Err(err);
392                }
393                let ordering = fn_args.const_at(1).to_value();
394                let layout = bx.layout_of(ty);
395                let source = args[0].immediate();
396                OperandValue::Immediate(bx.atomic_load(
397                    bx.backend_type(layout),
398                    source,
399                    parse_atomic_ordering(ordering),
400                    layout.size,
401                ))
402            }
403            sym::atomic_store => {
404                let ty = fn_args.type_at(0);
405                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
406                    let err = invalid_monomorphization_int_or_ptr_type(ty);
407                    return IntrinsicResult::Err(err);
408                }
409                let ordering = fn_args.const_at(1).to_value();
410                let size = bx.layout_of(ty).size;
411                let val = args[1].immediate();
412                let ptr = args[0].immediate();
413                bx.atomic_store(val, ptr, parse_atomic_ordering(ordering), size);
414                OperandValue::ZeroSized
415            }
416            // These are all AtomicRMW ops
417            sym::atomic_cxchg | sym::atomic_cxchgweak => {
418                let ty = fn_args.type_at(0);
419                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
420                    let err = invalid_monomorphization_int_or_ptr_type(ty);
421                    return IntrinsicResult::Err(err);
422                }
423                let succ_ordering = fn_args.const_at(1).to_value();
424                let fail_ordering = fn_args.const_at(2).to_value();
425                let weak = name == sym::atomic_cxchgweak;
426                let dst = args[0].immediate();
427                let cmp = args[1].immediate();
428                let src = args[2].immediate();
429                let (val, success) = bx.atomic_cmpxchg(
430                    dst,
431                    cmp,
432                    src,
433                    parse_atomic_ordering(succ_ordering),
434                    parse_atomic_ordering(fail_ordering),
435                    weak,
436                );
437                let val = bx.from_immediate(val);
438                let success = bx.from_immediate(success);
439
440                let mut builder = OperandRefBuilder::new(result_layout);
441                builder.insert_imm(FieldIdx::from_u32(0), val);
442                builder.insert_imm(FieldIdx::from_u32(1), success);
443                builder.build(bx.cx()).val
444            }
445            sym::atomic_max | sym::atomic_min => {
446                let atom_op = if name == sym::atomic_max {
447                    AtomicRmwBinOp::AtomicMax
448                } else {
449                    AtomicRmwBinOp::AtomicMin
450                };
451
452                let ty = fn_args.type_at(0);
453                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Int(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Int(_)) {
454                    let ordering = fn_args.const_at(1).to_value();
455                    let ptr = args[0].immediate();
456                    let val = args[1].immediate();
457                    OperandValue::Immediate(bx.atomic_rmw(
458                        atom_op,
459                        ptr,
460                        val,
461                        parse_atomic_ordering(ordering),
462                        /* ret_ptr */ false,
463                    ))
464                } else {
465                    let err = invalid_monomorphization_int_type(ty);
466                    return IntrinsicResult::Err(err);
467                }
468            }
469            sym::atomic_umax | sym::atomic_umin => {
470                let atom_op = if name == sym::atomic_umax {
471                    AtomicRmwBinOp::AtomicUMax
472                } else {
473                    AtomicRmwBinOp::AtomicUMin
474                };
475
476                let ty = fn_args.type_at(0);
477                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Uint(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Uint(_)) {
478                    let ordering = fn_args.const_at(1).to_value();
479                    let ptr = args[0].immediate();
480                    let val = args[1].immediate();
481                    OperandValue::Immediate(bx.atomic_rmw(
482                        atom_op,
483                        ptr,
484                        val,
485                        parse_atomic_ordering(ordering),
486                        /* ret_ptr */ false,
487                    ))
488                } else {
489                    let err = invalid_monomorphization_int_type(ty);
490                    return IntrinsicResult::Err(err);
491                }
492            }
493            sym::atomic_xchg => {
494                let ty = fn_args.type_at(0);
495                let ordering = fn_args.const_at(1).to_value();
496                if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
497                    let ptr = args[0].immediate();
498                    let val = args[1].immediate();
499                    let atomic_op = AtomicRmwBinOp::AtomicXchg;
500                    OperandValue::Immediate(bx.atomic_rmw(
501                        atomic_op,
502                        ptr,
503                        val,
504                        parse_atomic_ordering(ordering),
505                        /* ret_ptr */ ty.is_raw_ptr(),
506                    ))
507                } else {
508                    let err = invalid_monomorphization_int_or_ptr_type(ty);
509                    return IntrinsicResult::Err(err);
510                }
511            }
512            sym::atomic_xadd
513            | sym::atomic_xsub
514            | sym::atomic_and
515            | sym::atomic_nand
516            | sym::atomic_or
517            | sym::atomic_xor => {
518                let atom_op = match name {
519                    sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd,
520                    sym::atomic_xsub => AtomicRmwBinOp::AtomicSub,
521                    sym::atomic_and => AtomicRmwBinOp::AtomicAnd,
522                    sym::atomic_nand => AtomicRmwBinOp::AtomicNand,
523                    sym::atomic_or => AtomicRmwBinOp::AtomicOr,
524                    sym::atomic_xor => AtomicRmwBinOp::AtomicXor,
525                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
526                };
527
528                // The type of the in-memory data.
529                let ty_mem = fn_args.type_at(0);
530                // The type of the 2nd operand, given by-value.
531                let ty_op = fn_args.type_at(1);
532
533                let ordering = fn_args.const_at(2).to_value();
534                // We require either both arguments to have the same integer type, or the first to
535                // be a pointer and the second to be `usize`.
536                if (int_type_width_signed(ty_mem, bx.tcx()).is_some() && ty_op == ty_mem)
537                    || (ty_mem.is_raw_ptr() && ty_op == bx.tcx().types.usize)
538                {
539                    let ptr = args[0].immediate(); // of type "pointer to `ty_mem`"
540                    let val = args[1].immediate(); // of type `ty_op`
541                    OperandValue::Immediate(bx.atomic_rmw(
542                        atom_op,
543                        ptr,
544                        val,
545                        parse_atomic_ordering(ordering),
546                        /* ret_ptr */ ty_mem.is_raw_ptr(),
547                    ))
548                } else {
549                    let err = invalid_monomorphization_int_or_ptr_type(ty_mem);
550                    return IntrinsicResult::Err(err);
551                }
552            }
553            sym::atomic_fence => {
554                let ordering = fn_args.const_at(0).to_value();
555                bx.atomic_fence(parse_atomic_ordering(ordering), SynchronizationScope::CrossThread);
556                OperandValue::ZeroSized
557            }
558
559            sym::atomic_singlethreadfence => {
560                let ordering = fn_args.const_at(0).to_value();
561                bx.atomic_fence(
562                    parse_atomic_ordering(ordering),
563                    SynchronizationScope::SingleThread,
564                );
565                OperandValue::ZeroSized
566            }
567
568            sym::nontemporal_store => {
569                let dst = args[0].deref(bx.cx());
570                args[1].val.nontemporal_store(bx, dst);
571                OperandValue::ZeroSized
572            }
573
574            sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
575                let ty = fn_args.type_at(0);
576                let pointee_size = bx.layout_of(ty).size;
577
578                let a = args[0].immediate();
579                let b = args[1].immediate();
580                let a = bx.ptrtoint(a, bx.type_isize());
581                let b = bx.ptrtoint(b, bx.type_isize());
582                let pointee_size = bx.const_usize(pointee_size.bytes());
583                OperandValue::Immediate(if name == sym::ptr_offset_from {
584                    // This is the same sequence that Clang emits for pointer subtraction.
585                    // It can be neither `nsw` nor `nuw` because the input is treated as
586                    // unsigned but then the output is treated as signed, so neither works.
587                    let d = bx.sub(a, b);
588                    // this is where the signed magic happens (notice the `s` in `exactsdiv`)
589                    bx.exactsdiv(d, pointee_size)
590                } else {
591                    // The `_unsigned` version knows the relative ordering of the pointers,
592                    // so can use `sub nuw` and `udiv exact` instead of dealing in signed.
593                    let d = bx.unchecked_usub(a, b);
594                    bx.exactudiv(d, pointee_size)
595                })
596            }
597
598            sym::cold_path => {
599                // This is a no-op. The intrinsic is just a hint to the optimizer.
600                OperandValue::ZeroSized
601            }
602
603            _ => {
604                // Need to use backend-specific things in the implementation.
605                let result =
606                    bx.codegen_intrinsic_call(instance, args, result_layout, result_place, span);
607                if let IntrinsicResult::Operand(op) = result {
608                    op
609                } else {
610                    return result;
611                }
612            }
613        };
614
615        if true {
    if !op_val.is_expected_variant_for_type(bx.cx(), result_layout) {
        {
            ::core::panicking::panic_fmt(format_args!("[{0:?}] Value {1:?} is wrong for type {2:?}",
                    name, op_val, result_layout));
        }
    };
};debug_assert!(
616            op_val.is_expected_variant_for_type(bx.cx(), result_layout),
617            "[{name:?}] Value {op_val:?} is wrong for type {result_layout:?}",
618        );
619
620        IntrinsicResult::Operand(op_val)
621    }
622}
623
624// Returns the width of an int Ty, and if it's signed or not
625// Returns None if the type is not an integer
626// FIXME: there’s multiple of this functions, investigate using some of the already existing
627// stuffs.
628fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
629    match ty.kind() {
630        ty::Int(t) => {
631            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true))
632        }
633        ty::Uint(t) => {
634            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false))
635        }
636        _ => None,
637    }
638}
639
640// Returns the width of a float Ty
641// Returns None if the type is not a float
642fn float_type_width(ty: Ty<'_>) -> Option<u64> {
643    match ty.kind() {
644        ty::Float(t) => Some(t.bit_width()),
645        _ => None,
646    }
647}