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::diagnostics::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 pointee_layout.is_ssa_standalone()
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            sym::size_of_val => {
165                let tp_ty = fn_args.type_at(0);
166                let (_, meta) = args[0].val.pointer_parts();
167                let (llsize, _) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta, span);
168                OperandValue::Immediate(llsize)
169            }
170            sym::align_of_val => {
171                let tp_ty = fn_args.type_at(0);
172                let (_, meta) = args[0].val.pointer_parts();
173                let (_, llalign) = size_of_val::size_and_align_of_dst(bx, tp_ty, meta, span);
174                OperandValue::Immediate(llalign)
175            }
176            sym::vtable_size | sym::vtable_align => {
177                let vtable = args[0].immediate();
178                let idx = match name {
179                    sym::vtable_size => ty::COMMON_VTABLE_ENTRIES_SIZE,
180                    sym::vtable_align => ty::COMMON_VTABLE_ENTRIES_ALIGN,
181                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
182                };
183                let value = meth::VirtualIndex::from_index(idx).get_usize(
184                    bx,
185                    vtable,
186                    instance.ty(bx.tcx(), bx.typing_env()),
187                );
188                match name {
189                    // Size is always <= isize::MAX.
190                    sym::vtable_size => {
191                        let size_bound = bx.data_layout().ptr_sized_integer().signed_max() as u128;
192                        bx.range_metadata(value, WrappingRange { start: 0, end: size_bound });
193                    }
194                    // Alignment is always a power of two, thus 1..=0x800…000,
195                    // but also bounded by the maximum we support in type layout.
196                    sym::vtable_align => {
197                        let align_bound = Align::max_for_target(bx.data_layout()).bytes().into();
198                        bx.range_metadata(value, WrappingRange { start: 1, end: align_bound })
199                    }
200                    _ => {}
201                }
202                OperandValue::Immediate(value)
203            }
204            sym::arith_offset => {
205                let ty = fn_args.type_at(0);
206                let layout = bx.layout_of(ty);
207                let ptr = args[0].immediate();
208                let offset = args[1].immediate();
209                OperandValue::Immediate(bx.gep(bx.backend_type(layout), ptr, &[offset]))
210            }
211            sym::copy => {
212                copy_intrinsic(
213                    bx,
214                    true,
215                    false,
216                    fn_args.type_at(0),
217                    args[1].immediate(),
218                    args[0].immediate(),
219                    args[2].immediate(),
220                );
221                OperandValue::ZeroSized
222            }
223            sym::write_bytes => {
224                memset_intrinsic(
225                    bx,
226                    false,
227                    fn_args.type_at(0),
228                    args[0].immediate(),
229                    args[1].immediate(),
230                    args[2].immediate(),
231                );
232                OperandValue::ZeroSized
233            }
234
235            sym::volatile_copy_nonoverlapping_memory => {
236                copy_intrinsic(
237                    bx,
238                    false,
239                    true,
240                    fn_args.type_at(0),
241                    args[0].immediate(),
242                    args[1].immediate(),
243                    args[2].immediate(),
244                );
245                OperandValue::ZeroSized
246            }
247            sym::volatile_copy_memory => {
248                copy_intrinsic(
249                    bx,
250                    true,
251                    true,
252                    fn_args.type_at(0),
253                    args[0].immediate(),
254                    args[1].immediate(),
255                    args[2].immediate(),
256                );
257                OperandValue::ZeroSized
258            }
259            sym::volatile_set_memory => {
260                memset_intrinsic(
261                    bx,
262                    true,
263                    fn_args.type_at(0),
264                    args[0].immediate(),
265                    args[1].immediate(),
266                    args[2].immediate(),
267                );
268                OperandValue::ZeroSized
269            }
270            sym::volatile_store | sym::unaligned_volatile_store => {
271                let dst = args[0].deref(bx.cx());
272                let dst = if name == sym::volatile_store { dst } else { dst.unaligned() };
273                args[1].val.volatile_store(bx, dst);
274                OperandValue::ZeroSized
275            }
276            sym::disjoint_bitor => {
277                let a = args[0].immediate();
278                let b = args[1].immediate();
279                OperandValue::Immediate(bx.or_disjoint(a, b))
280            }
281            sym::exact_div => {
282                let ty = args[0].layout.ty;
283                match int_type_width_signed(ty, bx.tcx()) {
284                    Some((_width, signed)) => OperandValue::Immediate(if signed {
285                        bx.exactsdiv(args[0].immediate(), args[1].immediate())
286                    } else {
287                        bx.exactudiv(args[0].immediate(), args[1].immediate())
288                    }),
289                    None => {
290                        let err = bx
291                            .tcx()
292                            .dcx()
293                            .emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty });
294                        return IntrinsicResult::Err(err);
295                    }
296                }
297            }
298            sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => {
299                match float_type_width(args[0].layout.ty) {
300                    Some(_width) => OperandValue::Immediate(match name {
301                        sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()),
302                        sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()),
303                        sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()),
304                        sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()),
305                        sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()),
306                        _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
307                    }),
308                    None => {
309                        let err =
310                            bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
311                                span,
312                                name,
313                                ty: args[0].layout.ty,
314                            });
315                        return IntrinsicResult::Err(err);
316                    }
317                }
318            }
319            sym::fadd_algebraic
320            | sym::fsub_algebraic
321            | sym::fmul_algebraic
322            | sym::fdiv_algebraic
323            | sym::frem_algebraic => match float_type_width(args[0].layout.ty) {
324                Some(_width) => OperandValue::Immediate(match name {
325                    sym::fadd_algebraic => {
326                        bx.fadd_algebraic(args[0].immediate(), args[1].immediate())
327                    }
328                    sym::fsub_algebraic => {
329                        bx.fsub_algebraic(args[0].immediate(), args[1].immediate())
330                    }
331                    sym::fmul_algebraic => {
332                        bx.fmul_algebraic(args[0].immediate(), args[1].immediate())
333                    }
334                    sym::fdiv_algebraic => {
335                        bx.fdiv_algebraic(args[0].immediate(), args[1].immediate())
336                    }
337                    sym::frem_algebraic => {
338                        bx.frem_algebraic(args[0].immediate(), args[1].immediate())
339                    }
340                    _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
341                }),
342                None => {
343                    let err = bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicFloatType {
344                        span,
345                        name,
346                        ty: args[0].layout.ty,
347                    });
348                    return IntrinsicResult::Err(err);
349                }
350            },
351
352            sym::float_to_int_unchecked => {
353                if float_type_width(args[0].layout.ty).is_none() {
354                    let err =
355                        bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
356                            span,
357                            ty: args[0].layout.ty,
358                        });
359                    return IntrinsicResult::Err(err);
360                }
361                let Some((_width, signed)) = int_type_width_signed(result_layout.ty, bx.tcx())
362                else {
363                    let err =
364                        bx.tcx().dcx().emit_err(InvalidMonomorphization::FloatToIntUnchecked {
365                            span,
366                            ty: result_layout.ty,
367                        });
368                    return IntrinsicResult::Err(err);
369                };
370                OperandValue::Immediate(if signed {
371                    bx.fptosi(args[0].immediate(), bx.backend_type(result_layout))
372                } else {
373                    bx.fptoui(args[0].immediate(), bx.backend_type(result_layout))
374                })
375            }
376
377            sym::atomic_load => {
378                let ty = fn_args.type_at(0);
379                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
380                    let err = invalid_monomorphization_int_or_ptr_type(ty);
381                    return IntrinsicResult::Err(err);
382                }
383                let ordering = fn_args.const_at(1).to_value();
384                let volatile = fn_args.const_at(2).to_value();
385                let layout = bx.layout_of(ty);
386                let source = args[0].immediate();
387                OperandValue::Immediate(bx.atomic_load(
388                    bx.backend_type(layout),
389                    source,
390                    parse_atomic_ordering(ordering),
391                    volatile.to_leaf().try_to_bool().unwrap(),
392                    layout.size,
393                ))
394            }
395            sym::atomic_store => {
396                let ty = fn_args.type_at(0);
397                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
398                    let err = invalid_monomorphization_int_or_ptr_type(ty);
399                    return IntrinsicResult::Err(err);
400                }
401                let ordering = fn_args.const_at(1).to_value();
402                let volatile = fn_args.const_at(2).to_value();
403                let size = bx.layout_of(ty).size;
404                let val = args[1].immediate();
405                let ptr = args[0].immediate();
406                bx.atomic_store(
407                    val,
408                    ptr,
409                    parse_atomic_ordering(ordering),
410                    volatile.to_leaf().try_to_bool().unwrap(),
411                    size,
412                );
413                OperandValue::ZeroSized
414            }
415            // These are all AtomicRMW ops
416            sym::atomic_cxchg | sym::atomic_cxchgweak => {
417                let ty = fn_args.type_at(0);
418                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
419                    let err = invalid_monomorphization_int_or_ptr_type(ty);
420                    return IntrinsicResult::Err(err);
421                }
422                let succ_ordering = fn_args.const_at(1).to_value();
423                let fail_ordering = fn_args.const_at(2).to_value();
424                let weak = name == sym::atomic_cxchgweak;
425                let dst = args[0].immediate();
426                let cmp = args[1].immediate();
427                let src = args[2].immediate();
428                let (val, success) = bx.atomic_cmpxchg(
429                    dst,
430                    cmp,
431                    src,
432                    parse_atomic_ordering(succ_ordering),
433                    parse_atomic_ordering(fail_ordering),
434                    weak,
435                );
436                let val = bx.from_immediate(val);
437                let success = bx.from_immediate(success);
438
439                let mut builder = OperandRefBuilder::new(result_layout);
440                builder.insert_imm(FieldIdx::from_u32(0), val);
441                builder.insert_imm(FieldIdx::from_u32(1), success);
442                builder.build(bx.cx()).val
443            }
444            sym::atomic_max | sym::atomic_min => {
445                let atom_op = if name == sym::atomic_max {
446                    AtomicRmwBinOp::AtomicMax
447                } else {
448                    AtomicRmwBinOp::AtomicMin
449                };
450
451                let ty = fn_args.type_at(0);
452                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Int(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Int(_)) {
453                    let ordering = fn_args.const_at(1).to_value();
454                    let ptr = args[0].immediate();
455                    let val = args[1].immediate();
456                    OperandValue::Immediate(bx.atomic_rmw(
457                        atom_op,
458                        ptr,
459                        val,
460                        parse_atomic_ordering(ordering),
461                        /* ret_ptr */ false,
462                    ))
463                } else {
464                    let err = invalid_monomorphization_int_type(ty);
465                    return IntrinsicResult::Err(err);
466                }
467            }
468            sym::atomic_umax | sym::atomic_umin => {
469                let atom_op = if name == sym::atomic_umax {
470                    AtomicRmwBinOp::AtomicUMax
471                } else {
472                    AtomicRmwBinOp::AtomicUMin
473                };
474
475                let ty = fn_args.type_at(0);
476                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Uint(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Uint(_)) {
477                    let ordering = fn_args.const_at(1).to_value();
478                    let ptr = args[0].immediate();
479                    let val = args[1].immediate();
480                    OperandValue::Immediate(bx.atomic_rmw(
481                        atom_op,
482                        ptr,
483                        val,
484                        parse_atomic_ordering(ordering),
485                        /* ret_ptr */ false,
486                    ))
487                } else {
488                    let err = invalid_monomorphization_int_type(ty);
489                    return IntrinsicResult::Err(err);
490                }
491            }
492            sym::atomic_xchg => {
493                let ty = fn_args.type_at(0);
494                let ordering = fn_args.const_at(1).to_value();
495                if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
496                    let ptr = args[0].immediate();
497                    let val = args[1].immediate();
498                    let atomic_op = AtomicRmwBinOp::AtomicXchg;
499                    OperandValue::Immediate(bx.atomic_rmw(
500                        atomic_op,
501                        ptr,
502                        val,
503                        parse_atomic_ordering(ordering),
504                        /* ret_ptr */ ty.is_raw_ptr(),
505                    ))
506                } else {
507                    let err = invalid_monomorphization_int_or_ptr_type(ty);
508                    return IntrinsicResult::Err(err);
509                }
510            }
511            sym::atomic_xadd
512            | sym::atomic_xsub
513            | sym::atomic_and
514            | sym::atomic_nand
515            | sym::atomic_or
516            | sym::atomic_xor => {
517                let atom_op = match name {
518                    sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd,
519                    sym::atomic_xsub => AtomicRmwBinOp::AtomicSub,
520                    sym::atomic_and => AtomicRmwBinOp::AtomicAnd,
521                    sym::atomic_nand => AtomicRmwBinOp::AtomicNand,
522                    sym::atomic_or => AtomicRmwBinOp::AtomicOr,
523                    sym::atomic_xor => AtomicRmwBinOp::AtomicXor,
524                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
525                };
526
527                // The type of the in-memory data.
528                let ty_mem = fn_args.type_at(0);
529                // The type of the 2nd operand, given by-value.
530                let ty_op = fn_args.type_at(1);
531
532                let ordering = fn_args.const_at(2).to_value();
533                // We require either both arguments to have the same integer type, or the first to
534                // be a pointer and the second to be `usize`.
535                if (int_type_width_signed(ty_mem, bx.tcx()).is_some() && ty_op == ty_mem)
536                    || (ty_mem.is_raw_ptr() && ty_op == bx.tcx().types.usize)
537                {
538                    let ptr = args[0].immediate(); // of type "pointer to `ty_mem`"
539                    let val = args[1].immediate(); // of type `ty_op`
540                    OperandValue::Immediate(bx.atomic_rmw(
541                        atom_op,
542                        ptr,
543                        val,
544                        parse_atomic_ordering(ordering),
545                        /* ret_ptr */ ty_mem.is_raw_ptr(),
546                    ))
547                } else {
548                    let err = invalid_monomorphization_int_or_ptr_type(ty_mem);
549                    return IntrinsicResult::Err(err);
550                }
551            }
552            sym::atomic_fence => {
553                let ordering = fn_args.const_at(0).to_value();
554                bx.atomic_fence(parse_atomic_ordering(ordering), SynchronizationScope::CrossThread);
555                OperandValue::ZeroSized
556            }
557
558            sym::atomic_singlethreadfence => {
559                let ordering = fn_args.const_at(0).to_value();
560                bx.atomic_fence(
561                    parse_atomic_ordering(ordering),
562                    SynchronizationScope::SingleThread,
563                );
564                OperandValue::ZeroSized
565            }
566
567            sym::nontemporal_store => {
568                let dst = args[0].deref(bx.cx());
569                args[1].val.nontemporal_store(bx, dst);
570                OperandValue::ZeroSized
571            }
572
573            sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
574                let ty = fn_args.type_at(0);
575                let pointee_size = bx.layout_of(ty).size;
576
577                let a = args[0].immediate();
578                let b = args[1].immediate();
579                let a = bx.ptrtoint(a, bx.type_isize());
580                let b = bx.ptrtoint(b, bx.type_isize());
581                let pointee_size = bx.const_usize(pointee_size.bytes());
582                OperandValue::Immediate(if name == sym::ptr_offset_from {
583                    // This is the same sequence that Clang emits for pointer subtraction.
584                    // It can be neither `nsw` nor `nuw` because the input is treated as
585                    // unsigned but then the output is treated as signed, so neither works.
586                    let d = bx.sub(a, b);
587                    // this is where the signed magic happens (notice the `s` in `exactsdiv`)
588                    bx.exactsdiv(d, pointee_size)
589                } else {
590                    // The `_unsigned` version knows the relative ordering of the pointers,
591                    // so can use `sub nuw` and `udiv exact` instead of dealing in signed.
592                    let d = bx.unchecked_usub(a, b);
593                    bx.exactudiv(d, pointee_size)
594                })
595            }
596
597            sym::cold_path => {
598                // This is a no-op. The intrinsic is just a hint to the optimizer.
599                OperandValue::ZeroSized
600            }
601
602            _ => {
603                // Need to use backend-specific things in the implementation.
604                let result =
605                    bx.codegen_intrinsic_call(instance, args, result_layout, result_place, span);
606                if let IntrinsicResult::Operand(op) = result {
607                    op
608                } else {
609                    return result;
610                }
611            }
612        };
613
614        if true {
    if !op_val.is_expected_variant_for_type(result_layout) {
        {
            ::core::panicking::panic_fmt(format_args!("[{0:?}] Value {1:?} is wrong for type {2:?}",
                    name, op_val, result_layout));
        }
    };
};debug_assert!(
615            op_val.is_expected_variant_for_type(result_layout),
616            "[{name:?}] Value {op_val:?} is wrong for type {result_layout:?}",
617        );
618
619        IntrinsicResult::Operand(op_val)
620    }
621}
622
623// Returns the width of an int Ty, and if it's signed or not
624// Returns None if the type is not an integer
625// FIXME: there’s multiple of this functions, investigate using some of the already existing
626// stuffs.
627fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
628    match ty.kind() {
629        ty::Int(t) => {
630            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true))
631        }
632        ty::Uint(t) => {
633            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false))
634        }
635        _ => None,
636    }
637}
638
639// Returns the width of a float Ty
640// Returns None if the type is not a float
641fn float_type_width(ty: Ty<'_>) -> Option<u64> {
642    match ty.kind() {
643        ty::Float(t) => Some(t.bit_width()),
644        _ => None,
645    }
646}