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 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const arch = builtin.cpu.arch;
3const cpu = builtin.cpu;
4const arch = cpu.arch;
45
56const linkage: std.builtin.GlobalLinkage = if (builtin.is_test) .Internal else .Weak;
67
......@@ -24,6 +25,11 @@ const supports_atomic_ops = switch (arch) {
2425// load/store atomically.
2526// Objects bigger than this threshold require the use of a lock.
2627const 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
2733 // XXX: On x86/x86_64 we could check the presence of cmpxchg8b/cmpxchg16b
2834 // and set this parameter accordingly.
2935 else => @sizeOf(usize),
......@@ -36,20 +42,44 @@ const SpinlockTable = struct {
3642 const max_spinlocks = 64;
3743
3844 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
3951 // Prevent false sharing by providing enough padding between two
4052 // 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
4355 fn acquire(self: *@This()) void {
4456 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) {
4668 .Unlocked => break,
4769 .Locked => {},
4870 }
4971 }
5072 }
5173 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 }
5383 }
5484 };
5585