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