aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/internal/runtime/atomic/atomic_amd64.go3
-rw-r--r--src/internal/runtime/atomic/atomic_amd64.s12
-rw-r--r--src/internal/runtime/atomic/xchg8_test.go39
3 files changed, 54 insertions, 0 deletions
diff --git a/src/internal/runtime/atomic/atomic_amd64.go b/src/internal/runtime/atomic/atomic_amd64.go
index b439954093..2a2d07e511 100644
--- a/src/internal/runtime/atomic/atomic_amd64.go
+++ b/src/internal/runtime/atomic/atomic_amd64.go
@@ -58,6 +58,9 @@ func Xadd64(ptr *uint64, delta int64) uint64
func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
//go:noescape
+func Xchg8(ptr *uint8, new uint8) uint8
+
+//go:noescape
func Xchg(ptr *uint32, new uint32) uint32
//go:noescape
diff --git a/src/internal/runtime/atomic/atomic_amd64.s b/src/internal/runtime/atomic/atomic_amd64.s
index ec75bf9332..d6dc7a32d6 100644
--- a/src/internal/runtime/atomic/atomic_amd64.s
+++ b/src/internal/runtime/atomic/atomic_amd64.s
@@ -117,6 +117,18 @@ TEXT ·Xaddint64(SB), NOSPLIT, $0-24
TEXT ·Xadduintptr(SB), NOSPLIT, $0-24
JMP ·Xadd64(SB)
+// uint8 Xchg(ptr *uint8, new uint8)
+// Atomically:
+// old := *ptr;
+// *ptr = new;
+// return old;
+TEXT ·Xchg8(SB), NOSPLIT, $0-17
+ MOVQ ptr+0(FP), BX
+ MOVB new+8(FP), AX
+ XCHGB AX, 0(BX)
+ MOVB AX, ret+16(FP)
+ RET
+
// uint32 Xchg(ptr *uint32, new uint32)
// Atomically:
// old := *ptr;
diff --git a/src/internal/runtime/atomic/xchg8_test.go b/src/internal/runtime/atomic/xchg8_test.go
new file mode 100644
index 0000000000..139062422e
--- /dev/null
+++ b/src/internal/runtime/atomic/xchg8_test.go
@@ -0,0 +1,39 @@
+// Copyright 2024 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64
+
+package atomic_test
+
+import (
+ "internal/runtime/atomic"
+ "testing"
+)
+
+func TestXchg8(t *testing.T) {
+ var a [16]uint8
+ for i := range a {
+ next := uint8(i + 50)
+ a[i] = next
+ }
+ b := a
+
+ // Compare behavior against non-atomic implementation. Expect the operation
+ // to work at any byte offset and to not clobber neighboring values.
+ for i := range a {
+ next := uint8(i + 100)
+ pa := atomic.Xchg8(&a[i], next)
+ pb := b[i]
+ b[i] = next
+ if pa != pb {
+ t.Errorf("atomic.Xchg8(a[%d]); %d != %d", i, pa, pb)
+ }
+ if a != b {
+ t.Errorf("after atomic.Xchg8(a[%d]); %d != %d", i, a, b)
+ }
+ if t.Failed() {
+ break
+ }
+ }
+}