mirror of
https://github.com/golang/go
synced 2024-11-22 22:30:02 -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/asm/internal/lex"
|
||||||
"cmd/internal/obj"
|
"cmd/internal/obj"
|
||||||
"cmd/internal/obj/ppc64"
|
"cmd/internal/obj/ppc64"
|
||||||
|
"cmd/internal/obj/riscv"
|
||||||
"cmd/internal/obj/x86"
|
"cmd/internal/obj/x86"
|
||||||
"cmd/internal/sys"
|
"cmd/internal/sys"
|
||||||
)
|
)
|
||||||
@ -46,7 +47,11 @@ func (p *Parser) append(prog *obj.Prog, cond string, doLabel bool) {
|
|||||||
p.errorf("%v", err)
|
p.errorf("%v", err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
case sys.RISCV64:
|
||||||
|
if err := riscv.ParseSuffix(prog, cond); err != nil {
|
||||||
|
p.errorf("unrecognized suffix .%q", cond)
|
||||||
|
return
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
p.errorf("unrecognized suffix .%q", cond)
|
p.errorf("unrecognized suffix .%q", cond)
|
||||||
return
|
return
|
||||||
|
@ -217,8 +217,8 @@ next:
|
|||||||
for {
|
for {
|
||||||
tok = p.nextToken()
|
tok = p.nextToken()
|
||||||
if len(operands) == 0 && len(items) == 0 {
|
if len(operands) == 0 && len(items) == 0 {
|
||||||
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386) && tok == '.' {
|
if p.arch.InFamily(sys.ARM, sys.ARM64, sys.AMD64, sys.I386, sys.RISCV64) && tok == '.' {
|
||||||
// Suffixes: ARM conditionals or x86 modifiers.
|
// Suffixes: ARM conditionals, RISCV rounding mode or x86 modifiers.
|
||||||
tok = p.nextToken()
|
tok = p.nextToken()
|
||||||
str := p.lex.Text()
|
str := p.lex.Text()
|
||||||
if tok != scanner.Ident {
|
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
|
// 11.7: Single-Precision Floating-Point Conversion and Move Instructions
|
||||||
FCVTWS F0, X5 // d31200c0
|
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 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
|
FCVTSW X5, F0 // 538002d0
|
||||||
FCVTSL X5, F0 // 538022d0
|
FCVTSL X5, F0 // 538022d0
|
||||||
FCVTWUS F0, X5 // d31210c0
|
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 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
|
FCVTSWU X5, F0 // 538012d0
|
||||||
FCVTSLU X5, F0 // 538032d0
|
FCVTSLU X5, F0 // 538032d0
|
||||||
FSGNJS F1, F0, F2 // 53011020
|
FSGNJS F1, F0, F2 // 53011020
|
||||||
@ -277,11 +297,31 @@ start:
|
|||||||
|
|
||||||
// 12.5: Double-Precision Floating-Point Conversion and Move Instructions
|
// 12.5: Double-Precision Floating-Point Conversion and Move Instructions
|
||||||
FCVTWD F0, X5 // d31200c2
|
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 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
|
FCVTDW X5, F0 // 538002d2
|
||||||
FCVTDL X5, F0 // 538022d2
|
FCVTDL X5, F0 // 538022d2
|
||||||
FCVTWUD F0, X5 // d31210c2
|
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 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
|
FCVTDWU X5, F0 // 538012d2
|
||||||
FCVTDLU X5, F0 // 538032d2
|
FCVTDLU X5, F0 // 538032d2
|
||||||
FCVTSD F0, F1 // d3001040
|
FCVTSD F0, F1 // d3001040
|
||||||
|
@ -314,7 +314,7 @@ type Prog struct {
|
|||||||
RegTo2 int16 // 2nd destination operand
|
RegTo2 int16 // 2nd destination operand
|
||||||
Mark uint16 // bitmask of arch-specific items
|
Mark uint16 // bitmask of arch-specific items
|
||||||
Optab uint16 // arch-specific opcode index
|
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
|
Back uint8 // for x86 back end: backwards branch state
|
||||||
Ft uint8 // for x86 back end: type index of Prog.From
|
Ft uint8 // for x86 back end: type index of Prog.From
|
||||||
Tt uint8 // for x86 back end: type index of Prog.To
|
Tt uint8 // for x86 back end: type index of Prog.To
|
||||||
|
@ -28,7 +28,12 @@
|
|||||||
|
|
||||||
package riscv
|
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
|
//go:generate go run ../stringer.go -i $GOFILE -o anames.go -p riscv
|
||||||
|
|
||||||
@ -607,6 +612,50 @@ const (
|
|||||||
ALAST
|
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
|
// All unary instructions which write to their arguments (as opposed to reading
|
||||||
// from them) go here. The assembly parser uses this information to populate
|
// from them) go here. The assembly parser uses this information to populate
|
||||||
// its AST in a semantically reasonable way.
|
// its AST in a semantically reasonable way.
|
||||||
|
@ -13,6 +13,7 @@ import (
|
|||||||
func init() {
|
func init() {
|
||||||
obj.RegisterRegister(obj.RBaseRISCV, REG_END, RegName)
|
obj.RegisterRegister(obj.RBaseRISCV, REG_END, RegName)
|
||||||
obj.RegisterOpcode(obj.ABaseRISCV, Anames)
|
obj.RegisterOpcode(obj.ABaseRISCV, Anames)
|
||||||
|
obj.RegisterOpSuffix("riscv64", opSuffixString)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegName(r int) string {
|
func RegName(r int) string {
|
||||||
@ -31,3 +32,18 @@ func RegName(r int) string {
|
|||||||
return fmt.Sprintf("Rgok(%d)", r-obj.RBaseRISCV)
|
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"
|
"internal/abi"
|
||||||
"log"
|
"log"
|
||||||
"math/bits"
|
"math/bits"
|
||||||
|
"strings"
|
||||||
)
|
)
|
||||||
|
|
||||||
func buildop(ctxt *obj.Link) {}
|
func buildop(ctxt *obj.Link) {}
|
||||||
@ -2273,8 +2274,12 @@ func instructionsForProg(p *obj.Prog) []*instruction {
|
|||||||
ins.imm = 0x0ff
|
ins.imm = 0x0ff
|
||||||
|
|
||||||
case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
|
case AFCVTWS, AFCVTLS, AFCVTWUS, AFCVTLUS, AFCVTWD, AFCVTLD, AFCVTWUD, AFCVTLUD:
|
||||||
// Set the rounding mode in funct3 to round to zero.
|
// Set the default rounding mode in funct3 to round to zero.
|
||||||
ins.funct3 = 1
|
if p.Scond&rmSuffixBit == 0 {
|
||||||
|
ins.funct3 = uint32(RM_RTZ)
|
||||||
|
} else {
|
||||||
|
ins.funct3 = uint32(p.Scond &^ rmSuffixBit)
|
||||||
|
}
|
||||||
|
|
||||||
case AFNES, AFNED:
|
case AFNES, AFNED:
|
||||||
// Replace FNE[SD] with FEQ[SD] and NOT.
|
// 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
|
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{
|
var LinkRISCV64 = obj.LinkArch{
|
||||||
Arch: sys.ArchRISCV64,
|
Arch: sys.ArchRISCV64,
|
||||||
Init: buildop,
|
Init: buildop,
|
||||||
|
Loading…
Reference in New Issue
Block a user