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["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

View File

@ -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 {

View File

@ -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

View File

@ -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

View File

@ -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 {

View File

@ -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) {

View File

@ -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
)

View File

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

View File

@ -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)

View File

@ -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 := ""

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
// 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 {

View File

@ -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)

View File

@ -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