]> Cypherpunks.ru repositories - gostls13.git/blob - src/runtime/internal/atomic/atomic_arm.go
runtime/internal/atomic: add arm/arm64 operators for And/Or
[gostls13.git] / src / runtime / internal / atomic / atomic_arm.go
1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 //go:build arm
6
7 package atomic
8
9 import (
10         "internal/cpu"
11         "unsafe"
12 )
13
14 const (
15         offsetARMHasV7Atomics = unsafe.Offsetof(cpu.ARM.HasV7Atomics)
16 )
17
18 // Export some functions via linkname to assembly in sync/atomic.
19 //
20 //go:linkname Xchg
21 //go:linkname Xchguintptr
22
23 type spinlock struct {
24         v uint32
25 }
26
27 //go:nosplit
28 func (l *spinlock) lock() {
29         for {
30                 if Cas(&l.v, 0, 1) {
31                         return
32                 }
33         }
34 }
35
36 //go:nosplit
37 func (l *spinlock) unlock() {
38         Store(&l.v, 0)
39 }
40
41 var locktab [57]struct {
42         l   spinlock
43         pad [cpu.CacheLinePadSize - unsafe.Sizeof(spinlock{})]byte
44 }
45
46 func addrLock(addr *uint64) *spinlock {
47         return &locktab[(uintptr(unsafe.Pointer(addr))>>3)%uintptr(len(locktab))].l
48 }
49
50 // Atomic add and return new value.
51 //
52 //go:nosplit
53 func Xadd(val *uint32, delta int32) uint32 {
54         for {
55                 oval := *val
56                 nval := oval + uint32(delta)
57                 if Cas(val, oval, nval) {
58                         return nval
59                 }
60         }
61 }
62
63 //go:noescape
64 func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
65
66 //go:nosplit
67 func Xchg(addr *uint32, v uint32) uint32 {
68         for {
69                 old := *addr
70                 if Cas(addr, old, v) {
71                         return old
72                 }
73         }
74 }
75
76 //go:nosplit
77 func Xchguintptr(addr *uintptr, v uintptr) uintptr {
78         return uintptr(Xchg((*uint32)(unsafe.Pointer(addr)), uint32(v)))
79 }
80
81 // Not noescape -- it installs a pointer to addr.
82 func StorepNoWB(addr unsafe.Pointer, v unsafe.Pointer)
83
84 //go:noescape
85 func Store(addr *uint32, v uint32)
86
87 //go:noescape
88 func StoreRel(addr *uint32, v uint32)
89
90 //go:noescape
91 func StoreReluintptr(addr *uintptr, v uintptr)
92
93 //go:nosplit
94 func goCas64(addr *uint64, old, new uint64) bool {
95         if uintptr(unsafe.Pointer(addr))&7 != 0 {
96                 *(*int)(nil) = 0 // crash on unaligned uint64
97         }
98         _ = *addr // if nil, fault before taking the lock
99         var ok bool
100         addrLock(addr).lock()
101         if *addr == old {
102                 *addr = new
103                 ok = true
104         }
105         addrLock(addr).unlock()
106         return ok
107 }
108
109 //go:nosplit
110 func goXadd64(addr *uint64, delta int64) uint64 {
111         if uintptr(unsafe.Pointer(addr))&7 != 0 {
112                 *(*int)(nil) = 0 // crash on unaligned uint64
113         }
114         _ = *addr // if nil, fault before taking the lock
115         var r uint64
116         addrLock(addr).lock()
117         r = *addr + uint64(delta)
118         *addr = r
119         addrLock(addr).unlock()
120         return r
121 }
122
123 //go:nosplit
124 func goXchg64(addr *uint64, v uint64) uint64 {
125         if uintptr(unsafe.Pointer(addr))&7 != 0 {
126                 *(*int)(nil) = 0 // crash on unaligned uint64
127         }
128         _ = *addr // if nil, fault before taking the lock
129         var r uint64
130         addrLock(addr).lock()
131         r = *addr
132         *addr = v
133         addrLock(addr).unlock()
134         return r
135 }
136
137 //go:nosplit
138 func goLoad64(addr *uint64) uint64 {
139         if uintptr(unsafe.Pointer(addr))&7 != 0 {
140                 *(*int)(nil) = 0 // crash on unaligned uint64
141         }
142         _ = *addr // if nil, fault before taking the lock
143         var r uint64
144         addrLock(addr).lock()
145         r = *addr
146         addrLock(addr).unlock()
147         return r
148 }
149
150 //go:nosplit
151 func goStore64(addr *uint64, v uint64) {
152         if uintptr(unsafe.Pointer(addr))&7 != 0 {
153                 *(*int)(nil) = 0 // crash on unaligned uint64
154         }
155         _ = *addr // if nil, fault before taking the lock
156         addrLock(addr).lock()
157         *addr = v
158         addrLock(addr).unlock()
159 }
160
161 //go:nosplit
162 func Or8(addr *uint8, v uint8) {
163         // Align down to 4 bytes and use 32-bit CAS.
164         uaddr := uintptr(unsafe.Pointer(addr))
165         addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
166         word := uint32(v) << ((uaddr & 3) * 8) // little endian
167         for {
168                 old := *addr32
169                 if Cas(addr32, old, old|word) {
170                         return
171                 }
172         }
173 }
174
175 //go:nosplit
176 func And8(addr *uint8, v uint8) {
177         // Align down to 4 bytes and use 32-bit CAS.
178         uaddr := uintptr(unsafe.Pointer(addr))
179         addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
180         word := uint32(v) << ((uaddr & 3) * 8)    // little endian
181         mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian
182         word |= ^mask
183         for {
184                 old := *addr32
185                 if Cas(addr32, old, old&word) {
186                         return
187                 }
188         }
189 }
190
191 //go:nosplit
192 func Or(addr *uint32, v uint32) {
193         for {
194                 old := *addr
195                 if Cas(addr, old, old|v) {
196                         return
197                 }
198         }
199 }
200
201 //go:nosplit
202 func And(addr *uint32, v uint32) {
203         for {
204                 old := *addr
205                 if Cas(addr, old, old&v) {
206                         return
207                 }
208         }
209 }
210
211 //go:nosplit
212 func Or32(addr *uint32, v uint32) uint32 {
213         for {
214                 old := *addr
215                 if Cas(addr, old, old|v) {
216                         return old
217                 }
218         }
219 }
220
221 //go:nosplit
222 func And32(addr *uint32, v uint32) uint32 {
223         for {
224                 old := *addr
225                 if Cas(addr, old, old&v) {
226                         return old
227                 }
228         }
229 }
230
231 //go:nosplit
232 func Or64(addr *uint64, v uint64) uint64 {
233         for {
234                 old := *addr
235                 if Cas64(addr, old, old|v) {
236                         return old
237                 }
238         }
239 }
240
241 //go:nosplit
242 func And64(addr *uint64, v uint64) uint64 {
243         for {
244                 old := *addr
245                 if Cas64(addr, old, old&v) {
246                         return old
247                 }
248         }
249 }
250
251 //go:nosplit
252 func Oruintptr(addr *uintptr, v uintptr) uintptr {
253         for {
254                 old := *addr
255                 if Casuintptr(addr, old, old|v) {
256                         return old
257                 }
258         }
259 }
260
261 //go:nosplit
262 func Anduintptr(addr *uintptr, v uintptr) uintptr {
263         for {
264                 old := *addr
265                 if Casuintptr(addr, old, old&v) {
266                         return old
267                 }
268         }
269 }
270
271 //go:nosplit
272 func armcas(ptr *uint32, old, new uint32) bool
273
274 //go:noescape
275 func Load(addr *uint32) uint32
276
277 // NO go:noescape annotation; *addr escapes if result escapes (#31525)
278 func Loadp(addr unsafe.Pointer) unsafe.Pointer
279
280 //go:noescape
281 func Load8(addr *uint8) uint8
282
283 //go:noescape
284 func LoadAcq(addr *uint32) uint32
285
286 //go:noescape
287 func LoadAcquintptr(ptr *uintptr) uintptr
288
289 //go:noescape
290 func Cas64(addr *uint64, old, new uint64) bool
291
292 //go:noescape
293 func CasRel(addr *uint32, old, new uint32) bool
294
295 //go:noescape
296 func Xadd64(addr *uint64, delta int64) uint64
297
298 //go:noescape
299 func Xchg64(addr *uint64, v uint64) uint64
300
301 //go:noescape
302 func Load64(addr *uint64) uint64
303
304 //go:noescape
305 func Store8(addr *uint8, v uint8)
306
307 //go:noescape
308 func Store64(addr *uint64, v uint64)