about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-03-19 12:25:34 -0700
committerbors <bors@rust-lang.org>2016-03-19 12:25:34 -0700
commit8eeb5062d115b846a66685e73ce29697f7eeee11 (patch)
treecfd2d819b031934155a4bf3fc52f20ab15a95b87
parent151be09333b53a761c847107bc659769632ae6c6 (diff)
parent421fed188c66379cb2f00c7e4ad7b7381b3abaa9 (diff)
downloadrust-8eeb5062d115b846a66685e73ce29697f7eeee11.tar.gz
rust-8eeb5062d115b846a66685e73ce29697f7eeee11.zip
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
-rw-r--r--src/libcore/intrinsics.rs24
-rw-r--r--src/libcore/sync/atomic.rs197
-rw-r--r--src/librustc_trans/trans/intrinsic.rs27
-rw-r--r--src/librustc_typeck/check/intrinsic.rs12
-rw-r--r--src/test/run-pass/atomic-compare_exchange.rs36
-rw-r--r--src/test/run-pass/intrinsic-atomics.rs12
6 files changed, 174 insertions, 134 deletions
diff --git a/src/libcore/intrinsics.rs b/src/libcore/intrinsics.rs
index 69cfd0368d6..ccd1ffa8497 100644
--- a/src/libcore/intrinsics.rs
+++ b/src/libcore/intrinsics.rs
@@ -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<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+    #[cfg(not(stage0))]
+    pub fn atomic_cxchg_acq<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+    #[cfg(not(stage0))]
+    pub fn atomic_cxchg_rel<T>(dst: *mut T, old: T, src: T) -> (T, bool);
+    #[cfg(not(stage0))]
+    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;
+    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;
+    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;
+    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;
+    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);
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 0c831bff763..40555481fc0 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -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]
diff --git a/src/librustc_trans/trans/intrinsic.rs b/src/librustc_trans/trans/intrinsic.rs
index 49cacaac766..05b8086de13 100644
--- a/src/librustc_trans/trans/intrinsic.rs
+++ b/src/librustc_trans/trans/intrinsic.rs
@@ -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());
diff --git a/src/librustc_typeck/check/intrinsic.rs b/src/librustc_typeck/check/intrinsic.rs
index 3282d17d3a0..2cd166ebe7e 100644
--- a/src/librustc_typeck/check/intrinsic.rs
+++ b/src/librustc_typeck/check/intrinsic.rs
@@ -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)),
diff --git a/src/test/run-pass/atomic-compare_exchange.rs b/src/test/run-pass/atomic-compare_exchange.rs
index 7946704709c..1d9fa248e3d 100644
--- a/src/test/run-pass/atomic-compare_exchange.rs
+++ b/src/test/run-pass/atomic-compare_exchange.rs
@@ -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();
 }
diff --git a/src/test/run-pass/intrinsic-atomics.rs b/src/test/run-pass/intrinsic-atomics.rs
index 3cc125e9513..a675528424e 100644
--- a/src/test/run-pass/intrinsic-atomics.rs
+++ b/src/test/run-pass/intrinsic-atomics.rs
@@ -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);