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] +} -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) { 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