nx_atomic_intrinsic_test.nx source
↩ module page · 114 lines · 3916 B
1// nx_atomic_intrinsic_test.nx -- exercise the __atomic_* compiler
2// builtins. Single-threaded smoke; SMP semantics get exercised by
3// nx_thread_pool integration tests once threads ship.
4//
5// Each test isolates one builtin so a failure points at the exact
6// codegen path: load / store / cas / faa / fence.
7
8import "nx_kernel_v2.nx"
9import "nx_log.nx"
10
11const NX_MO_RELAXED: i64 = 0
12const NX_MO_ACQUIRE: i64 = 2
13const NX_MO_RELEASE: i64 = 3
14const NX_MO_ACQ_REL: i64 = 4
15const NX_MO_SEQ_CST: i64 = 5
16
17func t1_load_store_round_trip() -> i64 {
18 let raw: *u8 = sys_mmap(16)
19 let cell: *i64 = raw as *i64
20 *cell = 0
21 __atomic_store_i64(cell, 42, NX_MO_SEQ_CST)
22 let r: i64 = __atomic_load_i64(cell, NX_MO_SEQ_CST)
23 if r != 42 { return 1 }
24 return 0
25}
26
27func t2_cas_success() -> i64 {
28 let raw: *u8 = sys_mmap(16)
29 let cell: *i64 = raw as *i64
30 *cell = 100
31 let ok: i64 = __atomic_cas_i64(cell, 100, 200, NX_MO_SEQ_CST)
32 if ok != 1 { return 21 }
33 if *cell != 200 { return 22 }
34 return 0
35}
36
37func t3_cas_failure_leaves_cell() -> i64 {
38 let raw: *u8 = sys_mmap(16)
39 let cell: *i64 = raw as *i64
40 *cell = 100
41 let r: i64 = __atomic_cas_i64(cell, 999, 7, NX_MO_SEQ_CST)
42 if r != 0 { return 31 }
43 if *cell != 100 { return 32 }
44 return 0
45}
46
47func t4_faa_returns_prior() -> i64 {
48 let raw: *u8 = sys_mmap(16)
49 let cell: *i64 = raw as *i64
50 *cell = 10
51 let prior: i64 = __atomic_faa_i64(cell, 5, NX_MO_SEQ_CST)
52 if prior != 10 { return 41 }
53 if *cell != 15 { return 42 }
54 let prior2: i64 = __atomic_faa_i64(cell, -3, NX_MO_SEQ_CST)
55 if prior2 != 15 { return 43 }
56 if *cell != 12 { return 44 }
57 return 0
58}
59
60func t5_fence_compiles_and_runs() -> i64 {
61 __atomic_fence(NX_MO_SEQ_CST)
62 __atomic_fence(NX_MO_RELAXED)
63 __atomic_fence(NX_MO_ACQUIRE)
64 __atomic_fence(NX_MO_RELEASE)
65 return 0
66}
67
68// Composite spinlock pattern. Take + take-fail + release + take.
69func t6_spinlock_via_cas() -> i64 {
70 let raw: *u8 = sys_mmap(16)
71 let lock: *i64 = raw as *i64
72 *lock = 0
73 let take_a: i64 = __atomic_cas_i64(lock, 0, 1, NX_MO_ACQUIRE)
74 if take_a != 1 { return 61 }
75 let take_b: i64 = __atomic_cas_i64(lock, 0, 1, NX_MO_ACQUIRE)
76 if take_b != 0 { return 62 }
77 __atomic_store_i64(lock, 0, NX_MO_RELEASE)
78 let take_c: i64 = __atomic_cas_i64(lock, 0, 1, NX_MO_ACQUIRE)
79 if take_c != 1 { return 63 }
80 return 0
81}
82
83func main() -> nx_exit {
84 println("=== nx_atomic intrinsic smoke (compiler-builtin codegen) ===" as *u8)
85
86 let r1: i64 = t1_load_store_round_trip()
87 if r1 != 0 { println("T1 load/store FAIL" as *u8); return r1 }
88 println("T1 load/store PASS __atomic_load_i64 + __atomic_store_i64 round-trip" as *u8)
89
90 let r2: i64 = t2_cas_success()
91 if r2 != 0 { println("T2 cas success FAIL" as *u8); return r2 }
92 println("T2 cas success PASS __atomic_cas_i64 swaps + reports 1" as *u8)
93
94 let r3: i64 = t3_cas_failure_leaves_cell()
95 if r3 != 0 { println("T3 cas failure FAIL" as *u8); return r3 }
96 println("T3 cas failure PASS __atomic_cas_i64 leaves cell + reports 0" as *u8)
97
98 let r4: i64 = t4_faa_returns_prior()
99 if r4 != 0 { println("T4 faa FAIL" as *u8); return r4 }
100 println("T4 faa PASS __atomic_faa_i64 returns prior + adds delta" as *u8)
101
102 let r5: i64 = t5_fence_compiles_and_runs()
103 if r5 != 0 { println("T5 fence FAIL" as *u8); return r5 }
104 println("T5 fence PASS __atomic_fence at all 5 memory orders" as *u8)
105
106 let r6: i64 = t6_spinlock_via_cas()
107 if r6 != 0 { println("T6 spinlock FAIL" as *u8); return r6 }
108 println("T6 spinlock PASS CAS-based take/release discipline holds" as *u8)
109
110 println("" as *u8)
111 println("All atomic intrinsics emit real RV64A AMO + lr.d/sc.d (riscv) /" as *u8)
112 println("LOCK CMPXCHG / XADD (x86_64). Single-threaded today; SMP-ready bits." as *u8)
113 return 0
114}