Skip to main content

rustc_codegen_ssa/mir/
intrinsic.rs

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