github.com/primecitizens/pcz/std@v0.2.1/core/atomic/atomic_arm.s (about) 1 // SPDX-License-Identifier: Apache-2.0 2 // Copyright 2023 The Prime Citizens 3 // 4 // Copyright 2015 The Go Authors. All rights reserved. 5 // Use of this source code is governed by a BSD-style 6 // license that can be found in the LICENSE file. 7 8 //go:build arm 9 10 #include "textflag.h" 11 #include "funcdata.h" 12 13 // armPublicationBarrier is a native store/store barrier for ARMv7+. 14 // On earlier ARM revisions, armPublicationBarrier is a no-op. 15 // This will not work on SMP ARMv6 machines, if any are in use. 16 // To implement publicationBarrier in sys_$GOOS_arm.s using the native 17 // instructions, use: 18 // 19 // TEXT ·PublicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 20 // B runtime·armPublicationBarrier(SB) 21 // 22 TEXT ·PublicationBarrier(SB),NOSPLIT|NOFRAME,$0-0 23 MOVB runtime·goarm(SB), R11 24 CMP $7, R11 25 BLT 2(PC) 26 DMB MB_ST 27 RET 28 29 // bool armcas(int32 *val, int32 old, int32 new) 30 // 31 // To implement ·cas in sys_$GOOS_arm.s 32 // using the native instructions, use: 33 // 34 // TEXT ·cas(SB),NOSPLIT,$0 35 // B ·armcas(SB) 36 // 37 TEXT ·armcas(SB),NOSPLIT,$0-13 38 MOVW ptr+0(FP), R1 39 MOVW old+4(FP), R2 40 MOVW new+8(FP), R3 41 casl: 42 LDREX (R1), R0 43 CMP R0, R2 44 BNE casfail 45 46 MOVB runtime·goarm(SB), R8 47 CMP $7, R8 48 BLT 2(PC) 49 DMB MB_ISHST 50 51 STREX R3, (R1), R0 52 CMP $0, R0 53 BNE casl 54 MOVW $1, R0 55 56 CMP $7, R8 57 BLT 2(PC) 58 DMB MB_ISH 59 60 MOVB R0, ret+12(FP) 61 RET 62 casfail: 63 MOVW $0, R0 64 MOVB R0, ret+12(FP) 65 RET 66 67 // 64-bit atomics 68 // The native ARM implementations use LDREXD/STREXD, which are 69 // available on ARMv6k or later. We use them only on ARMv7. 70 // On older ARM, we use Go implementations which simulate 64-bit 71 // atomics with locks. 72 TEXT armCas64<>(SB),NOSPLIT,$0-21 73 // addr is already in R1 74 MOVW old_lo+4(FP), R2 75 MOVW old_hi+8(FP), R3 76 MOVW new_lo+12(FP), R4 77 MOVW new_hi+16(FP), R5 78 cas64loop: 79 LDREXD (R1), R6 // loads R6 and R7 80 CMP R2, R6 81 BNE cas64fail 82 CMP R3, R7 83 BNE cas64fail 84 85 DMB MB_ISHST 86 87 STREXD R4, (R1), R0 // stores R4 and R5 88 CMP $0, R0 89 BNE cas64loop 90 MOVW $1, R0 91 92 DMB MB_ISH 93 94 MOVBU R0, swapped+20(FP) 95 RET 96 cas64fail: 97 MOVW $0, R0 98 MOVBU R0, swapped+20(FP) 99 RET 100 101 TEXT armAdd64<>(SB),NOSPLIT,$0-20 102 // addr is already in R1 103 MOVW delta_lo+4(FP), R2 104 MOVW delta_hi+8(FP), R3 105 106 add64loop: 107 LDREXD (R1), R4 // loads R4 and R5 108 ADD.S R2, R4 109 ADC R3, R5 110 111 DMB MB_ISHST 112 113 STREXD R4, (R1), R0 // stores R4 and R5 114 CMP $0, R0 115 BNE add64loop 116 117 DMB MB_ISH 118 119 MOVW R4, new_lo+12(FP) 120 MOVW R5, new_hi+16(FP) 121 RET 122 123 TEXT armSwap64<>(SB),NOSPLIT,$0-20 124 // addr is already in R1 125 MOVW new_lo+4(FP), R2 126 MOVW new_hi+8(FP), R3 127 128 swap64loop: 129 LDREXD (R1), R4 // loads R4 and R5 130 131 DMB MB_ISHST 132 133 STREXD R2, (R1), R0 // stores R2 and R3 134 CMP $0, R0 135 BNE swap64loop 136 137 DMB MB_ISH 138 139 MOVW R4, old_lo+12(FP) 140 MOVW R5, old_hi+16(FP) 141 RET 142 143 TEXT armLoad64<>(SB),NOSPLIT,$0-12 144 // addr is already in R1 145 146 LDREXD (R1), R2 // loads R2 and R3 147 DMB MB_ISH 148 149 MOVW R2, val_lo+4(FP) 150 MOVW R3, val_hi+8(FP) 151 RET 152 153 TEXT armStore64<>(SB),NOSPLIT,$0-12 154 // addr is already in R1 155 MOVW val_lo+4(FP), R2 156 MOVW val_hi+8(FP), R3 157 158 store64loop: 159 LDREXD (R1), R4 // loads R4 and R5 160 161 DMB MB_ISHST 162 163 STREXD R2, (R1), R0 // stores R2 and R3 164 CMP $0, R0 165 BNE store64loop 166 167 DMB MB_ISH 168 RET 169 170 // The following functions all panic if their address argument isn't 171 // 8-byte aligned. Since we're calling back into Go code to do this, 172 // we have to cooperate with stack unwinding. In the normal case, the 173 // functions tail-call into the appropriate implementation, which 174 // means they must not open a frame. Hence, when they go down the 175 // panic path, at that point they push the LR to create a real frame 176 // (they don't need to pop it because panic won't return; however, we 177 // do need to set the SP delta back). 178 179 // Check if R1 is 8-byte aligned, panic if not. 180 // Clobbers R2. 181 #define CHECK_ALIGN \ 182 AND.S $7, R1, R2 \ 183 BEQ 4(PC) \ 184 MOVW.W R14, -4(R13) /* prepare a real frame */ \ 185 BL ·panicUnaligned(SB) \ 186 ADD $4, R13 /* compensate SP delta */ 187 188 // 189 // Store 190 // 191 192 TEXT ·Store64(SB),NOSPLIT,$-4-12 193 NO_LOCAL_POINTERS 194 MOVW addr+0(FP), R1 195 CHECK_ALIGN 196 197 MOVB runtime·goarm(SB), R11 198 CMP $7, R11 199 BLT 2(PC) 200 JMP armStore64<>(SB) 201 JMP ·goStore64(SB) 202 203 TEXT ·StoreUintptr(SB),NOSPLIT,$0-8 204 B ·Store(SB) 205 206 TEXT ·StorePointer(SB),NOSPLIT,$0-8 207 B ·Store(SB) 208 209 TEXT ·StoreInt32(SB),NOSPLIT,$0-8 210 B ·Store(SB) 211 212 TEXT ·StoreInt64(SB),NOSPLIT,$0-12 213 B ·Store64(SB) 214 215 // 216 // StoreRel 217 // 218 219 TEXT ·StoreRel32(SB),NOSPLIT,$0-8 220 B ·Store(SB) 221 222 TEXT ·StoreRelUintptr(SB),NOSPLIT,$0-8 223 B ·Store(SB) 224 225 // 226 // Load 227 // 228 229 TEXT ·Load64(SB),NOSPLIT,$-4-12 230 NO_LOCAL_POINTERS 231 MOVW addr+0(FP), R1 232 CHECK_ALIGN 233 234 MOVB runtime·goarm(SB), R11 235 CMP $7, R11 236 BLT 2(PC) 237 JMP armLoad64<>(SB) 238 JMP ·goLoad64(SB) 239 240 TEXT ·LoadUintptr(SB),NOSPLIT,$0-8 241 B ·Load32(SB) 242 243 TEXT ·LoadPointer(SB),NOSPLIT|NOFRAME,$0-8 244 B ·Load32(SB) 245 246 TEXT ·LoadUint(SB),NOSPLIT,$0-8 247 B ·Load32(SB) 248 249 TEXT ·LoadInt32(SB),NOSPLIT,$0-8 250 B ·Load32(SB) 251 252 TEXT ·LoadInt64(SB),NOSPLIT,$-4-12 253 B ·Load64(SB) 254 255 // 256 // LoadAcq 257 // 258 259 TEXT ·LoadAcq32(SB),NOSPLIT|NOFRAME,$0-8 260 B ·Load32(SB) 261 262 TEXT ·LoadAcqUintptr(SB),NOSPLIT|NOFRAME,$0-8 263 B ·Load32(SB) 264 265 // 266 // bitwise 267 // 268 269 // 270 // Swap 271 // 272 273 TEXT ·Swap64(SB),NOSPLIT,$-4-20 274 NO_LOCAL_POINTERS 275 MOVW addr+0(FP), R1 276 CHECK_ALIGN 277 278 MOVB runtime·goarm(SB), R11 279 CMP $7, R11 280 BLT 2(PC) 281 JMP armSwap64<>(SB) 282 JMP ·goSwap64(SB) 283 284 TEXT ·SwapInt32(SB),NOSPLIT,$0-12 285 B ·Swap32(SB) 286 287 TEXT ·SwapInt64(SB),NOSPLIT,$-4-20 288 B ·Swap64(SB) 289 290 // 291 // Add 292 // 293 294 TEXT ·Add64(SB),NOSPLIT,$-4-20 295 NO_LOCAL_POINTERS 296 MOVW addr+0(FP), R1 297 CHECK_ALIGN 298 299 MOVB runtime·goarm(SB), R11 300 CMP $7, R11 301 BLT 2(PC) 302 JMP armAdd64<>(SB) 303 JMP ·goAdd64(SB) 304 305 TEXT ·AddUintptr(SB),NOSPLIT,$0-12 306 B ·Add32(SB) 307 308 TEXT ·AddInt32(SB),NOSPLIT,$0-12 309 B ·Add32(SB) 310 311 TEXT ·AddInt64(SB),NOSPLIT,$-4-20 312 B ·Add64(SB) 313 314 // 315 // Compare and swap 316 // 317 318 TEXT ·Cas64(SB),NOSPLIT,$-4-21 319 NO_LOCAL_POINTERS 320 MOVW addr+0(FP), R1 321 CHECK_ALIGN 322 323 MOVB runtime·goarm(SB), R11 324 CMP $7, R11 325 BLT 2(PC) 326 JMP armCas64<>(SB) 327 JMP ·goCas64(SB) 328 329 TEXT ·CasInt32(SB),NOSPLIT,$0-13 330 B ·Cas(SB) 331 332 TEXT ·CasInt64(SB),NOSPLIT,$-4-21 333 B ·Cas64(SB) 334 335 TEXT ·CasUintptr(SB),NOSPLIT,$0-13 336 B ·Cas(SB) 337 338 TEXT ·CasUnsafePointer(SB),NOSPLIT,$0-13 339 B ·Cas(SB) 340 341 TEXT ·CasRel32(SB),NOSPLIT,$0-13 342 B ·Cas(SB)