From 3c3b8dd4f0590881f7010014985d05cce1c9e943 Mon Sep 17 00:00:00 2001 From: Rhys Hiltner Date: Fri, 14 Mar 2025 09:36:06 -0700 Subject: [PATCH] internal/runtime/atomic: add Xchg8 for s390x and wasm This makes the single-byte atomic.Xchg8 operation available on all GOARCHes, including those without direct / single-instruction support. Fixes #69735 Change-Id: Icb6aff8f907257db81ea440dc4d29f96b3cff6c4 Reviewed-on: https://go-review.googlesource.com/c/go/+/657936 Reviewed-by: Mauri de Souza Meneguzzo Reviewed-by: Keith Randall Reviewed-by: David Chase LUCI-TryBot-Result: Go LUCI Reviewed-by: Keith Randall Auto-Submit: Rhys Hiltner TryBot-Result: Gopher Robot --- src/internal/runtime/atomic/atomic_arm.go | 18 ------------ src/internal/runtime/atomic/atomic_s390x.go | 5 ++++ src/internal/runtime/atomic/atomic_wasm.go | 5 ++++ src/internal/runtime/atomic/xchg8.go | 32 +++++++++++++++++++++ src/internal/runtime/atomic/xchg8_test.go | 2 -- 5 files changed, 42 insertions(+), 20 deletions(-) create mode 100644 src/internal/runtime/atomic/xchg8.go diff --git a/src/internal/runtime/atomic/atomic_arm.go b/src/internal/runtime/atomic/atomic_arm.go index 8d8ffcf7dc..e858fb7cd1 100644 --- a/src/internal/runtime/atomic/atomic_arm.go +++ b/src/internal/runtime/atomic/atomic_arm.go @@ -77,24 +77,6 @@ func Xchg(addr *uint32, v uint32) uint32 { //go:noescape func Xchg8(addr *uint8, v uint8) uint8 -//go:nosplit -func goXchg8(addr *uint8, v uint8) uint8 { - // Align down to 4 bytes and use 32-bit CAS. - addr32 := (*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(addr)) &^ 3)) - shift := (uintptr(unsafe.Pointer(addr)) & 3) * 8 // little endian - word := uint32(v) << shift - mask := uint32(0xFF) << shift - - for { - old := *addr32 // Read the old 32-bit value - // Clear the old 8 bits then insert the new value - if Cas(addr32, old, (old&^mask)|word) { - // Return the old 8-bit value - return uint8((old & mask) >> shift) - } - } -} - //go:nosplit func Xchguintptr(addr *uintptr, v uintptr) uintptr { return uintptr(Xchg((*uint32)(unsafe.Pointer(addr)), uint32(v))) diff --git a/src/internal/runtime/atomic/atomic_s390x.go b/src/internal/runtime/atomic/atomic_s390x.go index 68b4e160f9..bd5d867bec 100644 --- a/src/internal/runtime/atomic/atomic_s390x.go +++ b/src/internal/runtime/atomic/atomic_s390x.go @@ -128,6 +128,11 @@ func Xadduintptr(ptr *uintptr, delta uintptr) uintptr //go:noescape func Xchg(ptr *uint32, new uint32) uint32 +//go:nosplit +func Xchg8(addr *uint8, v uint8) uint8 { + return goXchg8(addr, v) +} + //go:noescape func Xchg64(ptr *uint64, new uint64) uint64 diff --git a/src/internal/runtime/atomic/atomic_wasm.go b/src/internal/runtime/atomic/atomic_wasm.go index d1dcfec7ad..3f14da138c 100644 --- a/src/internal/runtime/atomic/atomic_wasm.go +++ b/src/internal/runtime/atomic/atomic_wasm.go @@ -114,6 +114,11 @@ func Xchg(ptr *uint32, new uint32) uint32 { return old } +//go:nosplit +func Xchg8(addr *uint8, v uint8) uint8 { + return goXchg8(addr, v) +} + //go:nosplit //go:noinline func Xchg64(ptr *uint64, new uint64) uint64 { diff --git a/src/internal/runtime/atomic/xchg8.go b/src/internal/runtime/atomic/xchg8.go new file mode 100644 index 0000000000..4fdea9a3d6 --- /dev/null +++ b/src/internal/runtime/atomic/xchg8.go @@ -0,0 +1,32 @@ +// Copyright 2025 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. + +package atomic + +import ( + "internal/goarch" + "unsafe" +) + +//go:nosplit +func goXchg8(addr *uint8, v uint8) uint8 { + // Align down to 4 bytes and use 32-bit CAS. + addr32 := (*uint32)(unsafe.Pointer(uintptr(unsafe.Pointer(addr)) &^ 3)) + shift := (uintptr(unsafe.Pointer(addr)) & 3) + if goarch.BigEndian { + shift = shift ^ 3 + } + shift = shift * 8 + word := uint32(v) << shift + mask := uint32(0xFF) << shift + + for { + old := *addr32 // Read the old 32-bit value + // Clear the old 8 bits then insert the new value + if Cas(addr32, old, (old&^mask)|word) { + // Return the old 8-bit value + return uint8((old & mask) >> shift) + } + } +} diff --git a/src/internal/runtime/atomic/xchg8_test.go b/src/internal/runtime/atomic/xchg8_test.go index 952dfe4aad..1214c9cedc 100644 --- a/src/internal/runtime/atomic/xchg8_test.go +++ b/src/internal/runtime/atomic/xchg8_test.go @@ -2,8 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -//go:build 386 || amd64 || arm || arm64 || loong64 || mips || mipsle || mips64 || mips64le || ppc64 || ppc64le || riscv64 - package atomic_test import ( -- 2.50.0