Auto merge of #32244 - Amanieu:compare_exchange_result, r=alexcrichton
Change compare_exchange to return a Result<T, T> As per the discussion in #31767 I also changed the feature name from `extended_compare_and_swap` to `compare_exchange`. r? @alexcrichton
This commit is contained in:
commit
8eeb5062d1
@ -53,19 +53,35 @@ extern "rust-intrinsic" {
|
||||
// NB: These intrinsics take raw pointers because they mutate aliased
|
||||
// memory, which is not valid for either `&` or `&mut`.
|
||||
|
||||
#[cfg(stage0)]
|
||||
pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
#[cfg(stage0)]
|
||||
pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
#[cfg(stage0)]
|
||||
pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
#[cfg(stage0)]
|
||||
pub fn atomic_cxchg_acqrel<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
#[cfg(stage0)]
|
||||
pub fn atomic_cxchg_relaxed<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_failrelaxed<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_failacq<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
pub fn atomic_cxchg_acqrel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_relaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_failacq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_acq_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchg_acqrel_failrelaxed<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
|
||||
#[cfg(not(stage0))]
|
||||
pub fn atomic_cxchgweak<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
|
@ -77,6 +77,8 @@ use marker::{Send, Sync};
|
||||
use intrinsics;
|
||||
use cell::UnsafeCell;
|
||||
|
||||
use result::Result::{self, Ok, Err};
|
||||
|
||||
use default::Default;
|
||||
use fmt;
|
||||
|
||||
@ -311,13 +313,16 @@ impl AtomicBool {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
|
||||
self.compare_exchange(current, new, order, strongest_failure_ordering(order))
|
||||
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
|
||||
Ok(x) => x,
|
||||
Err(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a value into the `bool` if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
/// The return value is a result indicating whether the new value was written and containing
|
||||
/// the previous value. On success this value is guaranteed to be equal to `new`.
|
||||
///
|
||||
/// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
|
||||
/// operation. The first describes the required ordering if the operation succeeds while the
|
||||
@ -336,13 +341,13 @@ impl AtomicBool {
|
||||
/// false,
|
||||
/// Ordering::Acquire,
|
||||
/// Ordering::Relaxed),
|
||||
/// true);
|
||||
/// Ok(true));
|
||||
/// assert_eq!(some_bool.load(Ordering::Relaxed), false);
|
||||
///
|
||||
/// assert_eq!(some_bool.compare_exchange(true, true,
|
||||
/// Ordering::SeqCst,
|
||||
/// Ordering::Acquire),
|
||||
/// false);
|
||||
/// Err(false));
|
||||
/// assert_eq!(some_bool.load(Ordering::Relaxed), false);
|
||||
/// ```
|
||||
#[inline]
|
||||
@ -351,19 +356,22 @@ impl AtomicBool {
|
||||
current: bool,
|
||||
new: bool,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> bool {
|
||||
failure: Ordering) -> Result<bool, bool> {
|
||||
let current = if current { UINT_TRUE } else { 0 };
|
||||
let new = if new { UINT_TRUE } else { 0 };
|
||||
|
||||
unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) > 0 }
|
||||
match unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) } {
|
||||
Ok(x) => Ok(x > 0),
|
||||
Err(x) => Err(x > 0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a value into the `bool` if the current value is the same as the `current` value.
|
||||
///
|
||||
/// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
|
||||
/// comparison succeeds, which can result in more efficient code on some platforms. The
|
||||
/// returned value is a tuple of the existing value and a flag indicating whether the
|
||||
/// new value was written.
|
||||
/// return value is a result indicating whether the new value was written and containing the
|
||||
/// previous value.
|
||||
///
|
||||
/// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering if the operation
|
||||
@ -382,13 +390,9 @@ impl AtomicBool {
|
||||
/// let new = true;
|
||||
/// let mut old = val.load(Ordering::Relaxed);
|
||||
/// loop {
|
||||
/// let result = val.compare_exchange_weak(old, new,
|
||||
/// Ordering::SeqCst,
|
||||
/// Ordering::Relaxed);
|
||||
/// if result.1 {
|
||||
/// break;
|
||||
/// } else {
|
||||
/// old = result.0;
|
||||
/// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
|
||||
/// Ok(_) => break,
|
||||
/// Err(x) => old = x,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@ -398,14 +402,15 @@ impl AtomicBool {
|
||||
current: bool,
|
||||
new: bool,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> (bool, bool) {
|
||||
failure: Ordering) -> Result<bool, bool> {
|
||||
let current = if current { UINT_TRUE } else { 0 };
|
||||
let new = if new { UINT_TRUE } else { 0 };
|
||||
|
||||
let result = unsafe {
|
||||
atomic_compare_exchange_weak(self.v.get(), current, new, success, failure)
|
||||
};
|
||||
(result.0 > 0, result.1)
|
||||
match unsafe { atomic_compare_exchange_weak(self.v.get(), current, new,
|
||||
success, failure) } {
|
||||
Ok(x) => Ok(x > 0),
|
||||
Err(x) => Err(x > 0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Logical "and" with a boolean value.
|
||||
@ -644,13 +649,16 @@ impl AtomicIsize {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, current: isize, new: isize, order: Ordering) -> isize {
|
||||
self.compare_exchange(current, new, order, strongest_failure_ordering(order))
|
||||
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
|
||||
Ok(x) => x,
|
||||
Err(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a value into the `isize` if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
/// The return value is a result indicating whether the new value was written and containing
|
||||
/// the previous value. On success this value is guaranteed to be equal to `new`.
|
||||
///
|
||||
/// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
|
||||
/// operation. The first describes the required ordering if the operation succeeds while the
|
||||
@ -668,13 +676,13 @@ impl AtomicIsize {
|
||||
/// assert_eq!(some_isize.compare_exchange(5, 10,
|
||||
/// Ordering::Acquire,
|
||||
/// Ordering::Relaxed),
|
||||
/// 5);
|
||||
/// Ok(5));
|
||||
/// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
|
||||
///
|
||||
/// assert_eq!(some_isize.compare_exchange(6, 12,
|
||||
/// Ordering::SeqCst,
|
||||
/// Ordering::Acquire),
|
||||
/// 10);
|
||||
/// Err(10));
|
||||
/// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
@ -683,7 +691,7 @@ impl AtomicIsize {
|
||||
current: isize,
|
||||
new: isize,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> isize {
|
||||
failure: Ordering) -> Result<isize, isize> {
|
||||
unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
|
||||
}
|
||||
|
||||
@ -691,8 +699,8 @@ impl AtomicIsize {
|
||||
///
|
||||
/// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
|
||||
/// comparison succeeds, which can result in more efficient code on some platforms. The
|
||||
/// returned value is a tuple of the existing value and a flag indicating whether the
|
||||
/// new value was written.
|
||||
/// return value is a result indicating whether the new value was written and containing the
|
||||
/// previous value.
|
||||
///
|
||||
/// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering if the operation
|
||||
@ -711,13 +719,9 @@ impl AtomicIsize {
|
||||
/// let mut old = val.load(Ordering::Relaxed);
|
||||
/// loop {
|
||||
/// let new = old * 2;
|
||||
/// let result = val.compare_exchange_weak(old, new,
|
||||
/// Ordering::SeqCst,
|
||||
/// Ordering::Relaxed);
|
||||
/// if result.1 {
|
||||
/// break;
|
||||
/// } else {
|
||||
/// old = result.0;
|
||||
/// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
|
||||
/// Ok(_) => break,
|
||||
/// Err(x) => old = x,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@ -727,7 +731,7 @@ impl AtomicIsize {
|
||||
current: isize,
|
||||
new: isize,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> (isize, bool) {
|
||||
failure: Ordering) -> Result<isize, isize> {
|
||||
unsafe { atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) }
|
||||
}
|
||||
|
||||
@ -921,13 +925,16 @@ impl AtomicUsize {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, current: usize, new: usize, order: Ordering) -> usize {
|
||||
self.compare_exchange(current, new, order, strongest_failure_ordering(order))
|
||||
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
|
||||
Ok(x) => x,
|
||||
Err(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a value into the `usize` if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
/// The return value is a result indicating whether the new value was written and containing
|
||||
/// the previous value. On success this value is guaranteed to be equal to `new`.
|
||||
///
|
||||
/// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
|
||||
/// operation. The first describes the required ordering if the operation succeeds while the
|
||||
@ -945,13 +952,13 @@ impl AtomicUsize {
|
||||
/// assert_eq!(some_isize.compare_exchange(5, 10,
|
||||
/// Ordering::Acquire,
|
||||
/// Ordering::Relaxed),
|
||||
/// 5);
|
||||
/// Ok(5));
|
||||
/// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
|
||||
///
|
||||
/// assert_eq!(some_isize.compare_exchange(6, 12,
|
||||
/// Ordering::SeqCst,
|
||||
/// Ordering::Acquire),
|
||||
/// 10);
|
||||
/// Err(10));
|
||||
/// assert_eq!(some_isize.load(Ordering::Relaxed), 10);
|
||||
/// ```
|
||||
#[inline]
|
||||
@ -960,7 +967,7 @@ impl AtomicUsize {
|
||||
current: usize,
|
||||
new: usize,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> usize {
|
||||
failure: Ordering) -> Result<usize, usize> {
|
||||
unsafe { atomic_compare_exchange(self.v.get(), current, new, success, failure) }
|
||||
}
|
||||
|
||||
@ -968,8 +975,8 @@ impl AtomicUsize {
|
||||
///
|
||||
/// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
|
||||
/// comparison succeeds, which can result in more efficient code on some platforms. The
|
||||
/// returned value is a tuple of the existing value and a flag indicating whether the
|
||||
/// new value was written.
|
||||
/// return value is a result indicating whether the new value was written and containing the
|
||||
/// previous value.
|
||||
///
|
||||
/// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering if the operation
|
||||
@ -988,13 +995,9 @@ impl AtomicUsize {
|
||||
/// let mut old = val.load(Ordering::Relaxed);
|
||||
/// loop {
|
||||
/// let new = old * 2;
|
||||
/// let result = val.compare_exchange_weak(old, new,
|
||||
/// Ordering::SeqCst,
|
||||
/// Ordering::Relaxed);
|
||||
/// if result.1 {
|
||||
/// break;
|
||||
/// } else {
|
||||
/// old = result.0;
|
||||
/// match val.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
|
||||
/// Ok(_) => break,
|
||||
/// Err(x) => old = x,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@ -1004,7 +1007,7 @@ impl AtomicUsize {
|
||||
current: usize,
|
||||
new: usize,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> (usize, bool) {
|
||||
failure: Ordering) -> Result<usize, usize> {
|
||||
unsafe { atomic_compare_exchange_weak(self.v.get(), current, new, success, failure) }
|
||||
}
|
||||
|
||||
@ -1206,13 +1209,16 @@ impl<T> AtomicPtr<T> {
|
||||
#[inline]
|
||||
#[stable(feature = "rust1", since = "1.0.0")]
|
||||
pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
|
||||
self.compare_exchange(current, new, order, strongest_failure_ordering(order))
|
||||
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
|
||||
Ok(x) => x,
|
||||
Err(x) => x,
|
||||
}
|
||||
}
|
||||
|
||||
/// Stores a value into the pointer if the current value is the same as the `current` value.
|
||||
///
|
||||
/// The return value is always the previous value. If it is equal to `current`, then the value
|
||||
/// was updated.
|
||||
/// The return value is a result indicating whether the new value was written and containing
|
||||
/// the previous value. On success this value is guaranteed to be equal to `new`.
|
||||
///
|
||||
/// `compare_exchange` takes two `Ordering` arguments to describe the memory ordering of this
|
||||
/// operation. The first describes the required ordering if the operation succeeds while the
|
||||
@ -1240,10 +1246,17 @@ impl<T> AtomicPtr<T> {
|
||||
current: *mut T,
|
||||
new: *mut T,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> *mut T {
|
||||
failure: Ordering) -> Result<*mut T, *mut T> {
|
||||
unsafe {
|
||||
atomic_compare_exchange(self.p.get() as *mut usize, current as usize,
|
||||
new as usize, success, failure) as *mut T
|
||||
let res = atomic_compare_exchange(self.p.get() as *mut usize,
|
||||
current as usize,
|
||||
new as usize,
|
||||
success,
|
||||
failure);
|
||||
match res {
|
||||
Ok(x) => Ok(x as *mut T),
|
||||
Err(x) => Err(x as *mut T),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1251,8 +1264,8 @@ impl<T> AtomicPtr<T> {
|
||||
///
|
||||
/// Unlike `compare_exchange`, this function is allowed to spuriously fail even when the
|
||||
/// comparison succeeds, which can result in more efficient code on some platforms. The
|
||||
/// returned value is a tuple of the existing value and a flag indicating whether the
|
||||
/// new value was written.
|
||||
/// return value is a result indicating whether the new value was written and containing the
|
||||
/// previous value.
|
||||
///
|
||||
/// `compare_exchange_weak` takes two `Ordering` arguments to describe the memory
|
||||
/// ordering of this operation. The first describes the required ordering if the operation
|
||||
@ -1271,13 +1284,9 @@ impl<T> AtomicPtr<T> {
|
||||
/// let new = &mut 10;
|
||||
/// let mut old = some_ptr.load(Ordering::Relaxed);
|
||||
/// loop {
|
||||
/// let result = some_ptr.compare_exchange_weak(old, new,
|
||||
/// Ordering::SeqCst,
|
||||
/// Ordering::Relaxed);
|
||||
/// if result.1 {
|
||||
/// break;
|
||||
/// } else {
|
||||
/// old = result.0;
|
||||
/// match some_ptr.compare_exchange_weak(old, new, Ordering::SeqCst, Ordering::Relaxed) {
|
||||
/// Ok(_) => break,
|
||||
/// Err(x) => old = x,
|
||||
/// }
|
||||
/// }
|
||||
/// ```
|
||||
@ -1287,12 +1296,18 @@ impl<T> AtomicPtr<T> {
|
||||
current: *mut T,
|
||||
new: *mut T,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> (*mut T, bool) {
|
||||
let result = unsafe {
|
||||
atomic_compare_exchange_weak(self.p.get() as *mut usize, current as usize,
|
||||
new as usize, success, failure)
|
||||
};
|
||||
(result.0 as *mut T, result.1)
|
||||
failure: Ordering) -> Result<*mut T, *mut T> {
|
||||
unsafe {
|
||||
let res = atomic_compare_exchange_weak(self.p.get() as *mut usize,
|
||||
current as usize,
|
||||
new as usize,
|
||||
success,
|
||||
failure);
|
||||
match res {
|
||||
Ok(x) => Ok(x as *mut T),
|
||||
Err(x) => Err(x as *mut T),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1370,8 +1385,8 @@ unsafe fn atomic_compare_exchange<T>(dst: *mut T,
|
||||
old: T,
|
||||
new: T,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> T {
|
||||
match (success, failure) {
|
||||
failure: Ordering) -> Result<T, T> {
|
||||
let (val, ok) = match (success, failure) {
|
||||
(Acquire, Acquire) => intrinsics::atomic_cxchg_acq(dst, old, new),
|
||||
(Release, Relaxed) => intrinsics::atomic_cxchg_rel(dst, old, new),
|
||||
(AcqRel, Acquire) => intrinsics::atomic_cxchg_acqrel(dst, old, new),
|
||||
@ -1384,6 +1399,11 @@ unsafe fn atomic_compare_exchange<T>(dst: *mut T,
|
||||
(_, Release) => panic!("there is no such thing as an acquire/release failure ordering"),
|
||||
(_, AcqRel) => panic!("there is no such thing as a release failure ordering"),
|
||||
_ => panic!("a failure ordering can't be stronger than a success ordering"),
|
||||
};
|
||||
if ok {
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(val)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1393,13 +1413,20 @@ unsafe fn atomic_compare_exchange<T>(dst: *mut T,
|
||||
old: T,
|
||||
new: T,
|
||||
success: Ordering,
|
||||
_: Ordering) -> T {
|
||||
match success {
|
||||
_: Ordering) -> Result<T, T>
|
||||
where T: ::cmp::Eq + ::marker::Copy
|
||||
{
|
||||
let val = match success {
|
||||
Acquire => intrinsics::atomic_cxchg_acq(dst, old, new),
|
||||
Release => intrinsics::atomic_cxchg_rel(dst, old, new),
|
||||
AcqRel => intrinsics::atomic_cxchg_acqrel(dst, old, new),
|
||||
Relaxed => intrinsics::atomic_cxchg_relaxed(dst, old, new),
|
||||
SeqCst => intrinsics::atomic_cxchg(dst, old, new),
|
||||
};
|
||||
if val == old {
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(val)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1409,8 +1436,8 @@ unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T,
|
||||
old: T,
|
||||
new: T,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> (T, bool) {
|
||||
match (success, failure) {
|
||||
failure: Ordering) -> Result<T, T> {
|
||||
let (val, ok) = match (success, failure) {
|
||||
(Acquire, Acquire) => intrinsics::atomic_cxchgweak_acq(dst, old, new),
|
||||
(Release, Relaxed) => intrinsics::atomic_cxchgweak_rel(dst, old, new),
|
||||
(AcqRel, Acquire) => intrinsics::atomic_cxchgweak_acqrel(dst, old, new),
|
||||
@ -1423,6 +1450,11 @@ unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T,
|
||||
(_, Release) => panic!("there is no such thing as an acquire/release failure ordering"),
|
||||
(_, AcqRel) => panic!("there is no such thing as a release failure ordering"),
|
||||
_ => panic!("a failure ordering can't be stronger than a success ordering"),
|
||||
};
|
||||
if ok {
|
||||
Ok(val)
|
||||
} else {
|
||||
Err(val)
|
||||
}
|
||||
}
|
||||
|
||||
@ -1432,11 +1464,10 @@ unsafe fn atomic_compare_exchange_weak<T>(dst: *mut T,
|
||||
old: T,
|
||||
new: T,
|
||||
success: Ordering,
|
||||
failure: Ordering) -> (T, bool)
|
||||
failure: Ordering) -> Result<T, T>
|
||||
where T: ::cmp::Eq + ::marker::Copy
|
||||
{
|
||||
let result = atomic_compare_exchange(dst, old, new, success, failure);
|
||||
(result, result == old)
|
||||
atomic_compare_exchange(dst, old, new, success, failure)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
|
@ -725,6 +725,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
(_, name) if name.starts_with("atomic_") => {
|
||||
let split: Vec<&str> = name.split('_').collect();
|
||||
|
||||
let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak";
|
||||
let (order, failorder) = match split.len() {
|
||||
2 => (llvm::SequentiallyConsistent, llvm::SequentiallyConsistent),
|
||||
3 => match split[2] {
|
||||
@ -733,16 +734,16 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
"acq" => (llvm::Acquire, llvm::Acquire),
|
||||
"rel" => (llvm::Release, llvm::Monotonic),
|
||||
"acqrel" => (llvm::AcquireRelease, llvm::Acquire),
|
||||
"failrelaxed" if split[1] == "cxchg" || split[1] == "cxchgweak" =>
|
||||
"failrelaxed" if is_cxchg =>
|
||||
(llvm::SequentiallyConsistent, llvm::Monotonic),
|
||||
"failacq" if split[1] == "cxchg" || split[1] == "cxchgweak" =>
|
||||
"failacq" if is_cxchg =>
|
||||
(llvm::SequentiallyConsistent, llvm::Acquire),
|
||||
_ => ccx.sess().fatal("unknown ordering in atomic intrinsic")
|
||||
},
|
||||
4 => match (split[2], split[3]) {
|
||||
("acq", "failrelaxed") if split[1] == "cxchg" || split[1] == "cxchgweak" =>
|
||||
("acq", "failrelaxed") if is_cxchg =>
|
||||
(llvm::Acquire, llvm::Monotonic),
|
||||
("acqrel", "failrelaxed") if split[1] == "cxchg" || split[1] == "cxchgweak" =>
|
||||
("acqrel", "failrelaxed") if is_cxchg =>
|
||||
(llvm::AcquireRelease, llvm::Monotonic),
|
||||
_ => ccx.sess().fatal("unknown ordering in atomic intrinsic")
|
||||
},
|
||||
@ -750,22 +751,17 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
};
|
||||
|
||||
match split[1] {
|
||||
"cxchg" => {
|
||||
"cxchg" | "cxchgweak" => {
|
||||
let cmp = from_immediate(bcx, llargs[1]);
|
||||
let src = from_immediate(bcx, llargs[2]);
|
||||
let ptr = PointerCast(bcx, llargs[0], val_ty(src).ptr_to());
|
||||
let res = AtomicCmpXchg(bcx, ptr, cmp, src, order, failorder, llvm::False);
|
||||
ExtractValue(bcx, res, 0)
|
||||
}
|
||||
|
||||
"cxchgweak" => {
|
||||
let cmp = from_immediate(bcx, llargs[1]);
|
||||
let src = from_immediate(bcx, llargs[2]);
|
||||
let ptr = PointerCast(bcx, llargs[0], val_ty(src).ptr_to());
|
||||
let val = AtomicCmpXchg(bcx, ptr, cmp, src, order, failorder, llvm::True);
|
||||
let weak = if split[1] == "cxchgweak" { llvm::True } else { llvm::False };
|
||||
let val = AtomicCmpXchg(bcx, ptr, cmp, src, order, failorder, weak);
|
||||
let result = ExtractValue(bcx, val, 0);
|
||||
let success = ZExt(bcx, ExtractValue(bcx, val, 1), Type::bool(bcx.ccx()));
|
||||
Store(bcx, result, StructGEP(bcx, llresult, 0));
|
||||
Store(bcx,
|
||||
result,
|
||||
PointerCast(bcx, StructGEP(bcx, llresult, 0), val_ty(src).ptr_to()));
|
||||
Store(bcx, success, StructGEP(bcx, llresult, 1));
|
||||
C_nil(ccx)
|
||||
}
|
||||
@ -778,6 +774,7 @@ pub fn trans_intrinsic_call<'a, 'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
|
||||
}
|
||||
to_immediate(bcx, AtomicLoad(bcx, ptr, order), tp_ty)
|
||||
}
|
||||
|
||||
"store" => {
|
||||
let val = from_immediate(bcx, llargs[1]);
|
||||
let ptr = PointerCast(bcx, llargs[0], val_ty(val).ptr_to());
|
||||
|
@ -84,14 +84,10 @@ pub fn check_intrinsic_type(ccx: &CrateCtxt, it: &hir::ForeignItem) {
|
||||
|
||||
//We only care about the operation here
|
||||
let (n_tps, inputs, output) = match split[1] {
|
||||
"cxchg" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)),
|
||||
param(ccx, 0),
|
||||
param(ccx, 0)),
|
||||
param(ccx, 0)),
|
||||
"cxchgweak" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)),
|
||||
param(ccx, 0),
|
||||
param(ccx, 0)),
|
||||
tcx.mk_tup(vec!(param(ccx, 0), tcx.types.bool))),
|
||||
"cxchg" | "cxchgweak" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)),
|
||||
param(ccx, 0),
|
||||
param(ccx, 0)),
|
||||
tcx.mk_tup(vec!(param(ccx, 0), tcx.types.bool))),
|
||||
"load" => (1, vec!(tcx.mk_imm_ptr(param(ccx, 0))),
|
||||
param(ccx, 0)),
|
||||
"store" => (1, vec!(tcx.mk_mut_ptr(param(ccx, 0)), param(ccx, 0)),
|
||||
|
@ -16,22 +16,22 @@ static ATOMIC: AtomicIsize = ATOMIC_ISIZE_INIT;
|
||||
|
||||
fn main() {
|
||||
// Make sure trans can emit all the intrinsics correctly
|
||||
ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed);
|
||||
ATOMIC.compare_exchange(0, 1, Acquire, Relaxed);
|
||||
ATOMIC.compare_exchange(0, 1, Release, Relaxed);
|
||||
ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed);
|
||||
ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed);
|
||||
ATOMIC.compare_exchange(0, 1, Acquire, Acquire);
|
||||
ATOMIC.compare_exchange(0, 1, AcqRel, Acquire);
|
||||
ATOMIC.compare_exchange(0, 1, SeqCst, Acquire);
|
||||
ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst);
|
||||
ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed);
|
||||
ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed);
|
||||
ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed);
|
||||
ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed);
|
||||
ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed);
|
||||
ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire);
|
||||
ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire);
|
||||
ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire);
|
||||
ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst);
|
||||
ATOMIC.compare_exchange(0, 1, Relaxed, Relaxed).ok();
|
||||
ATOMIC.compare_exchange(0, 1, Acquire, Relaxed).ok();
|
||||
ATOMIC.compare_exchange(0, 1, Release, Relaxed).ok();
|
||||
ATOMIC.compare_exchange(0, 1, AcqRel, Relaxed).ok();
|
||||
ATOMIC.compare_exchange(0, 1, SeqCst, Relaxed).ok();
|
||||
ATOMIC.compare_exchange(0, 1, Acquire, Acquire).ok();
|
||||
ATOMIC.compare_exchange(0, 1, AcqRel, Acquire).ok();
|
||||
ATOMIC.compare_exchange(0, 1, SeqCst, Acquire).ok();
|
||||
ATOMIC.compare_exchange(0, 1, SeqCst, SeqCst).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, Relaxed, Relaxed).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, Acquire, Relaxed).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, Release, Relaxed).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, AcqRel, Relaxed).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, SeqCst, Relaxed).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, Acquire, Acquire).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, AcqRel, Acquire).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, SeqCst, Acquire).ok();
|
||||
ATOMIC.compare_exchange_weak(0, 1, SeqCst, SeqCst).ok();
|
||||
}
|
||||
|
@ -15,9 +15,9 @@
|
||||
|
||||
mod rusti {
|
||||
extern "rust-intrinsic" {
|
||||
pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> T;
|
||||
pub fn atomic_cxchg<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
|
||||
pub fn atomic_cxchgweak<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
pub fn atomic_cxchgweak_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
|
||||
@ -56,13 +56,13 @@ pub fn main() {
|
||||
rusti::atomic_store_rel(&mut *x,1);
|
||||
assert_eq!(*x, 1);
|
||||
|
||||
assert_eq!(rusti::atomic_cxchg(&mut *x, 1, 2), 1);
|
||||
assert_eq!(rusti::atomic_cxchg(&mut *x, 1, 2), (1, true));
|
||||
assert_eq!(*x, 2);
|
||||
|
||||
assert_eq!(rusti::atomic_cxchg_acq(&mut *x, 1, 3), 2);
|
||||
assert_eq!(rusti::atomic_cxchg_acq(&mut *x, 1, 3), (2, false));
|
||||
assert_eq!(*x, 2);
|
||||
|
||||
assert_eq!(rusti::atomic_cxchg_rel(&mut *x, 2, 1), 2);
|
||||
assert_eq!(rusti::atomic_cxchg_rel(&mut *x, 2, 1), (2, true));
|
||||
assert_eq!(*x, 1);
|
||||
|
||||
assert_eq!(rusti::atomic_xchg(&mut *x, 0), 1);
|
||||
|
Loading…
x
Reference in New Issue
Block a user