From 0c68e1215e877edbb2b45573b89500de1bc8c105 Mon Sep 17 00:00:00 2001 From: rdon-key Date: Thu, 23 Jul 2026 14:06:37 +0900 Subject: [PATCH] runtime: add critical-section fallbacks for atomic And and Or --- src/runtime/atomics_critical.go | 168 ++++++++++++++++++ testdata/atomic.go | 24 +++ testdata/atomic.txt | 10 ++ .../gen-critical-atomics.go | 2 + 4 files changed, 204 insertions(+) diff --git a/src/runtime/atomics_critical.go b/src/runtime/atomics_critical.go index 74ce321f1..202e3dca9 100644 --- a/src/runtime/atomics_critical.go +++ b/src/runtime/atomics_critical.go @@ -105,6 +105,62 @@ func __atomic_add_fetch_2(ptr *uint16, value uint16, ordering uintptr) uint16 { return new } +//go:inline +func doAtomicAnd16(ptr *uint16, value uint16) (old, new uint16) { + mask := lockAtomics() + old = *ptr + new = old & value + *ptr = new + unlockAtomics(mask) + return old, new +} + +//export __atomic_fetch_and_2 +func __atomic_fetch_and_2(ptr *uint16, value uint16, ordering uintptr) uint16 { + old, _ := doAtomicAnd16(ptr, value) + return old +} + +//export __sync_fetch_and_and_2 +func __sync_fetch_and_and_2(ptr *uint16, value uint16) uint16 { + old, _ := doAtomicAnd16(ptr, value) + return old +} + +//export __atomic_and_fetch_2 +func __atomic_and_fetch_2(ptr *uint16, value uint16, ordering uintptr) uint16 { + _, new := doAtomicAnd16(ptr, value) + return new +} + +//go:inline +func doAtomicOr16(ptr *uint16, value uint16) (old, new uint16) { + mask := lockAtomics() + old = *ptr + new = old | value + *ptr = new + unlockAtomics(mask) + return old, new +} + +//export __atomic_fetch_or_2 +func __atomic_fetch_or_2(ptr *uint16, value uint16, ordering uintptr) uint16 { + old, _ := doAtomicOr16(ptr, value) + return old +} + +//export __sync_fetch_and_or_2 +func __sync_fetch_and_or_2(ptr *uint16, value uint16) uint16 { + old, _ := doAtomicOr16(ptr, value) + return old +} + +//export __atomic_or_fetch_2 +func __atomic_or_fetch_2(ptr *uint16, value uint16, ordering uintptr) uint16 { + _, new := doAtomicOr16(ptr, value) + return new +} + // 32-bit atomics. //export __atomic_load_4 @@ -194,6 +250,62 @@ func __atomic_add_fetch_4(ptr *uint32, value uint32, ordering uintptr) uint32 { return new } +//go:inline +func doAtomicAnd32(ptr *uint32, value uint32) (old, new uint32) { + mask := lockAtomics() + old = *ptr + new = old & value + *ptr = new + unlockAtomics(mask) + return old, new +} + +//export __atomic_fetch_and_4 +func __atomic_fetch_and_4(ptr *uint32, value uint32, ordering uintptr) uint32 { + old, _ := doAtomicAnd32(ptr, value) + return old +} + +//export __sync_fetch_and_and_4 +func __sync_fetch_and_and_4(ptr *uint32, value uint32) uint32 { + old, _ := doAtomicAnd32(ptr, value) + return old +} + +//export __atomic_and_fetch_4 +func __atomic_and_fetch_4(ptr *uint32, value uint32, ordering uintptr) uint32 { + _, new := doAtomicAnd32(ptr, value) + return new +} + +//go:inline +func doAtomicOr32(ptr *uint32, value uint32) (old, new uint32) { + mask := lockAtomics() + old = *ptr + new = old | value + *ptr = new + unlockAtomics(mask) + return old, new +} + +//export __atomic_fetch_or_4 +func __atomic_fetch_or_4(ptr *uint32, value uint32, ordering uintptr) uint32 { + old, _ := doAtomicOr32(ptr, value) + return old +} + +//export __sync_fetch_and_or_4 +func __sync_fetch_and_or_4(ptr *uint32, value uint32) uint32 { + old, _ := doAtomicOr32(ptr, value) + return old +} + +//export __atomic_or_fetch_4 +func __atomic_or_fetch_4(ptr *uint32, value uint32, ordering uintptr) uint32 { + _, new := doAtomicOr32(ptr, value) + return new +} + // 64-bit atomics. //export __atomic_load_8 @@ -282,3 +394,59 @@ func __atomic_add_fetch_8(ptr *uint64, value uint64, ordering uintptr) uint64 { _, new := doAtomicAdd64(ptr, value) return new } + +//go:inline +func doAtomicAnd64(ptr *uint64, value uint64) (old, new uint64) { + mask := lockAtomics() + old = *ptr + new = old & value + *ptr = new + unlockAtomics(mask) + return old, new +} + +//export __atomic_fetch_and_8 +func __atomic_fetch_and_8(ptr *uint64, value uint64, ordering uintptr) uint64 { + old, _ := doAtomicAnd64(ptr, value) + return old +} + +//export __sync_fetch_and_and_8 +func __sync_fetch_and_and_8(ptr *uint64, value uint64) uint64 { + old, _ := doAtomicAnd64(ptr, value) + return old +} + +//export __atomic_and_fetch_8 +func __atomic_and_fetch_8(ptr *uint64, value uint64, ordering uintptr) uint64 { + _, new := doAtomicAnd64(ptr, value) + return new +} + +//go:inline +func doAtomicOr64(ptr *uint64, value uint64) (old, new uint64) { + mask := lockAtomics() + old = *ptr + new = old | value + *ptr = new + unlockAtomics(mask) + return old, new +} + +//export __atomic_fetch_or_8 +func __atomic_fetch_or_8(ptr *uint64, value uint64, ordering uintptr) uint64 { + old, _ := doAtomicOr64(ptr, value) + return old +} + +//export __sync_fetch_and_or_8 +func __sync_fetch_and_or_8(ptr *uint64, value uint64) uint64 { + old, _ := doAtomicOr64(ptr, value) + return old +} + +//export __atomic_or_fetch_8 +func __atomic_or_fetch_8(ptr *uint64, value uint64, ordering uintptr) uint64 { + _, new := doAtomicOr64(ptr, value) + return new +} diff --git a/testdata/atomic.go b/testdata/atomic.go index 4d5ced301..d5f393155 100644 --- a/testdata/atomic.go +++ b/testdata/atomic.go @@ -23,6 +23,30 @@ func main() { uptr := uintptr(5) println("AddUintptr:", uint64(atomic.AddUintptr(&uptr, 8)), uint64(uptr)) + i32 = 12 + i64 = 12 + u32 = 12 + u64 = 12 + uptr = 12 + + println("AndInt32:", atomic.AndInt32(&i32, 10), i32) + println("AndInt64:", atomic.AndInt64(&i64, 10), i64) + println("AndUint32:", atomic.AndUint32(&u32, 10), u32) + println("AndUint64:", atomic.AndUint64(&u64, 10), u64) + println("AndUintptr:", uint64(atomic.AndUintptr(&uptr, 10)), uint64(uptr)) + + println("OrInt32:", atomic.OrInt32(&i32, 3), i32) + println("OrInt64:", atomic.OrInt64(&i64, 3), i64) + println("OrUint32:", atomic.OrUint32(&u32, 3), u32) + println("OrUint64:", atomic.OrUint64(&u64, 3), u64) + println("OrUintptr:", uint64(atomic.OrUintptr(&uptr, 3)), uint64(uptr)) + + i32 = 3 + i64 = 3 + u32 = 13 + u64 = 13 + uptr = 13 + println("SwapInt32:", atomic.SwapInt32(&i32, 33), i32) println("SwapInt64:", atomic.SwapInt64(&i64, 33), i64) println("SwapUint32:", atomic.SwapUint32(&u32, 33), u32) diff --git a/testdata/atomic.txt b/testdata/atomic.txt index 7bcde9365..d69fe7777 100644 --- a/testdata/atomic.txt +++ b/testdata/atomic.txt @@ -3,6 +3,16 @@ AddInt64: 3 3 AddUint32: 13 13 AddUint64: 13 13 AddUintptr: 13 13 +AndInt32: 12 8 +AndInt64: 12 8 +AndUint32: 12 8 +AndUint64: 12 8 +AndUintptr: 12 8 +OrInt32: 8 11 +OrInt64: 8 11 +OrUint32: 8 11 +OrUint64: 8 11 +OrUintptr: 8 11 SwapInt32: 3 33 SwapInt64: 3 33 SwapUint32: 13 33 diff --git a/tools/gen-critical-atomics/gen-critical-atomics.go b/tools/gen-critical-atomics/gen-critical-atomics.go index 98ceebb02..2e9cd01d5 100644 --- a/tools/gen-critical-atomics/gen-critical-atomics.go +++ b/tools/gen-critical-atomics/gen-critical-atomics.go @@ -145,6 +145,8 @@ func __atomic_{{$opname}}_fetch_{{$bytes}}(ptr *{{$type}}, value {{$type}}, orde {{template "cas" .}} {{template "swap" .}} {{template "rmw" (tuple "add" . false "new = old + value")}} +{{template "rmw" (tuple "and" . false "new = old & value")}} +{{template "rmw" (tuple "or" . false "new = old | value")}} {{- end}} {{template "atomics" 2 -}}