authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-04-16 06:36:54-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2022-04-16 06:36:54-04:00
loga315d51c0a0c8eda2467c5571f9d7e2495274dbd
tree6e7a943c717265136a465f47a8019ba38be7ebf5
parente428f85cfdebda103b94b2d8c35701af7d47ffdd
parent33956b8e558b1c422dab8f91643c0a9caae84501
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #11437 from koachan/sparc64-mutex

compiler_rt: atomics: Add TAS lock support for SPARC

1 files changed, 34 insertions(+), 4 deletions(-)

lib/std/special/compiler_rt/atomics.zig+34-4
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const arch = builtin.cpu.arch;3const cpu = builtin.cpu;
4const arch = cpu.arch;
45
5const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak;6const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak;
67
...@@ -24,6 +25,11 @@ const supports_atomic_ops = switch (arch) {...@@ -24,6 +25,11 @@ const supports_atomic_ops = switch (arch) {
24// load/store atomically.25// load/store atomically.
25// Objects bigger than this threshold require the use of a lock.26// Objects bigger than this threshold require the use of a lock.
26const largest_atomic_size = switch (arch) {27const largest_atomic_size = switch (arch) {
28 // On SPARC systems that lacks CAS and/or swap instructions, the only
29 // available atomic operation is a test-and-set (`ldstub`), so we force
30 // every atomic memory access to go through the lock.
31 .sparc, .sparcel => if (cpu.features.featureSetHas(.hasleoncasa)) @sizeOf(usize) else 0,
32
27 // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b33 // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b
28 // and set this parameter accordingly.34 // and set this parameter accordingly.
29 else => @sizeOf(usize),35 else => @sizeOf(usize),
...@@ -36,20 +42,44 @@ const SpinlockTable = struct {...@@ -36,20 +42,44 @@ const SpinlockTable = struct {
36 const max_spinlocks = 64;42 const max_spinlocks = 64;
3743
38 const Spinlock = struct {44 const Spinlock = struct {
45 // SPARC ldstub instruction will write a 255 into the memory location.
46 // We'll use that as a sign that the lock is currently held.
47 // See also: Section B.7 in SPARCv8 spec & A.29 in SPARCv9 spec.
48 const sparc_lock: type = enum(u8) { Unlocked = 0, Locked = 255 };
49 const other_lock: type = enum(usize) { Unlocked = 0, Locked };
50
39 // Prevent false sharing by providing enough padding between two51 // Prevent false sharing by providing enough padding between two
40 // consecutive spinlock elements52 // consecutive spinlock elements
41 v: enum(usize) { Unlocked = 0, Locked } align(cache_line_size) = .Unlocked,53 v: if (arch.isSPARC()) sparc_lock else other_lock align(cache_line_size) = .Unlocked,
4254
43 fn acquire(self: *@This()) void {55 fn acquire(self: *@This()) void {
44 while (true) {56 while (true) {
45 switch (@atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire)) {57 const flag = if (comptime arch.isSPARC()) flag: {
58 break :flag asm volatile ("ldstub [%[addr]], %[flag]"
59 : [flag] "=r" (-> @TypeOf(self.v)),
60 : [addr] "r" (&self.v),
61 : "memory"
62 );
63 } else flag: {
64 break :flag @atomicRmw(@TypeOf(self.v), &self.v, .Xchg, .Locked, .Acquire);
65 };
66
67 switch (flag) {
46 .Unlocked => break,68 .Unlocked => break,
47 .Locked => {},69 .Locked => {},
48 }70 }
49 }71 }
50 }72 }
51 fn release(self: *@This()) void {73 fn release(self: *@This()) void {
52 @atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .Release);74 if (comptime arch.isSPARC()) {
75 _ = asm volatile ("clrb [%[addr]]"
76 :
77 : [addr] "r" (&self.v),
78 : "memory"
79 );
80 } else {
81 @atomicStore(@TypeOf(self.v), &self.v, .Unlocked, .Release);
82 }
53 }83 }
54 };84 };
5585