authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2020-04-06 12:54:35+02:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-06 12:52:53-04:00
loga0b73c9f02b3bb9e550d0283053cc9fc6c1dade6
treebe500d4059b340ba39e48f648f76bc2c29ca4c1a
parentc5ced0d74a40c8a8a46bf1b65ece17479384ce7c

compiler-rt: Separate max size allowed for load/store and CAS

The v6m ISA has no way to express a CAS loop natively without turning off the interrupts or using the kernel cmpxchg harness. On such a platform the user has to provide a few __sync_* builtins to satisfy the linker.

1 files changed, 22 insertions(+), 5 deletions(-)

lib/std/special/compiler_rt/atomics.zig+22-5
......@@ -99,13 +99,30 @@ comptime {
9999// LLVM emits those iff the object size is known and the pointers are correctly
100100// aligned.
101101
102// The size (in bytes) of the biggest object that the architecture can access
103// atomically. Objects bigger than this threshold require the use of a lock.
102// The size (in bytes) of the biggest object that the architecture can
103// load/store atomically.
104// Objects bigger than this threshold require the use of a lock.
104105const largest_atomic_size = switch (builtin.arch) {
105106 .x86_64 => 16,
106107 else => @sizeOf(usize),
107108};
108109
110// The size (in bytes) of the biggest object that the architecture can perform
111// an atomic CAS operation with.
112// Objects bigger than this threshold require the use of a lock.
113const largest_atomic_cas_size = switch (builtin.arch) {
114 .arm, .armeb, .thumb, .thumbeb =>
115 // The ARM v6m ISA has no ldrex/strex and so it's impossible to do CAS
116 // operations unless we're targeting Linux or the user provides the missing
117 // builtin functions.
118 if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .has_v6m) and
119 std.Target.current.os.tag != .linux)
120 0
121 else
122 @sizeOf(usize),
123 else => @sizeOf(usize),
124};
125
109126fn atomicLoadFn(comptime T: type) fn (*T, i32) callconv(.C) T {
110127 return struct {
111128 fn atomic_load_N(src: *T, model: i32) callconv(.C) T {
......@@ -151,7 +168,7 @@ comptime {
151168fn atomicExchangeFn(comptime T: type) fn (*T, T, i32) callconv(.C) T {
152169 return struct {
153170 fn atomic_exchange_N(ptr: *T, val: T, model: i32) callconv(.C) T {
154 if (@sizeOf(T) > largest_atomic_size) {
171 if (@sizeOf(T) > largest_atomic_cas_size) {
155172 var sl = spinlocks.get(@ptrToInt(ptr));
156173 defer sl.release();
157174 const value = ptr.*;
......@@ -174,7 +191,7 @@ comptime {
174191fn atomicCompareExchangeFn(comptime T: type) fn (*T, *T, T, i32, i32) callconv(.C) i32 {
175192 return struct {
176193 fn atomic_compare_exchange_N(ptr: *T, expected: *T, desired: T, success: i32, failure: i32) callconv(.C) i32 {
177 if (@sizeOf(T) > largest_atomic_size) {
194 if (@sizeOf(T) > largest_atomic_cas_size) {
178195 var sl = spinlocks.get(@ptrToInt(ptr));
179196 defer sl.release();
180197 const value = ptr.*;
......@@ -205,7 +222,7 @@ comptime {
205222fn fetchFn(comptime T: type, comptime op: builtin.AtomicRmwOp) fn (*T, T, i32) callconv(.C) T {
206223 return struct {
207224 pub fn fetch_op_N(ptr: *T, val: T, model: i32) callconv(.C) T {
208 if (@sizeOf(T) > largest_atomic_size) {
225 if (@sizeOf(T) > largest_atomic_cas_size) {
209226 var sl = spinlocks.get(@ptrToInt(ptr));
210227 defer sl.release();
211228