]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/asm: refactor some operands that are not special registers on arm64
authorerifan01 <eric.fang@arm.com>
Wed, 12 Aug 2020 09:41:54 +0000 (17:41 +0800)
committerEric Fang <eric.fang@arm.com>
Fri, 1 Apr 2022 03:16:26 +0000 (03:16 +0000)
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>

14 files changed:
src/cmd/asm/internal/arch/arch.go
src/cmd/asm/internal/arch/arm64.go
src/cmd/asm/internal/asm/parse.go
src/cmd/asm/internal/asm/testdata/arm64.s
src/cmd/compile/internal/arm64/ssa.go
src/cmd/internal/obj/addrtype_string.go
src/cmd/internal/obj/arm64/a.out.go
src/cmd/internal/obj/arm64/anames7.go
src/cmd/internal/obj/arm64/asm7.go
src/cmd/internal/obj/arm64/list7.go
src/cmd/internal/obj/arm64/specialoperand_string.go [new file with mode: 0644]
src/cmd/internal/obj/link.go
src/cmd/internal/obj/pass.go
src/cmd/internal/obj/util.go

index 4d374cb828eadb595727a5f4e2552570a7f39d70..403e70eee79b98ff2247ba97bc48ec2424234cb2 100644 (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
index 24689c5ab17657816a67e7fe0b69a498e40d4c99..591c4d35db322915bdd2cbfbe5a2a82a068c2943 100644 (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 {
index 4cddcf48a466eebf1a09b8e93eb9183dd7d4bb8e..0bdf868f4857422c3b38f35f8b57cd2f4026c7c8 100644 (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
index 03f0c46cacd5c44bdf2af14c646f55f3f67463e3..1413bdf4760b706767584820458a5377f96c45c8 100644 (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
index 96a29224bf71d50b0201457ae965f54a55381eb6..48eb2190b2572141691cbd274c789b02f62697cd 100644 (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 {
index 71f0dd97a824845d3e2030821ea6476f9b05d1b7..e6277d39b012425ca223d685ef612a1e0728a4a0 100644 (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]
+}
+
+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) {
index f3480e0f5e18b88694b8b943768ed9083f848974..489651bad2df7731cde572bb763be416f3786441 100644 (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
+)
index 2ecd8164b6b2cc7e4b9886f35052fc4470297b57..54fc939c011f15dfc313a9013959e7de14554515 100644 (file)
@@ -15,6 +15,7 @@ var cnames7 = []string{
        "SHIFT",
        "EXTREG",
        "SPR",
+       "SPOP",
        "COND",
        "ARNG",
        "ELEM",
index bf33da50c1043ceda3e5c08397b552cce44d3bcd..6081b52c8ad5ac2e42165441439d37ddad838be1 100644 (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)
index e63a4815f98ebee91f2a03516958c38bee616886..0187ad334130a0baaf943b2d9a12e873e61fe49a 100644 (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 := ""
 
diff --git a/src/cmd/internal/obj/arm64/specialoperand_string.go b/src/cmd/internal/obj/arm64/specialoperand_string.go
new file mode 100644 (file)
index 0000000..eaaf109
--- /dev/null
@@ -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]]
+}
index e0a3138c38cee2bda99fea8d80a6a70e00d8e18f..a3eba73906f61bb4cb501354b2734c01f9f310f2 100644 (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 {
index 01657dd4f6fa0689fd2d3a042247df27d8a0a247..b91a15da97c7453dbb70e95d1a5b0d4ea206ab1c 100644 (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)
index 0c9dde7965797c7e39fd4a4095c3edb8a0b597de..4e1a2d19b676a5090a6688b9c2aa210a19ed3d89 100644 (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