Skip to content

Commit

Permalink
Auto merge of #51953 - japaric:atomic-load-store, r=alexcrichton
Browse files Browse the repository at this point in the history
enable Atomic*.{load,store} for ARMv6-M / MSP430

closes #45085

as proposed in #45085 (comment)

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
  • Loading branch information
bors committed Jul 6, 2018
2 parents 4d9fa23 + f9145d0 commit 0072c95
Show file tree
Hide file tree
Showing 9 changed files with 52 additions and 13 deletions.
5 changes: 4 additions & 1 deletion src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
15 changes: 12 additions & 3 deletions src/liballoc/task.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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> {
Expand Down
16 changes: 16 additions & 0 deletions src/libcore/sync/atomic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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 }
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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 }
}
Expand Down Expand Up @@ -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 }
}
Expand Down Expand Up @@ -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 }
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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) }
}
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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),
Expand Down Expand Up @@ -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,
Expand Down
4 changes: 4 additions & 0 deletions src/librustc/session/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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));
}
Expand Down
6 changes: 6 additions & 0 deletions src/librustc_target/spec/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
5 changes: 3 additions & 2 deletions src/librustc_target/spec/msp430_none_elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions src/librustc_target/spec/thumbv6m_none_eabi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
})
Expand Down
5 changes: 5 additions & 0 deletions src/test/run-make-fulldeps/target-without-atomic-cas/Makefile
Original file line number Diff line number Diff line change
@@ -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"'
5 changes: 0 additions & 5 deletions src/test/run-make-fulldeps/target-without-atomics/Makefile

This file was deleted.

0 comments on commit 0072c95

Please sign in to comment.