]> git.lizzy.rs Git - rust.git/commitdiff
enable Atomic*.{load,store} for ARMv6-M / MSP430
authorJorge Aparicio <jorge@japaric.io>
Sat, 30 Jun 2018 19:56:08 +0000 (14:56 -0500)
committerJorge Aparicio <jorge@japaric.io>
Thu, 5 Jul 2018 21:44:29 +0000 (16:44 -0500)
closes #45085

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

src/liballoc/lib.rs
src/liballoc/task.rs
src/libcore/lib.rs
src/libcore/sync/atomic.rs
src/librustc/session/config.rs
src/librustc_target/spec/mod.rs
src/librustc_target/spec/msp430_none_elf.rs
src/librustc_target/spec/thumbv6m_none_eabi.rs
src/libsyntax/feature_gate.rs

index 493448eaf88fa9b0704191d82994e52d951e4526..66bf8de1993a3faf99222e698eb84e5d744f3310 100644 (file)
@@ -86,6 +86,7 @@
 #![feature(box_patterns)]
 #![feature(box_syntax)]
 #![feature(cfg_target_has_atomic)]
+#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))]
 #![feature(coerce_unsized)]
 #![feature(collections_range)]
 #![feature(const_fn)]
@@ -162,7 +163,8 @@ mod boxed {
 #[cfg(test)]
 mod boxed_test;
 pub mod collections;
-#[cfg(target_has_atomic = "ptr")]
+#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
+#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
 pub mod sync;
 pub mod rc;
 pub mod raw_vec;
index f14fe3a20da93ab2e062b37f9bde24f0f3b615ee..c8e3e770ed2debee7461a2c20f750bc2f62358ce 100644 (file)
 
 pub use core::task::*;
 
-#[cfg(target_has_atomic = "ptr")]
+#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
+#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
 pub use self::if_arc::*;
 
-#[cfg(target_has_atomic = "ptr")]
+#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
+#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
 mod if_arc {
     use super::*;
     use core::marker::PhantomData;
@@ -47,7 +49,8 @@ unsafe fn wake_local(arc_self: &Arc<Self>) {
         }
     }
 
-    #[cfg(target_has_atomic = "ptr")]
+    #[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
+    #[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
     struct ArcWrapped<T>(PhantomData<T>);
 
     unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
index b2b38820a89ccd2982cbb8664410a744c41dbfeb..fe328bdd107074239c3857b941f90d56b6833a9f 100644 (file)
@@ -79,6 +79,7 @@
 #![feature(associated_type_defaults)]
 #![feature(attr_literals)]
 #![feature(cfg_target_has_atomic)]
+#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))]
 #![feature(concat_idents)]
 #![feature(const_fn)]
 #![feature(const_int_ops)]
index 7aba8b51cff510986be81832d27b24e4b5525967..647bf4fb40a38434c8c44cf268bdc8574e2cbc91 100644 (file)
@@ -371,6 +371,7 @@ pub fn store(&self, val: bool, order: Ordering) {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn swap(&self, val: bool, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> boo
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
     pub fn compare_exchange(&self,
                             current: bool,
                             new: bool,
@@ -537,6 +540,7 @@ pub fn compare_exchange_weak(&self,
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn store(&self, ptr: *mut T, order: Ordering) {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
     /// ```
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
+    #[cfg_attr(not(stage0), cfg(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 @@ pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) ->
     /// ```
     #[inline]
     #[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
+    #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
     pub fn compare_exchange(&self,
                             current: *mut T,
                             new: *mut T,
@@ -1138,6 +1148,7 @@ pub fn store(&self, val: $int_type, order: Ordering) {
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg_attr(not(stage0), cfg(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 @@ pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
 ```"),
                 #[inline]
                 #[$stable]
+                #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
                 pub fn compare_and_swap(&self,
                                         current: $int_type,
                                         new: $int_type,
@@ -1223,6 +1235,7 @@ pub fn compare_and_swap(&self,
 ```"),
                 #[inline]
                 #[$stable_cxchg]
+                #[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
                 pub fn compare_exchange(&self,
                                         current: $int_type,
                                         new: $int_type,
@@ -1677,6 +1690,7 @@ pub fn fetch_min(&self, val: $int_type, order: Ordering) -> $int_type {
 }
 
 #[inline]
+#[cfg_attr(not(stage0), cfg(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_attr(not(stage0), cfg(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_attr(not(stage0), cfg(target_has_atomic_cas))]
 unsafe fn atomic_compare_exchange<T>(dst: *mut T,
                                      old: T,
                                      new: T,
index f97e11ef72f490ae099f9867d215b2f37c68245f..93bfe1fc63851eebc1232e1b48271668c605c668 100644 (file)
@@ -1367,6 +1367,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.
@@ -1406,6 +1407,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
             }
         }
     }
+    if atomic_cas {
+        ret.insert((Symbol::intern("target_has_atomic_cas"), None));
+    }
     if sess.opts.debug_assertions {
         ret.insert((Symbol::intern("debug_assertions"), None));
     }
index e54cd773123c8e5b7b5d88ad4a2118d7ee2dd6ee..8ebf5f7c64deb2464b58835f007aa8db98b44767 100644 (file)
@@ -572,6 +572,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,
 
@@ -690,6 +693,7 @@ fn default() -> 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,
@@ -946,6 +950,7 @@ macro_rules! key {
         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);
@@ -1154,6 +1159,7 @@ macro_rules! target_option_val {
         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);
index ce42a908b0e431525d91e199722f06dc1d4c353c..291511dd42913d7ec606febd6c9167d4c41a4726 100644 (file)
@@ -34,9 +34,11 @@ 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
index 9fea07c36f4ef7be17075a65e03d8a267e405b06..0c45178b47a5b30a67c8a5233b24425596a1f45c 100644 (file)
@@ -31,7 +31,7 @@ pub fn target() -> TargetResult {
             features: "+strict-align".to_string(),
             // There are no atomic instructions available in the instruction set of the ARMv6-M
             // architecture
-            max_atomic_width: Some(0),
+            atomic_cas: false,
             .. super::thumb_base::opts()
         }
     })
index 2ae0e669fd031a3c0282c22f9f87c7b3ca63befd..59418f8bf2abb6a875463752eacedfae6b0c3f31 100644 (file)
@@ -479,6 +479,9 @@ pub fn walk_feature_fields<F>(&self, mut f: F)
 
     // Allows async and await syntax
     (active, async_await, "1.28.0", Some(50547), None),
+
+    // Allows async and await syntax
+    (active, cfg_target_has_atomic_cas, "1.28.0", Some(0), None),
 );
 
 declare_features! (
@@ -1099,6 +1102,7 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
     ("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
     ("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
     ("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
+    ("target_has_atomic_cas", "cfg_target_has_atomic_cas", cfg_fn!(cfg_target_has_atomic_cas)),
 ];
 
 #[derive(Debug, Eq, PartialEq)]