Skip to content

Commit f8440d6

Browse files
Add in atomic_{min,max}_x intrinsics
Co-authored-by: Greg Bowyer <gbowyer@fastmail.co.uk>
1 parent 7d1531f commit f8440d6

File tree

3 files changed

+314
-80
lines changed

3 files changed

+314
-80
lines changed

src/data_race.rs

Lines changed: 54 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -74,9 +74,9 @@ use rustc_middle::{mir, ty::layout::TyAndLayout};
7474
use rustc_target::abi::Size;
7575

7676
use crate::{
77-
ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MiriEvalContext, MiriEvalContextExt,
78-
OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag, ThreadId, VClock, VTimestamp,
79-
VectorIdx, MemoryKind, MiriMemoryKind
77+
ImmTy, Immediate, InterpResult, MPlaceTy, MemPlaceMeta, MemoryKind, MiriEvalContext,
78+
MiriEvalContextExt, MiriMemoryKind, OpTy, Pointer, RangeMap, Scalar, ScalarMaybeUninit, Tag,
79+
ThreadId, VClock, VTimestamp, VectorIdx,
8080
};
8181

8282
pub type AllocExtra = VClockAlloc;
@@ -542,6 +542,34 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
542542
Ok(old)
543543
}
544544

545+
/// Perform an conditional atomic exchange with a memory place and a new
546+
/// scalar value, the old value is returned.
547+
fn atomic_min_max_scalar(
548+
&mut self,
549+
place: &MPlaceTy<'tcx, Tag>,
550+
rhs: ImmTy<'tcx, Tag>,
551+
min: bool,
552+
atomic: AtomicRwOp,
553+
) -> InterpResult<'tcx, ImmTy<'tcx, Tag>> {
554+
let this = self.eval_context_mut();
555+
556+
let old = this.allow_data_races_mut(|this| this.read_immediate(&place.into()))?;
557+
let lt = this.overflowing_binary_op(mir::BinOp::Lt, &old, &rhs)?.0.to_bool()?;
558+
559+
let new_val = if min {
560+
if lt { &old } else { &rhs }
561+
} else {
562+
if lt { &rhs } else { &old }
563+
};
564+
565+
this.allow_data_races_mut(|this| this.write_immediate_to_mplace(**new_val, place))?;
566+
567+
this.validate_atomic_rmw(&place, atomic)?;
568+
569+
// Return the old value.
570+
Ok(old)
571+
}
572+
545573
/// Perform an atomic compare and exchange at a given memory location.
546574
/// On success an atomic RMW operation is performed and on failure
547575
/// only an atomic read occurs. If `can_fail_spuriously` is true,
@@ -687,15 +715,12 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
687715
}
688716
}
689717

690-
fn reset_vector_clocks(
691-
&mut self,
692-
ptr: Pointer<Tag>,
693-
size: Size
694-
) -> InterpResult<'tcx> {
718+
fn reset_vector_clocks(&mut self, ptr: Pointer<Tag>, size: Size) -> InterpResult<'tcx> {
695719
let this = self.eval_context_mut();
696720
if let Some(data_race) = &mut this.memory.extra.data_race {
697721
if data_race.multi_threaded.get() {
698-
let alloc_meta = this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap();
722+
let alloc_meta =
723+
this.memory.get_raw_mut(ptr.alloc_id)?.extra.data_race.as_mut().unwrap();
699724
alloc_meta.reset_clocks(ptr.offset, size);
700725
}
701726
}
@@ -715,28 +740,37 @@ pub struct VClockAlloc {
715740

716741
impl VClockAlloc {
717742
/// Create a new data-race detector for newly allocated memory.
718-
pub fn new_allocation(global: &MemoryExtra, len: Size, kind: MemoryKind<MiriMemoryKind>) -> VClockAlloc {
743+
pub fn new_allocation(
744+
global: &MemoryExtra,
745+
len: Size,
746+
kind: MemoryKind<MiriMemoryKind>,
747+
) -> VClockAlloc {
719748
let (alloc_timestamp, alloc_index) = match kind {
720749
// User allocated and stack memory should track allocation.
721750
MemoryKind::Machine(
722-
MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap
723-
) | MemoryKind::Stack => {
751+
MiriMemoryKind::Rust | MiriMemoryKind::C | MiriMemoryKind::WinHeap,
752+
)
753+
| MemoryKind::Stack => {
724754
let (alloc_index, clocks) = global.current_thread_state();
725755
let alloc_timestamp = clocks.clock[alloc_index];
726756
(alloc_timestamp, alloc_index)
727757
}
728758
// Other global memory should trace races but be allocated at the 0 timestamp.
729759
MemoryKind::Machine(
730-
MiriMemoryKind::Global | MiriMemoryKind::Machine | MiriMemoryKind::Env |
731-
MiriMemoryKind::ExternStatic | MiriMemoryKind::Tls
732-
) | MemoryKind::CallerLocation | MemoryKind::Vtable => {
733-
(0, VectorIdx::MAX_INDEX)
734-
}
760+
MiriMemoryKind::Global
761+
| MiriMemoryKind::Machine
762+
| MiriMemoryKind::Env
763+
| MiriMemoryKind::ExternStatic
764+
| MiriMemoryKind::Tls,
765+
)
766+
| MemoryKind::CallerLocation
767+
| MemoryKind::Vtable => (0, VectorIdx::MAX_INDEX),
735768
};
736769
VClockAlloc {
737770
global: Rc::clone(global),
738771
alloc_ranges: RefCell::new(RangeMap::new(
739-
len, MemoryCellClocks::new(alloc_timestamp, alloc_index)
772+
len,
773+
MemoryCellClocks::new(alloc_timestamp, alloc_index),
740774
)),
741775
}
742776
}
@@ -1015,7 +1049,8 @@ trait EvalContextPrivExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
10151049
true,
10161050
place_ptr,
10171051
size,
1018-
).map(|_| true);
1052+
)
1053+
.map(|_| true);
10191054
}
10201055
}
10211056

@@ -1267,7 +1302,6 @@ impl GlobalState {
12671302
.as_ref()
12681303
.expect("Joined with thread but thread has not terminated");
12691304

1270-
12711305
// The join thread happens-before the current thread
12721306
// so update the current vector clock.
12731307
// Is not a release operation so the clock is not incremented.

0 commit comments

Comments
 (0)