code wiki / (root) / nx_atomic_intrinsic_test.nx

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}