1 // Copyright 2015 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 #include "go_asm.h"
6 #include "textflag.h"
7 #include "funcdata.h"
8
9 // func armcas(ptr *int32, old, new int32) bool
10 // Atomically:
11 // if *ptr == old {
12 // *ptr = new
13 // return true
14 // } else {
15 // return false
16 // }
17 //
18 // To implement ·cas in sys_$GOOS_arm.s
19 // using the native instructions, use:
20 //
21 // TEXT ·cas(SB),NOSPLIT,$0
22 // B ·armcas(SB)
23 //
24 TEXT ·armcas(SB),NOSPLIT,$0-13
25 MOVW ptr+0(FP), R1
26 MOVW old+4(FP), R2
27 MOVW new+8(FP), R3
28 casl:
29 LDREX (R1), R0
30 CMP R0, R2
31 BNE casfail
32
33 #ifndef GOARM_7
34 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
35 CMP $0, R11
36 BEQ 2(PC)
37 #endif
38 DMB MB_ISHST
39
40 STREX R3, (R1), R0
41 CMP $0, R0
42 BNE casl
43 MOVW $1, R0
44
45 #ifndef GOARM_7
46 CMP $0, R11
47 BEQ 2(PC)
48 #endif
49 DMB MB_ISH
50
51 MOVB R0, ret+12(FP)
52 RET
53 casfail:
54 MOVW $0, R0
55 MOVB R0, ret+12(FP)
56 RET
57
58 // stubs
59
60 TEXT ·Loadp(SB),NOSPLIT|NOFRAME,$0-8
61 B ·Load(SB)
62
63 TEXT ·LoadAcq(SB),NOSPLIT|NOFRAME,$0-8
64 B ·Load(SB)
65
66 TEXT ·LoadAcquintptr(SB),NOSPLIT|NOFRAME,$0-8
67 B ·Load(SB)
68
69 TEXT ·Casint32(SB),NOSPLIT,$0-13
70 B ·Cas(SB)
71
72 TEXT ·Casint64(SB),NOSPLIT,$-4-21
73 B ·Cas64(SB)
74
75 TEXT ·Casuintptr(SB),NOSPLIT,$0-13
76 B ·Cas(SB)
77
78 TEXT ·Casp1(SB),NOSPLIT,$0-13
79 B ·Cas(SB)
80
81 TEXT ·CasRel(SB),NOSPLIT,$0-13
82 B ·Cas(SB)
83
84 TEXT ·Loadint32(SB),NOSPLIT,$0-8
85 B ·Load(SB)
86
87 TEXT ·Loadint64(SB),NOSPLIT,$-4-12
88 B ·Load64(SB)
89
90 TEXT ·Loaduintptr(SB),NOSPLIT,$0-8
91 B ·Load(SB)
92
93 TEXT ·Loaduint(SB),NOSPLIT,$0-8
94 B ·Load(SB)
95
96 TEXT ·Storeint32(SB),NOSPLIT,$0-8
97 B ·Store(SB)
98
99 TEXT ·Storeint64(SB),NOSPLIT,$0-12
100 B ·Store64(SB)
101
102 TEXT ·Storeuintptr(SB),NOSPLIT,$0-8
103 B ·Store(SB)
104
105 TEXT ·StorepNoWB(SB),NOSPLIT,$0-8
106 B ·Store(SB)
107
108 TEXT ·StoreRel(SB),NOSPLIT,$0-8
109 B ·Store(SB)
110
111 TEXT ·StoreReluintptr(SB),NOSPLIT,$0-8
112 B ·Store(SB)
113
114 TEXT ·Xaddint32(SB),NOSPLIT,$0-12
115 B ·Xadd(SB)
116
117 TEXT ·Xaddint64(SB),NOSPLIT,$-4-20
118 B ·Xadd64(SB)
119
120 TEXT ·Xadduintptr(SB),NOSPLIT,$0-12
121 B ·Xadd(SB)
122
123 TEXT ·Xchgint32(SB),NOSPLIT,$0-12
124 B ·Xchg(SB)
125
126 TEXT ·Xchgint64(SB),NOSPLIT,$-4-20
127 B ·Xchg64(SB)
128
129 // 64-bit atomics
130 // The native ARM implementations use LDREXD/STREXD, which are
131 // available on ARMv6k or later. We use them only on ARMv7.
132 // On older ARM, we use Go implementations which simulate 64-bit
133 // atomics with locks.
134 TEXT armCas64<>(SB),NOSPLIT,$0-21
135 // addr is already in R1
136 MOVW old_lo+4(FP), R2
137 MOVW old_hi+8(FP), R3
138 MOVW new_lo+12(FP), R4
139 MOVW new_hi+16(FP), R5
140 cas64loop:
141 LDREXD (R1), R6 // loads R6 and R7
142 CMP R2, R6
143 BNE cas64fail
144 CMP R3, R7
145 BNE cas64fail
146
147 DMB MB_ISHST
148
149 STREXD R4, (R1), R0 // stores R4 and R5
150 CMP $0, R0
151 BNE cas64loop
152 MOVW $1, R0
153
154 DMB MB_ISH
155
156 MOVBU R0, swapped+20(FP)
157 RET
158 cas64fail:
159 MOVW $0, R0
160 MOVBU R0, swapped+20(FP)
161 RET
162
163 TEXT armXadd64<>(SB),NOSPLIT,$0-20
164 // addr is already in R1
165 MOVW delta_lo+4(FP), R2
166 MOVW delta_hi+8(FP), R3
167
168 add64loop:
169 LDREXD (R1), R4 // loads R4 and R5
170 ADD.S R2, R4
171 ADC R3, R5
172
173 DMB MB_ISHST
174
175 STREXD R4, (R1), R0 // stores R4 and R5
176 CMP $0, R0
177 BNE add64loop
178
179 DMB MB_ISH
180
181 MOVW R4, new_lo+12(FP)
182 MOVW R5, new_hi+16(FP)
183 RET
184
185 TEXT armXchg64<>(SB),NOSPLIT,$0-20
186 // addr is already in R1
187 MOVW new_lo+4(FP), R2
188 MOVW new_hi+8(FP), R3
189
190 swap64loop:
191 LDREXD (R1), R4 // loads R4 and R5
192
193 DMB MB_ISHST
194
195 STREXD R2, (R1), R0 // stores R2 and R3
196 CMP $0, R0
197 BNE swap64loop
198
199 DMB MB_ISH
200
201 MOVW R4, old_lo+12(FP)
202 MOVW R5, old_hi+16(FP)
203 RET
204
205 TEXT armLoad64<>(SB),NOSPLIT,$0-12
206 // addr is already in R1
207
208 LDREXD (R1), R2 // loads R2 and R3
209 DMB MB_ISH
210
211 MOVW R2, val_lo+4(FP)
212 MOVW R3, val_hi+8(FP)
213 RET
214
215 TEXT armStore64<>(SB),NOSPLIT,$0-12
216 // addr is already in R1
217 MOVW val_lo+4(FP), R2
218 MOVW val_hi+8(FP), R3
219
220 store64loop:
221 LDREXD (R1), R4 // loads R4 and R5
222
223 DMB MB_ISHST
224
225 STREXD R2, (R1), R0 // stores R2 and R3
226 CMP $0, R0
227 BNE store64loop
228
229 DMB MB_ISH
230 RET
231
232 TEXT armAnd8<>(SB),NOSPLIT,$0-5
233 // addr is already in R1
234 MOVB v+4(FP), R2
235
236 and8loop:
237 LDREXB (R1), R6
238
239 DMB MB_ISHST
240
241 AND R2, R6
242 STREXB R6, (R1), R0
243 CMP $0, R0
244 BNE and8loop
245
246 DMB MB_ISH
247
248 RET
249
250 TEXT armOr8<>(SB),NOSPLIT,$0-5
251 // addr is already in R1
252 MOVB v+4(FP), R2
253
254 or8loop:
255 LDREXB (R1), R6
256
257 DMB MB_ISHST
258
259 ORR R2, R6
260 STREXB R6, (R1), R0
261 CMP $0, R0
262 BNE or8loop
263
264 DMB MB_ISH
265
266 RET
267
268 TEXT armXchg8<>(SB),NOSPLIT,$0-9
269 // addr is already in R1
270 MOVB v+4(FP), R2
271 xchg8loop:
272 LDREXB (R1), R6
273
274 DMB MB_ISHST
275
276 STREXB R2, (R1), R0
277 CMP $0, R0
278 BNE xchg8loop
279
280 DMB MB_ISH
281
282 MOVB R6, ret+8(FP)
283 RET
284
285 // The following functions all panic if their address argument isn't
286 // 8-byte aligned. Since we're calling back into Go code to do this,
287 // we have to cooperate with stack unwinding. In the normal case, the
288 // functions tail-call into the appropriate implementation, which
289 // means they must not open a frame. Hence, when they go down the
290 // panic path, at that point they push the LR to create a real frame
291 // (they don't need to pop it because panic won't return; however, we
292 // do need to set the SP delta back).
293
294 // Check if R1 is 8-byte aligned, panic if not.
295 // Clobbers R2.
296 #define CHECK_ALIGN \
297 AND.S $7, R1, R2 \
298 BEQ 4(PC) \
299 MOVW.W R14, -4(R13) /* prepare a real frame */ \
300 BL ·panicUnaligned(SB) \
301 ADD $4, R13 /* compensate SP delta */
302
303 TEXT ·Cas64(SB),NOSPLIT,$-4-21
304 NO_LOCAL_POINTERS
305 MOVW addr+0(FP), R1
306 CHECK_ALIGN
307
308 #ifndef GOARM_7
309 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
310 CMP $1, R11
311 BEQ 2(PC)
312 JMP ·goCas64(SB)
313 #endif
314 JMP armCas64<>(SB)
315
316 TEXT ·Xadd64(SB),NOSPLIT,$-4-20
317 NO_LOCAL_POINTERS
318 MOVW addr+0(FP), R1
319 CHECK_ALIGN
320
321 #ifndef GOARM_7
322 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
323 CMP $1, R11
324 BEQ 2(PC)
325 JMP ·goXadd64(SB)
326 #endif
327 JMP armXadd64<>(SB)
328
329 TEXT ·Xchg64(SB),NOSPLIT,$-4-20
330 NO_LOCAL_POINTERS
331 MOVW addr+0(FP), R1
332 CHECK_ALIGN
333
334 #ifndef GOARM_7
335 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
336 CMP $1, R11
337 BEQ 2(PC)
338 JMP ·goXchg64(SB)
339 #endif
340 JMP armXchg64<>(SB)
341
342 TEXT ·Load64(SB),NOSPLIT,$-4-12
343 NO_LOCAL_POINTERS
344 MOVW addr+0(FP), R1
345 CHECK_ALIGN
346
347 #ifndef GOARM_7
348 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
349 CMP $1, R11
350 BEQ 2(PC)
351 JMP ·goLoad64(SB)
352 #endif
353 JMP armLoad64<>(SB)
354
355 TEXT ·Store64(SB),NOSPLIT,$-4-12
356 NO_LOCAL_POINTERS
357 MOVW addr+0(FP), R1
358 CHECK_ALIGN
359
360 #ifndef GOARM_7
361 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
362 CMP $1, R11
363 BEQ 2(PC)
364 JMP ·goStore64(SB)
365 #endif
366 JMP armStore64<>(SB)
367
368 TEXT ·And8(SB),NOSPLIT,$-4-5
369 NO_LOCAL_POINTERS
370 MOVW addr+0(FP), R1
371
372 // Uses STREXB/LDREXB that is armv6k or later.
373 // For simplicity we only enable this on armv7.
374 #ifndef GOARM_7
375 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
376 CMP $1, R11
377 BEQ 2(PC)
378 JMP ·goAnd8(SB)
379 #endif
380 JMP armAnd8<>(SB)
381
382 TEXT ·Or8(SB),NOSPLIT,$-4-5
383 NO_LOCAL_POINTERS
384 MOVW addr+0(FP), R1
385
386 // Uses STREXB/LDREXB that is armv6k or later.
387 // For simplicity we only enable this on armv7.
388 #ifndef GOARM_7
389 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
390 CMP $1, R11
391 BEQ 2(PC)
392 JMP ·goOr8(SB)
393 #endif
394 JMP armOr8<>(SB)
395
396 TEXT ·Xchg8(SB),NOSPLIT,$-4-9
397 NO_LOCAL_POINTERS
398 MOVW addr+0(FP), R1
399
400 // Uses STREXB/LDREXB that is armv6k or later.
401 // For simplicity we only enable this on armv7.
402 #ifndef GOARM_7
403 MOVB internal∕cpu·ARM+const_offsetARMHasV7Atomics(SB), R11
404 CMP $1, R11
405 BEQ 2(PC)
406 JMP ·goXchg8(SB)
407 #endif
408 JMP armXchg8<>(SB)
409
View as plain text