arm64/instgen: support register with index in SVE This CL generates CL 759780. Change-Id: I430b74f92be3e6c5dc9c0f57fc8081612f16f874 Reviewed-on: https://go-review.googlesource.com/c/arch/+/759800 Reviewed-by: David Chase <drchase@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
diff --git a/arm64/instgen/encodings.go b/arm64/instgen/encodings.go index dd932cf..fc099be 100644 --- a/arm64/instgen/encodings.go +++ b/arm64/instgen/encodings.go
@@ -692,4 +692,290 @@ `Is the number [0-31] of the source and destination SIMD&FP register, encoded in the "Vdn" field. bit range mappings: Vdn: [0:5)`: {"encodeVdn05", `return v & 31, true`, "enc_Vdn"}, + `For the "16-bit to 32-bit" variant: is the immediate index of a pair of 16-bit elements within each 128-bit vector segment, in the range 0 to 3, encoded in the "i2" field. +bit range mappings: +i2: [19:21) +`: {"encodeI2_1921_16To32Bit", `if v > 3 { + return 0, false + } + return v << 19, true`, "enc_i2"}, + `For the "16-bit to 64-bit" variant: is the immediate index of a 64-bit group of four 16-bit values within each 128-bit vector segment, in the range 0 to 1, encoded in the "i1" field. +bit range mappings: +i1: [20:21) +`: {"encodeI1_2021_16To64Bit", `if v > 1 { + return 0, false + } + return v << 20, true`, "enc_i1"}, + `For the "16-bit to 64-bit" variant: is the name of the second source scalable vector register Z0-Z15, encoded in the "Zm" field. +bit range mappings: +Zm: [16:20) +`: {"encodeZm1620_16To64Bit", `if v > 15 { + return 0, false + } + return v << 16, true`, "enc_Zm"}, + `For the "16-bit" and "32-bit" variants: is the name of the second source scalable vector register Z0-Z7, encoded in the "Zm" field. +bit range mappings: +Zm: [16:19) +`: {"encodeZm1619_16Bit32Bit", `if v > 7 { + return 0, false + } + return v << 16, true`, "enc_Zm"}, + `For the "16-bit" variant: is the element index, in the range 0 to 7, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [22:23) +i3l: [19:21) +`: {"encodeI3hI3l_1923_16Bit", `if v > 7 { + return 0, false + } + return (v&3)<<19 | (v>>2)<<22, true`, "enc_i3h_i3l"}, + `For the "32-bit" variant: is the element index, in the range 0 to 3, encoded in the "i2" field. +bit range mappings: +i2: [19:21) +`: {"encodeI2_1921_32Bit", `if v > 3 { + return 0, false + } + return v << 19, true`, "enc_i2"}, + `For the "32-bit" variant: is the element index, in the range 0 to 7, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [19:21) +i3l: [11:12) +`: {"encodeI3hI3l_1119_32Bit", `if v > 7 { + return 0, false + } + return (v&1)<<11 | (v>>1)<<19, true`, "enc_i3h_i3l"}, + `For the "32-bit" variant: is the name of the second source scalable vector register Z0-Z7, encoded in the "Zm" field. +bit range mappings: +Zm: [16:19) +`: {"encodeZm1619_32Bit", `if v > 7 { + return 0, false + } + return v << 16, true`, "enc_Zm"}, + `For the "64-bit" variant: is the element index, in the range 0 to 1, encoded in the "i1" field. +bit range mappings: +i1: [20:21) +`: {"encodeI1_2021_64Bit", `if v > 1 { + return 0, false + } + return v << 20, true`, "enc_i1"}, + `For the "64-bit" variant: is the element index, in the range 0 to 3, encoded in the "i2h:i2l" fields. +bit range mappings: +i2h: [20:21) +i2l: [11:12) +`: {"encodeI2hI2l_1120_64Bit", `if v > 3 { + return 0, false + } + return (v&1)<<11 | (v>>1)<<20, true`, "enc_i2h_i2l"}, + `For the "64-bit" variant: is the name of the second source scalable vector register Z0-Z15, encoded in the "Zm" field. +bit range mappings: +Zm: [16:20) +`: {"encodeZm1620_64Bit", `if v > 15 { + return 0, false + } + return v << 16, true`, "enc_Zm"}, + `For the "8-bit to 16-bit" variant: is the immediate index of a pair of 8-bit elements within each 128-bit vector segment, in the range 0 to 7, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [22:23) +i3l: [19:21) +`: {"encodeI3hI3l_1923_8To16Bit", `if v > 7 { + return 0, false + } + return (v&3)<<19 | (v>>2)<<22, true`, "enc_i3h_i3l"}, + `For the "8-bit to 32-bit" variant: is the immediate index of a 32-bit group of four 8-bit values within each 128-bit vector segment, in the range 0 to 3, encoded in the "i2" field. +bit range mappings: +i2: [19:21) +`: {"encodeI2_1921_8To32Bit", `if v > 3 { + return 0, false + } + return v << 19, true`, "enc_i2"}, + `For the "8-bit to 32-bit" variant: is the name of the second source scalable vector register Z0-Z7, encoded in the "Zm" field. +bit range mappings: +Zm: [16:19) +`: {"encodeZm1619_8To32Bit", `if v > 7 { + return 0, false + } + return v << 16, true`, "enc_Zm"}, + `For the "Double-precision" variant: is the immediate index, in the range 0 to 1, encoded in the "i1" field. +bit range mappings: +i1: [20:21) +`: {"encodeI1_2021_DoublePrecision", `if v > 1 { + return 0, false + } + return v << 20, true`, "enc_i1"}, + `For the "Double-precision" variant: is the name of the second source scalable vector register Z0-Z15, encoded in the "Zm" field. +bit range mappings: +Zm: [16:20) +`: {"encodeZm1620_DoublePrecision", `if v > 15 { + return 0, false + } + return v << 16, true`, "enc_Zm"}, + `For the "Doubleword" variant: is the optional portion index, in the range 0 to 7, defaulting to 0, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [22:23) +i3l: [17:19) +`: {"encodeI3hI3l_1722_Doubleword", `if v > 7 { + return 0, false + } + return (v&3)<<17 | (v>>2)<<22, true`, "enc_i3h_i3l"}, + `For the "Half-precision" and "Single-precision" variants: is the name of the second source scalable vector register Z0-Z7, encoded in the "Zm" field. +bit range mappings: +Zm: [16:19) +`: {"encodeZm1619_HalfSinglePrecision", `if v > 7 { + return 0, false + } + return v << 16, true`, "enc_Zm"}, + `For the "Half-precision" variant: is the immediate index, in the range 0 to 7, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [22:23) +i3l: [19:21) +`: {"encodeI3hI3l_1923_HalfPrecision", `if v > 7 { + return 0, false + } + return (v&3)<<19 | (v>>2)<<22, true`, "enc_i3h_i3l"}, + `For the "Halfword" variant: is the optional portion index, in the range 0 to 1, defaulting to 0, encoded in the "i1" field. +bit range mappings: +i1: [17:18) +`: {"encodeI1_1718_Halfword", `if v > 1 { + return 0, false + } + return v << 17, true`, "enc_i1"}, + `For the "Single-precision" variant: is the immediate index, in the range 0 to 3, encoded in the "i2" field. +bit range mappings: +i2: [19:21) +`: {"encodeI2_1921_SinglePrecision", `if v > 3 { + return 0, false + } + return v << 19, true`, "enc_i2"}, + `For the "Word" variant: is the optional portion index, in the range 0 to 3, defaulting to 0, encoded in the "i2" field. +bit range mappings: +i2: [17:19) +`: {"encodeI2_1719_Word", `if v > 3 { + return 0, false + } + return v << 17, true`, "enc_i2"}, + `Is the immediate index of a 32-bit group of four 8-bit values within each 128-bit vector segment, in the range 0 to 3, encoded in the "i2" field. +bit range mappings: +i2: [19:21) +`: {"encodeI2_1921_8BitGroup", `if v > 3 { + return 0, false + } + return v << 19, true`, "enc_i2"}, + `Is the immediate index of a pair of 16-bit elements within each 128-bit vector segment, in the range 0 to 3, encoded in the "i2" field. +bit range mappings: +i2: [19:21) +`: {"encodeI2_1921_Pair16Bit", `if v > 3 { + return 0, false + } + return v << 19, true`, "enc_i2"}, + `Is the immediate index of a pair of 8-bit elements within each 128-bit vector segment, in the range 0 to 7, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [19:21) +i3l: [11:12) +`: {"encodeI3hI3l_1119_Pair8Bit", `if v > 7 { + return 0, false + } + return (v&1)<<11 | (v>>1)<<19, true`, "enc_i3h_i3l"}, + `Is the immediate index, in the range 0 to 15, encoded in the "i4h:i4l" fields. +bit range mappings: +i4h: [19:21) +i4l: [10:12) +`: {"encodeI4hI4l_1019", `if v > 15 { + return 0, false + } + return (v&3)<<10 | (v>>2)<<19, true`, "enc_i4h_i4l"}, + `Is the immediate index, in the range 0 to 7, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [19:21) +i3l: [11:12) +`: {"encodeI3hI3l_1119", `if v > 7 { + return 0, false + } + return (v&1)<<11 | (v>>1)<<19, true`, "enc_i3h_i3l"}, + `Is the immediate index, in the range 0 to 7, encoded in the "i3h:i3l" fields. +bit range mappings: +i3h: [22:23) +i3l: [19:21) +`: {"encodeI3hI3l_1922", `if v > 7 { + return 0, false + } + return (v&3)<<19 | (v>>2)<<22, true`, "enc_i3h_i3l"}, + `Is the immediate index, in the range 0 to one less than the number of elements in 128 bits, encoded in "i1:tsz". +bit range mappings: +i1: [20:21) +tsz: [16:20) +`: {"encodeI1Tsz_Delegate", `// The statement "range 0 to one less than the number of elements in 128 bits" + // is not possible to handle here, we delegate this to the caller. + return codeI1Tsz, false`, "enc_i1_tsz"}, + `Is the immediate index, in the range 0 to one less than the number of elements in 512 bits, encoded in "imm2:tsz". +bit range mappings: +imm2: [22:24) +tsz: [16:21) +`: {"encodeImm2Tsz_Delegate", `// The statement "range 0 to one less than the number of elements in 512 bits" + // is not possible to handle here, we delegate this to the caller. + return codeImm2Tsz, false`, "enc_imm2_tsz"}, + `Is the name of the first source scalable predicate register PN8-PN15, with predicate-as-counter encoding, encoded in the "PNn" field. +bit range mappings: +PNn: [5:8) +`: {"encodePnN_58", `if v >= 24 && v <= 31 { + // PN registers starts from 16. + return (v - 24) << 5, true + } + return 0, false`, "enc_PNn"}, + `Is the name of the second source scalable vector register Z0-Z7, encoded in the "Zm" field. +bit range mappings: +Zm: [16:19) +`: {"encodeZm_1619_Range0_7", `if v <= 7 { + return v << 16, true + } + return 0, false`, "enc_Zm"}, + `Is the portion index, in the range 0 to 3, encoded in the "imm2" field. +bit range mappings: +imm2: [8:10) +`: {"encodeImm2_810", `if v > 3 { + return 0, false + } + return v << 8, true`, "enc_imm2"}, + `Is the size specifier, +tsz <T> +0000 RESERVED +xxx1 B +xx10 H +x100 S +1000 D +bit range mappings: +tsz: [16:20) +`: {"encodeTsz_1620_SizeSpecifier4", `switch v { + case ARNG_B: + return 1 << 16, true + case ARNG_H: + return 2 << 16, true + case ARNG_S: + return 4 << 16, true + case ARNG_D: + return 8 << 16, true + } + return 0, false`, "enc_tsz"}, + + `Is the size specifier, +tsz <T> +00000 RESERVED +xxxx1 B +xxx10 H +xx100 S +x1000 D +10000 Q +bit range mappings: +tsz: [16:21) +`: {"encodeTsz_1621_SizeSpecifier5", `switch v { + case ARNG_B: + return 1 << 16, true + case ARNG_H: + return 2 << 16, true + case ARNG_S: + return 4 << 16, true + case ARNG_D: + return 8 << 16, true + case ARNG_Q: + return 16 << 16, true + } + return 0, false`, "enc_tsz"}, }
diff --git a/arm64/instgen/generator.go b/arm64/instgen/generator.go index 9f615b4..f9511e4 100644 --- a/arm64/instgen/generator.go +++ b/arm64/instgen/generator.go
@@ -202,6 +202,9 @@ "AC_ZREG": 0, "AC_SPZGREG": 1, "AC_VREG": 1, + "AC_ARNGIDX": 2, + "AC_ZREGIDX": 2, + "AC_PREGIDX": 2, } func readExistingGoOps(aoutPath string) map[string]bool { @@ -556,6 +559,10 @@ s = strings.Replace(s, ".", "_", -1) s = strings.Replace(s, " ", "_", -1) s = strings.Replace(s, "|", "", -1) + s = strings.Replace(s, "[", "_", -1) + s = strings.Replace(s, "]", "_", -1) + s = strings.Replace(s, "{", "", -1) + s = strings.Replace(s, "}", "", -1) return s } @@ -712,6 +719,7 @@ "Pm": "P", "Pg": "P", "PNd": "PN", + "PNn": "PN", "Pv": "P", "Vd": "V", @@ -914,6 +922,64 @@ log.Fatalf("Unexpected V with fixed arrangement: %s", opName) } } + } else if op.Typ == "AC_ARNGIDX" || op.Typ == "AC_ZREGIDX" || op.Typ == "AC_PREGIDX" { + // Operands that takes SVE/SIMD registers and arrangement with index. + // reg.T[index] + var regPrefix string + var regName string + var arrangement string + index := rng.IntN(4) + + if op.Typ == "AC_ARNGIDX" { + parts := strings.Split(opName, ".") + regName = strings.TrimSuffix(strings.TrimPrefix(parts[0], "<"), ">") + regPrefix = regMap[regName] + if regPrefix == "" { + log.Fatalf("Unknown register prefix: %s", regName) + } + + parts2 := strings.Split(parts[1], "[") + arrangement = strings.TrimSuffix(strings.TrimPrefix(parts2[0], "<"), ">") + } else if op.Typ == "AC_ZREGIDX" || op.Typ == "AC_PREGIDX" { + re := regexp.MustCompile(`<([A-Z][A-Za-z0-9]*)>`) + matches := re.FindStringSubmatch(opName) + if len(matches) > 1 { + regName = matches[1] + regPrefix = regMap[regName] + if regPrefix == "" { + log.Fatalf("Unknown register: %s", regName) + } + } else { + log.Fatalf("Unknown AC_[PZ]REGIDX: %s", opName) + } + } + + var goAsmOp, gnuAsmOp string + limit := 32 + if regPrefix == "P" || regPrefix == "PN" { + limit = 16 + } + regIdx := cachedOrNew(regCache, regName, limit) + if regPrefix == "V" { + log.Fatalf("Unexpected V with index: %s", opName) + } + + if arrangement != "" { + if arrMap[arrangement] { + arrIdx := cachedOrNew(arrCache, arrangement, len(sveArr)) + goAsmOp = fmt.Sprintf("%s%d.%s[%d]", regPrefix, regIdx, sveArr[arrIdx], index) + gnuAsmOp = goAsmOp + } else { + // Fixed arrangement + goAsmOp = fmt.Sprintf("%s%d.%s[%d]", regPrefix, regIdx, arrangement, index) + gnuAsmOp = goAsmOp + } + } else { + goAsmOp = fmt.Sprintf("%s%d[%d]", regPrefix, regIdx, index) + gnuAsmOp = goAsmOp + } + gnuAsmOps = append([]string{gnuAsmOp}, gnuAsmOps...) + goAsmOps = append(goAsmOps, goAsmOp) } else if op.Typ == "AC_SPZGREG" || op.Typ == "AC_VREG" { // Operands that takes scalar or NEON vector registers. // There arn't that much of shapes, just enumerate them... @@ -1043,7 +1109,9 @@ enc.Asm == "SUBP <Zdn>.<T>, <Pg>/M, <Zdn>.<T>, <Zm>.<T>" || enc.Asm == "UABAL <Zda>.<T>, <Zn>.<Tb>, <Zm>.<Tb>" || enc.Asm == "UCVTF <Zd>.<T>, <Zn>.<Tb>" || - enc.Asm == "UDOT <Zda>.H, <Zn>.B, <Zm>.B" { + enc.Asm == "UDOT <Zda>.H, <Zn>.B, <Zm>.B" || + enc.Asm == "SDOT <Zda>.H, <Zn>.B, <Zm>.B[<imm>]" || + enc.Asm == "UDOT <Zda>.H, <Zn>.B, <Zm>.B[<imm>]" { // Very new instruction encodings // GNU toolchain 2.45 doesn't know about these specific encodings yet. todoCase := e2eData{GoOp: enc.GoOp[1:], Asm: fmt.Sprintf("// TODO: %s", enc.Asm), highFeat: highFeat}
diff --git a/arm64/instgen/xmlspec/parser.go b/arm64/instgen/xmlspec/parser.go index b8b73ff..fc61da7 100644 --- a/arm64/instgen/xmlspec/parser.go +++ b/arm64/instgen/xmlspec/parser.go
@@ -80,10 +80,10 @@ } var operandRules = []operandRule{ - // AC_SPZGREG: Standard scalar registers (W, X, R). - {regexp.MustCompile(`^(<[WX][a-z]+>!?|<R><[a-z]+>|X[0-9]+|{<[WX][a-z]+>})$`), "AC_SPZGREG"}, - // AC_SPZGREG: Scalar registers or stack pointer (SP). - {regexp.MustCompile(`^<([WX][a-z]{1}|R><n)\|[W]?SP>$`), "AC_SPZGREG"}, + // AC_ARNG: Registers with arrangement (e.g. .B, .D, .S) or type variable (<T>). + {regexp.MustCompile(`^<[PVZ][a-zA-Z]+>\.([1-9]*[BDHQS]|<T[a-z]*>)$`), "AC_ARNG"}, + // AC_ZREG: Scalable vector registers (Z). + {regexp.MustCompile(`^<Z[a-z]+>$`), "AC_ZREG"}, // AC_PREG: Predicate registers (P). {regexp.MustCompile(`^<P[a-z]{1}>$`), "AC_PREG"}, // AC_PREG: Predicate-as-counter registers (PN). @@ -92,15 +92,19 @@ {regexp.MustCompile(`^<P[N]?[a-z]{1}>\/M$`), "AC_PREGZM"}, // AC_PREGZM: Predicate registers with zeroing predication (/Z). {regexp.MustCompile(`^<P[N]?[a-z]{1}>\/(Z|<ZM>)$`), "AC_PREGZM"}, - // AC_REGIDX: Registers with immediate index. - {regexp.MustCompile(`^(<[PZ][N]?[a-z]{1}>|ZT0)\[<[a-z]+>\]$`), "AC_REGIDX"}, - // AC_ZREG: Scalable vector registers (Z). - {regexp.MustCompile(`^<Z[a-z]+>$`), "AC_ZREG"}, - // AC_ARNG: Registers with arrangement (e.g. .B, .D, .S) or type variable (<T>). - {regexp.MustCompile(`^<[PVZ][a-zA-Z]+>\.([1-9]*[BDHQS]|<T[a-z]*>)$`), "AC_ARNG"}, + // AC_SPZGREG: Standard scalar registers (W, X, R). + {regexp.MustCompile(`^(<[WX][a-z]+>!?|<R><[a-z]+>|X[0-9]+|{<[WX][a-z]+>})$`), "AC_SPZGREG"}, + // AC_SPZGREG: Scalar registers or stack pointer (SP). + {regexp.MustCompile(`^<([WX][a-z]{1}|R><n)\|[W]?SP>$`), "AC_SPZGREG"}, + // AC_VREG: V registers (SIMD). + {regexp.MustCompile(`(^<Dd>|^<V>.*)$`), "AC_VREG"}, // AC_ARNGIDX: Register arrangement with index. {regexp.MustCompile(`^<[VZ][a-zA-Z]*>\.([1-9]*[BDHQS]|<T[a-z]*>)\[(<(index|imm)[1-9]*>|[0-9]+)\]$`), "AC_ARNGIDX"}, {regexp.MustCompile(`^{[\s]+<[PVZ][a-z]+[1-4]*>\.[BDHQS],*[\s]*}\[<index>\]$`), "AC_ARNGIDX"}, + // AC_PREGIDX: P Registers with immediate index. + {regexp.MustCompile(`^(<P[N]?[a-z]{1}>)\[<[a-z]+>\]$`), "AC_PREGIDX"}, + // AC_ZREGIDX: Z Registers with (optional) immediate index. + {regexp.MustCompile(`^(<Z[a-z]{1}>)\{?\[<[a-z]+>\]\}?$`), "AC_ZREGIDX"}, // AC_REGLIST1: List of 1 register with arrangement. {regexp.MustCompile(`^{[\s]+<[PVZ][a-z]+>\.([1-9]*[BDHQS]|<T[a-z]*>)[\s]+}$`), "AC_REGLIST1"}, // AC_REGLIST2: List of 2 registers with arrangement. @@ -131,16 +135,12 @@ {regexp.MustCompile(`^<[WX][dn]+>(\{\s*,\s*<pattern>(\{\s*,\s*MUL\s+#<imm>\s*\})?\s*\})?$`), "AC_REG_PATTERN"}, // AC_ZREG_PATTERN: Z register with rotate/replication pattern. {regexp.MustCompile(`^<Z[dn]+>\.(<T>|[BDHQS])(\{\s*,\s*<pattern>(\{\s*,\s*MUL\s+#<imm>\s*\})?\s*\})?$`), "AC_ZREG_PATTERN"}, - // AC_PREGIDX: Predicate register with index. - {regexp.MustCompile(`^<P[nm]>\.<T>\[\s*<Wv>\s*,\s*<imm>\s*\]$`), "AC_PREGIDX"}, + // AC_PREGSEL: Predicate register with selector register and immediate index. + {regexp.MustCompile(`^<P[nm]>\.<T>\[\s*<Wv>\s*,\s*<imm>\s*\]$`), "AC_PREGSEL"}, // AC_PREG_PATTERN: Predicate register with pattern. {regexp.MustCompile(`^<P[dn]>\.<T>(\{\s*,\s*<pattern>\s*\})?$`), "AC_PREG_PATTERN"}, - // AC_ZREGIDX: Z register with optional index. - {regexp.MustCompile(`^<Z[dn]>(\{\s*\[<imm>\]\s*\})?$`), "AC_ZREGIDX"}, // AC_IMM: Immediate value. {regexp.MustCompile(`(^#.*)|(<const>)$`), "AC_IMM"}, - // AC_VREG: V registers (SIMD). - {regexp.MustCompile(`(^<Dd>|^<V>.*)$`), "AC_VREG"}, } // warmUpCache initializes the XML decoding cache for the Instruction type. @@ -1014,7 +1014,7 @@ // <reg>.<T>[<index>] "AC_ARNGIDX": 3, "AC_ZREGIDX": 3, - "AC_REGIDX": 3, + "AC_PREGIDX": 3, // #<imm>, <shift> "AC_IMM": 2, // [<reg1>.<T1>, <reg2>.<T2>, <mod> <amount>] @@ -1026,7 +1026,7 @@ "AC_MEMOFFMULVL": 3, // <preg>.<T>[<selreg>, <imm>] // selreg must be a W reg, so one additional encoding func to check. - "AC_PREGIDX": 5, + "AC_PREGSEL": 5, // <width><reg> "AC_SPZGREG": 2, "AC_VREG": 2,