From: erifan01 Date: Wed, 12 Aug 2020 09:41:54 +0000 (+0800) Subject: cmd/asm: refactor some operands that are not special registers on arm64 X-Git-Tag: go1.19beta1~811 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=f5290ef947b2471db27c35321a49b4e3b756e56e;p=gostls13.git 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 Trust: Eric Fang Run-TryBot: Eric Fang TryBot-Result: Gopher Robot --- diff --git a/src/cmd/asm/internal/arch/arch.go b/src/cmd/asm/internal/arch/arch.go index 4d374cb828..403e70eee7 100644 --- a/src/cmd/asm/internal/arch/arch.go +++ b/src/cmd/asm/internal/arch/arch.go @@ -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 diff --git a/src/cmd/asm/internal/arch/arm64.go b/src/cmd/asm/internal/arch/arm64.go index 24689c5ab1..591c4d35db 100644 --- a/src/cmd/asm/internal/arch/arm64.go +++ b/src/cmd/asm/internal/arch/arm64.go @@ -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 { diff --git a/src/cmd/asm/internal/asm/parse.go b/src/cmd/asm/internal/asm/parse.go index 4cddcf48a4..0bdf868f48 100644 --- a/src/cmd/asm/internal/asm/parse.go +++ b/src/cmd/asm/internal/asm/parse.go @@ -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 diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index 03f0c46cac..1413bdf476 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -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 diff --git a/src/cmd/compile/internal/arm64/ssa.go b/src/cmd/compile/internal/arm64/ssa.go index 96a29224bf..48eb2190b2 100644 --- a/src/cmd/compile/internal/arm64/ssa.go +++ b/src/cmd/compile/internal/arm64/ssa.go @@ -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 { diff --git a/src/cmd/internal/obj/addrtype_string.go b/src/cmd/internal/obj/addrtype_string.go index 71f0dd97a8..e6277d39b0 100644 --- a/src/cmd/internal/obj/addrtype_string.go +++ b/src/cmd/internal/obj/addrtype_string.go @@ -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) { diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index f3480e0f5e..489651bad2 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -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. C_ELEM // Vn.[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 +) diff --git a/src/cmd/internal/obj/arm64/anames7.go b/src/cmd/internal/obj/arm64/anames7.go index 2ecd8164b6..54fc939c01 100644 --- a/src/cmd/internal/obj/arm64/anames7.go +++ b/src/cmd/internal/obj/arm64/anames7.go @@ -15,6 +15,7 @@ var cnames7 = []string{ "SHIFT", "EXTREG", "SPR", + "SPOP", "COND", "ARNG", "ELEM", diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index bf33da50c1..6081b52c8a 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -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), */ 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) diff --git a/src/cmd/internal/obj/arm64/list7.go b/src/cmd/internal/obj/arm64/list7.go index e63a4815f9..0187ad3341 100644 --- a/src/cmd/internal/obj/arm64/list7.go +++ b/src/cmd/internal/obj/arm64/list7.go @@ -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 index 0000000000..eaaf109052 --- /dev/null +++ b/src/cmd/internal/obj/arm64/specialoperand_string.go @@ -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]] +} diff --git a/src/cmd/internal/obj/link.go b/src/cmd/internal/obj/link.go index e0a3138c38..a3eba73906 100644 --- a/src/cmd/internal/obj/link.go +++ b/src/cmd/internal/obj/link.go @@ -94,6 +94,12 @@ import ( // type = TYPE_SCONST // val = string // +// +// 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 +// // // 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 { diff --git a/src/cmd/internal/obj/pass.go b/src/cmd/internal/obj/pass.go index 01657dd4f6..b91a15da97 100644 --- a/src/cmd/internal/obj/pass.go +++ b/src/cmd/internal/obj/pass.go @@ -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) diff --git a/src/cmd/internal/obj/util.go b/src/cmd/internal/obj/util.go index 0c9dde7965..4e1a2d19b6 100644 --- a/src/cmd/internal/obj/util.go +++ b/src/cmd/internal/obj/util.go @@ -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