cmd/asm, cmd/internal/obj: add riscv64 pseudo CSR ops

Add support for the riscv64 pseudo CSR ops; CSRR, CSRW, CSRS, CSRC,
CSRWI, CSRSI, CSRCI.

We also add tests to check that we can correctly encode CSRR
instructions that read all the RVV CSR registers.

Change-Id: I50b2d6da4f5847e65ab8017cd36f068b2ce525b3
Reviewed-on: https://go-review.googlesource.com/c/go/+/650577
Reviewed-by: Meng Zhuo <mengzhuo1203@gmail.com>
Reviewed-by: Carlos Amedee <carlos@golang.org>
LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Mark Freeman <markfreeman@google.com>
This commit is contained in:
Mark Ryan 2025-02-19 13:57:56 +01:00 committed by Mark Ryan
parent 02b3e0d4dd
commit ca10097f29
7 changed files with 112 additions and 9 deletions

View file

@ -47,6 +47,22 @@ func IsRISCV64CSRO(op obj.As) (imm bool, ok bool) {
return
}
// IsRISCV64PseudoCSRO reports whether the op is a pseudo instruction
// that uses CSR symbolic names, whether that instruction expects a register
// or an immediate source operand and what the expected index of the operand
// containing the CSR name should be.
func IsRISCV64PseudoCSRO(op obj.As) (imm bool, index int, ok bool) {
switch op {
case riscv.ACSRCI, riscv.ACSRSI, riscv.ACSRWI:
imm, index, ok = true, 1, true
case riscv.ACSRC, riscv.ACSRS, riscv.ACSRW:
imm, index, ok = false, 1, true
case riscv.ACSRR:
imm, index, ok = false, 0, true
}
return
}
var riscv64SpecialOperand map[string]riscv.SpecialOperand
// RISCV64SpecialOperand returns the internal representation of a special operand.

View file

@ -665,6 +665,25 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
prog.AddRestSource(a[1])
break
}
} else if p.arch.Family == sys.RISCV64 {
// RISCV64 pseudo instructions that reference CSRs with symbolic names.
if isImm, specialIndex, ok := arch.IsRISCV64PseudoCSRO(op); ok {
if a[0].Type != obj.TYPE_CONST && isImm {
p.errorf("invalid value for first operand to %s instruction, must be a 5 bit unsigned immediate", op)
return
}
if a[specialIndex].Type != obj.TYPE_SPECIAL {
p.errorf("invalid value for first or second operand to %s instruction, must be a CSR name", op)
return
}
prog.AddRestSourceArgs([]obj.Addr{a[specialIndex]})
if specialIndex == 0 {
prog.To = a[1]
} else {
prog.From = a[0]
}
break
}
}
prog.From = a[0]
prog.To = a[1]

View file

@ -177,6 +177,16 @@ start:
SD X5, 4(X6) // 23325300
// 7.1: CSR Instructions
CSRC X5, VSTART // 73b08200
CSRC $2, VSTART // 73708100
CSRCI $2, VSTART // 73708100
CSRR CYCLE, X5 // f32200c0
CSRR VCSR, X5 // f322f000
CSRR VL, X5 // f32200c2
CSRR VLENB, X5 // f32220c2
CSRR VSTART, X5 // f3228000
CSRR VXSAT, X5 // f3229000
CSRR VXRM, X5 // f322a000
CSRRC X0, CYCLE, X5 // f33200c0
CSRRC X0, CYCLE, X0 // 733000c0
CSRRC X10, CYCLE, X5 // f33205c0
@ -193,6 +203,12 @@ start:
CSRRW X10, CYCLE, X5 // f31205c0
CSRRW $2, TIME, X5 // f35211c0
CSRRWI $2, TIME, X5 // f35211c0
CSRS X10, VSTART // 73208500
CSRS $2, VSTART // 73608100
CSRSI $2, VSTART // 73608100
CSRW X10, VSTART // 73108500
CSRW $2, VSTART // 73508100
CSRWI $2, VSTART // 73508100
// 8.1: Base Counters and Timers (Zicntr)
RDCYCLE X5 // f32200c0

View file

@ -3,9 +3,14 @@
// license that can be found in the LICENSE file.
TEXT errors(SB),$0
CSRC X5, TU // ERROR "unknown CSR"
CSRC (X5), CYCLE // ERROR "integer register or immediate expected for 1st operand"
CSRC $-1, TIME // ERROR "immediate out of range 0 to 31"
CSRR TU, X5 // ERROR "unknown CSR"
CSRR CYCLE, (X5) // ERROR "needs an integer register output"
CSRRC (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
CSRRC X0, TU, X5 // ERROR "unknown CSR"
CSRRC X0, CYCLE // ERROR "missing CSR name"
CSRRC X0, X5 // ERROR "missing CSR name"
CSRRC X0, CYCLE, (X10) // ERROR "needs an integer register output"
CSRRC $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
CSRRCI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
@ -13,17 +18,25 @@ TEXT errors(SB),$0
CSRRS (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
CSRRS X0, CYCLE, (X10) // ERROR "needs an integer register output"
CSRRS X0, TU, X5 // ERROR "unknown CSR"
CSRRS X0, CYCLE // ERROR "missing CSR name"
CSRRS X0, X5 // ERROR "missing CSR name"
CSRRS $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
CSRRSI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
CSRRSI $1, TIME, (X15) // ERROR "needs an integer register output"
CSRRW (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
CSRRW X0, TU, X5 // ERROR "unknown CSR"
CSRRW X0, CYCLE // ERROR "missing CSR name"
CSRRW X0, X5 // ERROR "missing CSR name"
CSRRW X0, CYCLE, (X5) // ERROR "needs an integer register output"
CSRRW $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
CSRRWI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
CSRRWI $1, TIME, (X15) // ERROR "needs an integer register output"
CSRW X5, TU // ERROR "unknown CSR"
CSRW $-1, TIME // ERROR "immediate out of range 0 to 31"
CSRWI $32, TIME // ERROR "immediate out of range 0 to 31"
CSRS (X5), CYCLE // ERROR "integer register or immediate expected for 1st operand"
CSRS X5, TU // ERROR "unknown CSR"
CSRS $-1, TIME // ERROR "immediate out of range 0 to 31"
CSRSI $32, TIME // ERROR "immediate out of range 0 to 31"
CSRW (X5), CYCLE // ERROR "integer register or immediate expected for 1st operand"
MOV $errors(SB), (X5) // ERROR "address load must target register"
MOV $8(SP), (X5) // ERROR "address load must target register"
MOVB $8(SP), X5 // ERROR "unsupported address load"

View file

@ -921,6 +921,13 @@ var Anames = []string{
"BLEZ",
"BLTZ",
"BNEZ",
"CSRC",
"CSRCI",
"CSRR",
"CSRS",
"CSRSI",
"CSRW",
"CSRWI",
"FABSD",
"FABSS",
"FNED",

View file

@ -1490,6 +1490,13 @@ const (
ABLEZ
ABLTZ
ABNEZ
ACSRC
ACSRCI
ACSRR
ACSRS
ACSRSI
ACSRW
ACSRWI
AFABSD
AFABSS
AFNED

View file

@ -4362,12 +4362,41 @@ func instructionsForProg(p *obj.Prog, compress bool) []*instruction {
ins.imm = -1022
}
case ACSRRC, ACSRRCI, ACSRRS, ACSRRSI, ACSRRW, ACSRRWI:
case ACSRC, ACSRRC, ACSRCI, ACSRRCI, ACSRR, ACSRS, ACSRSI, ACSRRS, ACSRRSI, ACSRRW, ACSRRWI, ACSRW, ACSRWI:
switch {
case ins.as == ACSRCI || (ins.as == ACSRC && p.From.Type == obj.TYPE_CONST):
ins.as = ACSRRCI
ins.rd = REG_ZERO
case ins.as == ACSRC:
ins.as = ACSRRC
ins.rd = REG_ZERO
case ins.as == ACSRSI || (ins.as == ACSRS && p.From.Type == obj.TYPE_CONST):
ins.as = ACSRRSI
ins.rd = REG_ZERO
case ins.as == ACSRS:
ins.as = ACSRRS
ins.rd = REG_ZERO
case ins.as == ACSRWI || (ins.as == ACSRW && p.From.Type == obj.TYPE_CONST):
ins.as = ACSRRWI
ins.rd = REG_ZERO
case ins.as == ACSRW:
ins.as = ACSRRW
ins.rd = REG_ZERO
default:
if p.To.Type != obj.TYPE_REG {
p.Ctxt.Diag("%v: needs an integer register output", p)
return nil
}
}
if len(p.RestArgs) == 0 || p.RestArgs[0].Type != obj.TYPE_SPECIAL {
p.Ctxt.Diag("%v: missing CSR name", p)
return nil
}
if p.From.Type == obj.TYPE_CONST {
if ins.as == ACSRR {
ins.as = ACSRRS
ins.rs1 = REG_ZERO
} else if p.From.Type == obj.TYPE_CONST {
imm := p.From.Offset
if imm < 0 || imm >= 32 {
p.Ctxt.Diag("%v: immediate out of range 0 to 31", p)
@ -4380,10 +4409,6 @@ func instructionsForProg(p *obj.Prog, compress bool) []*instruction {
p.Ctxt.Diag("%v: integer register or immediate expected for 1st operand", p)
return nil
}
if p.To.Type != obj.TYPE_REG {
p.Ctxt.Diag("%v: needs an integer register output", p)
return nil
}
csrNum := SpecialOperand(p.RestArgs[0].Offset).encode()
if csrNum >= 1<<12 {
p.Ctxt.Diag("%v: unknown CSR", p)