1use either::Either;
2use rustc_abi::Size;
3use rustc_apfloat::{Float, FloatConvert};
4use rustc_middle::mir::interpret::{InterpResult, PointerArithmetic, Scalar};
5use rustc_middle::ty::layout::TyAndLayout;
6use rustc_middle::ty::{self, FloatTy, ScalarInt};
7use rustc_middle::{bug, mir, span_bug};
8use rustc_span::sym;
9use tracing::trace;
10
11use super::{ImmTy, InterpCx, Machine, MemPlaceMeta, interp_ok, throw_ub};
12
13pub enum AtomicRmwOp {
15 MirOp {
16 op: mir::BinOp,
17 neg: bool,
20 },
21 Max,
22 Min,
23 Swap,
24}
25
26impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> {
27 fn three_way_compare<T: Ord>(&self, lhs: T, rhs: T) -> ImmTy<'tcx, M::Provenance> {
28 let res = Ord::cmp(&lhs, &rhs);
29 return ImmTy::from_ordering(res, *self.tcx);
30 }
31
32 fn binary_char_op(&self, bin_op: mir::BinOp, l: char, r: char) -> ImmTy<'tcx, M::Provenance> {
33 use rustc_middle::mir::BinOp::*;
34
35 if bin_op == Cmp {
36 return self.three_way_compare(l, r);
37 }
38
39 let res = match bin_op {
40 Eq => l == r,
41 Ne => l != r,
42 Lt => l < r,
43 Le => l <= r,
44 Gt => l > r,
45 Ge => l >= r,
46 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("Invalid operation on char: {0:?}", bin_op))span_bug!(self.cur_span(), "Invalid operation on char: {:?}", bin_op),
47 };
48 ImmTy::from_bool(res, *self.tcx)
49 }
50
51 fn binary_bool_op(&self, bin_op: mir::BinOp, l: bool, r: bool) -> ImmTy<'tcx, M::Provenance> {
52 use rustc_middle::mir::BinOp::*;
53
54 let res = match bin_op {
55 Eq => l == r,
56 Ne => l != r,
57 Lt => l < r,
58 Le => l <= r,
59 Gt => l > r,
60 Ge => l >= r,
61 BitAnd => l & r,
62 BitOr => l | r,
63 BitXor => l ^ r,
64 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("Invalid operation on bool: {0:?}", bin_op))span_bug!(self.cur_span(), "Invalid operation on bool: {:?}", bin_op),
65 };
66 ImmTy::from_bool(res, *self.tcx)
67 }
68
69 fn binary_float_op<F: Float + FloatConvert<F> + Into<Scalar<M::Provenance>>>(
70 &self,
71 bin_op: mir::BinOp,
72 layout: TyAndLayout<'tcx>,
73 l: F,
74 r: F,
75 ) -> ImmTy<'tcx, M::Provenance> {
76 use rustc_middle::mir::BinOp::*;
77
78 let adjust_nan = |f: F| -> F { self.adjust_nan(f, &[l, r]) };
80
81 match bin_op {
82 Eq => ImmTy::from_bool(l == r, *self.tcx),
83 Ne => ImmTy::from_bool(l != r, *self.tcx),
84 Lt => ImmTy::from_bool(l < r, *self.tcx),
85 Le => ImmTy::from_bool(l <= r, *self.tcx),
86 Gt => ImmTy::from_bool(l > r, *self.tcx),
87 Ge => ImmTy::from_bool(l >= r, *self.tcx),
88 Add => ImmTy::from_scalar(adjust_nan((l + r).value).into(), layout),
89 Sub => ImmTy::from_scalar(adjust_nan((l - r).value).into(), layout),
90 Mul => ImmTy::from_scalar(adjust_nan((l * r).value).into(), layout),
91 Div => ImmTy::from_scalar(adjust_nan((l / r).value).into(), layout),
92 Rem => ImmTy::from_scalar(adjust_nan((l % r).value).into(), layout),
93 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid float op: `{0:?}`", bin_op))span_bug!(self.cur_span(), "invalid float op: `{:?}`", bin_op),
94 }
95 }
96
97 fn binary_int_op(
98 &self,
99 bin_op: mir::BinOp,
100 left: &ImmTy<'tcx, M::Provenance>,
101 right: &ImmTy<'tcx, M::Provenance>,
102 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
103 use rustc_middle::mir::BinOp::*;
104
105 let l = left.to_scalar_int()?;
107 let r = right.to_scalar_int()?;
108 let l_signed = || l.to_int(left.layout.size);
110 let l_unsigned = || l.to_uint(left.layout.size);
111 let r_signed = || r.to_int(right.layout.size);
112 let r_unsigned = || r.to_uint(right.layout.size);
113
114 let throw_ub_on_overflow = match bin_op {
115 AddUnchecked => Some(sym::unchecked_add),
116 SubUnchecked => Some(sym::unchecked_sub),
117 MulUnchecked => Some(sym::unchecked_mul),
118 ShlUnchecked => Some(sym::unchecked_shl),
119 ShrUnchecked => Some(sym::unchecked_shr),
120 _ => None,
121 };
122 let with_overflow = bin_op.is_overflowing();
123
124 if #[allow(non_exhaustive_omitted_patterns)] match bin_op {
Shl | ShlUnchecked | Shr | ShrUnchecked => true,
_ => false,
}matches!(bin_op, Shl | ShlUnchecked | Shr | ShrUnchecked) {
126 let l_bits = left.layout.size.bits();
127 let (shift_amount, overflow) = if right.layout.backend_repr.is_signed() {
130 let shift_amount = r_signed();
131 let rem = shift_amount.rem_euclid(l_bits.into());
132 (u128::try_from(rem).unwrap(), rem != shift_amount)
134 } else {
135 let shift_amount = r_unsigned();
136 let rem = shift_amount.rem_euclid(l_bits.into());
137 (rem, rem != shift_amount)
138 };
139 let shift_amount = u32::try_from(shift_amount).unwrap(); let result = if left.layout.backend_repr.is_signed() {
142 let l = l_signed();
143 let result = match bin_op {
144 Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(),
145 Shr | ShrUnchecked => l.checked_shr(shift_amount).unwrap(),
146 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
147 };
148 ScalarInt::truncate_from_int(result, left.layout.size).0
149 } else {
150 let l = l_unsigned();
151 let result = match bin_op {
152 Shl | ShlUnchecked => l.checked_shl(shift_amount).unwrap(),
153 Shr | ShrUnchecked => l.checked_shr(shift_amount).unwrap(),
154 _ => ::rustc_middle::util::bug::bug_fmt(format_args!("impossible case reached"))bug!(),
155 };
156 ScalarInt::truncate_from_uint(result, left.layout.size).0
157 };
158
159 if overflow && let Some(intrinsic) = throw_ub_on_overflow {
160 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::ShiftOverflow {
intrinsic,
shift_amount: if right.layout.backend_repr.is_signed() {
Either::Right(r_signed())
} else { Either::Left(r_unsigned()) },
});throw_ub!(ShiftOverflow {
161 intrinsic,
162 shift_amount: if right.layout.backend_repr.is_signed() {
163 Either::Right(r_signed())
164 } else {
165 Either::Left(r_unsigned())
166 }
167 });
168 }
169
170 return interp_ok(ImmTy::from_scalar_int(result, left.layout));
171 }
172
173 if left.layout.ty != right.layout.ty {
175 ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid asymmetric binary op {2:?}: {3:?} ({0}), {4:?} ({1})",
left.layout.ty, right.layout.ty, bin_op, l, r))span_bug!(
176 self.cur_span(),
177 "invalid asymmetric binary op {bin_op:?}: {l:?} ({l_ty}), {r:?} ({r_ty})",
178 l_ty = left.layout.ty,
179 r_ty = right.layout.ty,
180 )
181 }
182
183 let size = left.layout.size;
184
185 if left.layout.backend_repr.is_signed() {
187 let op: Option<fn(&i128, &i128) -> bool> = match bin_op {
188 Lt => Some(i128::lt),
189 Le => Some(i128::le),
190 Gt => Some(i128::gt),
191 Ge => Some(i128::ge),
192 _ => None,
193 };
194 if let Some(op) = op {
195 return interp_ok(ImmTy::from_bool(op(&l_signed(), &r_signed()), *self.tcx));
196 }
197 if bin_op == Cmp {
198 return interp_ok(self.three_way_compare(l_signed(), r_signed()));
199 }
200 let op: Option<fn(i128, i128) -> (i128, bool)> = match bin_op {
201 Div if r.is_null() => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::DivisionByZero)throw_ub!(DivisionByZero),
202 Rem if r.is_null() => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::RemainderByZero)throw_ub!(RemainderByZero),
203 Div => Some(i128::overflowing_div),
204 Rem => Some(i128::overflowing_rem),
205 Add | AddUnchecked | AddWithOverflow => Some(i128::overflowing_add),
206 Sub | SubUnchecked | SubWithOverflow => Some(i128::overflowing_sub),
207 Mul | MulUnchecked | MulWithOverflow => Some(i128::overflowing_mul),
208 _ => None,
209 };
210 if let Some(op) = op {
211 let l = l_signed();
212 let r = r_signed();
213
214 if #[allow(non_exhaustive_omitted_patterns)] match bin_op {
Rem | Div => true,
_ => false,
}matches!(bin_op, Rem | Div) {
217 if l == size.signed_int_min() && r == -1 {
218 if bin_op == Rem {
219 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::RemainderOverflow)throw_ub!(RemainderOverflow)
220 } else {
221 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::DivisionOverflow)throw_ub!(DivisionOverflow)
222 }
223 }
224 }
225
226 let (result, oflo) = op(l, r);
227 let (result, lossy) = ScalarInt::truncate_from_int(result, left.layout.size);
230 let overflow = oflo || lossy;
231 if overflow && let Some(intrinsic) = throw_ub_on_overflow {
232 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::ArithOverflow {
intrinsic,
});throw_ub!(ArithOverflow { intrinsic });
233 }
234 let res = ImmTy::from_scalar_int(result, left.layout);
235 return interp_ok(if with_overflow {
236 let overflow = ImmTy::from_bool(overflow, *self.tcx);
237 ImmTy::from_pair(res, overflow, self)
238 } else {
239 res
240 });
241 }
242 }
243 let l = l_unsigned();
245 let r = r_unsigned();
246
247 if bin_op == Cmp {
248 return interp_ok(self.three_way_compare(l, r));
249 }
250
251 interp_ok(match bin_op {
252 Eq => ImmTy::from_bool(l == r, *self.tcx),
253 Ne => ImmTy::from_bool(l != r, *self.tcx),
254
255 Lt => ImmTy::from_bool(l < r, *self.tcx),
256 Le => ImmTy::from_bool(l <= r, *self.tcx),
257 Gt => ImmTy::from_bool(l > r, *self.tcx),
258 Ge => ImmTy::from_bool(l >= r, *self.tcx),
259
260 BitOr => ImmTy::from_uint(l | r, left.layout),
261 BitAnd => ImmTy::from_uint(l & r, left.layout),
262 BitXor => ImmTy::from_uint(l ^ r, left.layout),
263
264 _ => {
265 if !!left.layout.backend_repr.is_signed() {
::core::panicking::panic("assertion failed: !left.layout.backend_repr.is_signed()")
};assert!(!left.layout.backend_repr.is_signed());
266 let op: fn(u128, u128) -> (u128, bool) = match bin_op {
267 Add | AddUnchecked | AddWithOverflow => u128::overflowing_add,
268 Sub | SubUnchecked | SubWithOverflow => u128::overflowing_sub,
269 Mul | MulUnchecked | MulWithOverflow => u128::overflowing_mul,
270 Div if r == 0 => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::DivisionByZero)throw_ub!(DivisionByZero),
271 Rem if r == 0 => do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::RemainderByZero)throw_ub!(RemainderByZero),
272 Div => u128::overflowing_div,
273 Rem => u128::overflowing_rem,
274 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("invalid binary op {0:?}: {1:?}, {2:?} (both {3})", bin_op,
left, right, right.layout.ty))span_bug!(
275 self.cur_span(),
276 "invalid binary op {:?}: {:?}, {:?} (both {})",
277 bin_op,
278 left,
279 right,
280 right.layout.ty,
281 ),
282 };
283 let (result, oflo) = op(l, r);
284 let (result, lossy) = ScalarInt::truncate_from_uint(result, left.layout.size);
287 let overflow = oflo || lossy;
288 if overflow && let Some(intrinsic) = throw_ub_on_overflow {
289 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::ArithOverflow {
intrinsic,
});throw_ub!(ArithOverflow { intrinsic });
290 }
291 let res = ImmTy::from_scalar_int(result, left.layout);
292 if with_overflow {
293 let overflow = ImmTy::from_bool(overflow, *self.tcx);
294 ImmTy::from_pair(res, overflow, self)
295 } else {
296 res
297 }
298 }
299 })
300 }
301
302 pub fn compute_size_in_bytes(&self, elem_size: Size, count: u64) -> Option<Size> {
305 elem_size
310 .bytes()
311 .checked_mul(count)
312 .map(Size::from_bytes)
313 .filter(|&total| total <= self.max_size_of_val())
314 }
315
316 fn binary_ptr_op(
317 &self,
318 bin_op: mir::BinOp,
319 left: &ImmTy<'tcx, M::Provenance>,
320 right: &ImmTy<'tcx, M::Provenance>,
321 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
322 use rustc_middle::mir::BinOp::*;
323
324 match bin_op {
325 Offset => {
327 let ptr = left.to_scalar().to_pointer(self);
328 let pointee_ty = left.layout.ty.builtin_deref(true).unwrap();
329 let pointee_layout = self.layout_of(pointee_ty)?;
330 if !pointee_layout.is_sized() {
::core::panicking::panic("assertion failed: pointee_layout.is_sized()")
};assert!(pointee_layout.is_sized());
331
332 let pointee_size = i64::try_from(pointee_layout.size.bytes()).unwrap();
334 let pointee_size = ImmTy::from_int(pointee_size, right.layout);
337 let (val, overflowed) = self
339 .binary_op(mir::BinOp::MulWithOverflow, right, &pointee_size)?
340 .to_scalar_pair();
341 if overflowed.to_bool()? {
343 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::PointerArithOverflow)throw_ub!(PointerArithOverflow)
344 }
345
346 let offset_bytes = val.to_target_isize(self)?;
347 if !right.layout.backend_repr.is_signed() && offset_bytes < 0 {
348 do yeet ::rustc_middle::mir::interpret::InterpErrorKind::UndefinedBehavior(::rustc_middle::mir::interpret::UndefinedBehaviorInfo::PointerArithOverflow)throw_ub!(PointerArithOverflow)
351 }
352 let offset_ptr = self.ptr_offset_inbounds(ptr, offset_bytes)?;
353 interp_ok(ImmTy::from_scalar(
354 Scalar::from_maybe_pointer(offset_ptr, self),
355 left.layout,
356 ))
357 }
358
359 _ => M::binary_ptr_op(self, bin_op, left, right),
361 }
362 }
363
364 pub fn binary_op(
368 &self,
369 bin_op: mir::BinOp,
370 left: &ImmTy<'tcx, M::Provenance>,
371 right: &ImmTy<'tcx, M::Provenance>,
372 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
373 {
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/operator.rs:373",
"rustc_const_eval::interpret::operator",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/interpret/operator.rs"),
::tracing_core::__macro_support::Option::Some(373u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::operator"),
::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!("Running binary op {0:?}: {1:?} ({2}), {3:?} ({4})",
bin_op, *left, left.layout.ty, *right, right.layout.ty) as
&dyn ::tracing::field::Value))])
});
} else { ; }
};trace!(
374 "Running binary op {:?}: {:?} ({}), {:?} ({})",
375 bin_op, *left, left.layout.ty, *right, right.layout.ty
376 );
377
378 match left.layout.ty.kind() {
379 ty::Char => {
380 {
match (&left.layout.ty, &right.layout.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(left.layout.ty, right.layout.ty);
381 let left = left.to_scalar();
382 let right = right.to_scalar();
383 interp_ok(self.binary_char_op(bin_op, left.to_char()?, right.to_char()?))
384 }
385 ty::Bool => {
386 {
match (&left.layout.ty, &right.layout.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(left.layout.ty, right.layout.ty);
387 let left = left.to_scalar();
388 let right = right.to_scalar();
389 interp_ok(self.binary_bool_op(bin_op, left.to_bool()?, right.to_bool()?))
390 }
391 ty::Float(fty) => {
392 {
match (&left.layout.ty, &right.layout.ty) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(left.layout.ty, right.layout.ty);
393 let layout = left.layout;
394 let left = left.to_scalar();
395 let right = right.to_scalar();
396 interp_ok(match fty {
397 FloatTy::F16 => {
398 self.binary_float_op(bin_op, layout, left.to_f16()?, right.to_f16()?)
399 }
400 FloatTy::F32 => {
401 self.binary_float_op(bin_op, layout, left.to_f32()?, right.to_f32()?)
402 }
403 FloatTy::F64 => {
404 self.binary_float_op(bin_op, layout, left.to_f64()?, right.to_f64()?)
405 }
406 FloatTy::F128 => {
407 self.binary_float_op(bin_op, layout, left.to_f128()?, right.to_f128()?)
408 }
409 })
410 }
411 _ if left.layout.ty.is_integral() => {
412 if !right.layout.ty.is_integral() {
{
::core::panicking::panic_fmt(format_args!("Unexpected types for BinOp: {0} {1:?} {2}",
left.layout.ty, bin_op, right.layout.ty));
}
};assert!(
414 right.layout.ty.is_integral(),
415 "Unexpected types for BinOp: {} {:?} {}",
416 left.layout.ty,
417 bin_op,
418 right.layout.ty
419 );
420
421 self.binary_int_op(bin_op, left, right)
422 }
423 _ if left.layout.ty.is_any_ptr() => {
424 if !(right.layout.ty.is_any_ptr() || right.layout.ty.is_integral()) {
{
::core::panicking::panic_fmt(format_args!("Unexpected types for BinOp: {0} {1:?} {2}",
left.layout.ty, bin_op, right.layout.ty));
}
};assert!(
427 right.layout.ty.is_any_ptr() || right.layout.ty.is_integral(),
428 "Unexpected types for BinOp: {} {:?} {}",
429 left.layout.ty,
430 bin_op,
431 right.layout.ty
432 );
433
434 self.binary_ptr_op(bin_op, left, right)
435 }
436 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("Invalid MIR: bad LHS type for binop: {0}", left.layout.ty))span_bug!(
437 self.cur_span(),
438 "Invalid MIR: bad LHS type for binop: {}",
439 left.layout.ty
440 ),
441 }
442 }
443
444 pub fn unary_op(
446 &self,
447 un_op: mir::UnOp,
448 val: &ImmTy<'tcx, M::Provenance>,
449 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
450 use rustc_middle::mir::UnOp::*;
451
452 let layout = val.layout;
453 {
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/operator.rs:453",
"rustc_const_eval::interpret::operator",
::tracing::Level::TRACE,
::tracing_core::__macro_support::Option::Some("compiler/rustc_const_eval/src/interpret/operator.rs"),
::tracing_core::__macro_support::Option::Some(453u32),
::tracing_core::__macro_support::Option::Some("rustc_const_eval::interpret::operator"),
::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!("Running unary op {0:?}: {1:?} ({2})",
un_op, val, layout.ty) as &dyn ::tracing::field::Value))])
});
} else { ; }
};trace!("Running unary op {:?}: {:?} ({})", un_op, val, layout.ty);
454
455 match layout.ty.kind() {
456 ty::Bool => {
457 let val = val.to_scalar();
458 let val = val.to_bool()?;
459 let res = match un_op {
460 Not => !val,
461 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("Invalid bool op {0:?}", un_op))span_bug!(self.cur_span(), "Invalid bool op {:?}", un_op),
462 };
463 interp_ok(ImmTy::from_bool(res, *self.tcx))
464 }
465 ty::Float(fty) => {
466 let val = val.to_scalar();
467 if un_op != Neg {
468 ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("Invalid float op {0:?}", un_op));span_bug!(self.cur_span(), "Invalid float op {:?}", un_op);
469 }
470
471 let res = match fty {
473 FloatTy::F16 => Scalar::from_f16(-val.to_f16()?),
474 FloatTy::F32 => Scalar::from_f32(-val.to_f32()?),
475 FloatTy::F64 => Scalar::from_f64(-val.to_f64()?),
476 FloatTy::F128 => Scalar::from_f128(-val.to_f128()?),
477 };
478 interp_ok(ImmTy::from_scalar(res, layout))
479 }
480 ty::Int(..) => {
481 let val = val.to_scalar().to_int(layout.size)?;
482 let res = match un_op {
483 Not => !val,
484 Neg => val.wrapping_neg(),
485 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("Invalid integer op {0:?}", un_op))span_bug!(self.cur_span(), "Invalid integer op {:?}", un_op),
486 };
487 let res = ScalarInt::truncate_from_int(res, layout.size).0;
488 interp_ok(ImmTy::from_scalar(res.into(), layout))
489 }
490 ty::Uint(..) => {
491 let val = val.to_scalar().to_uint(layout.size)?;
492 let res = match un_op {
493 Not => !val,
494 _ => ::rustc_middle::util::bug::span_bug_fmt(self.cur_span(),
format_args!("Invalid unsigned integer op {0:?}", un_op))span_bug!(self.cur_span(), "Invalid unsigned integer op {:?}", un_op),
495 };
496 let res = ScalarInt::truncate_from_uint(res, layout.size).0;
497 interp_ok(ImmTy::from_scalar(res.into(), layout))
498 }
499 ty::RawPtr(..) | ty::Ref(..) => {
500 {
match (&un_op, &PtrMetadata) {
(left_val, right_val) => {
if !(*left_val == *right_val) {
let kind = ::core::panicking::AssertKind::Eq;
::core::panicking::assert_failed(kind, &*left_val,
&*right_val, ::core::option::Option::None);
}
}
}
};assert_eq!(un_op, PtrMetadata);
501 self.deref_pointer(val)?; let (_, meta) = val.to_scalar_and_meta();
503 interp_ok(match meta {
504 MemPlaceMeta::Meta(scalar) => {
505 let ty = un_op.ty(*self.tcx, val.layout.ty);
506 let layout = self.layout_of(ty)?;
507 ImmTy::from_scalar(scalar, layout)
508 }
509 MemPlaceMeta::None => {
510 let unit_layout = self.layout_of(self.tcx.types.unit)?;
511 ImmTy::uninit(unit_layout)
512 }
513 })
514 }
515 _ => {
516 ::rustc_middle::util::bug::bug_fmt(format_args!("Unexpected unary op argument {0:?}",
val))bug!("Unexpected unary op argument {val:?}")
517 }
518 }
519 }
520
521 pub fn atomic_rmw_op(
522 &self,
523 op: AtomicRmwOp,
524 left: &ImmTy<'tcx, M::Provenance>,
525 right: &ImmTy<'tcx, M::Provenance>,
526 ) -> InterpResult<'tcx, ImmTy<'tcx, M::Provenance>> {
527 interp_ok(match op {
528 AtomicRmwOp::MirOp { op, neg } => {
529 let val = self.binary_op(op, &left, right)?;
530 if neg { self.unary_op(mir::UnOp::Not, &val)? } else { val }
531 }
532 AtomicRmwOp::Max => {
533 let lt = self.binary_op(mir::BinOp::Lt, &left, right)?.to_scalar().to_bool()?;
534 if lt { right } else { &left }.clone()
535 }
536 AtomicRmwOp::Min => {
537 let lt = self.binary_op(mir::BinOp::Lt, &left, right)?.to_scalar().to_bool()?;
538 if lt { &left } else { right }.clone()
539 }
540 AtomicRmwOp::Swap => right.clone(),
541 })
542 }
543}