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_session::config::OptLevel;
5use rustc_span::{ErrorGuaranteed, bug, span_bug, sym};
6use rustc_target::spec::Arch;
7
8use super::operand::{OperandRef, OperandValue};
9use super::place::PlaceValue;
10use super::{FunctionCx, IntrinsicResult};
11use crate::common::{AtomicRmwBinOp, SynchronizationScope};
12use crate::diagnostics::InvalidMonomorphization;
13use crate::mir::operand::OperandRefBuilder;
14use crate::traits::*;
15use crate::{MemFlags, meth, size_of_val};
16
17fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
18    bx: &mut Bx,
19    allow_overlap: bool,
20    volatile: bool,
21    ty: Ty<'tcx>,
22    dst: Bx::Value,
23    src: Bx::Value,
24    count: Bx::Value,
25) {
26    let layout = bx.layout_of(ty);
27    let size = layout.size;
28    let align = layout.align.abi;
29    let size = bx.unchecked_sumul(bx.const_usize(size.bytes()), count);
30    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
31    if allow_overlap {
32        bx.memmove(dst, align, src, align, size, flags);
33    } else {
34        bx.memcpy(dst, align, src, align, size, flags, None);
35    }
36}
37
38fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
39    bx: &mut Bx,
40    volatile: bool,
41    ty: Ty<'tcx>,
42    dst: Bx::Value,
43    val: Bx::Value,
44    count: Bx::Value,
45) {
46    let layout = bx.layout_of(ty);
47    let size = layout.size;
48    let align = layout.align.abi;
49    let size = bx.mul(bx.const_usize(size.bytes()), count);
50    let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() };
51    bx.memset(dst, val, size, align, flags);
52}
53
54impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
55    /// In the `Fallback` case, returns the instance that should be called instead.
56    pub fn codegen_intrinsic_call(
57        &mut self,
58        bx: &mut Bx,
59        instance: ty::Instance<'tcx>,
60        args: &[OperandRef<'tcx, Bx::Value>],
61        result_layout: ty::layout::TyAndLayout<'tcx>,
62        result_place: Option<PlaceValue<Bx::Value>>,
63        source_info: SourceInfo,
64    ) -> IntrinsicResult<'tcx, Bx::Value> {
65        // When `-Zforce-intrinsic-fallback` is enabled, always use the fallback body if it exists,
66        if bx.tcx().sess.opts.unstable_opts.force_intrinsic_fallback
67            && let Some(def) = bx.tcx().intrinsic(instance.def_id())
68            && !def.must_be_overridden
69        {
70            return IntrinsicResult::Fallback(ty::Instance::new_raw(
71                instance.def_id(),
72                instance.args,
73            ));
74        }
75
76        let span = source_info.span;
77
78        let name = bx.tcx().item_name(instance.def_id());
79        let fn_args = instance.args;
80
81        // If we're swapping something that's *not* an `OperandValue::Ref`,
82        // then we can do it directly and avoid the alloca.
83        // Otherwise, we'll let the fallback MIR body take care of it.
84        if let sym::typed_swap_nonoverlapping = name {
85            let pointee_ty = fn_args.type_at(0);
86            let pointee_layout = bx.layout_of(pointee_ty);
87            if pointee_layout.is_ssa_standalone()
88                // But if we're not going to optimize, trying to use the fallback
89                // body just makes things worse, so don't bother.
90                || bx.sess().opts.optimize == OptLevel::No
91                // NOTE(eddyb) SPIR-V's Logical addressing model doesn't allow for arbitrary
92                // reinterpretation of values as (chunkable) byte arrays, and the loop in the
93                // block optimization in `ptr::swap_nonoverlapping` is hard to rewrite back
94                // into the (unoptimized) direct swapping implementation, so we disable it.
95                || bx.sess().target.arch == Arch::SpirV
96            {
97                let align = pointee_layout.align.abi;
98                let x_place = args[0].val.deref(align);
99                let y_place = args[1].val.deref(align);
100                bx.typed_place_swap(x_place, y_place, pointee_layout);
101                return IntrinsicResult::Operand(OperandValue::ZeroSized);
102            }
103        }
104
105        let invalid_monomorphization_int_type = |ty| -> ErrorGuaranteed {
106            bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerType { span, name, ty })
107        };
108        let invalid_monomorphization_int_or_ptr_type = |ty| -> ErrorGuaranteed {
109            bx.tcx().dcx().emit_err(InvalidMonomorphization::BasicIntegerOrPtrType {
110                span,
111                name,
112                ty,
113            })
114        };
115
116        let parse_atomic_ordering = |ord: ty::Value<'tcx>| {
117            let discr = ord.to_branch()[0].to_leaf();
118            discr.to_atomic_ordering()
119        };
120
121        if args.is_empty() {
122            match name {
123                sym::abort
124                | sym::unreachable
125                | sym::cold_path
126                | sym::gpu_launch_sized_workgroup_mem
127                | sym::breakpoint
128                | sym::amdgpu_dispatch_ptr
129                | sym::assert_zero_valid
130                | sym::assert_mem_uninitialized_valid
131                | sym::assert_inhabited
132                | sym::ub_checks
133                | sym::contract_checks
134                | sym::atomic_fence
135                | sym::atomic_singlethreadfence
136                | sym::caller_location
137                | sym::offload_get_num_devices
138                | sym::return_address => {}
139                _ => {
140                    bug_impl(Some(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), Location::caller());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                    _ => bug_impl(None, format_args!("impossible case reached"), Location::caller())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                        _ => bug_impl(None, format_args!("impossible case reached"), Location::caller())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                    _ => bug_impl(None, format_args!("impossible case reached"), Location::caller())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
437                let mut builder = OperandRefBuilder::new(result_layout);
438                builder.insert_imm(FieldIdx::from_u32(0), val);
439                builder.insert_imm(FieldIdx::from_u32(1), success);
440                builder.build(bx.cx()).val
441            }
442            sym::atomic_max | sym::atomic_min => {
443                let atom_op = if name == sym::atomic_max {
444                    AtomicRmwBinOp::AtomicMax
445                } else {
446                    AtomicRmwBinOp::AtomicMin
447                };
448
449                let ty = fn_args.type_at(0);
450                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Int(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Int(_)) {
451                    let ordering = fn_args.const_at(1).to_value();
452                    let ptr = args[0].immediate();
453                    let val = args[1].immediate();
454                    OperandValue::Immediate(bx.atomic_rmw(
455                        atom_op,
456                        ptr,
457                        val,
458                        parse_atomic_ordering(ordering),
459                        /* ret_ptr */ false,
460                    ))
461                } else {
462                    let err = invalid_monomorphization_int_type(ty);
463                    return IntrinsicResult::Err(err);
464                }
465            }
466            sym::atomic_umax | sym::atomic_umin => {
467                let atom_op = if name == sym::atomic_umax {
468                    AtomicRmwBinOp::AtomicUMax
469                } else {
470                    AtomicRmwBinOp::AtomicUMin
471                };
472
473                let ty = fn_args.type_at(0);
474                if #[allow(non_exhaustive_omitted_patterns)] match ty.kind() {
    ty::Uint(_) => true,
    _ => false,
}matches!(ty.kind(), ty::Uint(_)) {
475                    let ordering = fn_args.const_at(1).to_value();
476                    let ptr = args[0].immediate();
477                    let val = args[1].immediate();
478                    OperandValue::Immediate(bx.atomic_rmw(
479                        atom_op,
480                        ptr,
481                        val,
482                        parse_atomic_ordering(ordering),
483                        /* ret_ptr */ false,
484                    ))
485                } else {
486                    let err = invalid_monomorphization_int_type(ty);
487                    return IntrinsicResult::Err(err);
488                }
489            }
490            sym::atomic_xchg => {
491                let ty = fn_args.type_at(0);
492                let ordering = fn_args.const_at(1).to_value();
493                if int_type_width_signed(ty, bx.tcx()).is_some() || ty.is_raw_ptr() {
494                    let ptr = args[0].immediate();
495                    let val = args[1].immediate();
496                    let atomic_op = AtomicRmwBinOp::AtomicXchg;
497                    OperandValue::Immediate(bx.atomic_rmw(
498                        atomic_op,
499                        ptr,
500                        val,
501                        parse_atomic_ordering(ordering),
502                        /* ret_ptr */ ty.is_raw_ptr(),
503                    ))
504                } else {
505                    let err = invalid_monomorphization_int_or_ptr_type(ty);
506                    return IntrinsicResult::Err(err);
507                }
508            }
509            sym::atomic_xadd
510            | sym::atomic_xsub
511            | sym::atomic_and
512            | sym::atomic_nand
513            | sym::atomic_or
514            | sym::atomic_xor => {
515                let atom_op = match name {
516                    sym::atomic_xadd => AtomicRmwBinOp::AtomicAdd,
517                    sym::atomic_xsub => AtomicRmwBinOp::AtomicSub,
518                    sym::atomic_and => AtomicRmwBinOp::AtomicAnd,
519                    sym::atomic_nand => AtomicRmwBinOp::AtomicNand,
520                    sym::atomic_or => AtomicRmwBinOp::AtomicOr,
521                    sym::atomic_xor => AtomicRmwBinOp::AtomicXor,
522                    _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
523                };
524
525                // The type of the in-memory data.
526                let ty_mem = fn_args.type_at(0);
527                // The type of the 2nd operand, given by-value.
528                let ty_op = fn_args.type_at(1);
529
530                let ordering = fn_args.const_at(2).to_value();
531                // We require either both arguments to have the same integer type, or the first to
532                // be a pointer and the second to be `usize`.
533                if (int_type_width_signed(ty_mem, bx.tcx()).is_some() && ty_op == ty_mem)
534                    || (ty_mem.is_raw_ptr() && ty_op == bx.tcx().types.usize)
535                {
536                    let ptr = args[0].immediate(); // of type "pointer to `ty_mem`"
537                    let val = args[1].immediate(); // of type `ty_op`
538                    OperandValue::Immediate(bx.atomic_rmw(
539                        atom_op,
540                        ptr,
541                        val,
542                        parse_atomic_ordering(ordering),
543                        /* ret_ptr */ ty_mem.is_raw_ptr(),
544                    ))
545                } else {
546                    let err = invalid_monomorphization_int_or_ptr_type(ty_mem);
547                    return IntrinsicResult::Err(err);
548                }
549            }
550            sym::atomic_fence => {
551                let ordering = fn_args.const_at(0).to_value();
552                bx.atomic_fence(parse_atomic_ordering(ordering), SynchronizationScope::CrossThread);
553                OperandValue::ZeroSized
554            }
555
556            sym::atomic_singlethreadfence => {
557                let ordering = fn_args.const_at(0).to_value();
558                bx.atomic_fence(
559                    parse_atomic_ordering(ordering),
560                    SynchronizationScope::SingleThread,
561                );
562                OperandValue::ZeroSized
563            }
564
565            sym::nontemporal_store => {
566                let dst = args[0].deref(bx.cx());
567                args[1].val.nontemporal_store(bx, dst);
568                OperandValue::ZeroSized
569            }
570
571            sym::ptr_offset_from | sym::ptr_offset_from_unsigned => {
572                let ty = fn_args.type_at(0);
573                let pointee_size = bx.layout_of(ty).size;
574
575                let a = args[0].immediate();
576                let b = args[1].immediate();
577                let a = bx.ptrtoint(a, bx.type_isize());
578                let b = bx.ptrtoint(b, bx.type_isize());
579                let pointee_size = bx.const_usize(pointee_size.bytes());
580                OperandValue::Immediate(if name == sym::ptr_offset_from {
581                    // This is the same sequence that Clang emits for pointer subtraction.
582                    // It can be neither `nsw` nor `nuw` because the input is treated as
583                    // unsigned but then the output is treated as signed, so neither works.
584                    let d = bx.sub(a, b);
585                    // this is where the signed magic happens (notice the `s` in `exactsdiv`)
586                    bx.exactsdiv(d, pointee_size)
587                } else {
588                    // The `_unsigned` version knows the relative ordering of the pointers,
589                    // so can use `sub nuw` and `udiv exact` instead of dealing in signed.
590                    let d = bx.unchecked_usub(a, b);
591                    bx.exactudiv(d, pointee_size)
592                })
593            }
594
595            sym::cold_path => {
596                // This is a no-op. The intrinsic is just a hint to the optimizer.
597                OperandValue::ZeroSized
598            }
599
600            _ => {
601                // Need to use backend-specific things in the implementation.
602                let result =
603                    bx.codegen_intrinsic_call(instance, args, result_layout, result_place, span);
604                if let IntrinsicResult::Operand(op) = result {
605                    op
606                } else {
607                    return result;
608                }
609            }
610        };
611
612        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!(
613            op_val.is_expected_variant_for_type(result_layout),
614            "[{name:?}] Value {op_val:?} is wrong for type {result_layout:?}",
615        );
616
617        IntrinsicResult::Operand(op_val)
618    }
619}
620
621// Returns the width of an int Ty, and if it's signed or not
622// Returns None if the type is not an integer
623// FIXME: there’s multiple of this functions, investigate using some of the already existing
624// stuffs.
625fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> {
626    match ty.kind() {
627        ty::Int(t) => {
628            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), true))
629        }
630        ty::Uint(t) => {
631            Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.pointer_width)), false))
632        }
633        _ => None,
634    }
635}
636
637// Returns the width of a float Ty
638// Returns None if the type is not a float
639fn float_type_width(ty: Ty<'_>) -> Option<u64> {
640    match ty.kind() {
641        ty::Float(t) => Some(t.bit_width()),
642        _ => None,
643    }
644}