aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/internal/obj/riscv/obj.go
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/internal/obj/riscv/obj.go')
-rw-r--r--src/cmd/internal/obj/riscv/obj.go149
1 files changed, 139 insertions, 10 deletions
diff --git a/src/cmd/internal/obj/riscv/obj.go b/src/cmd/internal/obj/riscv/obj.go
index 54c34af2f4..c6f66d0195 100644
--- a/src/cmd/internal/obj/riscv/obj.go
+++ b/src/cmd/internal/obj/riscv/obj.go
@@ -1042,27 +1042,35 @@ func immEven(x int64) error {
return nil
}
-// immIFits checks whether the immediate value x fits in nbits bits
-// as a signed integer. If it does not, an error is returned.
-func immIFits(x int64, nbits uint) error {
- nbits--
- min := int64(-1) << nbits
- max := int64(1)<<nbits - 1
+func immFits(x int64, nbits uint, signed bool) error {
+ label := "unsigned"
+ min, max := int64(0), int64(1)<<nbits-1
+ if signed {
+ label = "signed"
+ sbits := nbits - 1
+ min, max = int64(-1)<<sbits, int64(1)<<sbits-1
+ }
if x < min || x > max {
if nbits <= 16 {
- return fmt.Errorf("signed immediate %d must be in range [%d, %d] (%d bits)", x, min, max, nbits)
+ return fmt.Errorf("%s immediate %d must be in range [%d, %d] (%d bits)", label, x, min, max, nbits)
}
- return fmt.Errorf("signed immediate %#x must be in range [%#x, %#x] (%d bits)", x, min, max, nbits)
+ return fmt.Errorf("%s immediate %#x must be in range [%#x, %#x] (%d bits)", label, x, min, max, nbits)
}
return nil
}
+// immIFits checks whether the immediate value x fits in nbits bits
+// as a signed integer. If it does not, an error is returned.
+func immIFits(x int64, nbits uint) error {
+ return immFits(x, nbits, true)
+}
+
// immI extracts the signed integer of the specified size from an immediate.
func immI(as obj.As, imm int64, nbits uint) uint32 {
if err := immIFits(imm, nbits); err != nil {
panic(fmt.Sprintf("%v: %v", as, err))
}
- return uint32(imm)
+ return uint32(imm) & ((1 << nbits) - 1)
}
func wantImmI(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) {
@@ -1071,6 +1079,26 @@ func wantImmI(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) {
}
}
+// immUFits checks whether the immediate value x fits in nbits bits
+// as an unsigned integer. If it does not, an error is returned.
+func immUFits(x int64, nbits uint) error {
+ return immFits(x, nbits, false)
+}
+
+// immU extracts the unsigned integer of the specified size from an immediate.
+func immU(as obj.As, imm int64, nbits uint) uint32 {
+ if err := immUFits(imm, nbits); err != nil {
+ panic(fmt.Sprintf("%v: %v", as, err))
+ }
+ return uint32(imm) & ((1 << nbits) - 1)
+}
+
+func wantImmU(ctxt *obj.Link, ins *instruction, imm int64, nbits uint) {
+ if err := immUFits(imm, nbits); err != nil {
+ ctxt.Diag("%v: %v", ins, err)
+ }
+}
+
func wantReg(ctxt *obj.Link, ins *instruction, pos string, descr string, r, min, max uint32) {
if r < min || r > max {
var suffix string
@@ -1227,6 +1255,29 @@ func validateJ(ctxt *obj.Link, ins *instruction) {
wantNoneReg(ctxt, ins, "rs3", ins.rs3)
}
+func validateVsetvli(ctxt *obj.Link, ins *instruction) {
+ wantImmU(ctxt, ins, ins.imm, 11)
+ wantIntReg(ctxt, ins, "rd", ins.rd)
+ wantIntReg(ctxt, ins, "rs1", ins.rs1)
+ wantNoneReg(ctxt, ins, "rs2", ins.rs2)
+ wantNoneReg(ctxt, ins, "rs3", ins.rs3)
+}
+
+func validateVsetivli(ctxt *obj.Link, ins *instruction) {
+ wantImmU(ctxt, ins, ins.imm, 10)
+ wantIntReg(ctxt, ins, "rd", ins.rd)
+ wantImmU(ctxt, ins, int64(ins.rs1), 5)
+ wantNoneReg(ctxt, ins, "rs2", ins.rs2)
+ wantNoneReg(ctxt, ins, "rs3", ins.rs3)
+}
+
+func validateVsetvl(ctxt *obj.Link, ins *instruction) {
+ wantIntReg(ctxt, ins, "rd", ins.rd)
+ wantIntReg(ctxt, ins, "rs1", ins.rs1)
+ wantIntReg(ctxt, ins, "rs2", ins.rs2)
+ wantNoneReg(ctxt, ins, "rs3", ins.rs3)
+}
+
func validateRaw(ctxt *obj.Link, ins *instruction) {
// Treat the raw value specially as a 32-bit unsigned integer.
// Nobody wants to enter negative machine code.
@@ -1415,6 +1466,29 @@ func encodeCJImmediate(imm uint32) uint32 {
return bits << 2
}
+func encodeVset(as obj.As, rs1, rs2, rd uint32) uint32 {
+ enc := encode(as)
+ if enc == nil {
+ panic("encodeVset: could not encode instruction")
+ }
+ return enc.funct7<<25 | rs2<<20 | rs1<<15 | enc.funct3<<12 | rd<<7 | enc.opcode
+}
+
+func encodeVsetvli(ins *instruction) uint32 {
+ vtype := immU(ins.as, ins.imm, 11)
+ return encodeVset(ins.as, regI(ins.rs1), vtype, regI(ins.rd))
+}
+
+func encodeVsetivli(ins *instruction) uint32 {
+ vtype := immU(ins.as, ins.imm, 10)
+ avl := immU(ins.as, int64(ins.rs1), 5)
+ return encodeVset(ins.as, avl, vtype, regI(ins.rd))
+}
+
+func encodeVsetvl(ins *instruction) uint32 {
+ return encodeVset(ins.as, regI(ins.rs1), regI(ins.rs2), regI(ins.rd))
+}
+
func encodeRawIns(ins *instruction) uint32 {
// Treat the raw value specially as a 32-bit unsigned integer.
// Nobody wants to enter negative machine code.
@@ -1485,6 +1559,27 @@ func EncodeUImmediate(imm int64) (int64, error) {
return imm << 12, nil
}
+func EncodeVectorType(vsew, vlmul, vtail, vmask int64) (int64, error) {
+ vsewSO := SpecialOperand(vsew)
+ if vsewSO < SPOP_E8 || vsewSO > SPOP_E64 {
+ return -1, fmt.Errorf("invalid vector selected element width %q", vsewSO)
+ }
+ vlmulSO := SpecialOperand(vlmul)
+ if vlmulSO < SPOP_M1 || vlmulSO > SPOP_MF8 {
+ return -1, fmt.Errorf("invalid vector register group multiplier %q", vlmulSO)
+ }
+ vtailSO := SpecialOperand(vtail)
+ if vtailSO != SPOP_TA && vtailSO != SPOP_TU {
+ return -1, fmt.Errorf("invalid vector tail policy %q", vtailSO)
+ }
+ vmaskSO := SpecialOperand(vmask)
+ if vmaskSO != SPOP_MA && vmaskSO != SPOP_MU {
+ return -1, fmt.Errorf("invalid vector mask policy %q", vmaskSO)
+ }
+ vtype := vmaskSO.encode()<<7 | vtailSO.encode()<<6 | vsewSO.encode()<<3 | vlmulSO.encode()
+ return int64(vtype), nil
+}
+
type encoding struct {
encode func(*instruction) uint32 // encode returns the machine code for an instruction
validate func(*obj.Link, *instruction) // validate validates an instruction
@@ -1522,6 +1617,11 @@ var (
uEncoding = encoding{encode: encodeU, validate: validateU, length: 4}
jEncoding = encoding{encode: encodeJ, validate: validateJ, length: 4}
+ // Encodings for vector configuration setting instruction.
+ vsetvliEncoding = encoding{encode: encodeVsetvli, validate: validateVsetvli, length: 4}
+ vsetivliEncoding = encoding{encode: encodeVsetivli, validate: validateVsetivli, length: 4}
+ vsetvlEncoding = encoding{encode: encodeVsetvl, validate: validateVsetvl, length: 4}
+
// rawEncoding encodes a raw instruction byte sequence.
rawEncoding = encoding{encode: encodeRawIns, validate: validateRaw, length: 4}
@@ -1789,6 +1889,15 @@ var instructions = [ALAST & obj.AMask]instructionData{
ABSETI & obj.AMask: {enc: iIIEncoding, ternary: true},
//
+ // "V" Standard Extension for Vector Operations, Version 1.0
+ //
+
+ // 31.6. Vector Configuration-Setting Instructions
+ AVSETVLI & obj.AMask: {enc: vsetvliEncoding, immForm: AVSETIVLI},
+ AVSETIVLI & obj.AMask: {enc: vsetivliEncoding},
+ AVSETVL & obj.AMask: {enc: vsetvlEncoding},
+
+ //
// Privileged ISA
//
@@ -2345,7 +2454,12 @@ func instructionsForProg(p *obj.Prog) []*instruction {
ins := instructionForProg(p)
inss := []*instruction{ins}
- if len(p.RestArgs) > 1 {
+ if ins.as == AVSETVLI || ins.as == AVSETIVLI {
+ if len(p.RestArgs) != 4 {
+ p.Ctxt.Diag("incorrect number of arguments for instruction")
+ return nil
+ }
+ } else if len(p.RestArgs) > 1 {
p.Ctxt.Diag("too many source registers")
return nil
}
@@ -2583,6 +2697,21 @@ func instructionsForProg(p *obj.Prog) []*instruction {
// XNOR -> (NOT (XOR x y))
ins.as = AXOR
inss = append(inss, &instruction{as: AXORI, rs1: ins.rd, rs2: obj.REG_NONE, rd: ins.rd, imm: -1})
+
+ case AVSETVLI, AVSETIVLI:
+ ins.rs1, ins.rs2 = ins.rs2, obj.REG_NONE
+ vtype, err := EncodeVectorType(p.RestArgs[0].Offset, p.RestArgs[1].Offset, p.RestArgs[2].Offset, p.RestArgs[3].Offset)
+ if err != nil {
+ p.Ctxt.Diag("%v: %v", p, err)
+ }
+ ins.imm = int64(vtype)
+ if ins.as == AVSETIVLI {
+ if p.From.Type != obj.TYPE_CONST {
+ p.Ctxt.Diag("%v: expected immediate value", p)
+ }
+ ins.rs1 = uint32(p.From.Offset)
+ }
+
}
for _, ins := range inss {