Skip to content

Commit 2670839

Browse files
committed
Auto merge of #1721 - henryboisdequin:add-atomic-min-and-max, r=oli-obk
Add atomic min and max Closes #1718 Previous attempt: #1653 TODO: - [x] Merge `atomic_op` and `atomic_min_max` functions - [x] Fix CI **Note:** this PR also removes arbitrary trailing whitespace and generally formats the affected files
2 parents 904e66a + f8440d6 commit 2670839

File tree

3 files changed

+470
-129
lines changed

3 files changed

+470
-129
lines changed

src/data_race.rs

Lines changed: 57 additions & 23 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;
@@ -263,7 +263,7 @@ impl MemoryCellClocks {
263263
atomic_ops: None,
264264
}
265265
}
266-
266+
267267
/// Load the internal atomic memory cells if they exist.
268268
#[inline]
269269
fn atomic(&self) -> Option<&AtomicMemoryCellClocks> {
@@ -323,7 +323,7 @@ impl MemoryCellClocks {
323323
/// store relaxed semantics.
324324
fn store_relaxed(&mut self, clocks: &ThreadClockSet, index: VectorIdx) -> Result<(), DataRace> {
325325
self.atomic_write_detect(clocks, index)?;
326-
326+
327327
// The handling of release sequences was changed in C++20 and so
328328
// the code here is different to the paper since now all relaxed
329329
// stores block release sequences. The exception for same-thread
@@ -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,
@@ -678,7 +706,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: MiriEvalContextExt<'mir, 'tcx> {
678706
// Either Release | AcqRel | SeqCst
679707
clocks.apply_release_fence();
680708
}
681-
709+
682710
// Increment timestamp in case of release semantics.
683711
Ok(atomic != AtomicFenceOp::Acquire)
684712
})
@@ -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)