1
0
mirror of https://github.com/golang/go synced 2024-11-15 02:50:31 -07:00

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

@ -55,6 +55,10 @@ func IsLoong64RDTIME(op obj.As) bool {
return false return false
} }
func IsLoong64AMO(op obj.As) bool {
return loong64.IsAtomicInst(op)
}
func loong64RegisterNumber(name string, n int16) (int16, bool) { func loong64RegisterNumber(name string, n int16) (int16, bool) {
switch name { switch name {
case "F": case "F":

View File

@ -669,9 +669,17 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.Reg = p.getRegister(prog, op, &a[1]) prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2] prog.To = a[2]
case sys.Loong64: case sys.Loong64:
prog.From = a[0] switch {
prog.Reg = p.getRegister(prog, op, &a[1]) // Loong64 atomic instructions with one input and two outputs.
prog.To = a[2] case arch.IsLoong64AMO(op):
prog.From = a[0]
prog.To = a[1]
prog.RegTo2 = a[2].Reg
default:
prog.From = a[0]
prog.Reg = p.getRegister(prog, op, &a[1])
prog.To = a[2]
}
case sys.ARM: case sys.ARM:
// Special cases. // Special cases.
if arch.IsARMSTREX(op) { if arch.IsARMSTREX(op) {

View File

@ -231,3 +231,53 @@ lable2:
MOVV FCC0, R4 // 04dc1401 MOVV FCC0, R4 // 04dc1401
MOVV R4, FCC0 // 80d81401 MOVV R4, FCC0 // 80d81401
// Loong64 atomic memory access instructions
AMSWAPB R14, (R13), R12 // ac395c38
AMSWAPH R14, (R13), R12 // acb95c38
AMSWAPW R14, (R13), R12 // ac396038
AMSWAPV R14, (R13), R12 // acb96038
AMCASB R14, (R13), R12 // ac395838
AMCASH R14, (R13), R12 // acb95838
AMCASW R14, (R13), R12 // ac395938
AMCASV R14, (R13), R12 // acb95938
AMADDW R14, (R13), R12 // ac396138
AMADDV R14, (R13), R12 // acb96138
AMANDW R14, (R13), R12 // ac396238
AMANDV R14, (R13), R12 // acb96238
AMORW R14, (R13), R12 // ac396338
AMORV R14, (R13), R12 // acb96338
AMXORW R14, (R13), R12 // ac396438
AMXORV R14, (R13), R12 // acb96438
AMMAXW R14, (R13), R12 // ac396538
AMMAXV R14, (R13), R12 // acb96538
AMMINW R14, (R13), R12 // ac396638
AMMINV R14, (R13), R12 // acb96638
AMMAXWU R14, (R13), R12 // ac396738
AMMAXVU R14, (R13), R12 // acb96738
AMMINWU R14, (R13), R12 // ac396838
AMMINVU R14, (R13), R12 // acb96838
AMSWAPDBB R14, (R13), R12 // ac395e38
AMSWAPDBH R14, (R13), R12 // acb95e38
AMSWAPDBW R14, (R13), R12 // ac396938
AMSWAPDBV R14, (R13), R12 // acb96938
AMCASDBB R14, (R13), R12 // ac395a38
AMCASDBH R14, (R13), R12 // acb95a38
AMCASDBW R14, (R13), R12 // ac395b38
AMCASDBV R14, (R13), R12 // acb95b38
AMADDDBW R14, (R13), R12 // ac396a38
AMADDDBV R14, (R13), R12 // acb96a38
AMANDDBW R14, (R13), R12 // ac396b38
AMANDDBV R14, (R13), R12 // acb96b38
AMORDBW R14, (R13), R12 // ac396c38
AMORDBV R14, (R13), R12 // acb96c38
AMXORDBW R14, (R13), R12 // ac396d38
AMXORDBV R14, (R13), R12 // acb96d38
AMMAXDBW R14, (R13), R12 // ac396e38
AMMAXDBV R14, (R13), R12 // acb96e38
AMMINDBW R14, (R13), R12 // ac396f38
AMMINDBV R14, (R13), R12 // acb96f38
AMMAXDBWU R14, (R13), R12 // ac397038
AMMAXDBVU R14, (R13), R12 // acb97038
AMMINDBWU R14, (R13), R12 // ac397138
AMMINDBVU R14, (R13), R12 // acb97138

View File

@ -394,6 +394,56 @@ const (
AMOVVF AMOVVF
AMOVVD AMOVVD
// 2.2.7. Atomic Memory Access Instructions
AAMSWAPB
AAMSWAPH
AAMSWAPW
AAMSWAPV
AAMCASB
AAMCASH
AAMCASW
AAMCASV
AAMADDW
AAMADDV
AAMANDW
AAMANDV
AAMORW
AAMORV
AAMXORW
AAMXORV
AAMMAXW
AAMMAXV
AAMMINW
AAMMINV
AAMMAXWU
AAMMAXVU
AAMMINWU
AAMMINVU
AAMSWAPDBB
AAMSWAPDBH
AAMSWAPDBW
AAMSWAPDBV
AAMCASDBB
AAMCASDBH
AAMCASDBW
AAMCASDBV
AAMADDDBW
AAMADDDBV
AAMANDDBW
AAMANDDBV
AAMORDBW
AAMORDBV
AAMXORDBW
AAMXORDBV
AAMMAXDBW
AAMMAXDBV
AAMMINDBW
AAMMINDBV
AAMMAXDBWU
AAMMAXDBVU
AAMMINDBWU
AAMMINDBVU
// 2.2.10. Other Miscellaneous Instructions // 2.2.10. Other Miscellaneous Instructions
ARDTIMELW ARDTIMELW
ARDTIMEHW ARDTIMEHW

View File

@ -131,6 +131,54 @@ var Anames = []string{
"MOVDV", "MOVDV",
"MOVVF", "MOVVF",
"MOVVD", "MOVVD",
"AMSWAPB",
"AMSWAPH",
"AMSWAPW",
"AMSWAPV",
"AMCASB",
"AMCASH",
"AMCASW",
"AMCASV",
"AMADDW",
"AMADDV",
"AMANDW",
"AMANDV",
"AMORW",
"AMORV",
"AMXORW",
"AMXORV",
"AMMAXW",
"AMMAXV",
"AMMINW",
"AMMINV",
"AMMAXWU",
"AMMAXVU",
"AMMINWU",
"AMMINVU",
"AMSWAPDBB",
"AMSWAPDBH",
"AMSWAPDBW",
"AMSWAPDBV",
"AMCASDBB",
"AMCASDBH",
"AMCASDBW",
"AMCASDBV",
"AMADDDBW",
"AMADDDBV",
"AMANDDBW",
"AMANDDBV",
"AMORDBW",
"AMORDBV",
"AMXORDBW",
"AMXORDBV",
"AMMAXDBW",
"AMMAXDBV",
"AMMINDBW",
"AMMINDBV",
"AMMAXDBWU",
"AMMAXDBVU",
"AMMINDBWU",
"AMMINDBVU",
"RDTIMELW", "RDTIMELW",
"RDTIMEHW", "RDTIMEHW",
"RDTIMED", "RDTIMED",

View File

@ -356,7 +356,7 @@ var optab = []Optab{
{ATEQ, C_SCON, C_NONE, C_NONE, C_REG, C_NONE, 15, 8, 0, 0}, {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}, {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}, {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}, {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}, {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, // 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. // 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 { func pcAlignPadLength(ctxt *obj.Link, pc int64, alignedValue int64) int {
@ -1182,6 +1239,14 @@ func buildop(ctxt *obj.Link) {
case ANOOP: case ANOOP:
opset(obj.AUNDEF, r0) 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.Sym = p.From.Sym
rel2.Type = objabi.R_LOONG64_GOT_LO rel2.Type = objabi.R_LOONG64_GOT_LO
rel2.Add = 0x0 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 out[0] = o1