rustc_const_eval/interpret/intrinsics/
atomic.rs1use rustc_middle::mir::BinOp;
2use rustc_middle::{mir, span_bug, ty};
3use rustc_span::{Symbol, sym};
4use tracing::trace;
5
6use super::{
7 AtomicRmwOp, Immediate, InterpCx, InterpResult, Machine, OpTy, PlaceTy, Scalar, interp_ok,
8};
9
10impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
11 pub fn eval_atomic_intrinsic(
15 &mut self,
16 intrinsic_name: Symbol,
17 generic_args: ty::GenericArgsRef<'tcx>,
18 args: &[OpTy<'tcx, M::Provenance>],
19 dest: &PlaceTy<'tcx, M::Provenance>,
20 ret: Option<mir::BasicBlock>,
21 ) -> InterpResult<'tcx, bool> {
22 let get_ord_at = |i: usize| {
23 let ordering = generic_args.const_at(i).to_value();
24 ordering.to_branch()[0].to_value().to_leaf().to_atomic_ordering()
25 };
26
27 match intrinsic_name {
28 sym::atomic_load => {
29 let ord = get_ord_at(1);
30 let _volatile = generic_args.const_at(2).to_value(); let [ptr] = args else { ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid `atomic_load` call"))span_bug!(self.cur_span(), "invalid `atomic_load` call") };
32
33 let place = self.deref_pointer(ptr)?;
34 let val = M::atomic_load(self, &place, ord)?;
35 self.write_scalar(val, dest)?;
36 }
37 sym::atomic_store => {
38 let ord = get_ord_at(1);
39 let _volatile = generic_args.const_at(2).to_value(); let [ptr, val] = args else {
41 ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid `atomic_store` call"))span_bug!(self.cur_span(), "invalid `atomic_store` call")
42 };
43
44 let place = self.deref_pointer(ptr)?;
45 let val = self.read_immediate(val)?;
46 M::atomic_store(self, &place, &val, ord)?;
47 }
48 sym::atomic_or
49 | sym::atomic_xor
50 | sym::atomic_and
51 | sym::atomic_nand
52 | sym::atomic_xadd
53 | sym::atomic_xsub
54 | sym::atomic_min
55 | sym::atomic_umin
56 | sym::atomic_max
57 | sym::atomic_umax
58 | sym::atomic_xchg => {
59 let num_ty_generics = match intrinsic_name {
60 sym::atomic_min
61 | sym::atomic_umin
62 | sym::atomic_max
63 | sym::atomic_umax
64 | sym::atomic_xchg => 1,
65 _ => 2,
66 };
67 let ord = get_ord_at(num_ty_generics);
68 let [ptr, operand] = args else {
69 ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid `{0}` call", intrinsic_name))span_bug!(self.cur_span(), "invalid `{intrinsic_name}` call")
70 };
71
72 let place = self.deref_pointer(ptr)?;
73 let operand = self.read_immediate(operand)?;
74
75 let op = match intrinsic_name {
76 sym::atomic_or => AtomicRmwOp::MirOp { op: BinOp::BitOr, neg: false },
77 sym::atomic_xor => AtomicRmwOp::MirOp { op: BinOp::BitXor, neg: false },
78 sym::atomic_and => AtomicRmwOp::MirOp { op: BinOp::BitAnd, neg: false },
79 sym::atomic_nand => AtomicRmwOp::MirOp { op: BinOp::BitAnd, neg: true },
80 sym::atomic_xadd => AtomicRmwOp::MirOp { op: BinOp::Add, neg: false },
81 sym::atomic_xsub => AtomicRmwOp::MirOp { op: BinOp::Sub, neg: false },
82 sym::atomic_min => AtomicRmwOp::Min,
83 sym::atomic_umin => AtomicRmwOp::Min,
84 sym::atomic_max => AtomicRmwOp::Max,
85 sym::atomic_umax => AtomicRmwOp::Max,
86 sym::atomic_xchg => AtomicRmwOp::Swap,
87 _ => ::core::panicking::panic("internal error: entered unreachable code")unreachable!(),
88 };
89
90 let res = M::atomic_rmw(self, &place, op, &operand, ord)?;
91 self.write_scalar(res, dest)?;
92 }
93 sym::atomic_cxchg | sym::atomic_cxchgweak => {
94 let success_ord = get_ord_at(1);
95 let failure_ord = get_ord_at(2);
96 let [ptr, expected_old, new] = args else {
97 ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid `{0}` call", intrinsic_name))span_bug!(self.cur_span(), "invalid `{intrinsic_name}` call")
98 };
99
100 let place = self.deref_pointer(ptr)?;
101 let expected_old = self.read_immediate(expected_old)?;
102 let new = self.read_immediate(new)?;
103
104 let (actual_old, success) = M::atomic_compare_exchange(
105 self,
106 &place,
107 &expected_old,
108 &new,
109 intrinsic_name == sym::atomic_cxchgweak,
110 success_ord,
111 failure_ord,
112 )?;
113 let res = Immediate::ScalarPair(actual_old, Scalar::from_bool(success));
114 self.write_immediate(res, dest)?;
115 }
116 sym::atomic_fence | sym::atomic_singlethreadfence => {
117 let ord = get_ord_at(0);
118 let [] = args else {
119 ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid `{0}` call", intrinsic_name))span_bug!(self.cur_span(), "invalid `{intrinsic_name}` call")
120 };
121
122 M::atomic_fence(self, ord, intrinsic_name == sym::atomic_singlethreadfence)?;
123 }
124
125 _ => return interp_ok(false),
127 }
128
129 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_const_eval/src/interpret/intrinsics/atomic.rs:129",
"rustc_const_eval::interpret::intrinsics::atomic",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/interpret/intrinsics/atomic.rs"),
::tracing_core::__macro_support::Option::Some(129u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::intrinsics::atomic"),
::tracing_core::field::FieldSet::new(&["message"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::TRACE <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::TRACE <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
__CALLSITE.metadata().fields().value_set_all(&[(::tracing::__macro_support::Option::Some(&format_args!("{0:?}",
self.dump_place(&dest.clone().into())) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("{:?}", self.dump_place(&dest.clone().into()));
130 self.return_to_block(ret)?;
131 interp_ok(true)
132 }
133}