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:
erifan01 2020-08-12 17:41:54 +08:00 committed by Eric Fang
parent bb2b16d15e
commit f5290ef947
14 changed files with 330 additions and 219 deletions

View file

@ -278,46 +278,7 @@ func archArm64() *Arch {
} }
register["LR"] = arm64.REGLINK 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. // Pseudo-registers.
register["SB"] = RSB register["SB"] = RSB
register["FP"] = RFP register["FP"] = RFP

View file

@ -12,6 +12,7 @@ import (
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/obj/arm64" "cmd/internal/obj/arm64"
"errors" "errors"
"fmt"
) )
var arm64LS = map[string]uint8{ var arm64LS = map[string]uint8{
@ -52,7 +53,35 @@ func jumpArm64(word string) bool {
return arm64Jump[word] 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. // one of the comparison instructions that require special handling.
func IsARM64CMP(op obj.As) bool { func IsARM64CMP(op obj.As) bool {
switch op { switch op {

View file

@ -19,6 +19,7 @@ import (
"cmd/asm/internal/flags" "cmd/asm/internal/flags"
"cmd/asm/internal/lex" "cmd/asm/internal/lex"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/obj/arm64"
"cmd/internal/obj/x86" "cmd/internal/obj/x86"
"cmd/internal/src" "cmd/internal/src"
"cmd/internal/sys" "cmd/internal/sys"
@ -389,8 +390,19 @@ func (p *Parser) operand(a *obj.Addr) {
tok := p.next() tok := p.next()
name := tok.String() name := tok.String()
if tok.ScanToken == scanner.Ident && !p.atStartOfRegister(name) { if tok.ScanToken == scanner.Ident && !p.atStartOfRegister(name) {
// We have a symbol. Parse $sym±offset(symkind) switch p.arch.Family {
p.symbolReference(a, name, prefix) 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)) // fmt.Printf("SYM %s\n", obj.Dconv(&emptyProg, 0, a))
if p.peek() == scanner.EOF { if p.peek() == scanner.EOF {
return return

View file

@ -628,7 +628,8 @@ again:
CSELW LT, R2, R3, R4 // 44b0831a CSELW LT, R2, R3, R4 // 44b0831a
CSINC GT, R1, ZR, R3 // 23c49f9a CSINC GT, R1, ZR, R3 // 23c49f9a
CSNEG MI, R1, R2, R3 // 234482da 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 CSINVW MI, R2, ZR, R2 // 42409f5a
CINC EQ, R4, R9 // 8914849a CINC EQ, R4, R9 // 8914849a
CINCW PL, R2, ZR // 5f44821a CINCW PL, R2, ZR // 5f44821a

View file

@ -728,8 +728,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
p4.To.Type = obj.TYPE_BRANCH p4.To.Type = obj.TYPE_BRANCH
p4.To.SetTarget(p) p4.To.SetTarget(p)
p5 := s.Prog(arm64.ACSET) p5 := s.Prog(arm64.ACSET)
p5.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg p5.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
p5.From.Reg = arm64.COND_EQ p5.From.Offset = int64(arm64.SPOP_EQ)
p5.To.Type = obj.TYPE_REG p5.To.Type = obj.TYPE_REG
p5.To.Reg = out p5.To.Reg = out
p2.To.SetTarget(p5) p2.To.SetTarget(p5)
@ -778,8 +778,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
// CSET EQ, Rout // CSET EQ, Rout
p3 := s.Prog(arm64.ACSET) p3 := s.Prog(arm64.ACSET)
p3.From.Type = obj.TYPE_REG p3.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
p3.From.Reg = arm64.COND_EQ p3.From.Offset = int64(arm64.SPOP_EQ)
p3.To.Type = obj.TYPE_REG p3.To.Type = obj.TYPE_REG
p3.To.Reg = out p3.To.Reg = out
@ -978,24 +978,27 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
r1 = v.Args[1].Reg() r1 = v.Args[1].Reg()
} }
p := s.Prog(v.Op.Asm()) p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
p.From.Reg = condBits[ssa.Op(v.AuxInt)] condCode := condBits[ssa.Op(v.AuxInt)]
p.From.Offset = int64(condCode)
p.Reg = v.Args[0].Reg() p.Reg = v.Args[0].Reg()
p.SetFrom3Reg(r1) p.SetFrom3Reg(r1)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpARM64CSINC, ssa.OpARM64CSINV, ssa.OpARM64CSNEG: case ssa.OpARM64CSINC, ssa.OpARM64CSINV, ssa.OpARM64CSNEG:
p := s.Prog(v.Op.Asm()) p := s.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
p.From.Reg = condBits[ssa.Op(v.AuxInt)] condCode := condBits[ssa.Op(v.AuxInt)]
p.From.Offset = int64(condCode)
p.Reg = v.Args[0].Reg() p.Reg = v.Args[0].Reg()
p.SetFrom3Reg(v.Args[1].Reg()) p.SetFrom3Reg(v.Args[1].Reg())
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpARM64CSETM: case ssa.OpARM64CSETM:
p := s.Prog(arm64.ACSETM) p := s.Prog(arm64.ACSETM)
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
p.From.Reg = condBits[ssa.Op(v.AuxInt)] condCode := condBits[ssa.Op(v.AuxInt)]
p.From.Offset = int64(condCode)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpARM64DUFFZERO: case ssa.OpARM64DUFFZERO:
@ -1107,8 +1110,9 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
ssa.OpARM64NotGreaterEqualF: ssa.OpARM64NotGreaterEqualF:
// generate boolean values using CSET // generate boolean values using CSET
p := s.Prog(arm64.ACSET) p := s.Prog(arm64.ACSET)
p.From.Type = obj.TYPE_REG // assembler encodes conditional bits in Reg p.From.Type = obj.TYPE_SPECIAL // assembler encodes conditional bits in Offset
p.From.Reg = condBits[v.Op] condCode := condBits[v.Op]
p.From.Offset = int64(condCode)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpARM64PRFM: case ssa.OpARM64PRFM:
@ -1173,27 +1177,27 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
} }
} }
var condBits = map[ssa.Op]int16{ var condBits = map[ssa.Op]arm64.SpecialOperand{
ssa.OpARM64Equal: arm64.COND_EQ, ssa.OpARM64Equal: arm64.SPOP_EQ,
ssa.OpARM64NotEqual: arm64.COND_NE, ssa.OpARM64NotEqual: arm64.SPOP_NE,
ssa.OpARM64LessThan: arm64.COND_LT, ssa.OpARM64LessThan: arm64.SPOP_LT,
ssa.OpARM64LessThanU: arm64.COND_LO, ssa.OpARM64LessThanU: arm64.SPOP_LO,
ssa.OpARM64LessEqual: arm64.COND_LE, ssa.OpARM64LessEqual: arm64.SPOP_LE,
ssa.OpARM64LessEqualU: arm64.COND_LS, ssa.OpARM64LessEqualU: arm64.SPOP_LS,
ssa.OpARM64GreaterThan: arm64.COND_GT, ssa.OpARM64GreaterThan: arm64.SPOP_GT,
ssa.OpARM64GreaterThanU: arm64.COND_HI, ssa.OpARM64GreaterThanU: arm64.SPOP_HI,
ssa.OpARM64GreaterEqual: arm64.COND_GE, ssa.OpARM64GreaterEqual: arm64.SPOP_GE,
ssa.OpARM64GreaterEqualU: arm64.COND_HS, ssa.OpARM64GreaterEqualU: arm64.SPOP_HS,
ssa.OpARM64LessThanF: arm64.COND_MI, // Less than ssa.OpARM64LessThanF: arm64.SPOP_MI, // Less than
ssa.OpARM64LessEqualF: arm64.COND_LS, // Less than or equal to ssa.OpARM64LessEqualF: arm64.SPOP_LS, // Less than or equal to
ssa.OpARM64GreaterThanF: arm64.COND_GT, // Greater than ssa.OpARM64GreaterThanF: arm64.SPOP_GT, // Greater than
ssa.OpARM64GreaterEqualF: arm64.COND_GE, // Greater than or equal to ssa.OpARM64GreaterEqualF: arm64.SPOP_GE, // Greater than or equal to
// The following condition codes have unordered to handle comparisons related to NaN. // The following condition codes have unordered to handle comparisons related to NaN.
ssa.OpARM64NotLessThanF: arm64.COND_PL, // Greater than, equal to, or unordered ssa.OpARM64NotLessThanF: arm64.SPOP_PL, // Greater than, equal to, or unordered
ssa.OpARM64NotLessEqualF: arm64.COND_HI, // Greater than or unordered ssa.OpARM64NotLessEqualF: arm64.SPOP_HI, // Greater than or unordered
ssa.OpARM64NotGreaterThanF: arm64.COND_LE, // Less than, equal to or unordered ssa.OpARM64NotGreaterThanF: arm64.SPOP_LE, // Less than, equal to or unordered
ssa.OpARM64NotGreaterEqualF: arm64.COND_LT, // Less than or unordered ssa.OpARM64NotGreaterEqualF: arm64.SPOP_LT, // Less than or unordered
} }
var blockJump = map[ssa.BlockKind]struct { var blockJump = map[ssa.BlockKind]struct {

View file

@ -4,9 +4,30 @@ package obj
import "strconv" 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 { func (i AddrType) String() string {
if i >= AddrType(len(_AddrType_index)-1) { if i >= AddrType(len(_AddrType_index)-1) {

View file

@ -143,26 +143,6 @@ const (
REG_V30 REG_V30
REG_V31 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 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. // a special register and the low bits select the register.
// SYSREG_END is the last item in the automatically generated system register // SYSREG_END is the last item in the automatically generated system register
// declaration, and it is defined in the sysRegEnc.go file. // 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 ( const (
REG_SPECIAL = obj.RBaseARM64 + 1<<12 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: // Register assignments:
@ -388,7 +350,8 @@ const (
C_SHIFT // Rn<<2 C_SHIFT // Rn<<2
C_EXTREG // Rn.UXTB[<<3] C_EXTREG // Rn.UXTB[<<3]
C_SPR // REG_NZCV 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_ARNG // Vn.<T>
C_ELEM // Vn.<T>[index] C_ELEM // Vn.<T>[index]
C_LIST // [V1, V2, V3] C_LIST // [V1, V2, V3]
@ -1085,3 +1048,54 @@ const (
ARNG_S ARNG_S
ARNG_D 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
)

View file

@ -15,6 +15,7 @@ var cnames7 = []string{
"SHIFT", "SHIFT",
"EXTREG", "EXTREG",
"SPR", "SPR",
"SPOP",
"COND", "COND",
"ARNG", "ARNG",
"ELEM", "ELEM",

View file

@ -838,7 +838,8 @@ var optab = []Optab{
{AMSR, C_REG, C_NONE, C_NONE, C_SPR, 36, 4, 0, 0, 0}, {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}, {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}, {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}, {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}, {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}, {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}, {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 { var pstatefield = []struct {
reg int16 opd SpecialOperand
enc uint32 enc uint32
}{ }{
{REG_SPSel, 0<<16 | 4<<12 | 5<<5}, {SPOP_DAIFSet, 3<<16 | 4<<12 | 6<<5},
{REG_DAIFSet, 3<<16 | 4<<12 | 6<<5}, {SPOP_DAIFClr, 3<<16 | 4<<12 | 7<<5},
{REG_DAIFClr, 3<<16 | 4<<12 | 7<<5},
} }
var prfopfield = []struct { var prfopfield = map[SpecialOperand]uint32{
reg int16 SPOP_PLDL1KEEP: 0,
enc uint32 SPOP_PLDL1STRM: 1,
}{ SPOP_PLDL2KEEP: 2,
{REG_PLDL1KEEP, 0}, SPOP_PLDL2STRM: 3,
{REG_PLDL1STRM, 1}, SPOP_PLDL3KEEP: 4,
{REG_PLDL2KEEP, 2}, SPOP_PLDL3STRM: 5,
{REG_PLDL2STRM, 3}, SPOP_PLIL1KEEP: 8,
{REG_PLDL3KEEP, 4}, SPOP_PLIL1STRM: 9,
{REG_PLDL3STRM, 5}, SPOP_PLIL2KEEP: 10,
{REG_PLIL1KEEP, 8}, SPOP_PLIL2STRM: 11,
{REG_PLIL1STRM, 9}, SPOP_PLIL3KEEP: 12,
{REG_PLIL2KEEP, 10}, SPOP_PLIL3STRM: 13,
{REG_PLIL2STRM, 11}, SPOP_PSTL1KEEP: 16,
{REG_PLIL3KEEP, 12}, SPOP_PSTL1STRM: 17,
{REG_PLIL3STRM, 13}, SPOP_PSTL2KEEP: 18,
{REG_PSTL1KEEP, 16}, SPOP_PSTL2STRM: 19,
{REG_PSTL1STRM, 17}, SPOP_PSTL3KEEP: 20,
{REG_PSTL2KEEP, 18}, SPOP_PSTL3STRM: 21,
{REG_PSTL2STRM, 19},
{REG_PSTL3KEEP, 20},
{REG_PSTL3STRM, 21},
} }
// Used for padinng NOOP instruction // Used for padinng NOOP instruction
@ -1676,8 +1672,6 @@ func rclass(r int16) int {
return C_FREG return C_FREG
case REG_V0 <= r && r <= REG_V31: case REG_V0 <= r && r <= REG_V31:
return C_VREG return C_VREG
case COND_EQ <= r && r <= COND_NV:
return C_COND
case r == REGSP: case r == REGSP:
return C_RSP return C_RSP
case r >= REG_ARNG && r < REG_ELEM: case r >= REG_ARNG && r < REG_ELEM:
@ -1953,8 +1947,14 @@ func (c *ctxt7) aclass(a *obj.Addr) int {
case obj.TYPE_BRANCH: case obj.TYPE_BRANCH:
return C_SBRA 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 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 */ case 18: /* csel cond,Rn,Rm,Rd; cinc/cinv/cneg cond,Rn,Rd; cset cond,Rd */
o1 = c.oprrr(p, p.As) o1 = c.oprrr(p, p.As)
cond := int(p.From.Reg) cond := SpecialOperand(p.From.Offset)
// AL and NV are not allowed for CINC/CINV/CNEG/CSET/CSETM instructions if cond < SPOP_EQ || cond > SPOP_NV || (cond == SPOP_AL || cond == SPOP_NV) && p.From3Type() == obj.TYPE_NONE {
if cond < COND_EQ || cond > COND_NV || (cond == COND_AL || cond == COND_NV) && p.From3Type() == obj.TYPE_NONE {
c.ctxt.Diag("invalid condition: %v", p) c.ctxt.Diag("invalid condition: %v", p)
} else { } else {
cond -= COND_EQ cond -= SPOP_EQ
} }
r := int(p.Reg) 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 */ case 19: /* CCMN cond, (Rm|uimm5),Rn, uimm4 -> ccmn Rn,Rm,uimm4,cond */
nzcv := int(p.To.Offset) nzcv := int(p.To.Offset)
cond := int(p.From.Reg) cond := SpecialOperand(p.From.Offset)
if cond < COND_EQ || cond > COND_NV { if cond < SPOP_EQ || cond > SPOP_NV {
c.ctxt.Diag("invalid condition\n%v", p) c.ctxt.Diag("invalid condition\n%v", p)
} else { } else {
cond -= COND_EQ cond -= SPOP_EQ
} }
var rf int var rf int
if p.GetFrom3().Type == obj.TYPE_REG { 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 = c.opirr(p, AMSR)
o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */ o1 |= uint32((p.From.Offset & 0xF) << 8) /* Crm */
v := uint32(0) v := uint32(0)
for i := 0; i < len(pstatefield); i++ { // PSTATEfield can be special registers and special operands.
if pstatefield[i].reg == p.To.Reg { if p.To.Type == obj.TYPE_REG && p.To.Reg == REG_SPSel {
v = pstatefield[i].enc v = 0<<16 | 4<<12 | 5<<5
break } 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 */ case 57: /* floating point conditional compare */
o1 = c.oprrr(p, p.As) o1 = c.oprrr(p, p.As)
cond := int(p.From.Reg) cond := SpecialOperand(p.From.Offset)
if cond < COND_EQ || cond > COND_NV { if cond < SPOP_EQ || cond > SPOP_NV {
c.ctxt.Diag("invalid condition\n%v", p) c.ctxt.Diag("invalid condition\n%v", p)
} else { } else {
cond -= COND_EQ cond -= SPOP_EQ
} }
nzcv := int(p.To.Offset) 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> */ case 91: /* prfm imm(Rn), <prfop | $imm5> */
imm := uint32(p.From.Offset) imm := uint32(p.From.Offset)
r := p.From.Reg r := p.From.Reg
v := uint32(0xff) var v uint32
var ok bool
if p.To.Type == obj.TYPE_CONST { if p.To.Type == obj.TYPE_CONST {
v = uint32(p.To.Offset) v = uint32(p.To.Offset)
if v > 31 { ok = v <= 31
c.ctxt.Diag("illegal prefetch operation\n%v", p)
}
} else { } else {
for i := 0; i < len(prfopfield); i++ { v, ok = prfopfield[SpecialOperand(p.To.Offset)]
if prfopfield[i].reg == p.To.Reg { }
v = prfopfield[i].enc if !ok {
break c.ctxt.Diag("illegal prefetch operation:\n%v", p)
}
}
if v == 0xff {
c.ctxt.Diag("illegal prefetch operation:\n%v", p)
}
} }
o1 = c.opirr(p, p.As) o1 = c.opirr(p, p.As)

View file

@ -59,6 +59,7 @@ func init() {
obj.RegisterOpcode(obj.ABaseARM64, Anames) obj.RegisterOpcode(obj.ABaseARM64, Anames)
obj.RegisterRegisterList(obj.RegListARM64Lo, obj.RegListARM64Hi, rlconv) obj.RegisterRegisterList(obj.RegListARM64Lo, obj.RegListARM64Hi, rlconv)
obj.RegisterOpSuffix("arm64", obj.CConvARM) obj.RegisterOpSuffix("arm64", obj.CConvARM)
obj.RegisterSpecialOperands(int64(SPOP_BEGIN), int64(SPOP_END), SPCconv)
} }
func arrange(a int) string { func arrange(a int) string {
@ -108,50 +109,8 @@ func rconv(r int) string {
return fmt.Sprintf("F%d", r-REG_F0) return fmt.Sprintf("F%d", r-REG_F0)
case REG_V0 <= r && r <= REG_V31: case REG_V0 <= r && r <= REG_V31:
return fmt.Sprintf("V%d", r-REG_V0) return fmt.Sprintf("V%d", r-REG_V0)
case COND_EQ <= r && r <= COND_NV:
return strcond[r-COND_EQ]
case r == REGSP: case r == REGSP:
return "RSP" 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: case REG_UXTB <= r && r < REG_UXTH:
if ext != 0 { if ext != 0 {
return fmt.Sprintf("%s.UXTB<<%d", regname(r), ext) return fmt.Sprintf("%s.UXTB<<%d", regname(r), ext)
@ -223,6 +182,14 @@ func DRconv(a int) string {
return "C_??" 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 { func rlconv(list int64) string {
str := "" str := ""

View 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]]
}

View file

@ -94,6 +94,12 @@ import (
// type = TYPE_SCONST // type = TYPE_SCONST
// val = string // 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> // <register name>
// Any register: integer, floating point, control, segment, and so on. // Any register: integer, floating point, control, segment, and so on.
// If looking for specific register kind, must check type and reg value range. // If looking for specific register kind, must check type and reg value range.
@ -236,6 +242,7 @@ const (
TYPE_REGREG2 TYPE_REGREG2
TYPE_INDIR TYPE_INDIR
TYPE_REGLIST TYPE_REGLIST
TYPE_SPECIAL
) )
func (a *Addr) Target() *Prog { func (a *Addr) Target() *Prog {

View file

@ -112,6 +112,11 @@ func checkaddr(ctxt *Link, p *Prog, a *Addr) {
break break
} }
return 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) ctxt.Diag("invalid encoding for argument %v", p)

View file

@ -363,6 +363,9 @@ func writeDconv(w io.Writer, p *Prog, a *Addr, abiDetail bool) {
case TYPE_REGLIST: case TYPE_REGLIST:
io.WriteString(w, RLconv(a.Offset)) 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) 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 { type opSet struct {
lo As lo As
names []string names []string