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