-
Notifications
You must be signed in to change notification settings - Fork 389
WIP: Add in atomic_{min,max}_x
intrinsics
#1653
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -417,6 +417,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | |
"atomic_xsub_acqrel" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::AcqRel)?, | ||
"atomic_xsub_relaxed" => this.atomic_op(args, dest, BinOp::Sub, false, AtomicRwOp::Relaxed)?, | ||
|
||
"atomic_min" => this.atomic_min_max(args, dest, true, AtomicRwOp::SeqCst)?, | ||
"atomic_min_acq" => this.atomic_min_max(args, dest, true, AtomicRwOp::Acquire)?, | ||
"atomic_min_rel" => this.atomic_min_max(args, dest, true, AtomicRwOp::Release)?, | ||
"atomic_min_acqrel" => this.atomic_min_max(args, dest, true, AtomicRwOp::AcqRel)?, | ||
"atomic_min_relaxed" => this.atomic_min_max(args, dest, true, AtomicRwOp::Relaxed)?, | ||
"atomic_max" => this.atomic_min_max(args, dest, false, AtomicRwOp::SeqCst)?, | ||
"atomic_max_acq" => this.atomic_min_max(args, dest, false, AtomicRwOp::Acquire)?, | ||
"atomic_max_rel" => this.atomic_min_max(args, dest, false, AtomicRwOp::Release)?, | ||
"atomic_max_acqrel" => this.atomic_min_max(args, dest, false, AtomicRwOp::AcqRel)?, | ||
"atomic_max_relaxed" => this.atomic_min_max(args, dest, false, AtomicRwOp::Relaxed)?, | ||
"atomic_umin" => this.atomic_min_max(args, dest, true, AtomicRwOp::SeqCst)?, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What are these about? If "u" is for "unsigned", then the code needs to be different... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ;) I was just getting to that, you are fast on the review There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. :D Please make sure to add a test that does the max of |
||
"atomic_umin_acq" => this.atomic_min_max(args, dest, true, AtomicRwOp::Acquire)?, | ||
"atomic_umin_rel" => this.atomic_min_max(args, dest, true, AtomicRwOp::Release)?, | ||
"atomic_umin_acqrel" => this.atomic_min_max(args, dest, true, AtomicRwOp::AcqRel)?, | ||
"atomic_umin_relaxed" => this.atomic_min_max(args, dest, true, AtomicRwOp::Relaxed)?, | ||
"atomic_umax" => this.atomic_min_max(args, dest, false, AtomicRwOp::SeqCst)?, | ||
"atomic_umax_acq" => this.atomic_min_max(args, dest, false, AtomicRwOp::Acquire)?, | ||
"atomic_umax_rel" => this.atomic_min_max(args, dest, false, AtomicRwOp::Release)?, | ||
"atomic_umax_acqrel" => this.atomic_min_max(args, dest, false, AtomicRwOp::AcqRel)?, | ||
"atomic_umax_relaxed" => this.atomic_min_max(args, dest, false, AtomicRwOp::Relaxed)?, | ||
|
||
// Query type information | ||
"assert_zero_valid" | | ||
|
@@ -594,6 +614,31 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx | |
self.atomic_compare_exchange(args, dest, success, fail) | ||
} | ||
|
||
fn atomic_min_max( | ||
&mut self, args: &[OpTy<'tcx, Tag>], dest: PlaceTy<'tcx, Tag>, | ||
min: bool, | ||
atomic: AtomicRwOp | ||
) -> InterpResult<'tcx> { | ||
let this = self.eval_context_mut(); | ||
|
||
let &[place, rhs] = check_arg_count(args)?; | ||
let place = this.deref_operand(place)?; | ||
if !place.layout.ty.is_integral() { | ||
bug!("Atomic arithmetic operations only work on integer types"); | ||
} | ||
let rhs = this.read_immediate(rhs)?; | ||
|
||
// Check alignment requirements. Atomics must always be aligned to their size, | ||
// even if the type they wrap would be less aligned (e.g. AtomicU64 on 32bit must | ||
// be 8-aligned). | ||
let align = Align::from_bytes(place.layout.size.bytes()).unwrap(); | ||
this.memory.check_ptr_access(place.ptr, place.layout.size, align)?; | ||
|
||
let old = this.atomic_min_max_scalar(place, rhs, min, atomic)?; | ||
this.write_immediate(*old, dest)?; // old value is returned | ||
Ok(()) | ||
} | ||
|
||
fn float_to_int_unchecked<F>( | ||
&self, | ||
f: F, | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there anything fundamentally different between
atomic_op
andatomic_min_max
? Would it make sense to merge them into a single function? As we just established, they should be basically the same in terms of synchronization behavior, right?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AFAIK The
atomic_op
appears to take its output frombinary_op
with overflow which I think means that forLT
/GT
would result in new becoming the condition of the branch (e.g.1
) rather than being max or minThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry if I am missing something I am obviously super new to the miri codebase
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right, so currently it uses
mir::BinOp
to determine theatomic_op
. But we could instead use an enum likeand then we should be able to share much more code -- maybe?
Don't worry, these are good questions. :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am ok with that, I was under the impression the style was to keep towards
mir
more directly. I will play with that a bit when I figure out the test case and my test failures.I guess the other option is to match on
mir::BinOp::{Lt, Gt}
too which removes the need for a wrapper and punts the specifics toatomic_op
I will also play with thatThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Lt
is for less-than though, and this is not "atomic less-than", it is "atomic min". UsingLt
for this seems rather hacky.That's just what worked well so far.^^ But given that all the fetch_ operations behave very similarly, I feel we really should share as much code between them as we can.