We're skating on thin ice, and things are finally starting to melt around here.
(I want to avoid the debugging session that will happen when someone
uses atomicand8 expecting it to be atomic with respect to other operations.)
Change-Id: I254f1582be4eb1f2d7fbba05335a91c6bf0c7f02
Reviewed-on: https://go-review.googlesource.com/7861
Reviewed-by: Minux Ma <minux@golang.org>
ORB BX, (AX)
RET
+// void runtime·atomicand8(byte volatile*, byte);
+TEXT runtime·atomicand8(SB), NOSPLIT, $0-5
+ MOVL ptr+0(FP), AX
+ MOVB val+4(FP), BX
+ LOCK
+ ANDB BX, (AX)
+ RET
+
// void jmpdefer(fn, sp);
// called from deferreturn.
// 1. pop the caller
ORB BX, (AX)
RET
+// void runtime·atomicand8(byte volatile*, byte);
+TEXT runtime·atomicand8(SB), NOSPLIT, $0-9
+ MOVQ ptr+0(FP), AX
+ MOVB val+8(FP), BX
+ LOCK
+ ANDB BX, (AX)
+ RET
+
// void jmpdefer(fn, sp);
// called from deferreturn.
// 1. pop the caller
// Shift val for aligned ptr. R4 = val << R6
SLD R6, R4, R4
-atomicor8_again:
+again:
SYNC
LWAR (R5), R6
OR R4, R6
STWCCC R6, (R5)
- BNE atomicor8_again
+ BNE again
+ SYNC
+ ISYNC
+ RETURN
+
+// void runtime·atomicand8(byte volatile*, byte);
+TEXT runtime·atomicand8(SB), NOSPLIT, $0-9
+ MOVD ptr+0(FP), R3
+ MOVBZ val+8(FP), R4
+ // Align ptr down to 4 bytes so we can use 32-bit load/store.
+ // R5 = (R3 << 0) & ~3
+ RLDCR $0, R3, $~3, R5
+ // Compute val shift.
+#ifdef GOARCH_ppc64
+ // Big endian. ptr = ptr ^ 3
+ XOR $3, R3
+#endif
+ // R6 = ((ptr & 3) * 8) = (ptr << 3) & (3*8)
+ RLDC $3, R3, $(3*8), R6
+ // Shift val for aligned ptr. R4 = val << R6 | ^(0xFF << R6)
+ MOVD $0xFF, R7
+ SLD R6, R4
+ SLD R6, R7
+ XOR $-1, R7
+ OR R7, R4
+again:
+ SYNC
+ LWAR (R5), R6
+ AND R4, R6
+ STWCCC R6, (R5)
+ BNE again
SYNC
ISYNC
RETURN
//go:noescape
func atomicload64(ptr *uint64) uint64
+//go:noescape
+func atomicand8(ptr *uint8, val uint8)
+
//go:noescape
func atomicor8(ptr *uint8, val uint8)
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
//go:noescape
func cas64(ptr *uint64, old, new uint64) bool
//go:noescape
func xchguintptr(ptr *uintptr, new uintptr) uintptr
+//go:noescape
+func atomicand8(ptr *uint8, val uint8)
+
//go:noescape
func atomicor8(ptr *uint8, val uint8)
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
//go:noescape
func cas64(ptr *uint64, old, new uint64) bool
}
}
}
+
+//go:nosplit
+func atomicand8(addr *uint8, v uint8) {
+ // Align down to 4 bytes and use 32-bit CAS.
+ uaddr := uintptr(unsafe.Pointer(addr))
+ addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
+ mask := 0xFF << ((uaddr & 3) * 8) // little endian
+ word := uint32(v) << ((uaddr & 3) * 8) // little endian
+ word |= ^mask
+ for {
+ old := *addr32
+ if cas(addr32, old, old&word) {
+ return
+ }
+ }
+}
}
}
+//go:nosplit
+func atomicand8(addr *uint8, v uint8) {
+ // TODO(dfc) implement this in asm.
+ // Align down to 4 bytes and use 32-bit CAS.
+ uaddr := uintptr(unsafe.Pointer(addr))
+ addr32 := (*uint32)(unsafe.Pointer(uaddr &^ 3))
+ word := uint32(v) << ((uaddr & 3) * 8) // little endian
+ mask := uint32(0xFF) << ((uaddr & 3) * 8) // little endian
+ word |= ^mask
+ for {
+ old := *addr32
+ if cas(addr32, old, old&word) {
+ return
+ }
+ }
+}
+
//go:noescape
func cas64(ptr *uint64, old, new uint64) bool
//go:noescape
func atomicloadp(ptr unsafe.Pointer) unsafe.Pointer
+//go:noescape
+func atomicand8(ptr *uint8, val uint8)
+
//go:noescape
func atomicor8(ptr *uint8, val uint8)
+// NOTE: Do not add atomicxor8 (XOR is not idempotent).
+
//go:noescape
func cas64(ptr *uint64, old, new uint64) bool
return &weak_cgo_allocate != nil
}
-// Slow for now as we serialize this, since this is on a debug path
-// speed is not critical at this point.
-var andlock mutex
-
-//go:nowritebarrier
-func atomicand8(src *byte, val byte) {
- lock(&andlock)
- *src &= val
- unlock(&andlock)
-}
-
var gcdatamask bitvector
var gcbssmask bitvector