blob: 21d5adcdbc5cfce77480569153a490de4c5101ba [file] [log] [blame]
// Copyright 2014 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.
// RISC-V's atomic operations have two bits, aq ("acquire") and rl ("release"),
// which may be toggled on and off. Their precise semantics are defined in
// section 6.3 of the specification, but the basic idea is as follows:
//
// - If neither aq nor rl is set, the CPU may reorder the atomic arbitrarily.
// It guarantees only that it will execute atomically.
//
// - If aq is set, the CPU may move the instruction backward, but not forward.
//
// - If rl is set, the CPU may move the instruction forward, but not backward.
//
// - If both are set, the CPU may not reorder the instruction at all.
//
// These four modes correspond to other well-known memory models on other CPUs.
// On ARM, aq corresponds to a dmb ishst, aq+rl corresponds to a dmb ish. On
// Intel, aq corresponds to an lfence, rl to an sfence, and aq+rl to an mfence
// (or a lock prefix).
//
// Go's memory model requires that
// - if a read happens after a write, the read must observe the write, and
// that
// - if a read happens concurrently with a write, the read may observe the
// write.
// aq is sufficient to guarantee this, so that's what we use here. (This jibes
// with ARM, which uses dmb ishst.)
#include "textflag.h"
// func Cas(ptr *uint64, old, new uint64) bool
// Atomically:
// if(*val == old){
// *val = new;
// return 1;
// } else {
// return 0;
// }
TEXT ·Cas(SB), NOSPLIT, $0-17
MOV ptr+0(FP), A0
MOVW old+8(FP), A1
MOVW new+12(FP), A2
cas_again:
LRW (A0), A3
BNE A3, A1, cas_fail
SCW A2, (A0), A4
BNE A4, ZERO, cas_again
MOV $1, A0
MOVB A0, ret+16(FP)
RET
cas_fail:
MOV $0, A0
MOV A0, ret+16(FP)
RET
// func Cas64(ptr *uint64, old, new uint64) bool
TEXT ·Cas64(SB), NOSPLIT, $0-25
MOV ptr+0(FP), A0
MOV old+8(FP), A1
MOV new+16(FP), A2
cas_again:
LRD (A0), A3
BNE A3, A1, cas_fail
SCD A2, (A0), A4
BNE A4, ZERO, cas_again
MOV $1, A0
MOVB A0, ret+24(FP)
RET
cas_fail:
MOVB ZERO, ret+24(FP)
RET
// func Load(ptr *uint32) uint32
TEXT ·Load(SB),NOSPLIT|NOFRAME,$0-12
MOV ptr+0(FP), A0
LRW (A0), A0
MOVW A0, ret+8(FP)
RET
// func Load8(ptr *uint8) uint8
TEXT ·Load8(SB),NOSPLIT|NOFRAME,$0-9
MOV ptr+0(FP), A0
FENCE
MOVBU (A0), A1
FENCE
MOVB A1, ret+8(FP)
RET
// func Load64(ptr *uint64) uint64
TEXT ·Load64(SB),NOSPLIT|NOFRAME,$0-16
MOV ptr+0(FP), A0
LRD (A0), A0
MOV A0, ret+8(FP)
RET
// func Store(ptr *uint32, val uint32)
TEXT ·Store(SB), NOSPLIT, $0-12
MOV ptr+0(FP), A0
MOVW val+8(FP), A1
AMOSWAPW A1, (A0), ZERO
RET
// func Store8(ptr *uint8, val uint8)
TEXT ·Store8(SB), NOSPLIT, $0-9
MOV ptr+0(FP), A0
MOVBU val+8(FP), A1
FENCE
MOVB A1, (A0)
FENCE
RET
// func Store64(ptr *uint64, val uint64)
TEXT ·Store64(SB), NOSPLIT, $0-16
MOV ptr+0(FP), A0
MOV val+8(FP), A1
AMOSWAPD A1, (A0), ZERO
RET
TEXT ·Casp1(SB), NOSPLIT, $0-25
JMP ·Cas64(SB)
TEXT ·Casint32(SB),NOSPLIT,$0-17
JMP ·Cas(SB)
TEXT ·Casint64(SB),NOSPLIT,$0-25
JMP ·Cas64(SB)
TEXT ·Casuintptr(SB),NOSPLIT,$0-25
JMP ·Cas64(SB)
TEXT ·CasRel(SB), NOSPLIT, $0-17
JMP ·Cas(SB)
TEXT ·Loaduintptr(SB),NOSPLIT,$0-16
JMP ·Load64(SB)
TEXT ·Storeint32(SB),NOSPLIT,$0-12
JMP ·Store(SB)
TEXT ·Storeint64(SB),NOSPLIT,$0-16
JMP ·Store64(SB)
TEXT ·Storeuintptr(SB),NOSPLIT,$0-16
JMP ·Store64(SB)
TEXT ·Loaduint(SB),NOSPLIT,$0-16
JMP ·Loaduintptr(SB)
TEXT ·Loadint32(SB),NOSPLIT,$0-12
JMP ·Load(SB)
TEXT ·Loadint64(SB),NOSPLIT,$0-16
JMP ·Load64(SB)
TEXT ·Xaddint32(SB),NOSPLIT,$0-20
JMP ·Xadd(SB)
TEXT ·Xaddint64(SB),NOSPLIT,$0-24
MOV ptr+0(FP), A0
MOV delta+8(FP), A1
AMOADDD A1, (A0), A0
ADD A0, A1, A0
MOVW A0, ret+16(FP)
RET
TEXT ·LoadAcq(SB),NOSPLIT|NOFRAME,$0-12
JMP ·Load(SB)
TEXT ·LoadAcq64(SB),NOSPLIT|NOFRAME,$0-16
JMP ·Load64(SB)
TEXT ·LoadAcquintptr(SB),NOSPLIT|NOFRAME,$0-16
JMP ·Load64(SB)
// func Loadp(ptr unsafe.Pointer) unsafe.Pointer
TEXT ·Loadp(SB),NOSPLIT,$0-16
JMP ·Load64(SB)
// func StorepNoWB(ptr unsafe.Pointer, val unsafe.Pointer)
TEXT ·StorepNoWB(SB), NOSPLIT, $0-16
JMP ·Store64(SB)
TEXT ·StoreRel(SB), NOSPLIT, $0-12
JMP ·Store(SB)
TEXT ·StoreRel64(SB), NOSPLIT, $0-16
JMP ·Store64(SB)
TEXT ·StoreReluintptr(SB), NOSPLIT, $0-16
JMP ·Store64(SB)
// func Xchg(ptr *uint32, new uint32) uint32
TEXT ·Xchg(SB), NOSPLIT, $0-20
MOV ptr+0(FP), A0
MOVW new+8(FP), A1
AMOSWAPW A1, (A0), A1
MOVW A1, ret+16(FP)
RET
// func Xchg64(ptr *uint64, new uint64) uint64
TEXT ·Xchg64(SB), NOSPLIT, $0-24
MOV ptr+0(FP), A0
MOV new+8(FP), A1
AMOSWAPD A1, (A0), A1
MOV A1, ret+16(FP)
RET
// Atomically:
// *val += delta;
// return *val;
// func Xadd(ptr *uint32, delta int32) uint32
TEXT ·Xadd(SB), NOSPLIT, $0-20
MOV ptr+0(FP), A0
MOVW delta+8(FP), A1
AMOADDW A1, (A0), A2
ADD A2,A1,A0
MOVW A0, ret+16(FP)
RET
// func Xadd64(ptr *uint64, delta int64) uint64
TEXT ·Xadd64(SB), NOSPLIT, $0-24
MOV ptr+0(FP), A0
MOV delta+8(FP), A1
AMOADDD A1, (A0), A2
ADD A2, A1, A0
MOV A0, ret+16(FP)
RET
// func Xadduintptr(ptr *uintptr, delta uintptr) uintptr
TEXT ·Xadduintptr(SB), NOSPLIT, $0-24
JMP ·Xadd64(SB)
// func Xchgint32(ptr *int32, new int32) int32
TEXT ·Xchgint32(SB), NOSPLIT, $0-20
JMP ·Xchg(SB)
// func Xchgint64(ptr *int64, new int64) int64
TEXT ·Xchgint64(SB), NOSPLIT, $0-24
JMP ·Xchg64(SB)
// func Xchguintptr(ptr *uintptr, new uintptr) uintptr
TEXT ·Xchguintptr(SB), NOSPLIT, $0-24
JMP ·Xchg64(SB)
// func And8(ptr *uint8, val uint8)
TEXT ·And8(SB), NOSPLIT, $0-9
MOV ptr+0(FP), A0
MOVBU val+8(FP), A1
AND $3, A0, A2
AND $-4, A0
SLL $3, A2
XOR $255, A1
SLL A2, A1
XOR $-1, A1
AMOANDW A1, (A0), ZERO
RET
// func Or8(ptr *uint8, val uint8)
TEXT ·Or8(SB), NOSPLIT, $0-9
MOV ptr+0(FP), A0
MOVBU val+8(FP), A1
AND $3, A0, A2
AND $-4, A0
SLL $3, A2
SLL A2, A1
AMOORW A1, (A0), ZERO
RET
// func And(ptr *uint32, val uint32)
TEXT ·And(SB), NOSPLIT, $0-12
MOV ptr+0(FP), A0
MOVW val+8(FP), A1
AMOANDW A1, (A0), ZERO
RET
// func Or(ptr *uint32, val uint32)
TEXT ·Or(SB), NOSPLIT, $0-12
MOV ptr+0(FP), A0
MOVW val+8(FP), A1
AMOORW A1, (A0), ZERO
RET