}
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
"cmd/internal/obj"
"cmd/internal/obj/arm64"
"errors"
+ "fmt"
)
var arm64LS = map[string]uint8{
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 {
"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"
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
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
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)
// 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
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:
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:
}
}
-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 {
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]
+}
+
+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}
+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) {
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
)
// 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:
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]
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
+)
"SHIFT",
"EXTREG",
"SPR",
+ "SPOP",
"COND",
"ARNG",
"ELEM",
{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},
{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
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:
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
}
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)
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 {
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
+ }
}
}
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)
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)
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 {
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)
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 := ""
--- /dev/null
+// 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]]
+}
// 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.
TYPE_REGREG2
TYPE_INDIR
TYPE_REGLIST
+ TYPE_SPECIAL
)
func (a *Addr) Target() *Prog {
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)
case TYPE_REGLIST:
io.WriteString(w, RLconv(a.Offset))
+
+ case TYPE_SPECIAL:
+ io.WriteString(w, SPCconv(a.Offset))
}
}
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