Skip to content

Commit 8da1096

Browse files
committed
Auto merge of #116010 - RalfJung:more-typed-immediates, r=oli-obk
interpret: more consistently use ImmTy in operators and casts The diff in src/tools/miri/src/shims/x86/sse2.rs should hopefully suffice to explain why this is nicer. :)
2 parents 4e7baa4 + 769138e commit 8da1096

File tree

9 files changed

+96
-97
lines changed

9 files changed

+96
-97
lines changed

src/concurrency/data_race.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -516,8 +516,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
516516
let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
517517

518518
// Atomics wrap around on overflow.
519-
let val = this.binary_op(op, &old, rhs)?;
520-
let val = if neg { this.unary_op(mir::UnOp::Not, &val)? } else { val };
519+
let val = this.wrapping_binary_op(op, &old, rhs)?;
520+
let val = if neg { this.wrapping_unary_op(mir::UnOp::Not, &val)? } else { val };
521521
this.allow_data_races_mut(|this| this.write_immediate(*val, place))?;
522522

523523
this.validate_atomic_rmw(place, atomic)?;
@@ -561,7 +561,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
561561

562562
this.validate_overlapping_atomic(place)?;
563563
let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
564-
let lt = this.binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
564+
let lt = this.wrapping_binary_op(mir::BinOp::Lt, &old, &rhs)?.to_scalar().to_bool()?;
565565

566566
let new_val = if min {
567567
if lt { &old } else { &rhs }
@@ -605,7 +605,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriInterpCxExt<'mir, 'tcx> {
605605
// Read as immediate for the sake of `binary_op()`
606606
let old = this.allow_data_races_mut(|this| this.read_immediate(place))?;
607607
// `binary_op` will bail if either of them is not a scalar.
608-
let eq = this.binary_op(mir::BinOp::Eq, &old, expect_old)?;
608+
let eq = this.wrapping_binary_op(mir::BinOp::Eq, &old, expect_old)?;
609609
// If the operation would succeed, but is "weak", fail some portion
610610
// of the time, based on `success_rate`.
611611
let success_rate = 1.0 - this.machine.cmpxchg_weak_failure_rate;

src/helpers.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -1013,15 +1013,15 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10131013
fn float_to_int_checked<F>(
10141014
&self,
10151015
f: F,
1016-
dest_ty: Ty<'tcx>,
1016+
cast_to: TyAndLayout<'tcx>,
10171017
round: rustc_apfloat::Round,
1018-
) -> Option<Scalar<Provenance>>
1018+
) -> Option<ImmTy<'tcx, Provenance>>
10191019
where
10201020
F: rustc_apfloat::Float + Into<Scalar<Provenance>>,
10211021
{
10221022
let this = self.eval_context_ref();
10231023

1024-
match dest_ty.kind() {
1024+
let val = match cast_to.ty.kind() {
10251025
// Unsigned
10261026
ty::Uint(t) => {
10271027
let size = Integer::from_uint_ty(this, *t).size();
@@ -1033,11 +1033,11 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10331033
) {
10341034
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
10351035
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1036-
None
1036+
return None
10371037
} else {
10381038
// Floating point value can be represented by the integer type after rounding.
10391039
// The INEXACT flag is ignored on purpose to allow rounding.
1040-
Some(Scalar::from_uint(res.value, size))
1040+
Scalar::from_uint(res.value, size)
10411041
}
10421042
}
10431043
// Signed
@@ -1051,20 +1051,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
10511051
) {
10521052
// Floating point value is NaN (flagged with INVALID_OP) or outside the range
10531053
// of values of the integer type (flagged with OVERFLOW or UNDERFLOW).
1054-
None
1054+
return None
10551055
} else {
10561056
// Floating point value can be represented by the integer type after rounding.
10571057
// The INEXACT flag is ignored on purpose to allow rounding.
1058-
Some(Scalar::from_int(res.value, size))
1058+
Scalar::from_int(res.value, size)
10591059
}
10601060
}
10611061
// Nothing else
10621062
_ =>
10631063
span_bug!(
10641064
this.cur_span(),
1065-
"attempted float-to-int conversion with non-int output type {dest_ty:?}"
1065+
"attempted float-to-int conversion with non-int output type {}",
1066+
cast_to.ty,
10661067
),
1067-
}
1068+
};
1069+
Some(ImmTy::from_scalar(val, cast_to))
10681070
}
10691071

10701072
/// Returns an integer type that is twice wide as `ty`

src/machine.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -998,7 +998,7 @@ impl<'mir, 'tcx> Machine<'mir, 'tcx> for MiriMachine<'mir, 'tcx> {
998998
bin_op: mir::BinOp,
999999
left: &ImmTy<'tcx, Provenance>,
10001000
right: &ImmTy<'tcx, Provenance>,
1001-
) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)> {
1001+
) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> {
10021002
ecx.binary_ptr_op(bin_op, left, right)
10031003
}
10041004

src/operator.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use log::trace;
22

3-
use rustc_middle::{mir, ty::Ty};
3+
use rustc_middle::mir;
44
use rustc_target::abi::Size;
55

66
use crate::*;
@@ -11,7 +11,7 @@ pub trait EvalContextExt<'tcx> {
1111
bin_op: mir::BinOp,
1212
left: &ImmTy<'tcx, Provenance>,
1313
right: &ImmTy<'tcx, Provenance>,
14-
) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)>;
14+
) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)>;
1515
}
1616

1717
impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
@@ -20,7 +20,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
2020
bin_op: mir::BinOp,
2121
left: &ImmTy<'tcx, Provenance>,
2222
right: &ImmTy<'tcx, Provenance>,
23-
) -> InterpResult<'tcx, (Scalar<Provenance>, bool, Ty<'tcx>)> {
23+
) -> InterpResult<'tcx, (ImmTy<'tcx, Provenance>, bool)> {
2424
use rustc_middle::mir::BinOp::*;
2525

2626
trace!("ptr_op: {:?} {:?} {:?}", *left, bin_op, *right);
@@ -50,7 +50,7 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
5050
Ge => left >= right,
5151
_ => bug!(),
5252
};
53-
(Scalar::from_bool(res), false, self.tcx.types.bool)
53+
(ImmTy::from_bool(res, *self.tcx), false)
5454
}
5555

5656
// Some more operations are possible with atomics.
@@ -65,12 +65,12 @@ impl<'mir, 'tcx> EvalContextExt<'tcx> for super::MiriInterpCx<'mir, 'tcx> {
6565
right.to_scalar().to_target_usize(self)?,
6666
self.machine.layouts.usize,
6767
);
68-
let (result, overflowing, _ty) =
68+
let (result, overflowing) =
6969
self.overflowing_binary_op(bin_op, &left, &right)?;
7070
// Construct a new pointer with the provenance of `ptr` (the LHS).
7171
let result_ptr =
72-
Pointer::new(ptr.provenance, Size::from_bytes(result.to_target_usize(self)?));
73-
(Scalar::from_maybe_pointer(result_ptr, self), overflowing, left.layout.ty)
72+
Pointer::new(ptr.provenance, Size::from_bytes(result.to_scalar().to_target_usize(self)?));
73+
(ImmTy::from_scalar(Scalar::from_maybe_pointer(result_ptr, self), left.layout), overflowing)
7474
}
7575

7676
_ => span_bug!(self.cur_span(), "Invalid operator on pointers: {:?}", bin_op),

src/shims/intrinsics/mod.rs

+5-6
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8989
let [left, right] = check_arg_count(args)?;
9090
let left = this.read_immediate(left)?;
9191
let right = this.read_immediate(right)?;
92-
let (val, _overflowed, _ty) =
93-
this.overflowing_binary_op(mir::BinOp::Eq, &left, &right)?;
92+
let val = this.wrapping_binary_op(mir::BinOp::Eq, &left, &right)?;
9493
// We're type punning a bool as an u8 here.
95-
this.write_scalar(val, dest)?;
94+
this.write_scalar(val.to_scalar(), dest)?;
9695
}
9796
"const_allocate" => {
9897
// For now, for compatibility with the run-time implementation of this, we just return null.
@@ -369,7 +368,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
369368
ty::Float(FloatTy::F32) => {
370369
let f = val.to_scalar().to_f32()?;
371370
this
372-
.float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
371+
.float_to_int_checked(f, dest.layout, Round::TowardZero)
373372
.ok_or_else(|| {
374373
err_ub_format!(
375374
"`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -380,7 +379,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
380379
ty::Float(FloatTy::F64) => {
381380
let f = val.to_scalar().to_f64()?;
382381
this
383-
.float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
382+
.float_to_int_checked(f, dest.layout, Round::TowardZero)
384383
.ok_or_else(|| {
385384
err_ub_format!(
386385
"`float_to_int_unchecked` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -396,7 +395,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
396395
),
397396
};
398397

399-
this.write_scalar(res, dest)?;
398+
this.write_immediate(*res, dest)?;
400399
}
401400

402401
// Other

src/shims/intrinsics/simd.rs

+21-21
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6060
let op = this.read_immediate(&this.project_index(&op, i)?)?;
6161
let dest = this.project_index(&dest, i)?;
6262
let val = match which {
63-
Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(),
63+
Op::MirOp(mir_op) => this.wrapping_unary_op(mir_op, &op)?.to_scalar(),
6464
Op::Abs => {
6565
// Works for f32 and f64.
6666
let ty::Float(float_ty) = op.layout.ty.kind() else {
@@ -177,7 +177,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
177177
let dest = this.project_index(&dest, i)?;
178178
let val = match which {
179179
Op::MirOp(mir_op) => {
180-
let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?;
180+
let (val, overflowed) = this.overflowing_binary_op(mir_op, &left, &right)?;
181181
if matches!(mir_op, BinOp::Shl | BinOp::Shr) {
182182
// Shifts have extra UB as SIMD operations that the MIR binop does not have.
183183
// See <https://github.com/rust-lang/rust/issues/91237>.
@@ -188,13 +188,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
188188
}
189189
if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) {
190190
// Special handling for boolean-returning operations
191-
assert_eq!(ty, this.tcx.types.bool);
192-
let val = val.to_bool().unwrap();
191+
assert_eq!(val.layout.ty, this.tcx.types.bool);
192+
let val = val.to_scalar().to_bool().unwrap();
193193
bool_to_simd_element(val, dest.layout.size)
194194
} else {
195-
assert_ne!(ty, this.tcx.types.bool);
196-
assert_eq!(ty, dest.layout.ty);
197-
val
195+
assert_ne!(val.layout.ty, this.tcx.types.bool);
196+
assert_eq!(val.layout.ty, dest.layout.ty);
197+
val.to_scalar()
198198
}
199199
}
200200
Op::SaturatingOp(mir_op) => {
@@ -304,18 +304,18 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
304304
let op = this.read_immediate(&this.project_index(&op, i)?)?;
305305
res = match which {
306306
Op::MirOp(mir_op) => {
307-
this.binary_op(mir_op, &res, &op)?
307+
this.wrapping_binary_op(mir_op, &res, &op)?
308308
}
309309
Op::MirOpBool(mir_op) => {
310310
let op = imm_from_bool(simd_element_to_bool(op)?);
311-
this.binary_op(mir_op, &res, &op)?
311+
this.wrapping_binary_op(mir_op, &res, &op)?
312312
}
313313
Op::Max => {
314314
if matches!(res.layout.ty.kind(), ty::Float(_)) {
315315
ImmTy::from_scalar(fmax_op(&res, &op)?, res.layout)
316316
} else {
317317
// Just boring integers, so NaNs to worry about
318-
if this.binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? {
318+
if this.wrapping_binary_op(BinOp::Ge, &res, &op)?.to_scalar().to_bool()? {
319319
res
320320
} else {
321321
op
@@ -327,7 +327,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
327327
ImmTy::from_scalar(fmin_op(&res, &op)?, res.layout)
328328
} else {
329329
// Just boring integers, so NaNs to worry about
330-
if this.binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? {
330+
if this.wrapping_binary_op(BinOp::Le, &res, &op)?.to_scalar().to_bool()? {
331331
res
332332
} else {
333333
op
@@ -356,7 +356,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
356356
let mut res = init;
357357
for i in 0..op_len {
358358
let op = this.read_immediate(&this.project_index(&op, i)?)?;
359-
res = this.binary_op(mir_op, &res, &op)?;
359+
res = this.wrapping_binary_op(mir_op, &res, &op)?;
360360
}
361361
this.write_immediate(*res, dest)?;
362362
}
@@ -441,17 +441,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
441441
// Int-to-(int|float): always safe
442442
(ty::Int(_) | ty::Uint(_), ty::Int(_) | ty::Uint(_) | ty::Float(_))
443443
if safe_cast || unsafe_cast =>
444-
this.int_to_int_or_float(&op, dest.layout.ty)?,
444+
this.int_to_int_or_float(&op, dest.layout)?,
445445
// Float-to-float: always safe
446446
(ty::Float(_), ty::Float(_)) if safe_cast || unsafe_cast =>
447-
this.float_to_float_or_int(&op, dest.layout.ty)?,
447+
this.float_to_float_or_int(&op, dest.layout)?,
448448
// Float-to-int in safe mode
449449
(ty::Float(_), ty::Int(_) | ty::Uint(_)) if safe_cast =>
450-
this.float_to_float_or_int(&op, dest.layout.ty)?,
450+
this.float_to_float_or_int(&op, dest.layout)?,
451451
// Float-to-int in unchecked mode
452452
(ty::Float(FloatTy::F32), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
453453
let f = op.to_scalar().to_f32()?;
454-
this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
454+
this.float_to_int_checked(f, dest.layout, Round::TowardZero)
455455
.ok_or_else(|| {
456456
err_ub_format!(
457457
"`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -462,7 +462,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
462462
}
463463
(ty::Float(FloatTy::F64), ty::Int(_) | ty::Uint(_)) if unsafe_cast => {
464464
let f = op.to_scalar().to_f64()?;
465-
this.float_to_int_checked(f, dest.layout.ty, Round::TowardZero)
465+
this.float_to_int_checked(f, dest.layout, Round::TowardZero)
466466
.ok_or_else(|| {
467467
err_ub_format!(
468468
"`simd_cast` intrinsic called on {f} which cannot be represented in target type `{:?}`",
@@ -473,12 +473,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
473473
}
474474
// Ptr-to-ptr cast
475475
(ty::RawPtr(..), ty::RawPtr(..)) if ptr_cast =>
476-
this.ptr_to_ptr(&op, dest.layout.ty)?,
476+
this.ptr_to_ptr(&op, dest.layout)?,
477477
// Ptr/Int casts
478478
(ty::RawPtr(..), ty::Int(_) | ty::Uint(_)) if expose_cast =>
479-
this.pointer_expose_address_cast(&op, dest.layout.ty)?,
479+
this.pointer_expose_address_cast(&op, dest.layout)?,
480480
(ty::Int(_) | ty::Uint(_), ty::RawPtr(..)) if from_exposed_cast =>
481-
this.pointer_from_exposed_address_cast(&op, dest.layout.ty)?,
481+
this.pointer_from_exposed_address_cast(&op, dest.layout)?,
482482
// Error otherwise
483483
_ =>
484484
throw_unsup_format!(
@@ -487,7 +487,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
487487
to_ty = dest.layout.ty,
488488
),
489489
};
490-
this.write_immediate(val, &dest)?;
490+
this.write_immediate(*val, &dest)?;
491491
}
492492
}
493493
"shuffle" => {

src/shims/x86/mod.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -80,8 +80,8 @@ fn bin_op_float<'tcx, F: rustc_apfloat::Float>(
8080
) -> InterpResult<'tcx, Scalar<Provenance>> {
8181
match which {
8282
FloatBinOp::Arith(which) => {
83-
let (res, _overflow, _ty) = this.overflowing_binary_op(which, left, right)?;
84-
Ok(res)
83+
let res = this.wrapping_binary_op(which, left, right)?;
84+
Ok(res.to_scalar())
8585
}
8686
FloatBinOp::Cmp(which) => {
8787
let left = left.to_scalar().to_float::<F>()?;

0 commit comments

Comments
 (0)