cmd/internal/obj/loong64: add atomic memory access instructions support

The AM* atomic access instruction performs a sequence of “read-modify-write”
operations on a memory cell atomically. Specifically, it retrieves the old
value at the specified address in memory and writes it to the general register
rd, performs some simple operations on the old value in memory and the value
in the general register rk, and then write the result of the operation back
to the memory address pointed to by general register rj.

Go asm syntax:
	AM{SWAP/ADD/AND/OR/XOR/MAX/MIN}[DB]{W/V} RK, (RJ), RD
	AM{MAX/MIN}[DB]{WU/VU} RK, (RJ), RD

Equivalent platform assembler syntax:
	am{swap/add/and/or/xor/max/min}[_db].{w/d} rd, rk, rj
	am{max/min}[_db].{wu/du} rd, rk, rj

Ref: https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html

Change-Id: I99ea4553ae731675180d63691c19ef334e7e7817
Reviewed-on: https://go-review.googlesource.com/c/go/+/481577
Reviewed-by: Meidan Li <limeidan@loongson.cn>
Reviewed-by: sophie zhao <zhaoxiaolin@loongson.cn>
Reviewed-by: Mauri de Souza Meneguzzo <mauri870@gmail.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Qiqi Huang <huangqiqi@loongson.cn>
Reviewed-by: WANG Xuerui <git@xen0n.name>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Cherry Mui <cherryyz@google.com>
This commit is contained in:
Guoqi Chen 2023-04-01 03:43:20 +08:00 committed by Cherry Mui
parent ca17bda856
commit 504212bbd7
6 changed files with 241 additions and 4 deletions

View file

@ -356,7 +356,7 @@ var optab = []Optab{
{ATEQ, C_SCON, C_NONE, C_NONE, C_REG, C_NONE, 15, 8, 0, 0},
{ARDTIMELW, C_NONE, C_NONE, C_NONE, C_REG, C_REG, 62, 4, 0, 0},
{AAMSWAPW, C_REG, C_NONE, C_NONE, C_ZOREG, C_REG, 66, 4, 0, 0},
{ANOOP, C_NONE, C_NONE, C_NONE, C_NONE, C_NONE, 49, 4, 0, 0},
{obj.APCALIGN, C_SCON, C_NONE, C_NONE, C_NONE, C_NONE, 0, 0, 0, 0},
@ -374,6 +374,63 @@ var optab = []Optab{
{obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0},
}
var atomicInst = map[obj.As]uint32{
AAMSWAPB: 0x070B8 << 15, // amswap.b
AAMSWAPH: 0x070B9 << 15, // amswap.h
AAMSWAPW: 0x070C0 << 15, // amswap.w
AAMSWAPV: 0x070C1 << 15, // amswap.d
AAMCASB: 0x070B0 << 15, // amcas.b
AAMCASH: 0x070B1 << 15, // amcas.h
AAMCASW: 0x070B2 << 15, // amcas.w
AAMCASV: 0x070B3 << 15, // amcas.d
AAMADDW: 0x070C2 << 15, // amadd.w
AAMADDV: 0x070C3 << 15, // amadd.d
AAMANDW: 0x070C4 << 15, // amand.w
AAMANDV: 0x070C5 << 15, // amand.d
AAMORW: 0x070C6 << 15, // amor.w
AAMORV: 0x070C7 << 15, // amor.d
AAMXORW: 0x070C8 << 15, // amxor.w
AAMXORV: 0x070C9 << 15, // amxor.d
AAMMAXW: 0x070CA << 15, // ammax.w
AAMMAXV: 0x070CB << 15, // ammax.d
AAMMINW: 0x070CC << 15, // ammin.w
AAMMINV: 0x070CD << 15, // ammin.d
AAMMAXWU: 0x070CE << 15, // ammax.wu
AAMMAXVU: 0x070CF << 15, // ammax.du
AAMMINWU: 0x070D0 << 15, // ammin.wu
AAMMINVU: 0x070D1 << 15, // ammin.du
AAMSWAPDBB: 0x070BC << 15, // amswap_db.b
AAMSWAPDBH: 0x070BD << 15, // amswap_db.h
AAMSWAPDBW: 0x070D2 << 15, // amswap_db.w
AAMSWAPDBV: 0x070D3 << 15, // amswap_db.d
AAMCASDBB: 0x070B4 << 15, // amcas_db.b
AAMCASDBH: 0x070B5 << 15, // amcas_db.h
AAMCASDBW: 0x070B6 << 15, // amcas_db.w
AAMCASDBV: 0x070B7 << 15, // amcas_db.d
AAMADDDBW: 0x070D4 << 15, // amadd_db.w
AAMADDDBV: 0x070D5 << 15, // amadd_db.d
AAMANDDBW: 0x070D6 << 15, // amand_db.w
AAMANDDBV: 0x070D7 << 15, // amand_db.d
AAMORDBW: 0x070D8 << 15, // amor_db.w
AAMORDBV: 0x070D9 << 15, // amor_db.d
AAMXORDBW: 0x070DA << 15, // amxor_db.w
AAMXORDBV: 0x070DB << 15, // amxor_db.d
AAMMAXDBW: 0x070DC << 15, // ammax_db.w
AAMMAXDBV: 0x070DD << 15, // ammax_db.d
AAMMINDBW: 0x070DE << 15, // ammin_db.w
AAMMINDBV: 0x070DF << 15, // ammin_db.d
AAMMAXDBWU: 0x070E0 << 15, // ammax_db.wu
AAMMAXDBVU: 0x070E1 << 15, // ammax_db.du
AAMMINDBWU: 0x070E2 << 15, // ammin_db.wu
AAMMINDBVU: 0x070E3 << 15, // ammin_db.du
}
func IsAtomicInst(as obj.As) bool {
_, ok := atomicInst[as]
return ok
}
// pcAlignPadLength returns the number of bytes required to align pc to alignedValue,
// reporting an error if alignedValue is not a power of two or is out of range.
func pcAlignPadLength(ctxt *obj.Link, pc int64, alignedValue int64) int {
@ -1182,6 +1239,14 @@ func buildop(ctxt *obj.Link) {
case ANOOP:
opset(obj.AUNDEF, r0)
case AAMSWAPW:
for i := range atomicInst {
if i == AAMSWAPW {
continue
}
opset(i, r0)
}
}
}
}
@ -1817,6 +1882,18 @@ func (c *ctxt0) asmout(p *obj.Prog, o *Optab, out []uint32) {
rel2.Sym = p.From.Sym
rel2.Type = objabi.R_LOONG64_GOT_LO
rel2.Add = 0x0
case 66: // am* From, To, RegTo2 ==> am* RegTo2, From, To
rk := p.From.Reg
rj := p.To.Reg
rd := p.RegTo2
// See section 2.2.7.1 of https://loongson.github.io/LoongArch-Documentation/LoongArch-Vol1-EN.html
// for the register usage constraints.
if rd == rj || rd == rk {
c.ctxt.Diag("illegal register combination: %v\n", p)
}
o1 = OP_RRR(atomicInst[p.As], uint32(rk), uint32(rj), uint32(rd))
}
out[0] = o1