From bbf688a84de7001d033764b848a50cbad42f3d5a Mon Sep 17 00:00:00 2001 From: Jorge Aparicio Date: Sat, 30 Jun 2018 14:56:08 -0500 Subject: [PATCH] enable Atomic*.{load,store} for ARMv6-M / MSP430 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 | 4 +++- src/liballoc/task.rs | 9 ++++++--- src/libcore/lib.rs | 1 + src/libcore/sync/atomic.rs | 16 ++++++++++++++++ src/librustc/session/config.rs | 4 ++++ src/librustc_target/spec/mod.rs | 6 ++++++ src/librustc_target/spec/msp430_none_elf.rs | 6 ++++-- src/librustc_target/spec/thumbv6m_none_eabi.rs | 2 +- src/libsyntax/feature_gate.rs | 4 ++++ 9 files changed, 45 insertions(+), 7 deletions(-) diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs index 493448eaf88fa..66bf8de1993a3 100644 --- a/src/liballoc/lib.rs +++ b/src/liballoc/lib.rs @@ -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; diff --git a/src/liballoc/task.rs b/src/liballoc/task.rs index f14fe3a20da93..c8e3e770ed2de 100644 --- a/src/liballoc/task.rs +++ b/src/liballoc/task.rs @@ -12,10 +12,12 @@ 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 @@ mod 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)))] struct ArcWrapped(PhantomData); unsafe impl UnsafeWake for ArcWrapped { diff --git a/src/libcore/lib.rs b/src/libcore/lib.rs index b2b38820a89cc..fe328bdd10707 100644 --- a/src/libcore/lib.rs +++ b/src/libcore/lib.rs @@ -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)] diff --git a/src/libcore/sync/atomic.rs b/src/libcore/sync/atomic.rs index 7aba8b51cff51..647bf4fb40a38 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_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 @@ impl AtomicBool { /// ``` #[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 @@ impl AtomicBool { /// ``` #[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 @@ impl AtomicBool { /// ``` #[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 @@ impl AtomicBool { /// ``` #[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 @@ impl AtomicBool { /// ``` #[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 @@ impl AtomicBool { /// ``` #[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 @@ impl AtomicPtr { /// ``` #[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 @@ impl AtomicPtr { /// ``` #[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 @@ impl AtomicPtr { /// ``` #[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 @@ assert_eq!(some_var.swap(10, Ordering::Relaxed), 5); ```"), #[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 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[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 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); ```"), #[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 @@ atomic_int!{ } #[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(dst: *const T, order: Ordering) -> T { } #[inline] +#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] unsafe fn atomic_swap(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(dst: *mut T, val: T, order: Ordering) -> T { } #[inline] +#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))] unsafe fn atomic_compare_exchange(dst: *mut T, old: T, new: T, diff --git a/src/librustc/session/config.rs b/src/librustc/session/config.rs index f97e11ef72f49..93bfe1fc63851 100644 --- a/src/librustc/session/config.rs +++ b/src/librustc/session/config.rs @@ -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)); } diff --git a/src/librustc_target/spec/mod.rs b/src/librustc_target/spec/mod.rs index e54cd773123c8..8ebf5f7c64deb 100644 --- a/src/librustc_target/spec/mod.rs +++ b/src/librustc_target/spec/mod.rs @@ -572,6 +572,9 @@ pub struct TargetOptions { /// Don't use this field; instead use the `.max_atomic_width()` method. pub max_atomic_width: Option, + /// 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 @@ 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, @@ -946,6 +950,7 @@ impl Target { key!(no_integrated_as, bool); key!(max_atomic_width, Option); key!(min_atomic_width, Option); + key!(atomic_cas, bool); try!(key!(panic_strategy, PanicStrategy)); key!(crt_static_allows_dylibs, bool); key!(crt_static_default, bool); @@ -1154,6 +1159,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 ce42a908b0e43..291511dd42913 100644 --- a/src/librustc_target/spec/msp430_none_elf.rs +++ b/src/librustc_target/spec/msp430_none_elf.rs @@ -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 diff --git a/src/librustc_target/spec/thumbv6m_none_eabi.rs b/src/librustc_target/spec/thumbv6m_none_eabi.rs index 9fea07c36f4ef..0c45178b47a5b 100644 --- a/src/librustc_target/spec/thumbv6m_none_eabi.rs +++ b/src/librustc_target/spec/thumbv6m_none_eabi.rs @@ -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() } }) diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs index 2ae0e669fd031..59418f8bf2abb 100644 --- a/src/libsyntax/feature_gate.rs +++ b/src/libsyntax/feature_gate.rs @@ -479,6 +479,9 @@ declare_features! ( // 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 @@ const GATED_CFGS: &[(&str, &str, fn(&Features) -> 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)]