authorgravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-04-15 05:59:55+07:00
committergravatar for koachan@protonmail.comKoakuma <koachan@protonmail.com> 2022-04-15 08:09:57+07:00
log274e2a1ef1513bb2960becf60854e6e4d574ff5c
treec5bd0864d1c6af7415abc301cfef4b4720d5a329
parentd66c61a2cf69665223815a1a12a1f93b30b99571

compiler_rt: atomics: Add TAS lock support for SPARC

Some SPARC CPUs (particularly old and/or embedded ones) only has atomic TAS instruction available (`ldstub`). This adds support for emitting that instruction in the spinlock.

1 files changed, 27 insertions(+), 3 deletions(-)

lib/std/special/compiler_rt/atomics.zig+27-3
...@@ -24,6 +24,13 @@ const supports_atomic_ops = switch (arch) {...@@ -24,6 +24,13 @@ const supports_atomic_ops = switch (arch) {
24// load/store atomically.24// load/store atomically.
25// Objects bigger than this threshold require the use of a lock.25// Objects bigger than this threshold require the use of a lock.
26const largest_atomic_size = switch (arch) {26const largest_atomic_size = switch (arch) {
27 // On SPARC systems that lacks CAS and/or swap instructions, the only
28 // available atomic operation is a test-and-set (`ldstub`), so we force
29 // every atomic memory access to go through the lock.
30 // XXX: Check the presence of CAS/swap instructions and set this parameter
31 // accordingly.
32 .sparc, .sparcel, .sparcv9 => 0,
33
27 // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b34 // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b
28 // and set this parameter accordingly.35 // and set this parameter accordingly.
29 else => @sizeOf(usize),36 else => @sizeOf(usize),
...@@ -38,18 +45,35 @@ const SpinlockTable = struct {...@@ -38,18 +45,35 @@ const SpinlockTable = struct {
38 const Spinlock = struct {45 const Spinlock = struct {
39 // Prevent false sharing by providing enough padding between two46 // Prevent false sharing by providing enough padding between two
40 // consecutive spinlock elements47 // consecutive spinlock elements
41 v: enum(usize) { Unlocked = 0, Locked } align(cache_line_size) = .Unlocked,48 v: if (arch.isSPARC()) enum(u8) { Unlocked = 0, Locked = 255 } else enum(usize) { Unlocked = 0, Locked } align(cache_line_size) = .Unlocked,
4249
43 fn acquire(self: *@This()) void {50 fn acquire(self: *@This()) void {
44 while (true) {51 while (true) {
45 switch (@atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire)) {52 const flag = if (comptime arch.isSPARC())
53 asm volatile ("ldstub [%[addr]], %[flag]"
54 : [flag] "=r" (-> @TypeOf(self.v)),
55 : [addr] "r" (&self.v),
56 : "memory"
57 )
58 else
59 @atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire);
60
61 switch (flag) {
46 .Unlocked => break,62 .Unlocked => break,
47 .Locked => {},63 .Locked => {},
48 }64 }
49 }65 }
50 }66 }
51 fn release(self: *@This()) void {67 fn release(self: *@This()) void {
52 @atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .Release);68 if (comptime arch.isSPARC()) {
69 _ = asm volatile ("clr [%[addr]]"
70 :
71 : [addr] "r" (&self.v),
72 : "memory"
73 );
74 } else {
75 @atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .Release);
76 }
53 }77 }
54 };78 };
5579