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);
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);
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 layout = bx.layout_of(ty);
385                let source = args[0].immediate();
386                OperandValue::Immediate(bx.atomic_load(
387                    bx.backend_type(layout),
388                    source,
389                    parse_atomic_ordering(ordering),
390                    layout.size,
391                ))
392            }
393            sym::atomic_store => {
394                let ty = fn_args.type_at(0);
395                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
396                    let err = invalid_monomorphization_int_or_ptr_type(ty);
397                    return IntrinsicResult::Err(err);
398                }
399                let ordering = fn_args.const_at(1).to_value();
400                let size = bx.layout_of(ty).size;
401                let val = args[1].immediate();
402                let ptr = args[0].immediate();
403                bx.atomic_store(val, ptr, parse_atomic_ordering(ordering), size);
404                OperandValue::ZeroSized
405            }
406            // These are all AtomicRMW ops
407            sym::atomic_cxchg | sym::atomic_cxchgweak => {
408                let ty = fn_args.type_at(0);
409                if !(int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr()) {
410                    let err = invalid_monomorphization_int_or_ptr_type(ty);
411                    return IntrinsicResult::Err(err);
412                }
413                let succ_ordering = fn_args.const_at(1).to_value();
414                let fail_ordering = fn_args.const_at(2).to_value();
415                let weak = name == sym::atomic_cxchgweak;
416                let dst = args[0].immediate();
417                let cmp = args[1].immediate();
418                let src = args[2].immediate();
419                let (val, success) = bx.atomic_cmpxchg(
420                    dst,
421                    cmp,
422                    src,
423                    parse_atomic_ordering(succ_ordering),
424                    parse_atomic_ordering(fail_ordering),
425                    weak,
426                );
427                let val = bx.from_immediate(val);
428                let success = bx.from_immediate(success);
429
430                let mut builder = OperandRefBuilder::new(result_layout);
431                builder.insert_imm(FieldIdx::from_u32(0), val);
432                builder.insert_imm(FieldIdx::from_u32(1), success);
433                builder.build(bx.cx()).val
434            }
435            sym::atomic_max | sym::atomic_min => {
436                let atom_op = if name == sym::atomic_max {
437                    AtomicRmwBinOp::AtomicMax
438                } else {
439                    AtomicRmwBinOp::AtomicMin
440                };
441
442                let ty = fn_args.type_at(0);
443                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Int(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Int(_)) {
444                    let ordering = fn_args.const_at(1).to_value();
445                    let ptr = args[0].immediate();
446                    let val = args[1].immediate();
447                    OperandValue::Immediate(bx.atomic_rmw(
448                        atom_op,
449                        ptr,
450                        val,
451                        parse_atomic_ordering(ordering),
452                        /* ret_ptr */ false,
453                    ))
454                } else {
455                    let err = invalid_monomorphization_int_type(ty);
456                    return IntrinsicResult::Err(err);
457                }
458            }
459            sym::atomic_umax | sym::atomic_umin => {
460                let atom_op = if name == sym::atomic_umax {
461                    AtomicRmwBinOp::AtomicUMax
462                } else {
463                    AtomicRmwBinOp::AtomicUMin
464                };
465
466                let ty = fn_args.type_at(0);
467                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Uint(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Uint(_)) {
468                    let ordering = fn_args.const_at(1).to_value();
469                    let ptr = args[0].immediate();
470                    let val = args[1].immediate();
471                    OperandValue::Immediate(bx.atomic_rmw(
472                        atom_op,
473                        ptr,
474                        val,
475                        parse_atomic_ordering(ordering),
476                        /* ret_ptr */ false,
477                    ))
478                } else {
479                    let err = invalid_monomorphization_int_type(ty);
480                    return IntrinsicResult::Err(err);
481                }
482            }
483            sym::atomic_xchg => {
484                let ty = fn_args.type_at(0);
485                let ordering = fn_args.const_at(1).to_value();
486                if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
487                    let ptr = args[0].immediate();
488                    let val = args[1].immediate();
489                    let atomic_op = AtomicRmwBinOp::AtomicXchg;
490                    OperandValue::Immediate(bx.atomic_rmw(
491                        atomic_op,
492                        ptr,
493                        val,
494                        parse_atomic_ordering(ordering),
495                        /* ret_ptr */ ty.is_raw_ptr(),
496                    ))
497                } else {
498                    let err = invalid_monomorphization_int_or_ptr_type(ty);
499                    return IntrinsicResult::Err(err);
500                }
501            }
502            sym::atomic_xadd
503            | sym::atomic_xsub
504            | sym::atomic_and
505            | sym::atomic_nand
506            | sym::atomic_or
507            | sym::atomic_xor => {
508                let atom_op = match name {
509                    sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd,
510                    sym::atomic_xsub => AtomicRmwBinOp::AtomicSub,
511                    sym::atomic_and => AtomicRmwBinOp::AtomicAnd,
512                    sym::atomic_nand => AtomicRmwBinOp::AtomicNand,
513                    sym::atomic_or => AtomicRmwBinOp::AtomicOr,
514                    sym::atomic_xor => AtomicRmwBinOp::AtomicXor,
515                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
516                };
517
518                // The type of the in-memory data.
519                let ty_mem = fn_args.type_at(0);
520                // The type of the 2nd operand, given by-value.
521                let ty_op = fn_args.type_at(1);
522
523                let ordering = fn_args.const_at(2).to_value();
524                // We require either both arguments to have the same integer type, or the first to
525                // be a pointer and the second to be `usize`.
526                if (int_type_width_signed(ty_mem, bx.tcx()).is_some() && ty_op == ty_mem)
527                    || (ty_mem.is_raw_ptr() && ty_op == bx.tcx().types.usize)
528                {
529                    let ptr = args[0].immediate(); // of type "pointer to `ty_mem`"
530                    let val = args[1].immediate(); // of type `ty_op`
531                    OperandValue::Immediate(bx.atomic_rmw(
532                        atom_op,
533                        ptr,
534                        val,
535                        parse_atomic_ordering(ordering),
536                        /* ret_ptr */ ty_mem.is_raw_ptr(),
537                    ))
538                } else {
539                    let err = invalid_monomorphization_int_or_ptr_type(ty_mem);
540                    return IntrinsicResult::Err(err);
541                }
542            }
543            sym::atomic_fence => {
544                let ordering = fn_args.const_at(0).to_value();
545                bx.atomic_fence(parse_atomic_ordering(ordering), SynchronizationScope::CrossThread);
546                OperandValue::ZeroSized
547            }
548
549            sym::atomic_singlethreadfence => {
550                let ordering = fn_args.const_at(0).to_value();
551                bx.atomic_fence(
552                    parse_atomic_ordering(ordering),
553                    SynchronizationScope::SingleThread,
554                );
555                OperandValue::ZeroSized
556            }
557
558            sym::nontemporal_store => {
559                let dst = args[0].deref(bx.cx());
560                args[1].val.nontemporal_store(bx, dst);
561                OperandValue::ZeroSized
562            }
563
564            sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
565                let ty = fn_args.type_at(0);
566                let pointee_size = bx.layout_of(ty).size;
567
568                let a = args[0].immediate();
569                let b = args[1].immediate();
570                let a = bx.ptrtoint(a, bx.type_isize());
571                let b = bx.ptrtoint(b, bx.type_isize());
572                let pointee_size = bx.const_usize(pointee_size.bytes());
573                OperandValue::Immediate(if name == sym::ptr_offset_from {
574                    // This is the same sequence that Clang emits for pointer subtraction.
575                    // It can be neither `nsw` nor `nuw` because the input is treated as
576                    // unsigned but then the output is treated as signed, so neither works.
577                    let d = bx.sub(a, b);
578                    // this is where the signed magic happens (notice the `s` in `exactsdiv`)
579                    bx.exactsdiv(d, pointee_size)
580                } else {
581                    // The `_unsigned` version knows the relative ordering of the pointers,
582                    // so can use `sub nuw` and `udiv exact` instead of dealing in signed.
583                    let d = bx.unchecked_usub(a, b);
584                    bx.exactudiv(d, pointee_size)
585                })
586            }
587
588            sym::cold_path => {
589                // This is a no-op. The intrinsic is just a hint to the optimizer.
590                OperandValue::ZeroSized
591            }
592
593            _ => {
594                // Need to use backend-specific things in the implementation.
595                let result =
596                    bx.codegen_intrinsic_call(instance, args, result_layout, result_place, span);
597                if let IntrinsicResult::Operand(op) = result {
598                    op
599                } else {
600                    return result;
601                }
602            }
603        };
604
605        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!(
606            op_val.is_expected_variant_for_type(result_layout),
607            "[{name:?}] Value {op_val:?} is wrong for type {result_layout:?}",
608        );
609
610        IntrinsicResult::Operand(op_val)
611    }
612}
613
614// Returns the width of an int Ty, and if it's signed or not
615// Returns None if the type is not an integer
616// FIXME: there’s multiple of this functions, investigate using some of the already existing
617// stuffs.
618fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
619    match ty.kind() {
620        ty::Int(t) => {
621            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true))
622        }
623        ty::Uint(t) => {
624            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false))
625        }
626        _ => None,
627    }
628}
629
630// Returns the width of a float Ty
631// Returns None if the type is not a float
632fn float_type_width(ty: Ty<'_>) -> Option<u64> {
633    match ty.kind() {
634        ty::Float(t) => Some(t.bit_width()),
635        _ => None,
636    }
637}