Skip to content

Commit bbf688a

Browse files
committed
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.
1 parent 94eb176 commit bbf688a

File tree

9 files changed

+45
-7
lines changed

9 files changed

+45
-7
lines changed

src/liballoc/lib.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,7 @@
8686
#![feature(box_patterns)]
8787
#![feature(box_syntax)]
8888
#![feature(cfg_target_has_atomic)]
89+
#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))]
8990
#![feature(coerce_unsized)]
9091
#![feature(collections_range)]
9192
#![feature(const_fn)]
@@ -162,7 +163,8 @@ mod boxed {
162163
#[cfg(test)]
163164
mod boxed_test;
164165
pub mod collections;
165-
#[cfg(target_has_atomic = "ptr")]
166+
#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
167+
#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
166168
pub mod sync;
167169
pub mod rc;
168170
pub mod raw_vec;

src/liballoc/task.rs

+6-3
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,12 @@
1212
1313
pub use core::task::*;
1414

15-
#[cfg(target_has_atomic = "ptr")]
15+
#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
16+
#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
1617
pub use self::if_arc::*;
1718

18-
#[cfg(target_has_atomic = "ptr")]
19+
#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
20+
#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
1921
mod if_arc {
2022
use super::*;
2123
use core::marker::PhantomData;
@@ -47,7 +49,8 @@ mod if_arc {
4749
}
4850
}
4951

50-
#[cfg(target_has_atomic = "ptr")]
52+
#[cfg_attr(stage0, cfg(target_has_atomic = "ptr"))]
53+
#[cfg_attr(not(stage0), cfg(all(target_has_atomic = "ptr", target_has_atomic_cas)))]
5154
struct ArcWrapped<T>(PhantomData<T>);
5255

5356
unsafe impl<T: Wake + 'static> UnsafeWake for ArcWrapped<T> {

src/libcore/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@
7979
#![feature(associated_type_defaults)]
8080
#![feature(attr_literals)]
8181
#![feature(cfg_target_has_atomic)]
82+
#![cfg_attr(not(stage0), feature(cfg_target_has_atomic_cas))]
8283
#![feature(concat_idents)]
8384
#![feature(const_fn)]
8485
#![feature(const_int_ops)]

src/libcore/sync/atomic.rs

+16
Original file line numberDiff line numberDiff line change
@@ -371,6 +371,7 @@ impl AtomicBool {
371371
/// ```
372372
#[inline]
373373
#[stable(feature = "rust1", since = "1.0.0")]
374+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
374375
pub fn swap(&self, val: bool, order: Ordering) -> bool {
375376
unsafe { atomic_swap(self.v.get(), val as u8, order) != 0 }
376377
}
@@ -401,6 +402,7 @@ impl AtomicBool {
401402
/// ```
402403
#[inline]
403404
#[stable(feature = "rust1", since = "1.0.0")]
405+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
404406
pub fn compare_and_swap(&self, current: bool, new: bool, order: Ordering) -> bool {
405407
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
406408
Ok(x) => x,
@@ -446,6 +448,7 @@ impl AtomicBool {
446448
/// ```
447449
#[inline]
448450
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
451+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
449452
pub fn compare_exchange(&self,
450453
current: bool,
451454
new: bool,
@@ -537,6 +540,7 @@ impl AtomicBool {
537540
/// ```
538541
#[inline]
539542
#[stable(feature = "rust1", since = "1.0.0")]
543+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
540544
pub fn fetch_and(&self, val: bool, order: Ordering) -> bool {
541545
unsafe { atomic_and(self.v.get(), val as u8, order) != 0 }
542546
}
@@ -568,6 +572,7 @@ impl AtomicBool {
568572
/// ```
569573
#[inline]
570574
#[stable(feature = "rust1", since = "1.0.0")]
575+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
571576
pub fn fetch_nand(&self, val: bool, order: Ordering) -> bool {
572577
// We can't use atomic_nand here because it can result in a bool with
573578
// an invalid value. This happens because the atomic operation is done
@@ -610,6 +615,7 @@ impl AtomicBool {
610615
/// ```
611616
#[inline]
612617
#[stable(feature = "rust1", since = "1.0.0")]
618+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
613619
pub fn fetch_or(&self, val: bool, order: Ordering) -> bool {
614620
unsafe { atomic_or(self.v.get(), val as u8, order) != 0 }
615621
}
@@ -640,6 +646,7 @@ impl AtomicBool {
640646
/// ```
641647
#[inline]
642648
#[stable(feature = "rust1", since = "1.0.0")]
649+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
643650
pub fn fetch_xor(&self, val: bool, order: Ordering) -> bool {
644651
unsafe { atomic_xor(self.v.get(), val as u8, order) != 0 }
645652
}
@@ -786,6 +793,7 @@ impl<T> AtomicPtr<T> {
786793
/// ```
787794
#[inline]
788795
#[stable(feature = "rust1", since = "1.0.0")]
796+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
789797
pub fn swap(&self, ptr: *mut T, order: Ordering) -> *mut T {
790798
unsafe { atomic_swap(self.p.get() as *mut usize, ptr as usize, order) as *mut T }
791799
}
@@ -815,6 +823,7 @@ impl<T> AtomicPtr<T> {
815823
/// ```
816824
#[inline]
817825
#[stable(feature = "rust1", since = "1.0.0")]
826+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
818827
pub fn compare_and_swap(&self, current: *mut T, new: *mut T, order: Ordering) -> *mut T {
819828
match self.compare_exchange(current, new, order, strongest_failure_ordering(order)) {
820829
Ok(x) => x,
@@ -853,6 +862,7 @@ impl<T> AtomicPtr<T> {
853862
/// ```
854863
#[inline]
855864
#[stable(feature = "extended_compare_and_swap", since = "1.10.0")]
865+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
856866
pub fn compare_exchange(&self,
857867
current: *mut T,
858868
new: *mut T,
@@ -1138,6 +1148,7 @@ assert_eq!(some_var.swap(10, Ordering::Relaxed), 5);
11381148
```"),
11391149
#[inline]
11401150
#[$stable]
1151+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
11411152
pub fn swap(&self, val: $int_type, order: Ordering) -> $int_type {
11421153
unsafe { atomic_swap(self.v.get(), val, order) }
11431154
}
@@ -1170,6 +1181,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10);
11701181
```"),
11711182
#[inline]
11721183
#[$stable]
1184+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
11731185
pub fn compare_and_swap(&self,
11741186
current: $int_type,
11751187
new: $int_type,
@@ -1223,6 +1235,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10);
12231235
```"),
12241236
#[inline]
12251237
#[$stable_cxchg]
1238+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
12261239
pub fn compare_exchange(&self,
12271240
current: $int_type,
12281241
new: $int_type,
@@ -1677,6 +1690,7 @@ atomic_int!{
16771690
}
16781691

16791692
#[inline]
1693+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
16801694
fn strongest_failure_ordering(order: Ordering) -> Ordering {
16811695
match order {
16821696
Release => Relaxed,
@@ -1713,6 +1727,7 @@ unsafe fn atomic_load<T>(dst: *const T, order: Ordering) -> T {
17131727
}
17141728

17151729
#[inline]
1730+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
17161731
unsafe fn atomic_swap<T>(dst: *mut T, val: T, order: Ordering) -> T {
17171732
match order {
17181733
Acquire => intrinsics::atomic_xchg_acq(dst, val),
@@ -1751,6 +1766,7 @@ unsafe fn atomic_sub<T>(dst: *mut T, val: T, order: Ordering) -> T {
17511766
}
17521767

17531768
#[inline]
1769+
#[cfg_attr(not(stage0), cfg(target_has_atomic_cas))]
17541770
unsafe fn atomic_compare_exchange<T>(dst: *mut T,
17551771
old: T,
17561772
new: T,

src/librustc/session/config.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1367,6 +1367,7 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
13671367
let vendor = &sess.target.target.target_vendor;
13681368
let min_atomic_width = sess.target.target.min_atomic_width();
13691369
let max_atomic_width = sess.target.target.max_atomic_width();
1370+
let atomic_cas = sess.target.target.options.atomic_cas;
13701371

13711372
let mut ret = HashSet::new();
13721373
// Target bindings.
@@ -1406,6 +1407,9 @@ pub fn default_configuration(sess: &Session) -> ast::CrateConfig {
14061407
}
14071408
}
14081409
}
1410+
if atomic_cas {
1411+
ret.insert((Symbol::intern("target_has_atomic_cas"), None));
1412+
}
14091413
if sess.opts.debug_assertions {
14101414
ret.insert((Symbol::intern("debug_assertions"), None));
14111415
}

src/librustc_target/spec/mod.rs

+6
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,9 @@ pub struct TargetOptions {
572572
/// Don't use this field; instead use the `.max_atomic_width()` method.
573573
pub max_atomic_width: Option<u64>,
574574

575+
/// Whether the target supports atomic CAS operations natively
576+
pub atomic_cas: bool,
577+
575578
/// Panic strategy: "unwind" or "abort"
576579
pub panic_strategy: PanicStrategy,
577580

@@ -690,6 +693,7 @@ impl Default for TargetOptions {
690693
no_integrated_as: false,
691694
min_atomic_width: None,
692695
max_atomic_width: None,
696+
atomic_cas: true,
693697
panic_strategy: PanicStrategy::Unwind,
694698
abi_blacklist: vec![],
695699
crt_static_allows_dylibs: false,
@@ -946,6 +950,7 @@ impl Target {
946950
key!(no_integrated_as, bool);
947951
key!(max_atomic_width, Option<u64>);
948952
key!(min_atomic_width, Option<u64>);
953+
key!(atomic_cas, bool);
949954
try!(key!(panic_strategy, PanicStrategy));
950955
key!(crt_static_allows_dylibs, bool);
951956
key!(crt_static_default, bool);
@@ -1154,6 +1159,7 @@ impl ToJson for Target {
11541159
target_option_val!(no_integrated_as);
11551160
target_option_val!(min_atomic_width);
11561161
target_option_val!(max_atomic_width);
1162+
target_option_val!(atomic_cas);
11571163
target_option_val!(panic_strategy);
11581164
target_option_val!(crt_static_allows_dylibs);
11591165
target_option_val!(crt_static_default);

src/librustc_target/spec/msp430_none_elf.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,11 @@ pub fn target() -> TargetResult {
3434
linker: Some("msp430-elf-gcc".to_string()),
3535
no_integrated_as: true,
3636

37-
// There are no atomic instructions available in the MSP430
37+
// There are no atomic CAS instructions available in the MSP430
3838
// instruction set
39-
max_atomic_width: Some(0),
39+
max_atomic_width: Some(16),
40+
41+
atomic_cas: false,
4042

4143
// Because these devices have very little resources having an
4244
// unwinder is too onerous so we default to "abort" because the

src/librustc_target/spec/thumbv6m_none_eabi.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ pub fn target() -> TargetResult {
3131
features: "+strict-align".to_string(),
3232
// There are no atomic instructions available in the instruction set of the ARMv6-M
3333
// architecture
34-
max_atomic_width: Some(0),
34+
atomic_cas: false,
3535
.. super::thumb_base::opts()
3636
}
3737
})

src/libsyntax/feature_gate.rs

+4
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,9 @@ declare_features! (
479479

480480
// Allows async and await syntax
481481
(active, async_await, "1.28.0", Some(50547), None),
482+
483+
// Allows async and await syntax
484+
(active, cfg_target_has_atomic_cas, "1.28.0", Some(0), None),
482485
);
483486

484487
declare_features! (
@@ -1099,6 +1102,7 @@ const GATED_CFGS: &[(&str, &str, fn(&Features) -> bool)] = &[
10991102
("target_vendor", "cfg_target_vendor", cfg_fn!(cfg_target_vendor)),
11001103
("target_thread_local", "cfg_target_thread_local", cfg_fn!(cfg_target_thread_local)),
11011104
("target_has_atomic", "cfg_target_has_atomic", cfg_fn!(cfg_target_has_atomic)),
1105+
("target_has_atomic_cas", "cfg_target_has_atomic_cas", cfg_fn!(cfg_target_has_atomic_cas)),
11021106
];
11031107

11041108
#[derive(Debug, Eq, PartialEq)]

0 commit comments

Comments
 (0)