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