mirror of
https://github.com/golang/go
synced 2024-11-26 09:08:07 -07:00
cmd/asm, cmd/internal/obj: enable rounding mode suffix for riscv64
This CL adds rounding modes for riscv64 floating point conversion instructions by suffix with 5 modes: RNE, RTZ, RDN, RUP and RMM. For example, for round to nearest (RNE), we can use `FCVTLD.RNE` According to RISCV manual 8.7 and 9.5, we changed these conversion instructions: FCVTWS FCVTLS FCVTWUS FCVTLUS FCVTWD FCVTLD FCVTWUD FCVTLUD Note: Round towards zero (RTZ) by default for all these instructions above. Change-Id: I491e522e14d721e24aa7f528ee0c4640c54c5808 Reviewed-on: https://go-review.googlesource.com/c/go/+/504736 Reviewed-by: Joel Sing <joel@sing.id.au> Run-TryBot: M Zhuo <mengzhuo1203@gmail.com> Reviewed-by: Cherry Mui <cherryyz@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> TryBot-Result: Gopher Robot <gobot@golang.org> Reviewed-by: Than McIntosh <thanm@google.com>
This commit is contained in:
parent
d4112310a4
commit
3580c212c2
@ -16,6 +16,7 @@ import (
|
||||
"cmd/asm/internal/lex"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/ppc64"
|
||||
"cmd/internal/obj/riscv"
|
||||
"cmd/internal/obj/x86"
|
||||
"cmd/internal/sys"
|
||||
)
|
||||
@ -46,7 +47,11 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
|
||||
p.errorf("%v", err)
|
||||
return
|
||||
}
|
||||
|
||||
case sys.RISCV64:
|
||||
if err := riscv.ParseSuffix(prog, cond); err != nil {
|
||||
p.errorf("unrecognized suffix .%q", cond)
|
||||
return
|
||||
}
|
||||
default:
|
||||
p.errorf("unrecognized suffix .%q", cond)
|
||||
return
|
||||
|
@ -217,8 +217,8 @@ next:
|
||||
for {
|
||||
tok = p.nextToken()
|
||||
if len(operands) == 0 && len(items) == 0 {
|
||||
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
|
||||
// Suffixes: ARM conditionals or x86 modifiers.
|
||||
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386, sys.RISCV64) && tok == '.' {
|
||||
// Suffixes: ARM conditionals, RISCV rounding mode or x86 modifiers.
|
||||
tok = p.nextToken()
|
||||
str := p.lex.Text()
|
||||
if tok != scanner.Ident {
|
||||
|
40
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
40
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
@ -233,11 +233,31 @@ start:
|
||||
|
||||
// 11.7: Single-Precision Floating-Point Conversion and Move Instructions
|
||||
FCVTWS F0, X5 // d31200c0
|
||||
FCVTWS.RNE F0, X5 // d30200c0
|
||||
FCVTWS.RTZ F0, X5 // d31200c0
|
||||
FCVTWS.RDN F0, X5 // d32200c0
|
||||
FCVTWS.RUP F0, X5 // d33200c0
|
||||
FCVTWS.RMM F0, X5 // d34200c0
|
||||
FCVTLS F0, X5 // d31220c0
|
||||
FCVTLS.RNE F0, X5 // d30220c0
|
||||
FCVTLS.RTZ F0, X5 // d31220c0
|
||||
FCVTLS.RDN F0, X5 // d32220c0
|
||||
FCVTLS.RUP F0, X5 // d33220c0
|
||||
FCVTLS.RMM F0, X5 // d34220c0
|
||||
FCVTSW X5, F0 // 538002d0
|
||||
FCVTSL X5, F0 // 538022d0
|
||||
FCVTWUS F0, X5 // d31210c0
|
||||
FCVTWUS.RNE F0, X5 // d30210c0
|
||||
FCVTWUS.RTZ F0, X5 // d31210c0
|
||||
FCVTWUS.RDN F0, X5 // d32210c0
|
||||
FCVTWUS.RUP F0, X5 // d33210c0
|
||||
FCVTWUS.RMM F0, X5 // d34210c0
|
||||
FCVTLUS F0, X5 // d31230c0
|
||||
FCVTLUS.RNE F0, X5 // d30230c0
|
||||
FCVTLUS.RTZ F0, X5 // d31230c0
|
||||
FCVTLUS.RDN F0, X5 // d32230c0
|
||||
FCVTLUS.RUP F0, X5 // d33230c0
|
||||
FCVTLUS.RMM F0, X5 // d34230c0
|
||||
FCVTSWU X5, F0 // 538012d0
|
||||
FCVTSLU X5, F0 // 538032d0
|
||||
FSGNJS F1, F0, F2 // 53011020
|
||||
@ -277,11 +297,31 @@ start:
|
||||
|
||||
// 12.5: Double-Precision Floating-Point Conversion and Move Instructions
|
||||
FCVTWD F0, X5 // d31200c2
|
||||
FCVTWD.RNE F0, X5 // d30200c2
|
||||
FCVTWD.RTZ F0, X5 // d31200c2
|
||||
FCVTWD.RDN F0, X5 // d32200c2
|
||||
FCVTWD.RUP F0, X5 // d33200c2
|
||||
FCVTWD.RMM F0, X5 // d34200c2
|
||||
FCVTLD F0, X5 // d31220c2
|
||||
FCVTLD.RNE F0, X5 // d30220c2
|
||||
FCVTLD.RTZ F0, X5 // d31220c2
|
||||
FCVTLD.RDN F0, X5 // d32220c2
|
||||
FCVTLD.RUP F0, X5 // d33220c2
|
||||
FCVTLD.RMM F0, X5 // d34220c2
|
||||
FCVTDW X5, F0 // 538002d2
|
||||
FCVTDL X5, F0 // 538022d2
|
||||
FCVTWUD F0, X5 // d31210c2
|
||||
FCVTWUD.RNE F0, X5 // d30210c2
|
||||
FCVTWUD.RTZ F0, X5 // d31210c2
|
||||
FCVTWUD.RDN F0, X5 // d32210c2
|
||||
FCVTWUD.RUP F0, X5 // d33210c2
|
||||
FCVTWUD.RMM F0, X5 // d34210c2
|
||||
FCVTLUD F0, X5 // d31230c2
|
||||
FCVTLUD.RNE F0, X5 // d30230c2
|
||||
FCVTLUD.RTZ F0, X5 // d31230c2
|
||||
FCVTLUD.RDN F0, X5 // d32230c2
|
||||
FCVTLUD.RUP F0, X5 // d33230c2
|
||||
FCVTLUD.RMM F0, X5 // d34230c2
|
||||
FCVTDWU X5, F0 // 538012d2
|
||||
FCVTDLU X5, F0 // 538032d2
|
||||
FCVTSD F0, F1 // d3001040
|
||||
|
@ -314,7 +314,7 @@ type Prog struct {
|
||||
RegTo2 int16 // 2nd destination operand
|
||||
Mark uint16 // bitmask of arch-specific items
|
||||
Optab uint16 // arch-specific opcode index
|
||||
Scond uint8 // bits that describe instruction suffixes (e.g. ARM conditions)
|
||||
Scond uint8 // bits that describe instruction suffixes (e.g. ARM conditions, RISCV Rounding Mode)
|
||||
Back uint8 // for x86 back end: backwards branch state
|
||||
Ft uint8 // for x86 back end: type index of Prog.From
|
||||
Tt uint8 // for x86 back end: type index of Prog.To
|
||||
|
@ -28,7 +28,12 @@
|
||||
|
||||
package riscv
|
||||
|
||||
import "cmd/internal/obj"
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"cmd/internal/obj"
|
||||
)
|
||||
|
||||
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv
|
||||
|
||||
@ -607,6 +612,50 @@ const (
|
||||
ALAST
|
||||
)
|
||||
|
||||
// opSuffix encoding to uint8 which fit into p.Scond
|
||||
var rmSuffixSet = map[string]uint8{
|
||||
"RNE": RM_RNE,
|
||||
"RTZ": RM_RTZ,
|
||||
"RDN": RM_RDN,
|
||||
"RUP": RM_RUP,
|
||||
"RMM": RM_RMM,
|
||||
}
|
||||
|
||||
const rmSuffixBit uint8 = 1 << 7
|
||||
|
||||
func rmSuffixEncode(s string) (uint8, error) {
|
||||
if s == "" {
|
||||
return 0, errors.New("empty suffix")
|
||||
}
|
||||
enc, ok := rmSuffixSet[s]
|
||||
if !ok {
|
||||
return 0, fmt.Errorf("invalid encoding for unknown suffix:%q", s)
|
||||
}
|
||||
return enc | rmSuffixBit, nil
|
||||
}
|
||||
|
||||
func rmSuffixString(u uint8) (string, error) {
|
||||
if u&rmSuffixBit == 0 {
|
||||
return "", fmt.Errorf("invalid suffix, require round mode bit:%x", u)
|
||||
}
|
||||
|
||||
u &^= rmSuffixBit
|
||||
for k, v := range rmSuffixSet {
|
||||
if v == u {
|
||||
return k, nil
|
||||
}
|
||||
}
|
||||
return "", fmt.Errorf("unknown suffix:%x", u)
|
||||
}
|
||||
|
||||
const (
|
||||
RM_RNE uint8 = iota // Round to Nearest, ties to Even
|
||||
RM_RTZ // Round towards Zero
|
||||
RM_RDN // Round Down
|
||||
RM_RUP // Round Up
|
||||
RM_RMM // Round to Nearest, ties to Max Magnitude
|
||||
)
|
||||
|
||||
// All unary instructions which write to their arguments (as opposed to reading
|
||||
// from them) go here. The assembly parser uses this information to populate
|
||||
// its AST in a semantically reasonable way.
|
||||
|
@ -13,6 +13,7 @@ import (
|
||||
func init() {
|
||||
obj.RegisterRegister(obj.RBaseRISCV, REG_END, RegName)
|
||||
obj.RegisterOpcode(obj.ABaseRISCV, Anames)
|
||||
obj.RegisterOpSuffix("riscv64", opSuffixString)
|
||||
}
|
||||
|
||||
func RegName(r int) string {
|
||||
@ -31,3 +32,18 @@ func RegName(r int) string {
|
||||
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseRISCV)
|
||||
}
|
||||
}
|
||||
|
||||
func opSuffixString(s uint8) string {
|
||||
if s&rmSuffixBit == 0 {
|
||||
return ""
|
||||
}
|
||||
|
||||
ss, err := rmSuffixString(s)
|
||||
if err != nil {
|
||||
ss = fmt.Sprintf("<invalid 0x%x>", s)
|
||||
}
|
||||
if ss == "" {
|
||||
return ss
|
||||
}
|
||||
return fmt.Sprintf(".%s", ss)
|
||||
}
|
||||
|
@ -28,6 +28,7 @@ import (
|
||||
"internal/abi"
|
||||
"log"
|
||||
"math/bits"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func buildop(ctxt *obj.Link) {}
|
||||
@ -2273,8 +2274,12 @@ func instructionsForProg(p *obj.Prog) []*instruction {
|
||||
ins.imm = 0x0ff
|
||||
|
||||
case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
|
||||
// Set the rounding mode in funct3 to round to zero.
|
||||
ins.funct3 = 1
|
||||
// Set the default rounding mode in funct3 to round to zero.
|
||||
if p.Scond&rmSuffixBit == 0 {
|
||||
ins.funct3 = uint32(RM_RTZ)
|
||||
} else {
|
||||
ins.funct3 = uint32(p.Scond &^ rmSuffixBit)
|
||||
}
|
||||
|
||||
case AFNES, AFNED:
|
||||
// Replace FNE[SD] with FEQ[SD] and NOT.
|
||||
@ -2478,6 +2483,14 @@ func isUnsafePoint(p *obj.Prog) bool {
|
||||
return p.Mark&USES_REG_TMP == USES_REG_TMP || p.From.Reg == REG_TMP || p.To.Reg == REG_TMP || p.Reg == REG_TMP
|
||||
}
|
||||
|
||||
func ParseSuffix(prog *obj.Prog, cond string) (err error) {
|
||||
switch prog.As {
|
||||
case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
|
||||
prog.Scond, err = rmSuffixEncode(strings.TrimPrefix(cond, "."))
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
var LinkRISCV64 = obj.LinkArch{
|
||||
Arch: sys.ArchRISCV64,
|
||||
Init: buildop,
|
||||
|
Loading…
Reference in New Issue
Block a user