Skip to content

Commit dd82766

Browse files
committed
cmd/asm, cmd/internal/obj: add riscv64 generic CSR ops
Support is added for the generic RISC-V CSR operations; CSRRC, CSRRCI, CSRRS, CSRRSI, CSRRW, CSRRWI. These instructions require special handling as their second operand is a symbolic CSR register name and not an immediate value or a register. CSR names are implemented as special operands. RISC-V CSRs are not currently saved and restored when a go routine is asynchronously pre-empted so it is only safe to use these instructions in hand written assembler. Note that CSRRS was already partially supported by the assembler so this restriction predates this commit. We mention it here as this commit makes CSRRS much easier to use. Change-Id: I9ff8d804328b418a879d463e7d9cc31f489c7a00 Reviewed-on: https://go-review.googlesource.com/c/go/+/630519 Reviewed-by: Junyang Shao <[email protected]> Reviewed-by: Joel Sing <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]> Reviewed-by: Meng Zhuo <[email protected]> Reviewed-by: Michael Pratt <[email protected]>
1 parent f37d754 commit dd82766

File tree

8 files changed

+165
-13
lines changed

8 files changed

+165
-13
lines changed

src/cmd/asm/internal/arch/riscv64.go

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ package arch
1111
import (
1212
"cmd/internal/obj"
1313
"cmd/internal/obj/riscv"
14+
"fmt"
1415
)
1516

1617
// IsRISCV64AMO reports whether op is an AMO instruction that requires
@@ -32,16 +33,42 @@ func IsRISCV64VTypeI(op obj.As) bool {
3233
return op == riscv.AVSETVLI || op == riscv.AVSETIVLI
3334
}
3435

36+
// IsRISCV64CSRO reports whether the op is an instruction that uses
37+
// CSR symbolic names and whether that instruction expects a register
38+
// or an immediate source operand.
39+
func IsRISCV64CSRO(op obj.As) (imm bool, ok bool) {
40+
switch op {
41+
case riscv.ACSRRCI, riscv.ACSRRSI, riscv.ACSRRWI:
42+
imm = true
43+
fallthrough
44+
case riscv.ACSRRC, riscv.ACSRRS, riscv.ACSRRW:
45+
ok = true
46+
}
47+
return
48+
}
49+
3550
var riscv64SpecialOperand map[string]riscv.SpecialOperand
3651

3752
// RISCV64SpecialOperand returns the internal representation of a special operand.
3853
func RISCV64SpecialOperand(name string) riscv.SpecialOperand {
3954
if riscv64SpecialOperand == nil {
4055
// Generate mapping when function is first called.
4156
riscv64SpecialOperand = map[string]riscv.SpecialOperand{}
42-
for opd := riscv.SPOP_BEGIN; opd < riscv.SPOP_END; opd++ {
57+
for opd := riscv.SPOP_RVV_BEGIN; opd < riscv.SPOP_RVV_END; opd++ {
4358
riscv64SpecialOperand[opd.String()] = opd
4459
}
60+
// Add the CSRs
61+
for csrCode, csrName := range riscv.CSRs {
62+
// The set of RVV special operand names and the set of CSR special operands
63+
// names are disjoint and so can safely share a single namespace. However,
64+
// it's possible that a future update to the CSRs in inst.go could introduce
65+
// a conflict. This check ensures that such a conflict does not go
66+
// unnoticed.
67+
if _, ok := riscv64SpecialOperand[csrName]; ok {
68+
panic(fmt.Sprintf("riscv64 special operand %q redefined", csrName))
69+
}
70+
riscv64SpecialOperand[csrName] = riscv.SpecialOperand(int(csrCode) + int(riscv.SPOP_CSR_BEGIN))
71+
}
4572
}
4673
if opd, ok := riscv64SpecialOperand[name]; ok {
4774
return opd

src/cmd/asm/internal/asm/asm.go

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,21 @@ func (p *Parser) asmInstruction(op obj.As, cond string, a []obj.Addr) {
782782
prog.RegTo2 = a[2].Reg
783783
break
784784
}
785+
// RISCV64 instructions that reference CSRs with symbolic names.
786+
if isImm, ok := arch.IsRISCV64CSRO(op); ok {
787+
if a[0].Type != obj.TYPE_CONST && isImm {
788+
p.errorf("invalid value for first operand to %s instruction, must be a 5 bit unsigned immediate", op)
789+
return
790+
}
791+
if a[1].Type != obj.TYPE_SPECIAL {
792+
p.errorf("invalid value for second operand to %s instruction, must be a CSR name", op)
793+
return
794+
}
795+
prog.AddRestSourceArgs([]obj.Addr{a[1]})
796+
prog.From = a[0]
797+
prog.To = a[2]
798+
break
799+
}
785800
prog.From = a[0]
786801
prog.Reg = p.getRegister(prog, op, &a[1])
787802
prog.To = a[2]

src/cmd/asm/internal/asm/testdata/riscv64.s

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,24 @@ start:
172172
SD X5, (X6) // 23305300
173173
SD X5, 4(X6) // 23325300
174174

175+
// 7.1: CSR Instructions
176+
CSRRC X0, CYCLE, X5 // f33200c0
177+
CSRRC X0, CYCLE, X0 // 733000c0
178+
CSRRC X10, CYCLE, X5 // f33205c0
179+
CSRRC $2, TIME, X5 // f37211c0
180+
CSRRCI $2, TIME, X5 // f37211c0
181+
CSRRS X0, CYCLE, X5 // f32200c0
182+
CSRRS X0, CYCLE, X0 // 732000c0
183+
CSRRS X10, CYCLE, X5 // f32205c0
184+
CSRRS $2, TIME, X5 // f36211c0
185+
CSRRS X0, VLENB, X5 // f32220c2
186+
CSRRSI $2, TIME, X5 // f36211c0
187+
CSRRW X0, CYCLE, X5 // f31200c0
188+
CSRRW X0, CYCLE, X0 // 731000c0
189+
CSRRW X10, CYCLE, X5 // f31205c0
190+
CSRRW $2, TIME, X5 // f35211c0
191+
CSRRWI $2, TIME, X5 // f35211c0
192+
175193
// 8.1: Base Counters and Timers (Zicntr)
176194
RDCYCLE X5 // f32200c0
177195
RDTIME X5 // f32210c0

src/cmd/asm/internal/asm/testdata/riscv64error.s

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,27 @@
33
// license that can be found in the LICENSE file.
44

55
TEXT errors(SB),$0
6+
CSRRC (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
7+
CSRRC X0, TU, X5 // ERROR "unknown CSR"
8+
CSRRC X0, CYCLE // ERROR "missing CSR name"
9+
CSRRC X0, CYCLE, (X10) // ERROR "needs an integer register output"
10+
CSRRC $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
11+
CSRRCI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
12+
CSRRCI $1, TIME, (X15) // ERROR "needs an integer register output"
13+
CSRRS (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
14+
CSRRS X0, CYCLE, (X10) // ERROR "needs an integer register output"
15+
CSRRS X0, TU, X5 // ERROR "unknown CSR"
16+
CSRRS X0, CYCLE // ERROR "missing CSR name"
17+
CSRRS $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
18+
CSRRSI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
19+
CSRRSI $1, TIME, (X15) // ERROR "needs an integer register output"
20+
CSRRW (X10), CYCLE, X5 // ERROR "integer register or immediate expected for 1st operand"
21+
CSRRW X0, TU, X5 // ERROR "unknown CSR"
22+
CSRRW X0, CYCLE // ERROR "missing CSR name"
23+
CSRRW X0, CYCLE, (X5) // ERROR "needs an integer register output"
24+
CSRRW $-1, TIME, X15 // ERROR "immediate out of range 0 to 31"
25+
CSRRWI $32, TIME, X15 // ERROR "immediate out of range 0 to 31"
26+
CSRRWI $1, TIME, (X15) // ERROR "needs an integer register output"
627
MOV $errors(SB), (X5) // ERROR "address load must target register"
728
MOV $8(SP), (X5) // ERROR "address load must target register"
829
MOVB $8(SP), X5 // ERROR "unsupported address load"

src/cmd/internal/obj/link.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ import (
9999
//
100100
// <symbolic constant name>
101101
// Special symbolic constants for ARM64 (such as conditional flags, tlbi_op and so on)
102-
// and RISCV64 (such as names for vector configuration instruction arguments).
102+
// and RISCV64 (such as names for vector configuration instruction arguments and CSRs).
103103
// Encoding:
104104
// type = TYPE_SPECIAL
105105
// offset = The constant value corresponding to this symbol

src/cmd/internal/obj/riscv/cpu.go

Lines changed: 32 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ import (
3535
"cmd/internal/obj"
3636
)
3737

38+
var CSRs map[uint16]string = csrs
39+
3840
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv
3941

4042
const (
@@ -1315,9 +1317,10 @@ type SpecialOperand int
13151317

13161318
const (
13171319
SPOP_BEGIN SpecialOperand = obj.SpecialOperandRISCVBase
1320+
SPOP_RVV_BEGIN
13181321

13191322
// Vector mask policy.
1320-
SPOP_MA SpecialOperand = obj.SpecialOperandRISCVBase + iota - 1
1323+
SPOP_MA SpecialOperand = obj.SpecialOperandRISCVBase + iota - 2
13211324
SPOP_MU
13221325

13231326
// Vector tail policy.
@@ -1338,8 +1341,13 @@ const (
13381341
SPOP_E16
13391342
SPOP_E32
13401343
SPOP_E64
1344+
SPOP_RVV_END
1345+
1346+
// CSR names. 4096 special operands are reserved for RISC-V CSR names.
1347+
SPOP_CSR_BEGIN = SPOP_RVV_END
1348+
SPOP_CSR_END = SPOP_CSR_BEGIN + 4096
13411349

1342-
SPOP_END
1350+
SPOP_END = SPOP_CSR_END + 1
13431351
)
13441352

13451353
var specialOperands = map[SpecialOperand]struct {
@@ -1367,17 +1375,33 @@ var specialOperands = map[SpecialOperand]struct {
13671375
}
13681376

13691377
func (so SpecialOperand) encode() uint32 {
1370-
op, ok := specialOperands[so]
1371-
if ok {
1372-
return op.encoding
1378+
switch {
1379+
case so >= SPOP_RVV_BEGIN && so < SPOP_RVV_END:
1380+
op, ok := specialOperands[so]
1381+
if ok {
1382+
return op.encoding
1383+
}
1384+
case so >= SPOP_CSR_BEGIN && so < SPOP_CSR_END:
1385+
csrNum := uint16(so - SPOP_CSR_BEGIN)
1386+
if _, ok := csrs[csrNum]; ok {
1387+
return uint32(csrNum)
1388+
}
13731389
}
13741390
return 0
13751391
}
13761392

1393+
// String returns the textual representation of a SpecialOperand.
13771394
func (so SpecialOperand) String() string {
1378-
op, ok := specialOperands[so]
1379-
if ok {
1380-
return op.name
1395+
switch {
1396+
case so >= SPOP_RVV_BEGIN && so < SPOP_RVV_END:
1397+
op, ok := specialOperands[so]
1398+
if ok {
1399+
return op.name
1400+
}
1401+
case so >= SPOP_CSR_BEGIN && so < SPOP_CSR_END:
1402+
if csrName, ok := csrs[uint16(so-SPOP_CSR_BEGIN)]; ok {
1403+
return csrName
1404+
}
13811405
}
13821406
return ""
13831407
}

src/cmd/internal/obj/riscv/list.go

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,14 @@ func opSuffixString(s uint8) string {
5252
}
5353

5454
func specialOperandConv(a int64) string {
55+
var s string
56+
5557
spc := SpecialOperand(a)
5658
if spc >= SPOP_BEGIN && spc < SPOP_END {
57-
return spc.String()
59+
s = spc.String()
60+
}
61+
if s == "" {
62+
return "SPC_??"
5863
}
59-
return "SPC_??"
64+
return s
6065
}

src/cmd/internal/obj/riscv/obj.go

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1920,7 +1920,12 @@ var instructions = [ALAST & obj.AMask]instructionData{
19201920
ASD & obj.AMask: {enc: sIEncoding},
19211921

19221922
// 7.1: CSR Instructions
1923-
ACSRRS & obj.AMask: {enc: iIIEncoding},
1923+
ACSRRC & obj.AMask: {enc: iIIEncoding, immForm: ACSRRCI},
1924+
ACSRRCI & obj.AMask: {enc: iIIEncoding},
1925+
ACSRRS & obj.AMask: {enc: iIIEncoding, immForm: ACSRRSI},
1926+
ACSRRSI & obj.AMask: {enc: iIIEncoding},
1927+
ACSRRW & obj.AMask: {enc: iIIEncoding, immForm: ACSRRWI},
1928+
ACSRRWI & obj.AMask: {enc: iIIEncoding},
19241929

19251930
// 13.1: Multiplication Operations
19261931
AMUL & obj.AMask: {enc: rIIIEncoding, ternary: true},
@@ -3327,6 +3332,43 @@ func instructionsForProg(p *obj.Prog) []*instruction {
33273332
ins.imm = -1022
33283333
}
33293334

3335+
case ACSRRC, ACSRRCI, ACSRRS, ACSRRSI, ACSRRW, ACSRRWI:
3336+
if len(p.RestArgs) == 0 || p.RestArgs[0].Type != obj.TYPE_SPECIAL {
3337+
p.Ctxt.Diag("%v: missing CSR name", p)
3338+
return nil
3339+
}
3340+
if p.From.Type == obj.TYPE_CONST {
3341+
imm := p.From.Offset
3342+
if imm < 0 || imm >= 32 {
3343+
p.Ctxt.Diag("%v: immediate out of range 0 to 31", p)
3344+
return nil
3345+
}
3346+
ins.rs1 = uint32(imm) + REG_ZERO
3347+
} else if p.From.Type == obj.TYPE_REG {
3348+
ins.rs1 = uint32(p.From.Reg)
3349+
} else {
3350+
p.Ctxt.Diag("%v: integer register or immediate expected for 1st operand", p)
3351+
return nil
3352+
}
3353+
if p.To.Type != obj.TYPE_REG {
3354+
p.Ctxt.Diag("%v: needs an integer register output", p)
3355+
return nil
3356+
}
3357+
csrNum := SpecialOperand(p.RestArgs[0].Offset).encode()
3358+
if csrNum >= 1<<12 {
3359+
p.Ctxt.Diag("%v: unknown CSR", p)
3360+
return nil
3361+
}
3362+
if _, ok := CSRs[uint16(csrNum)]; !ok {
3363+
p.Ctxt.Diag("%v: unknown CSR", p)
3364+
return nil
3365+
}
3366+
ins.imm = int64(csrNum)
3367+
if ins.imm > 2047 {
3368+
ins.imm -= 4096
3369+
}
3370+
ins.rs2 = obj.REG_NONE
3371+
33303372
case AFENCE:
33313373
ins.rd, ins.rs1, ins.rs2 = REG_ZERO, REG_ZERO, obj.REG_NONE
33323374
ins.imm = 0x0ff

0 commit comments

Comments
 (0)