mirror of
https://github.com/golang/go.git
synced 2025-05-29 03:11:26 +00:00
cmd/asm: refactor some operands that are not special registers on arm64
The previous code treats some operands such as EQ, LT, etc. as special registers. However, they are not. This CL adds a new AddrType TYPE_SPOPD and a new class C_SPOPD to support this kind of special operands, and refactors the relevant code. This patch is a copy of CL 260861, contributed by Junchen Li(junchen.li@arm.com). Co-authored-by: Junchen Li(junchen.li@arm.com) Change-Id: I57b28da458ee3332f610602632e7eda03af435f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/302849 Reviewed-by: Cherry Mui <cherryyz@google.com> Trust: Eric Fang <eric.fang@arm.com> Run-TryBot: Eric Fang <eric.fang@arm.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
bb2b16d15e
commit
f5290ef947
@ -278,46 +278,7 @@ func archArm64() *Arch {
|
||||
}
|
||||
|
||||
register["LR"] = arm64.REGLINK
|
||||
register["DAIFSet"] = arm64.REG_DAIFSet
|
||||
register["DAIFClr"] = arm64.REG_DAIFClr
|
||||
register["PLDL1KEEP"] = arm64.REG_PLDL1KEEP
|
||||
register["PLDL1STRM"] = arm64.REG_PLDL1STRM
|
||||
register["PLDL2KEEP"] = arm64.REG_PLDL2KEEP
|
||||
register["PLDL2STRM"] = arm64.REG_PLDL2STRM
|
||||
register["PLDL3KEEP"] = arm64.REG_PLDL3KEEP
|
||||
register["PLDL3STRM"] = arm64.REG_PLDL3STRM
|
||||
register["PLIL1KEEP"] = arm64.REG_PLIL1KEEP
|
||||
register["PLIL1STRM"] = arm64.REG_PLIL1STRM
|
||||
register["PLIL2KEEP"] = arm64.REG_PLIL2KEEP
|
||||
register["PLIL2STRM"] = arm64.REG_PLIL2STRM
|
||||
register["PLIL3KEEP"] = arm64.REG_PLIL3KEEP
|
||||
register["PLIL3STRM"] = arm64.REG_PLIL3STRM
|
||||
register["PSTL1KEEP"] = arm64.REG_PSTL1KEEP
|
||||
register["PSTL1STRM"] = arm64.REG_PSTL1STRM
|
||||
register["PSTL2KEEP"] = arm64.REG_PSTL2KEEP
|
||||
register["PSTL2STRM"] = arm64.REG_PSTL2STRM
|
||||
register["PSTL3KEEP"] = arm64.REG_PSTL3KEEP
|
||||
register["PSTL3STRM"] = arm64.REG_PSTL3STRM
|
||||
|
||||
// Conditional operators, like EQ, NE, etc.
|
||||
register["EQ"] = arm64.COND_EQ
|
||||
register["NE"] = arm64.COND_NE
|
||||
register["HS"] = arm64.COND_HS
|
||||
register["CS"] = arm64.COND_HS
|
||||
register["LO"] = arm64.COND_LO
|
||||
register["CC"] = arm64.COND_LO
|
||||
register["MI"] = arm64.COND_MI
|
||||
register["PL"] = arm64.COND_PL
|
||||
register["VS"] = arm64.COND_VS
|
||||
register["VC"] = arm64.COND_VC
|
||||
register["HI"] = arm64.COND_HI
|
||||
register["LS"] = arm64.COND_LS
|
||||
register["GE"] = arm64.COND_GE
|
||||
register["LT"] = arm64.COND_LT
|
||||
register["GT"] = arm64.COND_GT
|
||||
register["LE"] = arm64.COND_LE
|
||||
register["AL"] = arm64.COND_AL
|
||||
register["NV"] = arm64.COND_NV
|
||||
// Pseudo-registers.
|
||||
register["SB"] = RSB
|
||||
register["FP"] = RFP
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
var arm64LS = map[string]uint8{
|
||||
@ -52,7 +53,35 @@ func jumpArm64(word string) bool {
|
||||
return arm64Jump[word]
|
||||
}
|
||||
|
||||
// IsARM64CMP reports whether the op (as defined by an arm.A* constant) is
|
||||
var arm64SpecialOperand map[string]arm64.SpecialOperand
|
||||
|
||||
// GetARM64SpecialOperand returns the internal representation of a special operand.
|
||||
func GetARM64SpecialOperand(name string) arm64.SpecialOperand {
|
||||
if arm64SpecialOperand == nil {
|
||||
// Generate the mapping automatically when the first time the function is called.
|
||||
arm64SpecialOperand = map[string]arm64.SpecialOperand{}
|
||||
for opd := arm64.SPOP_BEGIN; opd < arm64.SPOP_END; opd++ {
|
||||
s := fmt.Sprintf("%s", opd)
|
||||
arm64SpecialOperand[s] = opd
|
||||
}
|
||||
|
||||
// Handle some special cases.
|
||||
specialMapping := map[string]arm64.SpecialOperand{
|
||||
// The internal representation of CS(CC) and HS(LO) are the same.
|
||||
"CS": arm64.SPOP_HS,
|
||||
"CC": arm64.SPOP_LO,
|
||||
}
|
||||
for s, opd := range specialMapping {
|
||||
arm64SpecialOperand[s] = opd
|
||||
}
|
||||
}
|
||||
if opd, ok := arm64SpecialOperand[name]; ok {
|
||||
return opd
|
||||
}
|
||||
return arm64.SPOP_END
|
||||
}
|
||||
|
||||
// IsARM64CMP reports whether the op (as defined by an arm64.A* constant) is
|
||||
// one of the comparison instructions that require special handling.
|
||||
func IsARM64CMP(op obj.As) bool {
|
||||
switch op {
|
||||
|
@ -19,6 +19,7 @@ import (
|
||||
"cmd/asm/internal/flags"
|
||||
"cmd/asm/internal/lex"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm64"
|
||||
"cmd/internal/obj/x86"
|
||||
"cmd/internal/src"
|
||||
"cmd/internal/sys"
|
||||
@ -389,8 +390,19 @@ func (p *Parser) operand(a *obj.Addr) {
|
||||
tok := p.next()
|
||||
name := tok.String()
|
||||
if tok.ScanToken == scanner.Ident && !p.atStartOfRegister(name) {
|
||||
// We have a symbol. Parse $sym±offset(symkind)
|
||||
p.symbolReference(a, name, prefix)
|
||||
switch p.arch.Family {
|
||||
case sys.ARM64:
|
||||
// arm64 special operands.
|
||||
if opd := arch.GetARM64SpecialOperand(name); opd != arm64.SPOP_END {
|
||||
a.Type = obj.TYPE_SPECIAL
|
||||
a.Offset = int64(opd)
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
// We have a symbol. Parse $sym±offset(symkind)
|
||||
p.symbolReference(a, name, prefix)
|
||||
}
|
||||
// fmt.Printf("SYM %s\n", obj.Dconv(&emptyProg, 0, a))
|
||||
if p.peek() == scanner.EOF {
|
||||
return
|
||||
|
3
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
3
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@ -628,7 +628,8 @@ again:
|
||||
CSELW LT, R2, R3, R4 // 44b0831a
|
||||
CSINC GT, R1, ZR, R3 // 23c49f9a
|
||||
CSNEG MI, R1, R2, R3 // 234482da
|
||||
CSINV CS, R1, R2, R3 // CSINV HS, R1, R2, R3 // 232082da
|
||||
CSINV CS, R1, R2, R3 // CSINV HS, R1, R2, R3 // 232082da
|
||||
CSINV HS, R1, R2, R3 // 232082da
|
||||
CSINVW MI, R2, ZR, R2 // 42409f5a
|
||||
CINC EQ, R4, R9 // 8914849a
|
||||
CINCW PL, R2, ZR // 5f44821a
|
||||
|
@ -728,8 +728,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
p4.To.Type = obj.TYPE_BRANCH
|
||||
p4.To.SetTarget(p)
|
||||
p5 := s.Prog(arm64.ACSET)
|
||||
p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p5.From.Reg = arm64.COND_EQ
|
||||
p5.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
p5.From.Offset = int64(arm64.SPOP_EQ)
|
||||
p5.To.Type = obj.TYPE_REG
|
||||
p5.To.Reg = out
|
||||
p2.To.SetTarget(p5)
|
||||
@ -778,8 +778,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
|
||||
// CSET EQ, Rout
|
||||
p3 := s.Prog(arm64.ACSET)
|
||||
p3.From.Type = obj.TYPE_REG
|
||||
p3.From.Reg = arm64.COND_EQ
|
||||
p3.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
p3.From.Offset = int64(arm64.SPOP_EQ)
|
||||
p3.To.Type = obj.TYPE_REG
|
||||
p3.To.Reg = out
|
||||
|
||||
@ -978,24 +978,27 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
r1 = v.Args[1].Reg()
|
||||
}
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.Reg = v.Args[0].Reg()
|
||||
p.SetFrom3Reg(r1)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64CSINC, ssa.OpARM64CSINV, ssa.OpARM64CSNEG:
|
||||
p := s.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.Reg = v.Args[0].Reg()
|
||||
p.SetFrom3Reg(v.Args[1].Reg())
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64CSETM:
|
||||
p := s.Prog(arm64.ACSETM)
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[ssa.Op(v.AuxInt)]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64DUFFZERO:
|
||||
@ -1107,8 +1110,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
ssa.OpARM64NotGreaterEqualF:
|
||||
// generate boolean values using CSET
|
||||
p := s.Prog(arm64.ACSET)
|
||||
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg
|
||||
p.From.Reg = condBits[v.Op]
|
||||
p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
|
||||
condCode := condBits[v.Op]
|
||||
p.From.Offset = int64(condCode)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = v.Reg()
|
||||
case ssa.OpARM64PRFM:
|
||||
@ -1173,27 +1177,27 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||
}
|
||||
}
|
||||
|
||||
var condBits = map[ssa.Op]int16{
|
||||
ssa.OpARM64Equal: arm64.COND_EQ,
|
||||
ssa.OpARM64NotEqual: arm64.COND_NE,
|
||||
ssa.OpARM64LessThan: arm64.COND_LT,
|
||||
ssa.OpARM64LessThanU: arm64.COND_LO,
|
||||
ssa.OpARM64LessEqual: arm64.COND_LE,
|
||||
ssa.OpARM64LessEqualU: arm64.COND_LS,
|
||||
ssa.OpARM64GreaterThan: arm64.COND_GT,
|
||||
ssa.OpARM64GreaterThanU: arm64.COND_HI,
|
||||
ssa.OpARM64GreaterEqual: arm64.COND_GE,
|
||||
ssa.OpARM64GreaterEqualU: arm64.COND_HS,
|
||||
ssa.OpARM64LessThanF: arm64.COND_MI, // Less than
|
||||
ssa.OpARM64LessEqualF: arm64.COND_LS, // Less than or equal to
|
||||
ssa.OpARM64GreaterThanF: arm64.COND_GT, // Greater than
|
||||
ssa.OpARM64GreaterEqualF: arm64.COND_GE, // Greater than or equal to
|
||||
var condBits = map[ssa.Op]arm64.SpecialOperand{
|
||||
ssa.OpARM64Equal: arm64.SPOP_EQ,
|
||||
ssa.OpARM64NotEqual: arm64.SPOP_NE,
|
||||
ssa.OpARM64LessThan: arm64.SPOP_LT,
|
||||
ssa.OpARM64LessThanU: arm64.SPOP_LO,
|
||||
ssa.OpARM64LessEqual: arm64.SPOP_LE,
|
||||
ssa.OpARM64LessEqualU: arm64.SPOP_LS,
|
||||
ssa.OpARM64GreaterThan: arm64.SPOP_GT,
|
||||
ssa.OpARM64GreaterThanU: arm64.SPOP_HI,
|
||||
ssa.OpARM64GreaterEqual: arm64.SPOP_GE,
|
||||
ssa.OpARM64GreaterEqualU: arm64.SPOP_HS,
|
||||
ssa.OpARM64LessThanF: arm64.SPOP_MI, // Less than
|
||||
ssa.OpARM64LessEqualF: arm64.SPOP_LS, // Less than or equal to
|
||||
ssa.OpARM64GreaterThanF: arm64.SPOP_GT, // Greater than
|
||||
ssa.OpARM64GreaterEqualF: arm64.SPOP_GE, // Greater than or equal to
|
||||
|
||||
// The following condition codes have unordered to handle comparisons related to NaN.
|
||||
ssa.OpARM64NotLessThanF: arm64.COND_PL, // Greater than, equal to, or unordered
|
||||
ssa.OpARM64NotLessEqualF: arm64.COND_HI, // Greater than or unordered
|
||||
ssa.OpARM64NotGreaterThanF: arm64.COND_LE, // Less than, equal to or unordered
|
||||
ssa.OpARM64NotGreaterEqualF: arm64.COND_LT, // Less than or unordered
|
||||
ssa.OpARM64NotLessThanF: arm64.SPOP_PL, // Greater than, equal to, or unordered
|
||||
ssa.OpARM64NotLessEqualF: arm64.SPOP_HI, // Greater than or unordered
|
||||
ssa.OpARM64NotGreaterThanF: arm64.SPOP_LE, // Less than, equal to or unordered
|
||||
ssa.OpARM64NotGreaterEqualF: arm64.SPOP_LT, // Less than or unordered
|
||||
}
|
||||
|
||||
var blockJump = map[ssa.BlockKind]struct {
|
||||
|
@ -4,9 +4,30 @@ package obj
|
||||
|
||||
import "strconv"
|
||||
|
||||
const _AddrType_name = "TYPE_NONETYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLIST"
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[TYPE_NONE-0]
|
||||
_ = x[TYPE_BRANCH-1]
|
||||
_ = x[TYPE_TEXTSIZE-2]
|
||||
_ = x[TYPE_MEM-3]
|
||||
_ = x[TYPE_CONST-4]
|
||||
_ = x[TYPE_FCONST-5]
|
||||
_ = x[TYPE_SCONST-6]
|
||||
_ = x[TYPE_REG-7]
|
||||
_ = x[TYPE_ADDR-8]
|
||||
_ = x[TYPE_SHIFT-9]
|
||||
_ = x[TYPE_REGREG-10]
|
||||
_ = x[TYPE_REGREG2-11]
|
||||
_ = x[TYPE_INDIR-12]
|
||||
_ = x[TYPE_REGLIST-13]
|
||||
_ = x[TYPE_SPECIAL-14]
|
||||
}
|
||||
|
||||
var _AddrType_index = [...]uint8{0, 9, 20, 33, 41, 51, 62, 73, 81, 90, 100, 111, 123, 133, 145}
|
||||
const _AddrType_name = "TYPE_NONETYPE_BRANCHTYPE_TEXTSIZETYPE_MEMTYPE_CONSTTYPE_FCONSTTYPE_SCONSTTYPE_REGTYPE_ADDRTYPE_SHIFTTYPE_REGREGTYPE_REGREG2TYPE_INDIRTYPE_REGLISTTYPE_SPECIAL"
|
||||
|
||||
var _AddrType_index = [...]uint8{0, 9, 20, 33, 41, 51, 62, 73, 81, 90, 100, 111, 123, 133, 145, 157}
|
||||
|
||||
func (i AddrType) String() string {
|
||||
if i >= AddrType(len(_AddrType_index)-1) {
|
||||
|
@ -143,26 +143,6 @@ const (
|
||||
REG_V30
|
||||
REG_V31
|
||||
|
||||
// The EQ in
|
||||
// CSET EQ, R0
|
||||
// is encoded as TYPE_REG, even though it's not really a register.
|
||||
COND_EQ
|
||||
COND_NE
|
||||
COND_HS
|
||||
COND_LO
|
||||
COND_MI
|
||||
COND_PL
|
||||
COND_VS
|
||||
COND_VC
|
||||
COND_HI
|
||||
COND_LS
|
||||
COND_GE
|
||||
COND_LT
|
||||
COND_GT
|
||||
COND_LE
|
||||
COND_AL
|
||||
COND_NV
|
||||
|
||||
REG_RSP = REG_V31 + 32 // to differentiate ZR/SP, REG_RSP&0x1f = 31
|
||||
)
|
||||
|
||||
@ -197,28 +177,10 @@ const (
|
||||
// a special register and the low bits select the register.
|
||||
// SYSREG_END is the last item in the automatically generated system register
|
||||
// declaration, and it is defined in the sysRegEnc.go file.
|
||||
// Define the special register after REG_SPECIAL, the first value of it should be
|
||||
// REG_{name} = SYSREG_END + iota.
|
||||
const (
|
||||
REG_SPECIAL = obj.RBaseARM64 + 1<<12
|
||||
REG_DAIFSet = SYSREG_END + iota
|
||||
REG_DAIFClr
|
||||
REG_PLDL1KEEP
|
||||
REG_PLDL1STRM
|
||||
REG_PLDL2KEEP
|
||||
REG_PLDL2STRM
|
||||
REG_PLDL3KEEP
|
||||
REG_PLDL3STRM
|
||||
REG_PLIL1KEEP
|
||||
REG_PLIL1STRM
|
||||
REG_PLIL2KEEP
|
||||
REG_PLIL2STRM
|
||||
REG_PLIL3KEEP
|
||||
REG_PLIL3STRM
|
||||
REG_PSTL1KEEP
|
||||
REG_PSTL1STRM
|
||||
REG_PSTL2KEEP
|
||||
REG_PSTL2STRM
|
||||
REG_PSTL3KEEP
|
||||
REG_PSTL3STRM
|
||||
)
|
||||
|
||||
// Register assignments:
|
||||
@ -388,7 +350,8 @@ const (
|
||||
C_SHIFT // Rn<<2
|
||||
C_EXTREG // Rn.UXTB[<<3]
|
||||
C_SPR // REG_NZCV
|
||||
C_COND // EQ, NE, etc
|
||||
C_COND // condition code, EQ, NE, etc.
|
||||
C_SPOP // special operand, PLDL1KEEP, VMALLE1IS, etc.
|
||||
C_ARNG // Vn.<T>
|
||||
C_ELEM // Vn.<T>[index]
|
||||
C_LIST // [V1, V2, V3]
|
||||
@ -1085,3 +1048,54 @@ const (
|
||||
ARNG_S
|
||||
ARNG_D
|
||||
)
|
||||
|
||||
//go:generate stringer -type SpecialOperand -trimprefix SPOP_
|
||||
type SpecialOperand int
|
||||
|
||||
const (
|
||||
// PRFM
|
||||
SPOP_PLDL1KEEP SpecialOperand = iota // must be the first one
|
||||
SPOP_BEGIN SpecialOperand = iota - 1 // set as the lower bound
|
||||
SPOP_PLDL1STRM
|
||||
SPOP_PLDL2KEEP
|
||||
SPOP_PLDL2STRM
|
||||
SPOP_PLDL3KEEP
|
||||
SPOP_PLDL3STRM
|
||||
SPOP_PLIL1KEEP
|
||||
SPOP_PLIL1STRM
|
||||
SPOP_PLIL2KEEP
|
||||
SPOP_PLIL2STRM
|
||||
SPOP_PLIL3KEEP
|
||||
SPOP_PLIL3STRM
|
||||
SPOP_PSTL1KEEP
|
||||
SPOP_PSTL1STRM
|
||||
SPOP_PSTL2KEEP
|
||||
SPOP_PSTL2STRM
|
||||
SPOP_PSTL3KEEP
|
||||
SPOP_PSTL3STRM
|
||||
|
||||
// PSTATE fields
|
||||
SPOP_DAIFSet
|
||||
SPOP_DAIFClr
|
||||
|
||||
// Condition code, EQ, NE, etc. Their relative order to EQ is matter.
|
||||
SPOP_EQ
|
||||
SPOP_NE
|
||||
SPOP_HS
|
||||
SPOP_LO
|
||||
SPOP_MI
|
||||
SPOP_PL
|
||||
SPOP_VS
|
||||
SPOP_VC
|
||||
SPOP_HI
|
||||
SPOP_LS
|
||||
SPOP_GE
|
||||
SPOP_LT
|
||||
SPOP_GT
|
||||
SPOP_LE
|
||||
SPOP_AL
|
||||
SPOP_NV
|
||||
// Condition code end.
|
||||
|
||||
SPOP_END
|
||||
)
|
||||
|
@ -15,6 +15,7 @@ var cnames7 = []string{
|
||||
"SHIFT",
|
||||
"EXTREG",
|
||||
"SPR",
|
||||
"SPOP",
|
||||
"COND",
|
||||
"ARNG",
|
||||
"ELEM",
|
||||
|
@ -838,7 +838,8 @@ var optab = []Optab{
|
||||
{AMSR, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0},
|
||||
{AMOVD, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0},
|
||||
{AMSR, C_VCON, C_NONE, C_NONE, C_SPR, 37, 4, 0, 0, 0},
|
||||
{APRFM, C_UOREG32K, C_NONE, C_NONE, C_SPR, 91, 4, 0, 0, 0},
|
||||
{AMSR, C_VCON, C_NONE, C_NONE, C_SPOP, 37, 4, 0, 0, 0},
|
||||
{APRFM, C_UOREG32K, C_NONE, C_NONE, C_SPOP, 91, 4, 0, 0, 0},
|
||||
{APRFM, C_UOREG32K, C_NONE, C_NONE, C_LCON, 91, 4, 0, 0, 0},
|
||||
{ADMB, C_VCON, C_NONE, C_NONE, C_NONE, 51, 4, 0, 0, 0},
|
||||
{AHINT, C_VCON, C_NONE, C_NONE, C_NONE, 52, 4, 0, 0, 0},
|
||||
@ -873,40 +874,35 @@ var optab = []Optab{
|
||||
{obj.AXXX, C_NONE, C_NONE, C_NONE, C_NONE, 0, 4, 0, 0, 0},
|
||||
}
|
||||
|
||||
/*
|
||||
* valid pstate field values, and value to use in instruction
|
||||
*/
|
||||
// Valid pstate field values, and value to use in instruction.
|
||||
// Doesn't include special registers.
|
||||
var pstatefield = []struct {
|
||||
reg int16
|
||||
opd SpecialOperand
|
||||
enc uint32
|
||||
}{
|
||||
{REG_SPSel, 0<<16 | 4<<12 | 5<<5},
|
||||
{REG_DAIFSet, 3<<16 | 4<<12 | 6<<5},
|
||||
{REG_DAIFClr, 3<<16 | 4<<12 | 7<<5},
|
||||
{SPOP_DAIFSet, 3<<16 | 4<<12 | 6<<5},
|
||||
{SPOP_DAIFClr, 3<<16 | 4<<12 | 7<<5},
|
||||
}
|
||||
|
||||
var prfopfield = []struct {
|
||||
reg int16
|
||||
enc uint32
|
||||
}{
|
||||
{REG_PLDL1KEEP, 0},
|
||||
{REG_PLDL1STRM, 1},
|
||||
{REG_PLDL2KEEP, 2},
|
||||
{REG_PLDL2STRM, 3},
|
||||
{REG_PLDL3KEEP, 4},
|
||||
{REG_PLDL3STRM, 5},
|
||||
{REG_PLIL1KEEP, 8},
|
||||
{REG_PLIL1STRM, 9},
|
||||
{REG_PLIL2KEEP, 10},
|
||||
{REG_PLIL2STRM, 11},
|
||||
{REG_PLIL3KEEP, 12},
|
||||
{REG_PLIL3STRM, 13},
|
||||
{REG_PSTL1KEEP, 16},
|
||||
{REG_PSTL1STRM, 17},
|
||||
{REG_PSTL2KEEP, 18},
|
||||
{REG_PSTL2STRM, 19},
|
||||
{REG_PSTL3KEEP, 20},
|
||||
{REG_PSTL3STRM, 21},
|
||||
var prfopfield = map[SpecialOperand]uint32{
|
||||
SPOP_PLDL1KEEP: 0,
|
||||
SPOP_PLDL1STRM: 1,
|
||||
SPOP_PLDL2KEEP: 2,
|
||||
SPOP_PLDL2STRM: 3,
|
||||
SPOP_PLDL3KEEP: 4,
|
||||
SPOP_PLDL3STRM: 5,
|
||||
SPOP_PLIL1KEEP: 8,
|
||||
SPOP_PLIL1STRM: 9,
|
||||
SPOP_PLIL2KEEP: 10,
|
||||
SPOP_PLIL2STRM: 11,
|
||||
SPOP_PLIL3KEEP: 12,
|
||||
SPOP_PLIL3STRM: 13,
|
||||
SPOP_PSTL1KEEP: 16,
|
||||
SPOP_PSTL1STRM: 17,
|
||||
SPOP_PSTL2KEEP: 18,
|
||||
SPOP_PSTL2STRM: 19,
|
||||
SPOP_PSTL3KEEP: 20,
|
||||
SPOP_PSTL3STRM: 21,
|
||||
}
|
||||
|
||||
// Used for padinng NOOP instruction
|
||||
@ -1676,8 +1672,6 @@ func rclass(r int16) int {
|
||||
return C_FREG
|
||||
case REG_V0 <= r && r <= REG_V31:
|
||||
return C_VREG
|
||||
case COND_EQ <= r && r <= COND_NV:
|
||||
return C_COND
|
||||
case r == REGSP:
|
||||
return C_RSP
|
||||
case r >= REG_ARNG && r < REG_ELEM:
|
||||
@ -1953,8 +1947,14 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
|
||||
|
||||
case obj.TYPE_BRANCH:
|
||||
return C_SBRA
|
||||
}
|
||||
|
||||
case obj.TYPE_SPECIAL:
|
||||
opd := SpecialOperand(a.Offset)
|
||||
if SPOP_EQ <= opd && opd <= SPOP_NV {
|
||||
return C_COND
|
||||
}
|
||||
return C_SPOP
|
||||
}
|
||||
return C_GOK
|
||||
}
|
||||
|
||||
@ -3526,12 +3526,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
||||
case 18: /* csel cond,Rn,Rm,Rd; cinc/cinv/cneg cond,Rn,Rd; cset cond,Rd */
|
||||
o1 = c.oprrr(p, p.As)
|
||||
|
||||
cond := int(p.From.Reg)
|
||||
// AL and NV are not allowed for CINC/CINV/CNEG/CSET/CSETM instructions
|
||||
if cond < COND_EQ || cond > COND_NV || (cond == COND_AL || cond == COND_NV) && p.From3Type() == obj.TYPE_NONE {
|
||||
cond := SpecialOperand(p.From.Offset)
|
||||
if cond < SPOP_EQ || cond > SPOP_NV || (cond == SPOP_AL || cond == SPOP_NV) && p.From3Type() == obj.TYPE_NONE {
|
||||
c.ctxt.Diag("invalid condition: %v", p)
|
||||
} else {
|
||||
cond -= COND_EQ
|
||||
cond -= SPOP_EQ
|
||||
}
|
||||
|
||||
r := int(p.Reg)
|
||||
@ -3554,11 +3553,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
||||
case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */
|
||||
nzcv := int(p.To.Offset)
|
||||
|
||||
cond := int(p.From.Reg)
|
||||
if cond < COND_EQ || cond > COND_NV {
|
||||
cond := SpecialOperand(p.From.Offset)
|
||||
if cond < SPOP_EQ || cond > SPOP_NV {
|
||||
c.ctxt.Diag("invalid condition\n%v", p)
|
||||
} else {
|
||||
cond -= COND_EQ
|
||||
cond -= SPOP_EQ
|
||||
}
|
||||
var rf int
|
||||
if p.GetFrom3().Type == obj.TYPE_REG {
|
||||
@ -3919,10 +3918,16 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
||||
o1 = c.opirr(p, AMSR)
|
||||
o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */
|
||||
v := uint32(0)
|
||||
for i := 0; i < len(pstatefield); i++ {
|
||||
if pstatefield[i].reg == p.To.Reg {
|
||||
v = pstatefield[i].enc
|
||||
break
|
||||
// PSTATEfield can be special registers and special operands.
|
||||
if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SPSel {
|
||||
v = 0<<16 | 4<<12 | 5<<5
|
||||
} else if p.To.Type == obj.TYPE_SPECIAL {
|
||||
opd := SpecialOperand(p.To.Offset)
|
||||
for _, pf := range pstatefield {
|
||||
if pf.opd == opd {
|
||||
v = pf.enc
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -4220,11 +4225,11 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
||||
case 57: /* floating point conditional compare */
|
||||
o1 = c.oprrr(p, p.As)
|
||||
|
||||
cond := int(p.From.Reg)
|
||||
if cond < COND_EQ || cond > COND_NV {
|
||||
cond := SpecialOperand(p.From.Offset)
|
||||
if cond < SPOP_EQ || cond > SPOP_NV {
|
||||
c.ctxt.Diag("invalid condition\n%v", p)
|
||||
} else {
|
||||
cond -= COND_EQ
|
||||
cond -= SPOP_EQ
|
||||
}
|
||||
|
||||
nzcv := int(p.To.Offset)
|
||||
@ -4976,22 +4981,16 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) {
|
||||
case 91: /* prfm imm(Rn), <prfop | $imm5> */
|
||||
imm := uint32(p.From.Offset)
|
||||
r := p.From.Reg
|
||||
v := uint32(0xff)
|
||||
var v uint32
|
||||
var ok bool
|
||||
if p.To.Type == obj.TYPE_CONST {
|
||||
v = uint32(p.To.Offset)
|
||||
if v > 31 {
|
||||
c.ctxt.Diag("illegal prefetch operation\n%v", p)
|
||||
}
|
||||
ok = v <= 31
|
||||
} else {
|
||||
for i := 0; i < len(prfopfield); i++ {
|
||||
if prfopfield[i].reg == p.To.Reg {
|
||||
v = prfopfield[i].enc
|
||||
break
|
||||
}
|
||||
}
|
||||
if v == 0xff {
|
||||
c.ctxt.Diag("illegal prefetch operation:\n%v", p)
|
||||
}
|
||||
v, ok = prfopfield[SpecialOperand(p.To.Offset)]
|
||||
}
|
||||
if !ok {
|
||||
c.ctxt.Diag("illegal prefetch operation:\n%v", p)
|
||||
}
|
||||
|
||||
o1 = c.opirr(p, p.As)
|
||||
|
@ -59,6 +59,7 @@ func init() {
|
||||
obj.RegisterOpcode(obj.ABaseARM64, Anames)
|
||||
obj.RegisterRegisterList(obj.RegListARM64Lo, obj.RegListARM64Hi, rlconv)
|
||||
obj.RegisterOpSuffix("arm64", obj.CConvARM)
|
||||
obj.RegisterSpecialOperands(int64(SPOP_BEGIN), int64(SPOP_END), SPCconv)
|
||||
}
|
||||
|
||||
func arrange(a int) string {
|
||||
@ -108,50 +109,8 @@ func rconv(r int) string {
|
||||
return fmt.Sprintf("F%d", r-REG_F0)
|
||||
case REG_V0 <= r && r <= REG_V31:
|
||||
return fmt.Sprintf("V%d", r-REG_V0)
|
||||
case COND_EQ <= r && r <= COND_NV:
|
||||
return strcond[r-COND_EQ]
|
||||
case r == REGSP:
|
||||
return "RSP"
|
||||
case r == REG_DAIFSet:
|
||||
return "DAIFSet"
|
||||
case r == REG_DAIFClr:
|
||||
return "DAIFClr"
|
||||
case r == REG_PLDL1KEEP:
|
||||
return "PLDL1KEEP"
|
||||
case r == REG_PLDL1STRM:
|
||||
return "PLDL1STRM"
|
||||
case r == REG_PLDL2KEEP:
|
||||
return "PLDL2KEEP"
|
||||
case r == REG_PLDL2STRM:
|
||||
return "PLDL2STRM"
|
||||
case r == REG_PLDL3KEEP:
|
||||
return "PLDL3KEEP"
|
||||
case r == REG_PLDL3STRM:
|
||||
return "PLDL3STRM"
|
||||
case r == REG_PLIL1KEEP:
|
||||
return "PLIL1KEEP"
|
||||
case r == REG_PLIL1STRM:
|
||||
return "PLIL1STRM"
|
||||
case r == REG_PLIL2KEEP:
|
||||
return "PLIL2KEEP"
|
||||
case r == REG_PLIL2STRM:
|
||||
return "PLIL2STRM"
|
||||
case r == REG_PLIL3KEEP:
|
||||
return "PLIL3KEEP"
|
||||
case r == REG_PLIL3STRM:
|
||||
return "PLIL3STRM"
|
||||
case r == REG_PSTL1KEEP:
|
||||
return "PSTL1KEEP"
|
||||
case r == REG_PSTL1STRM:
|
||||
return "PSTL1STRM"
|
||||
case r == REG_PSTL2KEEP:
|
||||
return "PSTL2KEEP"
|
||||
case r == REG_PSTL2STRM:
|
||||
return "PSTL2STRM"
|
||||
case r == REG_PSTL3KEEP:
|
||||
return "PSTL3KEEP"
|
||||
case r == REG_PSTL3STRM:
|
||||
return "PSTL3STRM"
|
||||
case REG_UXTB <= r && r < REG_UXTH:
|
||||
if ext != 0 {
|
||||
return fmt.Sprintf("%s.UXTB<<%d", regname(r), ext)
|
||||
@ -223,6 +182,14 @@ func DRconv(a int) string {
|
||||
return "C_??"
|
||||
}
|
||||
|
||||
func SPCconv(a int64) string {
|
||||
spc := SpecialOperand(a)
|
||||
if spc >= SPOP_BEGIN && spc < SPOP_END {
|
||||
return fmt.Sprintf("%s", spc)
|
||||
}
|
||||
return "SPC_??"
|
||||
}
|
||||
|
||||
func rlconv(list int64) string {
|
||||
str := ""
|
||||
|
||||
|
60
src/cmd/internal/obj/arm64/specialoperand_string.go
Normal file
60
src/cmd/internal/obj/arm64/specialoperand_string.go
Normal file
@ -0,0 +1,60 @@
|
||||
// Code generated by "stringer -type SpecialOperand -trimprefix SPOP_"; DO NOT EDIT.
|
||||
|
||||
package arm64
|
||||
|
||||
import "strconv"
|
||||
|
||||
func _() {
|
||||
// An "invalid array index" compiler error signifies that the constant values have changed.
|
||||
// Re-run the stringer command to generate them again.
|
||||
var x [1]struct{}
|
||||
_ = x[SPOP_PLDL1KEEP-0]
|
||||
_ = x[SPOP_BEGIN-0]
|
||||
_ = x[SPOP_PLDL1STRM-1]
|
||||
_ = x[SPOP_PLDL2KEEP-2]
|
||||
_ = x[SPOP_PLDL2STRM-3]
|
||||
_ = x[SPOP_PLDL3KEEP-4]
|
||||
_ = x[SPOP_PLDL3STRM-5]
|
||||
_ = x[SPOP_PLIL1KEEP-6]
|
||||
_ = x[SPOP_PLIL1STRM-7]
|
||||
_ = x[SPOP_PLIL2KEEP-8]
|
||||
_ = x[SPOP_PLIL2STRM-9]
|
||||
_ = x[SPOP_PLIL3KEEP-10]
|
||||
_ = x[SPOP_PLIL3STRM-11]
|
||||
_ = x[SPOP_PSTL1KEEP-12]
|
||||
_ = x[SPOP_PSTL1STRM-13]
|
||||
_ = x[SPOP_PSTL2KEEP-14]
|
||||
_ = x[SPOP_PSTL2STRM-15]
|
||||
_ = x[SPOP_PSTL3KEEP-16]
|
||||
_ = x[SPOP_PSTL3STRM-17]
|
||||
_ = x[SPOP_DAIFSet-18]
|
||||
_ = x[SPOP_DAIFClr-19]
|
||||
_ = x[SPOP_EQ-20]
|
||||
_ = x[SPOP_NE-21]
|
||||
_ = x[SPOP_HS-22]
|
||||
_ = x[SPOP_LO-23]
|
||||
_ = x[SPOP_MI-24]
|
||||
_ = x[SPOP_PL-25]
|
||||
_ = x[SPOP_VS-26]
|
||||
_ = x[SPOP_VC-27]
|
||||
_ = x[SPOP_HI-28]
|
||||
_ = x[SPOP_LS-29]
|
||||
_ = x[SPOP_GE-30]
|
||||
_ = x[SPOP_LT-31]
|
||||
_ = x[SPOP_GT-32]
|
||||
_ = x[SPOP_LE-33]
|
||||
_ = x[SPOP_AL-34]
|
||||
_ = x[SPOP_NV-35]
|
||||
_ = x[SPOP_END-36]
|
||||
}
|
||||
|
||||
const _SpecialOperand_name = "PLDL1KEEPPLDL1STRMPLDL2KEEPPLDL2STRMPLDL3KEEPPLDL3STRMPLIL1KEEPPLIL1STRMPLIL2KEEPPLIL2STRMPLIL3KEEPPLIL3STRMPSTL1KEEPPSTL1STRMPSTL2KEEPPSTL2STRMPSTL3KEEPPSTL3STRMDAIFSetDAIFClrEQNEHSLOMIPLVSVCHILSGELTGTLEALNVEND"
|
||||
|
||||
var _SpecialOperand_index = [...]uint8{0, 9, 18, 27, 36, 45, 54, 63, 72, 81, 90, 99, 108, 117, 126, 135, 144, 153, 162, 169, 176, 178, 180, 182, 184, 186, 188, 190, 192, 194, 196, 198, 200, 202, 204, 206, 208, 211}
|
||||
|
||||
func (i SpecialOperand) String() string {
|
||||
if i < 0 || i >= SpecialOperand(len(_SpecialOperand_index)-1) {
|
||||
return "SpecialOperand(" + strconv.FormatInt(int64(i), 10) + ")"
|
||||
}
|
||||
return _SpecialOperand_name[_SpecialOperand_index[i]:_SpecialOperand_index[i+1]]
|
||||
}
|
@ -94,6 +94,12 @@ import (
|
||||
// type = TYPE_SCONST
|
||||
// val = string
|
||||
//
|
||||
// <symbolic constant name>
|
||||
// Special symbolic constants for ARM64, such as conditional flags, tlbi_op and so on.
|
||||
// Encoding:
|
||||
// type = TYPE_SPECIAL
|
||||
// offset = The constant value corresponding to this symbol
|
||||
//
|
||||
// <register name>
|
||||
// Any register: integer, floating point, control, segment, and so on.
|
||||
// If looking for specific register kind, must check type and reg value range.
|
||||
@ -236,6 +242,7 @@ const (
|
||||
TYPE_REGREG2
|
||||
TYPE_INDIR
|
||||
TYPE_REGLIST
|
||||
TYPE_SPECIAL
|
||||
)
|
||||
|
||||
func (a *Addr) Target() *Prog {
|
||||
|
@ -112,6 +112,11 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
|
||||
break
|
||||
}
|
||||
return
|
||||
case TYPE_SPECIAL:
|
||||
if a.Reg != 0 || a.Index != 0 || a.Scale != 0 || a.Name != 0 || a.Class != 0 || a.Sym != nil {
|
||||
break
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
ctxt.Diag("invalid encoding for argument %v", p)
|
||||
|
@ -363,6 +363,9 @@ func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
|
||||
|
||||
case TYPE_REGLIST:
|
||||
io.WriteString(w, RLconv(a.Offset))
|
||||
|
||||
case TYPE_SPECIAL:
|
||||
io.WriteString(w, SPCconv(a.Offset))
|
||||
}
|
||||
}
|
||||
|
||||
@ -575,6 +578,33 @@ func RLconv(list int64) string {
|
||||
return fmt.Sprintf("RL???%d", list)
|
||||
}
|
||||
|
||||
// Special operands
|
||||
type spcSet struct {
|
||||
lo int64
|
||||
hi int64
|
||||
SPCconv func(int64) string
|
||||
}
|
||||
|
||||
var spcSpace []spcSet
|
||||
|
||||
// RegisterSpecialOperands binds a pretty-printer (SPCconv) for special
|
||||
// operand numbers to a given special operand number range. Lo is inclusive,
|
||||
// hi is exclusive (valid special operands are lo through hi-1).
|
||||
func RegisterSpecialOperands(lo, hi int64, rlconv func(int64) string) {
|
||||
spcSpace = append(spcSpace, spcSet{lo, hi, rlconv})
|
||||
}
|
||||
|
||||
// SPCconv returns the string representation of the special operand spc.
|
||||
func SPCconv(spc int64) string {
|
||||
for i := range spcSpace {
|
||||
spcs := &spcSpace[i]
|
||||
if spcs.lo <= spc && spc < spcs.hi {
|
||||
return spcs.SPCconv(spc)
|
||||
}
|
||||
}
|
||||
return fmt.Sprintf("SPC???%d", spc)
|
||||
}
|
||||
|
||||
type opSet struct {
|
||||
lo As
|
||||
names []string
|
||||
|
Loading…
x
Reference in New Issue
Block a user