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.
This commit is contained in:
@@ -86,6 +86,7 @@
|
|||||||
#![feature(box_patterns)]
|
#![feature(box_patterns)]
|
||||||
#![feature(box_syntax)]
|
#![feature(box_syntax)]
|
||||||
#![feature(cfg_target_has_atomic)]
|
#![feature(cfg_target_has_atomic)]
|
||||||
|
#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))]
|
||||||
#![feature(coerce_unsized)]
|
#![feature(coerce_unsized)]
|
||||||
#![feature(collections_range)]
|
#![feature(collections_range)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
@@ -162,7 +163,8 @@ mod boxed {
|
|||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod boxed_test;
|
mod boxed_test;
|
||||||
pub mod collections;
|
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 sync;
|
||||||
pub mod rc;
|
pub mod rc;
|
||||||
pub mod raw_vec;
|
pub mod raw_vec;
|
||||||
|
|||||||
@@ -12,10 +12,12 @@
|
|||||||
|
|
||||||
pub use core::task::*;
|
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::*;
|
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 {
|
mod if_arc {
|
||||||
use super::*;
|
use super::*;
|
||||||
use core::marker::PhantomData;
|
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<T>(PhantomData<T>);
|
struct ArcWrapped<T>(PhantomData<T>);
|
||||||
|
|
||||||
unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
|
unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {
|
||||||
|
|||||||
@@ -79,6 +79,7 @@
|
|||||||
#![feature(associated_type_defaults)]
|
#![feature(associated_type_defaults)]
|
||||||
#![feature(attr_literals)]
|
#![feature(attr_literals)]
|
||||||
#![feature(cfg_target_has_atomic)]
|
#![feature(cfg_target_has_atomic)]
|
||||||
|
#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))]
|
||||||
#![feature(concat_idents)]
|
#![feature(concat_idents)]
|
||||||
#![feature(const_fn)]
|
#![feature(const_fn)]
|
||||||
#![feature(const_int_ops)]
|
#![feature(const_int_ops)]
|
||||||
|
|||||||
@@ -371,6 +371,7 @@ impl AtomicBool {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub fn swap(&self, val: bool, order: Ordering) -> bool {
|
||||||
unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
|
unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
|
||||||
}
|
}
|
||||||
@@ -401,6 +402,7 @@ impl AtomicBool {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
|
||||||
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
|
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
@@ -446,6 +448,7 @@ impl AtomicBool {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
pub fn compare_exchange(&self,
|
pub fn compare_exchange(&self,
|
||||||
current: bool,
|
current: bool,
|
||||||
new: bool,
|
new: bool,
|
||||||
@@ -537,6 +540,7 @@ impl AtomicBool {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
|
||||||
unsafe { atomic_and(self.v.get(), val as u8, order) != 0 }
|
unsafe { atomic_and(self.v.get(), val as u8, order) != 0 }
|
||||||
}
|
}
|
||||||
@@ -568,6 +572,7 @@ impl AtomicBool {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
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
|
// 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
|
// an invalid value. This happens because the atomic operation is done
|
||||||
@@ -610,6 +615,7 @@ impl AtomicBool {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
|
||||||
unsafe { atomic_or(self.v.get(), val as u8, order) != 0 }
|
unsafe { atomic_or(self.v.get(), val as u8, order) != 0 }
|
||||||
}
|
}
|
||||||
@@ -640,6 +646,7 @@ impl AtomicBool {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
|
||||||
unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
|
unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
|
||||||
}
|
}
|
||||||
@@ -786,6 +793,7 @@ impl<T> AtomicPtr<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
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 }
|
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]
|
#[inline]
|
||||||
#[stable(feature = "rust1", since = "1.0.0")]
|
#[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 {
|
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)) {
|
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
@@ -853,6 +862,7 @@ impl<T> AtomicPtr<T> {
|
|||||||
/// ```
|
/// ```
|
||||||
#[inline]
|
#[inline]
|
||||||
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
pub fn compare_exchange(&self,
|
pub fn compare_exchange(&self,
|
||||||
current: *mut T,
|
current: *mut T,
|
||||||
new: *mut T,
|
new: *mut T,
|
||||||
@@ -1138,6 +1148,7 @@ assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
|
|||||||
```"),
|
```"),
|
||||||
#[inline]
|
#[inline]
|
||||||
#[$stable]
|
#[$stable]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
|
pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
|
||||||
unsafe { atomic_swap(self.v.get(), val, order) }
|
unsafe { atomic_swap(self.v.get(), val, order) }
|
||||||
}
|
}
|
||||||
@@ -1170,6 +1181,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10);
|
|||||||
```"),
|
```"),
|
||||||
#[inline]
|
#[inline]
|
||||||
#[$stable]
|
#[$stable]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
pub fn compare_and_swap(&self,
|
pub fn compare_and_swap(&self,
|
||||||
current: $int_type,
|
current: $int_type,
|
||||||
new: $int_type,
|
new: $int_type,
|
||||||
@@ -1223,6 +1235,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10);
|
|||||||
```"),
|
```"),
|
||||||
#[inline]
|
#[inline]
|
||||||
#[$stable_cxchg]
|
#[$stable_cxchg]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
pub fn compare_exchange(&self,
|
pub fn compare_exchange(&self,
|
||||||
current: $int_type,
|
current: $int_type,
|
||||||
new: $int_type,
|
new: $int_type,
|
||||||
@@ -1677,6 +1690,7 @@ atomic_int!{
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
fn strongest_failure_ordering(order: Ordering) -> Ordering {
|
fn strongest_failure_ordering(order: Ordering) -> Ordering {
|
||||||
match order {
|
match order {
|
||||||
Release => Relaxed,
|
Release => Relaxed,
|
||||||
@@ -1713,6 +1727,7 @@ unsafe fn atomic_load<T>(dst: *const T, order: Ordering) -> T {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
|
||||||
match order {
|
match order {
|
||||||
Acquire => intrinsics::atomic_xchg_acq(dst, val),
|
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]
|
#[inline]
|
||||||
|
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
|
||||||
unsafe fn atomic_compare_exchange<T>(dst: *mut T,
|
unsafe fn atomic_compare_exchange<T>(dst: *mut T,
|
||||||
old: T,
|
old: T,
|
||||||
new: T,
|
new: T,
|
||||||
|
|||||||
@@ -1367,6 +1367,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
|
|||||||
let vendor = &sess.target.target.target_vendor;
|
let vendor = &sess.target.target.target_vendor;
|
||||||
let min_atomic_width = sess.target.target.min_atomic_width();
|
let min_atomic_width = sess.target.target.min_atomic_width();
|
||||||
let max_atomic_width = sess.target.target.max_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();
|
let mut ret = HashSet::new();
|
||||||
// Target bindings.
|
// 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 {
|
if sess.opts.debug_assertions {
|
||||||
ret.insert((Symbol::intern("debug_assertions"), None));
|
ret.insert((Symbol::intern("debug_assertions"), None));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -572,6 +572,9 @@ pub struct TargetOptions {
|
|||||||
/// Don't use this field; instead use the `.max_atomic_width()` method.
|
/// Don't use this field; instead use the `.max_atomic_width()` method.
|
||||||
pub max_atomic_width: Option<u64>,
|
pub max_atomic_width: Option<u64>,
|
||||||
|
|
||||||
|
/// Whether the target supports atomic CAS operations natively
|
||||||
|
pub atomic_cas: bool,
|
||||||
|
|
||||||
/// Panic strategy: "unwind" or "abort"
|
/// Panic strategy: "unwind" or "abort"
|
||||||
pub panic_strategy: PanicStrategy,
|
pub panic_strategy: PanicStrategy,
|
||||||
|
|
||||||
@@ -690,6 +693,7 @@ impl Default for TargetOptions {
|
|||||||
no_integrated_as: false,
|
no_integrated_as: false,
|
||||||
min_atomic_width: None,
|
min_atomic_width: None,
|
||||||
max_atomic_width: None,
|
max_atomic_width: None,
|
||||||
|
atomic_cas: true,
|
||||||
panic_strategy: PanicStrategy::Unwind,
|
panic_strategy: PanicStrategy::Unwind,
|
||||||
abi_blacklist: vec![],
|
abi_blacklist: vec![],
|
||||||
crt_static_allows_dylibs: false,
|
crt_static_allows_dylibs: false,
|
||||||
@@ -946,6 +950,7 @@ impl Target {
|
|||||||
key!(no_integrated_as, bool);
|
key!(no_integrated_as, bool);
|
||||||
key!(max_atomic_width, Option<u64>);
|
key!(max_atomic_width, Option<u64>);
|
||||||
key!(min_atomic_width, Option<u64>);
|
key!(min_atomic_width, Option<u64>);
|
||||||
|
key!(atomic_cas, bool);
|
||||||
try!(key!(panic_strategy, PanicStrategy));
|
try!(key!(panic_strategy, PanicStrategy));
|
||||||
key!(crt_static_allows_dylibs, bool);
|
key!(crt_static_allows_dylibs, bool);
|
||||||
key!(crt_static_default, bool);
|
key!(crt_static_default, bool);
|
||||||
@@ -1154,6 +1159,7 @@ impl ToJson for Target {
|
|||||||
target_option_val!(no_integrated_as);
|
target_option_val!(no_integrated_as);
|
||||||
target_option_val!(min_atomic_width);
|
target_option_val!(min_atomic_width);
|
||||||
target_option_val!(max_atomic_width);
|
target_option_val!(max_atomic_width);
|
||||||
|
target_option_val!(atomic_cas);
|
||||||
target_option_val!(panic_strategy);
|
target_option_val!(panic_strategy);
|
||||||
target_option_val!(crt_static_allows_dylibs);
|
target_option_val!(crt_static_allows_dylibs);
|
||||||
target_option_val!(crt_static_default);
|
target_option_val!(crt_static_default);
|
||||||
|
|||||||
@@ -34,9 +34,11 @@ pub fn target() -> TargetResult {
|
|||||||
linker: Some("msp430-elf-gcc".to_string()),
|
linker: Some("msp430-elf-gcc".to_string()),
|
||||||
no_integrated_as: true,
|
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
|
// instruction set
|
||||||
max_atomic_width: Some(0),
|
max_atomic_width: Some(16),
|
||||||
|
|
||||||
|
atomic_cas: false,
|
||||||
|
|
||||||
// Because these devices have very little resources having an
|
// Because these devices have very little resources having an
|
||||||
// unwinder is too onerous so we default to "abort" because the
|
// unwinder is too onerous so we default to "abort" because the
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ pub fn target() -> TargetResult {
|
|||||||
features: "+strict-align".to_string(),
|
features: "+strict-align".to_string(),
|
||||||
// There are no atomic instructions available in the instruction set of the ARMv6-M
|
// There are no atomic instructions available in the instruction set of the ARMv6-M
|
||||||
// architecture
|
// architecture
|
||||||
max_atomic_width: Some(0),
|
atomic_cas: false,
|
||||||
.. super::thumb_base::opts()
|
.. super::thumb_base::opts()
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -479,6 +479,9 @@ declare_features! (
|
|||||||
|
|
||||||
// Allows async and await syntax
|
// Allows async and await syntax
|
||||||
(active, async_await, "1.28.0", Some(50547), None),
|
(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! (
|
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_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
|
||||||
("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
|
("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", "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)]
|
#[derive(Debug, Eq, PartialEq)]
|
||||||
|
|||||||
Reference in New Issue
Block a user