1 use super::operand
::{OperandRef, OperandValue}
;
2 use super::place
::PlaceRef
;
4 use crate::common
::{span_invalid_monomorphization_error, IntPredicate}
;
9 use rustc_middle
::ty
::{self, Ty, TyCtxt}
;
10 use rustc_span
::{sym, Span}
;
11 use rustc_target
::abi
::call
::{FnAbi, PassMode}
;
13 fn copy_intrinsic
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
22 let layout
= bx
.layout_of(ty
);
23 let size
= layout
.size
;
24 let align
= layout
.align
.abi
;
25 let size
= bx
.mul(bx
.const_usize(size
.bytes()), count
);
26 let flags
= if volatile { MemFlags::VOLATILE }
else { MemFlags::empty() }
;
28 bx
.memmove(dst
, align
, src
, align
, size
, flags
);
30 bx
.memcpy(dst
, align
, src
, align
, size
, flags
);
34 fn memset_intrinsic
<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>>(
42 let layout
= bx
.layout_of(ty
);
43 let size
= layout
.size
;
44 let align
= layout
.align
.abi
;
45 let size
= bx
.mul(bx
.const_usize(size
.bytes()), count
);
46 let flags
= if volatile { MemFlags::VOLATILE }
else { MemFlags::empty() }
;
47 bx
.memset(dst
, val
, size
, align
, flags
);
50 impl<'a
, 'tcx
, Bx
: BuilderMethods
<'a
, 'tcx
>> FunctionCx
<'a
, 'tcx
, Bx
> {
51 pub fn codegen_intrinsic_call(
53 instance
: ty
::Instance
<'tcx
>,
54 fn_abi
: &FnAbi
<'tcx
, Ty
<'tcx
>>,
55 args
: &[OperandRef
<'tcx
, Bx
::Value
>],
59 let callee_ty
= instance
.ty(bx
.tcx(), ty
::ParamEnv
::reveal_all());
61 let (def_id
, substs
) = match *callee_ty
.kind() {
62 ty
::FnDef(def_id
, substs
) => (def_id
, substs
),
63 _
=> bug
!("expected fn item type, found {}", callee_ty
),
66 let sig
= callee_ty
.fn_sig(bx
.tcx());
67 let sig
= bx
.tcx().normalize_erasing_late_bound_regions(ty
::ParamEnv
::reveal_all(), &sig
);
68 let arg_tys
= sig
.inputs();
69 let ret_ty
= sig
.output();
70 let name
= bx
.tcx().item_name(def_id
);
71 let name_str
= &*name
.as_str();
73 let llret_ty
= bx
.backend_type(bx
.layout_of(ret_ty
));
74 let result
= PlaceRef
::new_sized(llresult
, fn_abi
.ret
.layout
);
76 let llval
= match name
{
78 bx
.assume(args
[0].immediate());
89 sym
::va_start
=> bx
.va_start(args
[0].immediate()),
90 sym
::va_end
=> bx
.va_end(args
[0].immediate()),
92 let tp_ty
= substs
.type_at(0);
93 if let OperandValue
::Pair(_
, meta
) = args
[0].val
{
94 let (llsize
, _
) = glue
::size_and_align_of_dst(bx
, tp_ty
, Some(meta
));
97 bx
.const_usize(bx
.layout_of(tp_ty
).size
.bytes())
100 sym
::min_align_of_val
=> {
101 let tp_ty
= substs
.type_at(0);
102 if let OperandValue
::Pair(_
, meta
) = args
[0].val
{
103 let (_
, llalign
) = glue
::size_and_align_of_dst(bx
, tp_ty
, Some(meta
));
106 bx
.const_usize(bx
.layout_of(tp_ty
).align
.abi
.bytes())
115 | sym
::variant_count
=> {
118 .const_eval_instance(ty
::ParamEnv
::reveal_all(), instance
, None
)
120 OperandRef
::from_const(bx
, value
, ret_ty
).immediate_or_packed_pair(bx
)
127 let ptr
= args
[0].immediate();
128 let offset
= args
[1].immediate();
129 bx
.inbounds_gep(ptr
, &[offset
])
131 sym
::arith_offset
=> {
132 let ptr
= args
[0].immediate();
133 let offset
= args
[1].immediate();
134 bx
.gep(ptr
, &[offset
])
137 sym
::copy_nonoverlapping
=> {
161 sym
::write_bytes
=> {
173 sym
::volatile_copy_nonoverlapping_memory
=> {
185 sym
::volatile_copy_memory
=> {
197 sym
::volatile_set_memory
=> {
208 sym
::volatile_store
=> {
209 let dst
= args
[0].deref(bx
.cx());
210 args
[1].val
.volatile_store(bx
, dst
);
213 sym
::unaligned_volatile_store
=> {
214 let dst
= args
[0].deref(bx
.cx());
215 args
[1].val
.unaligned_volatile_store(bx
, dst
);
218 sym
::add_with_overflow
219 | sym
::sub_with_overflow
220 | sym
::mul_with_overflow
231 | sym
::exact_div
=> {
233 match int_type_width_signed(ty
, bx
.tcx()) {
234 Some((_width
, signed
)) => match name
{
235 sym
::add_with_overflow
236 | sym
::sub_with_overflow
237 | sym
::mul_with_overflow
=> {
238 let op
= match name
{
239 sym
::add_with_overflow
=> OverflowOp
::Add
,
240 sym
::sub_with_overflow
=> OverflowOp
::Sub
,
241 sym
::mul_with_overflow
=> OverflowOp
::Mul
,
244 let (val
, overflow
) =
245 bx
.checked_binop(op
, ty
, args
[0].immediate(), args
[1].immediate());
246 // Convert `i1` to a `bool`, and write it to the out parameter
247 let val
= bx
.from_immediate(val
);
248 let overflow
= bx
.from_immediate(overflow
);
250 let dest
= result
.project_field(bx
, 0);
251 bx
.store(val
, dest
.llval
, dest
.align
);
252 let dest
= result
.project_field(bx
, 1);
253 bx
.store(overflow
, dest
.llval
, dest
.align
);
257 sym
::wrapping_add
=> bx
.add(args
[0].immediate(), args
[1].immediate()),
258 sym
::wrapping_sub
=> bx
.sub(args
[0].immediate(), args
[1].immediate()),
259 sym
::wrapping_mul
=> bx
.mul(args
[0].immediate(), args
[1].immediate()),
262 bx
.exactsdiv(args
[0].immediate(), args
[1].immediate())
264 bx
.exactudiv(args
[0].immediate(), args
[1].immediate())
267 sym
::unchecked_div
=> {
269 bx
.sdiv(args
[0].immediate(), args
[1].immediate())
271 bx
.udiv(args
[0].immediate(), args
[1].immediate())
274 sym
::unchecked_rem
=> {
276 bx
.srem(args
[0].immediate(), args
[1].immediate())
278 bx
.urem(args
[0].immediate(), args
[1].immediate())
281 sym
::unchecked_shl
=> bx
.shl(args
[0].immediate(), args
[1].immediate()),
282 sym
::unchecked_shr
=> {
284 bx
.ashr(args
[0].immediate(), args
[1].immediate())
286 bx
.lshr(args
[0].immediate(), args
[1].immediate())
289 sym
::unchecked_add
=> {
291 bx
.unchecked_sadd(args
[0].immediate(), args
[1].immediate())
293 bx
.unchecked_uadd(args
[0].immediate(), args
[1].immediate())
296 sym
::unchecked_sub
=> {
298 bx
.unchecked_ssub(args
[0].immediate(), args
[1].immediate())
300 bx
.unchecked_usub(args
[0].immediate(), args
[1].immediate())
303 sym
::unchecked_mul
=> {
305 bx
.unchecked_smul(args
[0].immediate(), args
[1].immediate())
307 bx
.unchecked_umul(args
[0].immediate(), args
[1].immediate())
313 span_invalid_monomorphization_error(
317 "invalid monomorphization of `{}` intrinsic: \
318 expected basic integer type, found `{}`",
326 sym
::fadd_fast
| sym
::fsub_fast
| sym
::fmul_fast
| sym
::fdiv_fast
| sym
::frem_fast
=> {
327 match float_type_width(arg_tys
[0]) {
328 Some(_width
) => match name
{
329 sym
::fadd_fast
=> bx
.fadd_fast(args
[0].immediate(), args
[1].immediate()),
330 sym
::fsub_fast
=> bx
.fsub_fast(args
[0].immediate(), args
[1].immediate()),
331 sym
::fmul_fast
=> bx
.fmul_fast(args
[0].immediate(), args
[1].immediate()),
332 sym
::fdiv_fast
=> bx
.fdiv_fast(args
[0].immediate(), args
[1].immediate()),
333 sym
::frem_fast
=> bx
.frem_fast(args
[0].immediate(), args
[1].immediate()),
337 span_invalid_monomorphization_error(
341 "invalid monomorphization of `{}` intrinsic: \
342 expected basic float type, found `{}`",
351 sym
::float_to_int_unchecked
=> {
352 if float_type_width(arg_tys
[0]).is_none() {
353 span_invalid_monomorphization_error(
357 "invalid monomorphization of `float_to_int_unchecked` \
358 intrinsic: expected basic float type, \
365 let (_width
, signed
) = match int_type_width_signed(ret_ty
, bx
.tcx()) {
368 span_invalid_monomorphization_error(
372 "invalid monomorphization of `float_to_int_unchecked` \
373 intrinsic: expected basic integer type, \
382 bx
.fptosi(args
[0].immediate(), llret_ty
)
384 bx
.fptoui(args
[0].immediate(), llret_ty
)
388 sym
::discriminant_value
=> {
389 if ret_ty
.is_integral() {
390 args
[0].deref(bx
.cx()).codegen_get_discr(bx
, ret_ty
)
392 span_bug
!(span
, "Invalid discriminant type for `{:?}`", arg_tys
[0])
396 // This requires that atomic intrinsics follow a specific naming pattern:
397 // "atomic_<operation>[_<ordering>]", and no ordering means SeqCst
398 name
if name_str
.starts_with("atomic_") => {
399 use crate::common
::AtomicOrdering
::*;
400 use crate::common
::{AtomicRmwBinOp, SynchronizationScope}
;
402 let split
: Vec
<&str> = name_str
.split('_'
).collect();
404 let is_cxchg
= split
[1] == "cxchg" || split
[1] == "cxchgweak";
405 let (order
, failorder
) = match split
.len() {
406 2 => (SequentiallyConsistent
, SequentiallyConsistent
),
407 3 => match split
[2] {
408 "unordered" => (Unordered
, Unordered
),
409 "relaxed" => (Monotonic
, Monotonic
),
410 "acq" => (Acquire
, Acquire
),
411 "rel" => (Release
, Monotonic
),
412 "acqrel" => (AcquireRelease
, Acquire
),
413 "failrelaxed" if is_cxchg
=> (SequentiallyConsistent
, Monotonic
),
414 "failacq" if is_cxchg
=> (SequentiallyConsistent
, Acquire
),
415 _
=> bx
.sess().fatal("unknown ordering in atomic intrinsic"),
417 4 => match (split
[2], split
[3]) {
418 ("acq", "failrelaxed") if is_cxchg
=> (Acquire
, Monotonic
),
419 ("acqrel", "failrelaxed") if is_cxchg
=> (AcquireRelease
, Monotonic
),
420 _
=> bx
.sess().fatal("unknown ordering in atomic intrinsic"),
422 _
=> bx
.sess().fatal("Atomic intrinsic not in correct format"),
425 let invalid_monomorphization
= |ty
| {
426 span_invalid_monomorphization_error(
430 "invalid monomorphization of `{}` intrinsic: \
431 expected basic integer type, found `{}`",
438 "cxchg" | "cxchgweak" => {
439 let ty
= substs
.type_at(0);
440 if int_type_width_signed(ty
, bx
.tcx()).is_some() {
441 let weak
= split
[1] == "cxchgweak";
442 let pair
= bx
.atomic_cmpxchg(
450 let val
= bx
.extract_value(pair
, 0);
451 let success
= bx
.extract_value(pair
, 1);
452 let val
= bx
.from_immediate(val
);
453 let success
= bx
.from_immediate(success
);
455 let dest
= result
.project_field(bx
, 0);
456 bx
.store(val
, dest
.llval
, dest
.align
);
457 let dest
= result
.project_field(bx
, 1);
458 bx
.store(success
, dest
.llval
, dest
.align
);
461 return invalid_monomorphization(ty
);
466 let ty
= substs
.type_at(0);
467 if int_type_width_signed(ty
, bx
.tcx()).is_some() {
468 let size
= bx
.layout_of(ty
).size
;
469 bx
.atomic_load(args
[0].immediate(), order
, size
)
471 return invalid_monomorphization(ty
);
476 let ty
= substs
.type_at(0);
477 if int_type_width_signed(ty
, bx
.tcx()).is_some() {
478 let size
= bx
.layout_of(ty
).size
;
479 bx
.atomic_store(args
[1].immediate(), args
[0].immediate(), order
, size
);
482 return invalid_monomorphization(ty
);
487 bx
.atomic_fence(order
, SynchronizationScope
::CrossThread
);
491 "singlethreadfence" => {
492 bx
.atomic_fence(order
, SynchronizationScope
::SingleThread
);
496 // These are all AtomicRMW ops
498 let atom_op
= match op
{
499 "xchg" => AtomicRmwBinOp
::AtomicXchg
,
500 "xadd" => AtomicRmwBinOp
::AtomicAdd
,
501 "xsub" => AtomicRmwBinOp
::AtomicSub
,
502 "and" => AtomicRmwBinOp
::AtomicAnd
,
503 "nand" => AtomicRmwBinOp
::AtomicNand
,
504 "or" => AtomicRmwBinOp
::AtomicOr
,
505 "xor" => AtomicRmwBinOp
::AtomicXor
,
506 "max" => AtomicRmwBinOp
::AtomicMax
,
507 "min" => AtomicRmwBinOp
::AtomicMin
,
508 "umax" => AtomicRmwBinOp
::AtomicUMax
,
509 "umin" => AtomicRmwBinOp
::AtomicUMin
,
510 _
=> bx
.sess().fatal("unknown atomic operation"),
513 let ty
= substs
.type_at(0);
514 if int_type_width_signed(ty
, bx
.tcx()).is_some() {
515 bx
.atomic_rmw(atom_op
, args
[0].immediate(), args
[1].immediate(), order
)
517 return invalid_monomorphization(ty
);
523 sym
::nontemporal_store
=> {
524 let dst
= args
[0].deref(bx
.cx());
525 args
[1].val
.nontemporal_store(bx
, dst
);
529 sym
::ptr_guaranteed_eq
| sym
::ptr_guaranteed_ne
=> {
530 let a
= args
[0].immediate();
531 let b
= args
[1].immediate();
532 if name
== sym
::ptr_guaranteed_eq
{
533 bx
.icmp(IntPredicate
::IntEQ
, a
, b
)
535 bx
.icmp(IntPredicate
::IntNE
, a
, b
)
539 sym
::ptr_offset_from
=> {
540 let ty
= substs
.type_at(0);
541 let pointee_size
= bx
.layout_of(ty
).size
;
543 // This is the same sequence that Clang emits for pointer subtraction.
544 // It can be neither `nsw` nor `nuw` because the input is treated as
545 // unsigned but then the output is treated as signed, so neither works.
546 let a
= args
[0].immediate();
547 let b
= args
[1].immediate();
548 let a
= bx
.ptrtoint(a
, bx
.type_isize());
549 let b
= bx
.ptrtoint(b
, bx
.type_isize());
550 let d
= bx
.sub(a
, b
);
551 let pointee_size
= bx
.const_usize(pointee_size
.bytes());
552 // this is where the signed magic happens (notice the `s` in `exactsdiv`)
553 bx
.exactsdiv(d
, pointee_size
)
557 // Need to use backend-specific things in the implementation.
558 bx
.codegen_intrinsic_call(instance
, fn_abi
, args
, llresult
, span
);
563 if !fn_abi
.ret
.is_ignore() {
564 if let PassMode
::Cast(ty
) = fn_abi
.ret
.mode
{
565 let ptr_llty
= bx
.type_ptr_to(bx
.cast_backend_type(&ty
));
566 let ptr
= bx
.pointercast(result
.llval
, ptr_llty
);
567 bx
.store(llval
, ptr
, result
.align
);
569 OperandRef
::from_immediate_or_packed_pair(bx
, llval
, result
.layout
)
577 // Returns the width of an int Ty, and if it's signed or not
578 // Returns None if the type is not an integer
579 // FIXME: there’s multiple of this functions, investigate using some of the already existing
581 fn int_type_width_signed(ty
: Ty
<'_
>, tcx
: TyCtxt
<'_
>) -> Option
<(u64, bool
)> {
583 ty
::Int(t
) => Some((t
.bit_width().unwrap_or(u64::from(tcx
.sess
.target
.ptr_width
)), true)),
584 ty
::Uint(t
) => Some((t
.bit_width().unwrap_or(u64::from(tcx
.sess
.target
.ptr_width
)), false)),
589 // Returns the width of a float Ty
590 // Returns None if the type is not a float
591 fn float_type_width(ty
: Ty
<'_
>) -> Option
<u64> {
593 ty
::Float(t
) => Some(t
.bit_width()),