about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-07-06 08:59:22 +0000
committerbors <bors@rust-lang.org>2018-07-06 08:59:22 +0000
commit0072c95aff4dc2c41fb8ed012f984b450bfce846 (patch)
treefba380cd17444258e3ed86e2bdd3f139eb26f8b3
parent4d9fa2326e184314749ccf79203f5ecc35e6225c (diff)
parentf9145d01e16d98b7dc969b66ffb6068df9cdd01d (diff)
downloadrust-0072c95aff4dc2c41fb8ed012f984b450bfce846.tar.gz
rust-0072c95aff4dc2c41fb8ed012f984b450bfce846.zip
Auto merge of #51953 - japaric:atomic-load-store, r=alexcrichton
enable Atomic*.{load,store} for ARMv6-M / MSP430

closes #45085

as proposed in https://github.com/rust-lang/rust/issues/45085#issuecomment-384825434

this commit adds an `atomic_cas` target option and extends the `#[cfg(target_has_atomic)]`
attribute to enable a subset of the `Atomic*` API on architectures that don't support atomic CAS
natively, like MSP430 and ARMv6-M.

r? @alexcrichton
-rw-r--r--src/liballoc/lib.rs5
-rw-r--r--src/liballoc/task.rs15
-rw-r--r--src/libcore/sync/atomic.rs16
-rw-r--r--src/librustc/session/config.rs4
-rw-r--r--src/librustc_target/spec/mod.rs6
-rw-r--r--src/librustc_target/spec/msp430_none_elf.rs5
-rw-r--r--src/librustc_target/spec/thumbv6m_none_eabi.rs4
-rw-r--r--src/test/run-make-fulldeps/target-without-atomic-cas/Makefile5
-rw-r--r--src/test/run-make-fulldeps/target-without-atomics/Makefile5
9 files changed, 52 insertions, 13 deletions
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 493448eaf88..35bf8d1b792 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -162,7 +162,10 @@ mod boxed {
 #[cfg(test)]
 mod boxed_test;
 pub mod collections;
-#[cfg(target_has_atomic = "ptr")]
+#[cfg(any(
+    all(stage0, target_has_atomic = "ptr"),
+    all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
+))]
 pub mod sync;
 pub mod rc;
 pub mod raw_vec;
diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs
index f14fe3a20da..9792d52dd66 100644
--- a/src/liballoc/task.rs
+++ b/src/liballoc/task.rs
@@ -12,10 +12,16 @@
 
 pub use core::task::*;
 
-#[cfg(target_has_atomic = "ptr")]
+#[cfg(any(
+    all(stage0, target_has_atomic = "ptr"),
+    all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
+))]
 pub use self::if_arc::*;
 
-#[cfg(target_has_atomic = "ptr")]
+#[cfg(any(
+    all(stage0, target_has_atomic = "ptr"),
+    all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
+))]
 mod if_arc {
     use super::*;
     use core::marker::PhantomData;
@@ -47,7 +53,10 @@ mod if_arc {
         }
     }
 
-    #[cfg(target_has_atomic = "ptr")]
+    #[cfg(any(
+        all(stage0, target_has_atomic = "ptr"),
+        all(not(stage0), target_has_atomic = "ptr", target_has_atomic = "cas")
+    ))]
     struct ArcWrapped<T>(PhantomData<T>);
 
     unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs
index 7aba8b51cff..e9d1fb89115 100644
--- a/src/libcore/sync/atomic.rs
+++ b/src/libcore/sync/atomic.rs
@@ -371,6 +371,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn swap(&self, val: bool, order: Ordering) -> bool {
         unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
     }
@@ -401,6 +402,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
         match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
             Ok(x) => x,
@@ -446,6 +448,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn compare_exchange(&self,
                             current: bool,
                             new: bool,
@@ -537,6 +540,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
         unsafe { atomic_and(self.v.get(), val as u8, order) != 0 }
     }
@@ -568,6 +572,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
         // We can't use atomic_nand here because it can result in a bool with
         // an invalid value. This happens because the atomic operation is done
@@ -610,6 +615,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
         unsafe { atomic_or(self.v.get(), val as u8, order) != 0 }
     }
@@ -640,6 +646,7 @@ impl AtomicBool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
         unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
     }
@@ -786,6 +793,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
         unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T }
     }
@@ -815,6 +823,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
         match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
             Ok(x) => x,
@@ -853,6 +862,7 @@ impl<T> AtomicPtr<T> {
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[cfg(any(stage0, target_has_atomic = "cas"))]
     pub fn compare_exchange(&self,
                             current: *mut T,
                             new: *mut T,
@@ -1138,6 +1148,7 @@ assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg(any(stage0, target_has_atomic = "cas"))]
                 pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
                     unsafe { atomic_swap(self.v.get(), val, order) }
                 }
@@ -1170,6 +1181,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10);
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg(any(stage0, target_has_atomic = "cas"))]
                 pub fn compare_and_swap(&self,
                                         current: $int_type,
                                         new: $int_type,
@@ -1223,6 +1235,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10);
 ```"),
                 #[inline]
                 #[$stable_cxchg]
+                #[cfg(any(stage0, target_has_atomic = "cas"))]
                 pub fn compare_exchange(&self,
                                         current: $int_type,
                                         new: $int_type,
@@ -1677,6 +1690,7 @@ atomic_int!{
 }
 
 #[inline]
+#[cfg(any(stage0, target_has_atomic = "cas"))]
 fn strongest_failure_ordering(order: Ordering) -> Ordering {
     match order {
         Release => Relaxed,
@@ -1713,6 +1727,7 @@ unsafe fn atomic_load<T>(dst: *const T, order: Ordering) -> T {
 }
 
 #[inline]
+#[cfg(any(stage0, target_has_atomic = "cas"))]
 unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
     match order {
         Acquire => intrinsics::atomic_xchg_acq(dst, val),
@@ -1751,6 +1766,7 @@ unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
 }
 
 #[inline]
+#[cfg(any(stage0, target_has_atomic = "cas"))]
 unsafe fn atomic_compare_exchange<T>(dst: *mut T,
                                      old: T,
                                      new: T,
diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs
index b188f850575..3d7aaf1b2d8 100644
--- a/src/librustc/session/config.rs
+++ b/src/librustc/session/config.rs
@@ -1369,6 +1369,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
     let vendor = &sess.target.target.target_vendor;
     let min_atomic_width = sess.target.target.min_atomic_width();
     let max_atomic_width = sess.target.target.max_atomic_width();
+    let atomic_cas = sess.target.target.options.atomic_cas;
 
     let mut ret = HashSet::new();
     // Target bindings.
@@ -1408,6 +1409,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
             }
         }
     }
+    if atomic_cas {
+        ret.insert((Symbol::intern("target_has_atomic"), Some(Symbol::intern("cas"))));
+    }
     if sess.opts.debug_assertions {
         ret.insert((Symbol::intern("debug_assertions"), None));
     }
diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs
index 49639915ee1..19e353c6a94 100644
--- a/src/librustc_target/spec/mod.rs
+++ b/src/librustc_target/spec/mod.rs
@@ -573,6 +573,9 @@ pub struct TargetOptions {
     /// Don't use this field; instead use the `.max_atomic_width()` method.
     pub max_atomic_width: Option<u64>,
 
+    /// Whether the target supports atomic CAS operations natively
+    pub atomic_cas: bool,
+
     /// Panic strategy: "unwind" or "abort"
     pub panic_strategy: PanicStrategy,
 
@@ -691,6 +694,7 @@ impl Default for TargetOptions {
             no_integrated_as: false,
             min_atomic_width: None,
             max_atomic_width: None,
+            atomic_cas: true,
             panic_strategy: PanicStrategy::Unwind,
             abi_blacklist: vec![],
             crt_static_allows_dylibs: false,
@@ -947,6 +951,7 @@ impl Target {
         key!(no_integrated_as, bool);
         key!(max_atomic_width, Option<u64>);
         key!(min_atomic_width, Option<u64>);
+        key!(atomic_cas, bool);
         try!(key!(panic_strategy, PanicStrategy));
         key!(crt_static_allows_dylibs, bool);
         key!(crt_static_default, bool);
@@ -1155,6 +1160,7 @@ impl ToJson for Target {
         target_option_val!(no_integrated_as);
         target_option_val!(min_atomic_width);
         target_option_val!(max_atomic_width);
+        target_option_val!(atomic_cas);
         target_option_val!(panic_strategy);
         target_option_val!(crt_static_allows_dylibs);
         target_option_val!(crt_static_default);
diff --git a/src/librustc_target/spec/msp430_none_elf.rs b/src/librustc_target/spec/msp430_none_elf.rs
index ce42a908b0e..3ac4c459c63 100644
--- a/src/librustc_target/spec/msp430_none_elf.rs
+++ b/src/librustc_target/spec/msp430_none_elf.rs
@@ -34,9 +34,10 @@ pub fn target() -> TargetResult {
             linker: Some("msp430-elf-gcc".to_string()),
             no_integrated_as: true,
 
-            // There are no atomic instructions available in the MSP430
+            // There are no atomic CAS instructions available in the MSP430
             // instruction set
-            max_atomic_width: Some(0),
+            max_atomic_width: Some(16),
+            atomic_cas: false,
 
             // Because these devices have very little resources having an
             // unwinder is too onerous so we default to "abort" because the
diff --git a/src/librustc_target/spec/thumbv6m_none_eabi.rs b/src/librustc_target/spec/thumbv6m_none_eabi.rs
index 9fea07c36f4..26812501814 100644
--- a/src/librustc_target/spec/thumbv6m_none_eabi.rs
+++ b/src/librustc_target/spec/thumbv6m_none_eabi.rs
@@ -29,9 +29,9 @@ pub fn target() -> TargetResult {
             // The ARMv6-M architecture doesn't support unaligned loads/stores so we disable them
             // with +strict-align.
             features: "+strict-align".to_string(),
-            // There are no atomic instructions available in the instruction set of the ARMv6-M
+            // There are no atomic CAS instructions available in the instruction set of the ARMv6-M
             // architecture
-            max_atomic_width: Some(0),
+            atomic_cas: false,
             .. super::thumb_base::opts()
         }
     })
diff --git a/src/test/run-make-fulldeps/target-without-atomic-cas/Makefile b/src/test/run-make-fulldeps/target-without-atomic-cas/Makefile
new file mode 100644
index 00000000000..c2eb4caea26
--- /dev/null
+++ b/src/test/run-make-fulldeps/target-without-atomic-cas/Makefile
@@ -0,0 +1,5 @@
+-include ../tools.mk
+
+# The target used below doesn't support atomic CAS operations. Verify that's the case
+all:
+	$(RUSTC) --print cfg --target thumbv6m-none-eabi | $(CGREP) -v 'target_has_atomic="cas"'
diff --git a/src/test/run-make-fulldeps/target-without-atomics/Makefile b/src/test/run-make-fulldeps/target-without-atomics/Makefile
deleted file mode 100644
index c5f575ddf84..00000000000
--- a/src/test/run-make-fulldeps/target-without-atomics/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
--include ../tools.mk
-
-# The target used below doesn't support atomic operations. Verify that's the case
-all:
-	$(RUSTC) --print cfg --target thumbv6m-none-eabi | $(CGREP) -v target_has_atomic