diff --git a/tests/pass/weak_memory/weak.rs b/tests/pass/weak_memory/weak.rs index 5e2e78882de5..71d57dd11ec7 100644 --- a/tests/pass/weak_memory/weak.rs +++ b/tests/pass/weak_memory/weak.rs @@ -8,8 +8,8 @@ // Spurious failure is possible, if you are really unlucky with // the RNG and always read the latest value from the store buffer. -use std::sync::atomic::AtomicUsize; use std::sync::atomic::Ordering::*; +use std::sync::atomic::{fence, AtomicUsize}; use std::thread::spawn; #[derive(Copy, Clone)] @@ -70,7 +70,7 @@ fn seq_cst() -> bool { r3 == 1 } -fn initialization_write() -> bool { +fn initialization_write(add_fence: bool) -> bool { let x = static_atomic(11); assert_eq!(x.load(Relaxed), 11); // work around https://github.com/rust-lang/miri/issues/2164 @@ -85,6 +85,9 @@ fn initialization_write() -> bool { let j2 = spawn(move || { reads_value(wait, 1); + if add_fence { + fence(AcqRel); + } x.load(Relaxed) }); @@ -94,6 +97,46 @@ fn initialization_write() -> bool { r2 == 11 } +fn faa_replaced_by_load() -> bool { + // Example from https://github.com/llvm/llvm-project/issues/56450#issuecomment-1183695905 + #[no_mangle] + pub fn rdmw(storing: &AtomicUsize, sync: &AtomicUsize, loading: &AtomicUsize) -> usize { + storing.store(1, Relaxed); + fence(Release); + // sync.fetch_add(0, Relaxed); + sync.load(Relaxed); + fence(Acquire); + loading.load(Relaxed) + } + + let x = static_atomic(0); + assert_eq!(x.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + let y = static_atomic(0); + assert_eq!(y.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + let z = static_atomic(0); + assert_eq!(z.load(Relaxed), 0); // work around https://github.com/rust-lang/miri/issues/2164 + + // Since each thread is so short, we need to make sure that they truely run at the same time + // Otherwise t1 will finish before t2 even starts + let go = static_atomic(0); + + let t1 = spawn(move || { + while go.load(Relaxed) == 0 {} + rdmw(y, x, z) + }); + + let t2 = spawn(move || { + while go.load(Relaxed) == 0 {} + rdmw(z, x, y) + }); + + go.store(1, Relaxed); + + let a = t1.join().unwrap(); + let b = t2.join().unwrap(); + (a, b) == (0, 0) +} + /// Asserts that the function returns true at least once in 100 runs fn assert_once(f: fn() -> bool) { assert!(std::iter::repeat_with(|| f()).take(100).any(|x| x)); @@ -102,5 +145,7 @@ fn assert_once(f: fn() -> bool) { pub fn main() { assert_once(relaxed); assert_once(seq_cst); - assert_once(initialization_write); + assert_once(|| initialization_write(false)); + assert_once(|| initialization_write(true)); + assert_once(faa_replaced_by_load); }