// Copyright (c) 2026 Petr BalvĂ­n (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause package arch import ( "encoding/hex" "strings" "testing" ) // The SVE encodings have no toolchain oracle: go tool asm knows no SVE at // all. The golden words below are therefore transcribed from the ARM // Architecture Reference Manual (DDI 0487J, Part C, Chapter C8, the // alphabetical list of SVE instructions) and cross-checked against two // independent implementations of the manual, the GNU assembler and LLVM: // the rows marked "GNU" match a vector in binutils-gdb's own // gas/testsuite/gas/aarch64/sve.d (assembled under -march=armv8-a+sve), the // rows marked "LLVM" match the Inst field assignments in // SVEInstrFormats.td's sve_int_bin_cons_arit_0, sve_int_bin_pred_arit_log, // sve_int_arith_imm0 and sve2_int_mul classes. Every class is covered by at // least one vector of each source. func extInstruction(t *testing.T, mnem string, form ExtForm) ExtInstr { t.Helper() for _, in := range Extensions(ARM64) { if in.Name == mnem && in.Form == form { return in } } t.Fatalf("no extended %s with the %s form", mnem, form) return ExtInstr{} } func TestArm64ExtGoldenBytes(t *testing.T) { for _, tt := range []struct { name string mnem string form ExtForm ops []ExtOperand want uint32 GNUas string // the matching binutils-gdb sve.d line, empty when the class evidence comes from LLVM alone }{ // Unpredicated three-vector forms: Zn, Zm, Zd. {"add z0.b, z0.b, z0.b", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04200000, "04200000 add z0.b, z0.b, z0.b"}, {"add z0.b, z0.b, z31.b", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(31, ExtArrB), ExtVector(0, ExtArrB)}, 0x043f0000, "043f0000 add z0.b, z0.b, z31.b"}, {"add z31.b, z0.b, z0.b", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(31, ExtArrB)}, 0x0420001f, "0420001f add z31.b, z0.b, z0.b"}, {"add z0.b, z2.b, z0.b", "ADD", ExtFormVectors, []ExtOperand{ExtVector(2, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04200040, "04200040 add z0.b, z2.b, z0.b"}, {"add z0.h, z0.h, z0.h", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrH), ExtVector(0, ExtArrH), ExtVector(0, ExtArrH)}, 0x04600000, "04600000 add z0.h, z0.h, z0.h"}, {"add z0.s, z0.s, z0.s", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrS), ExtVector(0, ExtArrS), ExtVector(0, ExtArrS)}, 0x04a00000, "04a00000 add z0.s, z0.s, z0.s"}, {"add z0.d, z0.d, z0.d", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrD), ExtVector(0, ExtArrD), ExtVector(0, ExtArrD)}, 0x04e00000, "04e00000 add z0.d, z0.d, z0.d"}, {"sub z0.b, z0.b, z0.b", "SUB", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04200400, "04200400 sub z0.b, z0.b, z0.b"}, {"sub z0.b, z0.b, z3.b", "SUB", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(3, ExtArrB), ExtVector(0, ExtArrB)}, 0x04230400, "04230400 sub z0.b, z0.b, z3.b"}, {"sqadd z0.b, z0.b, z0.b", "SQADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04201000, "04201000 sqadd z0.b, z0.b, z0.b"}, {"sqadd z0.b, z0.b, z3.b", "SQADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(3, ExtArrB), ExtVector(0, ExtArrB)}, 0x04231000, "04231000 sqadd z0.b, z0.b, z3.b"}, {"sqadd z0.d, z0.d, z0.d", "SQADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrD), ExtVector(0, ExtArrD), ExtVector(0, ExtArrD)}, 0x04e01000, "04e01000 sqadd z0.d, z0.d, z0.d"}, {"uqadd z0.b, z0.b, z0.b", "UQADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04201400, "04201400 uqadd z0.b, z0.b, z0.b"}, {"sqsub z0.b, z0.b, z0.b", "SQSUB", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04201800, "04201800 sqsub z0.b, z0.b, z0.b"}, {"sqsub z0.h, z0.h, z0.h", "SQSUB", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrH), ExtVector(0, ExtArrH), ExtVector(0, ExtArrH)}, 0x04601800, "04601800 sqsub z0.h, z0.h, z0.h"}, {"uqsub z0.b, z0.b, z0.b", "UQSUB", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04201c00, "04201c00 uqsub z0.b, z0.b, z0.b"}, {"mul z0.b, z0.b, z0.b (sve2)", "MUL", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04206000, "04206000 mul z0.b, z0.b, z0.b"}, {"mul z17.b, z21.b, z27.b (sve2)", "MUL", ExtFormVectors, []ExtOperand{ExtVector(21, ExtArrB), ExtVector(27, ExtArrB), ExtVector(17, ExtArrB)}, 0x043b62b1, "043b62b1 mul z17.b, z21.b, z27.b"}, {"mul z0.d, z0.d, z0.d (sve2)", "MUL", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrD), ExtVector(0, ExtArrD), ExtVector(0, ExtArrD)}, 0x04e06000, "04e06000 mul z0.d, z0.d, z0.d"}, {"smulh z0.b, z0.b, z0.b (sve2)", "SMULH", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04206800, "04206800 smulh z0.b, z0.b, z0.b"}, {"smulh z17.b, z21.b, z27.b (sve2)", "SMULH", ExtFormVectors, []ExtOperand{ExtVector(21, ExtArrB), ExtVector(27, ExtArrB), ExtVector(17, ExtArrB)}, 0x043b6ab1, "043b6ab1 smulh z17.b, z21.b, z27.b"}, {"umulh z0.b, z0.b, z0.b (sve2)", "UMULH", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, 0x04206c00, "04206c00 umulh z0.b, z0.b, z0.b"}, {"umulh z17.b, z21.b, z27.b (sve2)", "UMULH", ExtFormVectors, []ExtOperand{ExtVector(21, ExtArrB), ExtVector(27, ExtArrB), ExtVector(17, ExtArrB)}, 0x043b6eb1, "043b6eb1 umulh z17.b, z21.b, z27.b"}, // Governed destructive forms, merging: Zm, Pg/M, Zdn. {"add z0.b, p0/m, z0.b", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04000000, "04000000 add z0.b, p0/m, z0.b, z0.b"}, {"add z0.b, p2/m, z0.b", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(2, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04000800, "04000800 add z0.b, p2/m, z0.b, z0.b"}, {"add z0.b, p7/m, z0.b", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(7, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04001c00, "04001c00 add z0.b, p7/m, z0.b, z0.b"}, {"add z31.b, p0/m, z31.b", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(31, ExtArrB)}, 0x0400001f, "0400001f add z31.b, p0/m, z31.b, z0.b"}, {"add z0.b, p0/m, z0.b (zm 31)", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(31, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x040003e0, "040003e0 add z0.b, p0/m, z0.b, z31.b"}, {"add z0.s, p0/m, z0.s", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrS), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrS)}, 0x04800000, "04800000 add z0.s, p0/m, z0.s, z0.s"}, {"sub z0.b, p0/m, z0.b", "SUB", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04010000, "04010000 sub z0.b, p0/m, z0.b, z0.b"}, {"sub z0.b, p7/m, z0.b", "SUB", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(7, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04011c00, "04011c00 sub z0.b, p7/m, z0.b, z0.b"}, {"sub z3.b, p0/m, z3.b", "SUB", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(3, ExtArrB)}, 0x04010003, "04010003 sub z3.b, p0/m, z3.b, z0.b"}, {"subr z0.b, p0/m, z0.b", "SUBR", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04030000, "04030000 subr z0.b, p0/m, z0.b, z0.b"}, {"subr z0.h, p0/m, z0.h", "SUBR", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrH), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrH)}, 0x04430000, "04430000 subr z0.h, p0/m, z0.h, z0.h"}, {"mul z0.b, p0/m, z0.b", "MUL", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04100000, "04100000 mul z0.b, p0/m, z0.b, z0.b"}, {"mul z0.b, p2/m, z0.b", "MUL", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(2, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04100800, "04100800 mul z0.b, p2/m, z0.b, z0.b"}, {"mul z0.b, p0/m, z0.b (zm 31)", "MUL", ExtFormPredicated, []ExtOperand{ExtVector(31, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x041003e0, "041003e0 mul z0.b, p0/m, z0.b, z31.b"}, {"smulh z0.b, p0/m, z0.b", "SMULH", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04120000, "04120000 smulh z0.b, p0/m, z0.b, z0.b"}, {"smulh z0.b, p2/m, z0.b", "SMULH", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(2, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04120800, "04120800 smulh z0.b, p2/m, z0.b, z0.b"}, {"smulh z0.s, p0/m, z0.s", "SMULH", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrS), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrS)}, 0x04920000, "04920000 smulh z0.s, p0/m, z0.s, z0.s"}, {"umulh z0.b, p0/m, z0.b", "UMULH", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04130000, "04130000 umulh z0.b, p0/m, z0.b, z0.b"}, // Immediate forms: imm{, LSL #8}, Zdn. {"add z0.b, z0.b, #0", "ADD", ExtFormImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2520c000, "2520c000 add z0.b, z0.b, #0"}, {"add z0.b, z0.b, #127", "ADD", ExtFormImmediate, []ExtOperand{ExtImmediate(127), ExtVector(0, ExtArrB)}, 0x2520cfe0, "2520cfe0 add z0.b, z0.b, #127"}, {"add z0.h, z0.h, #0, lsl #8", "ADD", ExtFormImmediate, []ExtOperand{ExtShiftedImmediate(0, 8), ExtVector(0, ExtArrH)}, 0x2560e000, "2560e000 add z0.h, z0.h, #0, lsl #8"}, {"add z0.h, z0.h, #32512 (derived shift)", "ADD", ExtFormImmediate, []ExtOperand{ExtImmediate(32512), ExtVector(0, ExtArrH)}, 0x2560efe0, "2560efe0 is sqsub's GNU word for #32512; the classes share the encoding"}, {"sub z0.b, z0.b, #0", "SUB", ExtFormImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2521c000, "2521c000 sub z0.b, z0.b, #0"}, {"subr z0.b, z0.b, #0", "SUBR", ExtFormImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2523c000, "2523c000 subr z0.b, z0.b, #0"}, {"subr z0.b, z0.b, #255", "SUBR", ExtFormImmediate, []ExtOperand{ExtImmediate(255), ExtVector(0, ExtArrB)}, 0x2523dfe0, "2523dfe0 subr z0.b, z0.b, #255"}, {"subr z0.h, z0.h, #0, lsl #8", "SUBR", ExtFormImmediate, []ExtOperand{ExtShiftedImmediate(0, 8), ExtVector(0, ExtArrH)}, 0x2563e000, "2563e000 subr z0.h, z0.h, #0, lsl #8"}, {"sqadd z0.b, z0.b, #0", "SQADD", ExtFormImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2524c000, "2524c000 sqadd z0.b, z0.b, #0"}, {"uqadd z0.b, z0.b, #0", "UQADD", ExtFormImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2525c000, "2525c000 uqadd z0.b, z0.b, #0"}, {"sqsub z0.b, z0.b, #0", "SQSUB", ExtFormImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2526c000, "2526c000 sqsub z0.b, z0.b, #0"}, {"sqsub z0.b, z0.b, #255", "SQSUB", ExtFormImmediate, []ExtOperand{ExtImmediate(255), ExtVector(0, ExtArrB)}, 0x2526dfe0, "2526dfe0 sqsub z0.b, z0.b, #255"}, {"sqsub z0.h, z0.h, #0, lsl #8", "SQSUB", ExtFormImmediate, []ExtOperand{ExtShiftedImmediate(0, 8), ExtVector(0, ExtArrH)}, 0x2566e000, "2566e000 sqsub z0.h, z0.h, #0, lsl #8"}, {"uqsub z0.b, z0.b, #0", "UQSUB", ExtFormImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2527c000, "2527c000 uqsub z0.b, z0.b, #0 (class vector from the GNU table and LLVM: sve_int_arith_imm0 opc 0b111)"}, {"mul z0.b, z0.b, #0", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrB)}, 0x2530c000, "2530c000 mul z0.b, z0.b, #0"}, {"mul z0.b, z0.b, #127", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtImmediate(127), ExtVector(0, ExtArrB)}, 0x2530cfe0, "2530cfe0 mul z0.b, z0.b, #127"}, {"mul z0.b, z0.b, #-128", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtImmediate(-128), ExtVector(0, ExtArrB)}, 0x2530d000, "2530d000 mul z0.b, z0.b, #-128"}, {"mul z0.b, z0.b, #-1", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtImmediate(-1), ExtVector(0, ExtArrB)}, 0x2530dfe0, "2530dfe0 mul z0.b, z0.b, #-1"}, {"mul z0.h, z0.h, #0", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtImmediate(0), ExtVector(0, ExtArrH)}, 0x2570c000, "2570c000 mul z0.h, z0.h, #0"}, } { in := extInstruction(t, tt.mnem, tt.form) got, err := in.Encode(tt.ops) if err != nil { t.Errorf("%s: encode: %v", tt.name, err) continue } if want := hex.EncodeToString(extWordLE(tt.want)); hex.EncodeToString(got) != want { t.Errorf("%s:\n got %x\n want %s", tt.name, got, want) } } } // TestArm64ExtGoldenSources pins the cross-check contract: every encoding // class in the table carries at least one GNU-assembler vector, so no class // rests on transcription alone. func TestArm64ExtGoldenSources(t *testing.T) { classes := map[ExtForm]bool{} for _, tt := range []struct { mnem string form ExtForm }{ {"ADD", ExtFormVectors}, {"SUB", ExtFormVectors}, {"SQADD", ExtFormVectors}, {"UQADD", ExtFormVectors}, {"SQSUB", ExtFormVectors}, {"UQSUB", ExtFormVectors}, {"MUL", ExtFormVectors}, {"SMULH", ExtFormVectors}, {"UMULH", ExtFormVectors}, {"ADD", ExtFormPredicated}, {"SUB", ExtFormPredicated}, {"SUBR", ExtFormPredicated}, {"MUL", ExtFormPredicated}, {"SMULH", ExtFormPredicated}, {"UMULH", ExtFormPredicated}, {"ADD", ExtFormImmediate}, {"SUB", ExtFormImmediate}, {"SUBR", ExtFormImmediate}, {"SQADD", ExtFormImmediate}, {"UQADD", ExtFormImmediate}, {"SQSUB", ExtFormImmediate}, {"UQSUB", ExtFormImmediate}, {"MUL", ExtFormSignedImmediate}, } { if _, ok := extInstructionQuiet(tt.mnem, tt.form); !ok { t.Errorf("the table lacks %s with the %s form", tt.mnem, tt.form) } classes[tt.form] = true } for _, form := range []ExtForm{ExtFormVectors, ExtFormPredicated, ExtFormImmediate, ExtFormSignedImmediate} { if !classes[form] { t.Errorf("no golden vectors cover the %s form", form) } } } func extInstructionQuiet(mnem string, form ExtForm) (ExtInstr, bool) { for _, in := range Extensions(ARM64) { if in.Name == mnem && in.Form == form { return in, true } } return ExtInstr{}, false } // TestArm64ExtTableIntegrity checks the metadata contract: every entry names // its manual reference, summary and feature, the element-size field sits // at bits 23..22 for the classes that carry one, and the destination field // stays zero in the fixed word: five bits where a Z register is the // destination, four where a predicate is. func TestArm64ExtTableIntegrity(t *testing.T) { for _, in := range Extensions(ARM64) { if in.Name == "" || in.Summary == "" || in.Ref == "" { t.Errorf("%+v: name, summary and reference are mandatory", in) } if in.Feature != ExtFeatureSVE && in.Feature != ExtFeatureSVE2 && in.Feature != ExtFeatureSVE2p1 { t.Errorf("%s: feature %q is neither sve, sve2 nor sve2p1", in.Name, in.Feature) } if in.Form.Arity() < 0 || in.Form.Arity() > 4 { t.Errorf("%s: form %d carries an unusable arity %d", in.Name, in.Form, in.Form.Arity()) } if in.Size.Width != 0 && (in.Size.Off != 22 || in.Size.Width != 2) { t.Errorf("%s: the size field sits at bits %d..%d, the classes here put it at 23..22", in.Name, in.Size.Off, in.Size.Off+in.Size.Width-1) } // The destination register field and the element-size field are // operands wherever they exist, so Word carries both zero; the // class opcodes live around them and stay where they are. Where // the class carries no size field, bits 23..22 are class bits and // stay. // Forms whose destination is a predicate carry it in a four-bit // field; every other form keeps the five-bit Z or R destination. destMask := uint32(0x1f) switch in.Form { case ExtFormPredicateLogical, ExtFormPredicateSelect, ExtFormPredicateLogicalDest, ExtFormPredicateBreak, ExtFormPredicateBreakZero, ExtFormPredicatePermute, ExtFormPredicateFirst, ExtFormPredicateNext, ExtFormPredicateOne, ExtFormPredicateFFRRead, ExtFormPredicateMove, ExtFormPredicateUnpack, ExtFormPredicateTest, ExtFormWhile, ExtFormPredicateCounter, ExtFormZUnary, ExtFormCompare, ExtFormCompareWide: destMask = 0xf } roundOne := in.Form == ExtFormVectors || in.Form == ExtFormPredicated || in.Form == ExtFormImmediate || in.Form == ExtFormSignedImmediate // The loop terminators carry no destination at all, and the NE // variants put their opcode right in the slot another class would // fill with one, so the zero-destination invariant exempts them. term := in.Form == ExtFormCTerm if !term && (in.Word&destMask != 0 || (roundOne && in.Size.Width != 0 && in.Word&(0x3<<22) != 0)) { t.Errorf("%s: word %08x carries destination or size bits, want them zero", in.Name, in.Word) } } } func TestArm64ExtRejects(t *testing.T) { rgb := func(rs ...int) []ExtOperand { ops := make([]ExtOperand, len(rs)) for i, r := range rs { ops[i] = ExtVector(r, ExtArrB) } return ops } for _, tt := range []struct { name string mnem string form ExtForm ops []ExtOperand quote string // a fragment the error carries }{ {"no arrangement", "ADD", ExtFormVectors, []ExtOperand{{Kind: ExtZReg, Reg: 0}, ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, "no arrangement"}, {"mismatched arrangements", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrS), ExtVector(0, ExtArrB)}, "want .B"}, {"wrong arity", "ADD", ExtFormVectors, rgb(0, 0), "takes 3 operands"}, {"predicate in a vector position", "ADD", ExtFormVectors, []ExtOperand{ExtPredicate(0, ExtQualNone), ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, "scalable vector register"}, {"quadword arrangement has no size encoding", "ADD", ExtFormVectors, []ExtOperand{ExtVector(0, ExtArrQ), ExtVector(0, ExtArrQ), ExtVector(0, ExtArrQ)}, "no size encoding"}, {"zeroing qualifier", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualZeroing), ExtVector(0, ExtArrB)}, "/M"}, {"predicate beyond the 3-bit field", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(8, ExtQualMerging), ExtVector(0, ExtArrB)}, "P0-P7"}, {"predicate arrangement suffix", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtOperand{Kind: ExtPReg, Reg: 0, Qual: ExtQualMerging, Arr: ExtArrB}, ExtVector(0, ExtArrB)}, "arrangement"}, {"predicate operands disagree on arrangement", "ADD", ExtFormPredicated, []ExtOperand{ExtVector(0, ExtArrB), ExtPredicate(0, ExtQualMerging), ExtVector(0, ExtArrS)}, "must match"}, {"bare 256 on .B", "ADD", ExtFormImmediate, []ExtOperand{ExtImmediate(256), ExtVector(0, ExtArrB)}, "immediate 256"}, {"negative unsigned immediate", "ADD", ExtFormImmediate, []ExtOperand{ExtImmediate(-1), ExtVector(0, ExtArrB)}, "immediate -1"}, {"multiple of 256 beyond the imm8 span", "ADD", ExtFormImmediate, []ExtOperand{ExtImmediate(65536), ExtVector(0, ExtArrH)}, "immediate 65536"}, {"shift amount other than 0 or 8", "ADD", ExtFormImmediate, []ExtOperand{ExtShiftedImmediate(1, 4), ExtVector(0, ExtArrS)}, "0 or 8"}, {"shifted constant on .B", "ADD", ExtFormImmediate, []ExtOperand{ExtShiftedImmediate(1, 8), ExtVector(0, ExtArrB)}, ".B takes no shift"}, {"register where the immediate belongs", "ADD", ExtFormImmediate, []ExtOperand{ExtVector(0, ExtArrB), ExtVector(0, ExtArrB)}, "wants an immediate"}, {"signed immediate over the top", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtImmediate(128), ExtVector(0, ExtArrB)}, "128"}, {"signed immediate under the floor", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtImmediate(-129), ExtVector(0, ExtArrB)}, "-129"}, {"shift in the signed class", "MUL", ExtFormSignedImmediate, []ExtOperand{ExtShiftedImmediate(1, 8), ExtVector(0, ExtArrB)}, "no shift"}, } { in := extInstruction(t, tt.mnem, tt.form) _, err := in.Encode(tt.ops) if err == nil { t.Errorf("%s: encode succeeded, want an error", tt.name) continue } if !strings.Contains(err.Error(), tt.quote) { t.Errorf("%s: error %q lacks %q", tt.name, err, tt.quote) } } } // TestExtensionsArchBinding pins the registry's architecture binding: the // extended layer exists for arm64 and amd64 (the latter in amd64_ext.go), and // no other architecture sees a single instruction of either. func TestExtensionsArchBinding(t *testing.T) { for _, a := range []Arch{RISCV, LOONG64, Unknown} { if got := Extensions(a); len(got) != 0 { t.Errorf("Extensions(%s) carries %d instructions, want none", a, len(got)) } } if got := Extensions(ARM64); len(got) == 0 { t.Error("Extensions(ARM64) is empty") } if got := Extensions(AMD64); len(got) == 0 { t.Error("Extensions(AMD64) is empty") } } // TestArm64ExtPredicateGolden pins the SVE and SVE2.1 predicate family // against the toolchain-generated corpus: every row is one arm64sveenc.s // line, and the want word is that line's own expected encoding, byte // reversed out of the file's big-endian comment into the little-endian // instruction word. The corpus and the toolchain's encoding table // (inst_gen.go) are two independent generations from Arm's official ISA // description; both agree with the field layouts encoded here, and the // classes have no single-byte oracle beyond them (go tool asm carries no // SVE encodings). func TestArm64ExtPredicateGolden(t *testing.T) { for _, tt := range []struct { name string mnem string form ExtForm ops []ExtOperand want uint32 }{ {"PAND P4.B, P2.B, P1.Z, P14.B", "PAND", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2504444e}, {"PANDS P4.B, P2.B, P1.Z, P14.B", "PANDS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2544444e}, {"PBIC P4.B, P2.B, P1.Z, P14.B", "PBIC", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2504445e}, {"PBICS P4.B, P2.B, P1.Z, P14.B", "PBICS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2544445e}, {"PBRKA P5.B, P9.Z, P2.B", "PBRKA", ExtFormPredicateBreak, []ExtOperand{ExtPredicateSized(5, ExtArrB), ExtPredicate(9, ExtQualZeroing), ExtPredicateSized(2, ExtArrB)}, 0x251064a2}, {"PBRKAS P5.B, P9.Z, P4.B", "PBRKAS", ExtFormPredicateBreakZero, []ExtOperand{ExtPredicateSized(5, ExtArrB), ExtPredicate(9, ExtQualZeroing), ExtPredicateSized(4, ExtArrB)}, 0x255064a4}, {"PBRKB P5.B, P9.Z, P2.B", "PBRKB", ExtFormPredicateBreak, []ExtOperand{ExtPredicateSized(5, ExtArrB), ExtPredicate(9, ExtQualZeroing), ExtPredicateSized(2, ExtArrB)}, 0x259064a2}, {"PBRKBS P5.B, P9.Z, P4.B", "PBRKBS", ExtFormPredicateBreakZero, []ExtOperand{ExtPredicateSized(5, ExtArrB), ExtPredicate(9, ExtQualZeroing), ExtPredicateSized(4, ExtArrB)}, 0x25d064a4}, {"PBRKN P4.B, P2.B, P1.Z, P4.B", "PBRKN", ExtFormPredicateLogicalDest, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(4, ExtArrB)}, 0x25184444}, {"PBRKNS P4.B, P2.B, P1.Z, P4.B", "PBRKNS", ExtFormPredicateLogicalDest, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(4, ExtArrB)}, 0x25584444}, {"PBRKPA P4.B, P2.B, P1.Z, P14.B", "PBRKPA", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2504c44e}, {"PBRKPAS P4.B, P2.B, P1.Z, P14.B", "PBRKPAS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2544c44e}, {"PBRKPB P4.B, P2.B, P1.Z, P14.B", "PBRKPB", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2504c45e}, {"PBRKPBS P4.B, P2.B, P1.Z, P14.B", "PBRKPBS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2544c45e}, {"PEOR P4.B, P2.B, P1.Z, P14.B", "PEOR", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2504464e}, {"PEORS P4.B, P2.B, P1.Z, P14.B", "PEORS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2544464e}, {"PNAND P4.B, P2.B, P1.Z, P14.B", "PNAND", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2584465e}, {"PNANDS P4.B, P2.B, P1.Z, P14.B", "PNANDS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x25c4465e}, {"PNOR P4.B, P2.B, P1.Z, P14.B", "PNOR", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2584464e}, {"PNORS P4.B, P2.B, P1.Z, P14.B", "PNORS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x25c4464e}, {"PORN P4.B, P2.B, P1.Z, P14.B", "PORN", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2584445e}, {"PORNS P4.B, P2.B, P1.Z, P14.B", "PORNS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x25c4445e}, {"PORR P4.B, P2.B, P1.Z, P14.B", "PORR", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x2584444e}, {"PORRS P4.B, P2.B, P1.Z, P14.B", "PORRS", ExtFormPredicateLogical, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtPredicateSized(14, ExtArrB)}, 0x25c4444e}, {"PPFALSE P13.B", "PPFALSE", ExtFormPredicateOne, []ExtOperand{ExtPredicateSized(13, ExtArrB)}, 0x2518e40d}, {"PPFIRST P5.B, P9, P5.B", "PPFIRST", ExtFormPredicateFirst, []ExtOperand{ExtPredicateSized(5, ExtArrB), ExtPredicate(9, ExtQualNone), ExtPredicateSized(5, ExtArrB)}, 0x2558c125}, {"PPNEXT P5.D, P4, P5.D", "PPNEXT", ExtFormPredicateNext, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicate(4, ExtQualNone), ExtPredicateSized(5, ExtArrD)}, 0x25d9c485}, {"PPTEST P14.B, P0", "PPTEST", ExtFormPredicateTest, []ExtOperand{ExtPredicateSized(14, ExtArrB), ExtPredicate(0, ExtQualNone)}, 0x2550c1c0}, {"PPTRUE PN14.S", "PPTRUE", ExtFormPredicateCounter, []ExtOperand{ExtCounterPredicate(14, ExtArrS)}, 0x25a07816}, {"PPUNPKHI P14.B, P0.H", "PPUNPKHI", ExtFormPredicateUnpack, []ExtOperand{ExtPredicateSized(14, ExtArrB), ExtPredicateSized(0, ExtArrH)}, 0x053141c0}, {"PPUNPKLO P14.B, P0.H", "PPUNPKLO", ExtFormPredicateUnpack, []ExtOperand{ExtPredicateSized(14, ExtArrB), ExtPredicateSized(0, ExtArrH)}, 0x053041c0}, {"PRDFFR P14.Z, P0.B", "PRDFFR", ExtFormPredicateFFRRead, []ExtOperand{ExtPredicate(14, ExtQualZeroing), ExtPredicateSized(0, ExtArrB)}, 0x2518f1c0}, {"PRDFFR P13.B", "PRDFFR", ExtFormPredicateOne, []ExtOperand{ExtPredicateSized(13, ExtArrB)}, 0x2519f00d}, {"PRDFFRS P14.Z, P0.B", "PRDFFRS", ExtFormPredicateFFRRead, []ExtOperand{ExtPredicate(14, ExtQualZeroing), ExtPredicateSized(0, ExtArrB)}, 0x2558f1c0}, {"PREV P14.S, P13.S", "PREV", ExtFormPredicateMove, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtPredicateSized(13, ExtArrS)}, 0x05b441cd}, {"PSEL P4.B, P2.B, P1, P14.B", "PSEL", ExtFormPredicateSelect, []ExtOperand{ExtPredicateSized(4, ExtArrB), ExtPredicateSized(2, ExtArrB), ExtPredicate(1, ExtQualNone), ExtPredicateSized(14, ExtArrB)}, 0x2504465e}, {"PTRN1 P5.D, P4.D, P2.D", "PTRN1", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicateSized(4, ExtArrD), ExtPredicateSized(2, ExtArrD)}, 0x05e55082}, {"PTRN2 P5.D, P4.D, P2.D", "PTRN2", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicateSized(4, ExtArrD), ExtPredicateSized(2, ExtArrD)}, 0x05e55482}, {"PUZP1 P5.D, P4.D, P2.D", "PUZP1", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicateSized(4, ExtArrD), ExtPredicateSized(2, ExtArrD)}, 0x05e54882}, {"PUZP2 P5.D, P4.D, P2.D", "PUZP2", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicateSized(4, ExtArrD), ExtPredicateSized(2, ExtArrD)}, 0x05e54c82}, {"PWRFFR P13.B", "PWRFFR", ExtFormPredicateWrite, []ExtOperand{ExtPredicateSized(13, ExtArrB)}, 0x252891a0}, {"PZIP1 P5.D, P4.D, P2.D", "PZIP1", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicateSized(4, ExtArrD), ExtPredicateSized(2, ExtArrD)}, 0x05e54082}, {"PZIP2 P5.D, P4.D, P2.D", "PZIP2", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicateSized(4, ExtArrD), ExtPredicateSized(2, ExtArrD)}, 0x05e54482}, {"SETFFR ", "SETFFR", ExtFormNone, []ExtOperand{}, 0x252c9000}, {"PWHILEGE R2, R10, P10.H", "PWHILEGE", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562114a}, {"PWHILEGT R2, R10, P10.H", "PWHILEGT", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562115a}, {"PWHILEHI R2, R10, P10.H", "PWHILEHI", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562195a}, {"PWHILEHS R2, R10, P10.H", "PWHILEHS", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562194a}, {"PWHILELE R2, R10, P10.H", "PWHILELE", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562155a}, {"PWHILELO R2, R10, P10.H", "PWHILELO", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x25621d4a}, {"PWHILELS R2, R10, P10.H", "PWHILELS", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x25621d5a}, {"PWHILELT R2, R10, P10.H", "PWHILELT", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562154a}, {"PWHILERW R2, R10, P10.H", "PWHILERW", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562315a}, {"PWHILEWR R2, R10, P10.H", "PWHILEWR", ExtFormWhile, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562314a}, } { in := extInstruction(t, tt.mnem, tt.form) got, err := in.Encode(tt.ops) if err != nil { t.Errorf("%s: encode: %v", tt.name, err) continue } if want := hex.EncodeToString(extWordLE(tt.want)); hex.EncodeToString(got) != want { t.Errorf("%s:\n got %x\n want %s", tt.name, got, want) } } } // TestArm64ExtPredicateSources pins the cross-check contract of the // predicate family: every class the layer defines carries at least one // golden vector derived from the toolchain-generated corpus, so no class // rests on transcription alone. func TestArm64ExtPredicateSources(t *testing.T) { for _, tt := range []struct { mnem string form ExtForm }{ {"PAND", ExtFormPredicateLogical}, {"PANDS", ExtFormPredicateLogical}, {"PBIC", ExtFormPredicateLogical}, {"PBICS", ExtFormPredicateLogical}, {"PEOR", ExtFormPredicateLogical}, {"PEORS", ExtFormPredicateLogical}, {"PNAND", ExtFormPredicateLogical}, {"PNANDS", ExtFormPredicateLogical}, {"PNOR", ExtFormPredicateLogical}, {"PNORS", ExtFormPredicateLogical}, {"PORN", ExtFormPredicateLogical}, {"PORNS", ExtFormPredicateLogical}, {"PORR", ExtFormPredicateLogical}, {"PORRS", ExtFormPredicateLogical}, {"PSEL", ExtFormPredicateSelect}, {"PBRKA", ExtFormPredicateBreak}, {"PBRKAS", ExtFormPredicateBreakZero}, {"PBRKB", ExtFormPredicateBreak}, {"PBRKBS", ExtFormPredicateBreakZero}, {"PBRKN", ExtFormPredicateLogicalDest}, {"PBRKNS", ExtFormPredicateLogicalDest}, {"PBRKPA", ExtFormPredicateLogical}, {"PBRKPAS", ExtFormPredicateLogical}, {"PBRKPB", ExtFormPredicateLogical}, {"PBRKPBS", ExtFormPredicateLogical}, {"PTRN1", ExtFormPredicatePermute}, {"PTRN2", ExtFormPredicatePermute}, {"PUZP1", ExtFormPredicatePermute}, {"PUZP2", ExtFormPredicatePermute}, {"PZIP1", ExtFormPredicatePermute}, {"PZIP2", ExtFormPredicatePermute}, {"PPFALSE", ExtFormPredicateOne}, {"PPFIRST", ExtFormPredicateFirst}, {"PPNEXT", ExtFormPredicateNext}, {"PPTEST", ExtFormPredicateTest}, {"PPTRUE", ExtFormPredicateCounter}, {"PPUNPKHI", ExtFormPredicateUnpack}, {"PPUNPKLO", ExtFormPredicateUnpack}, {"PRDFFR", ExtFormPredicateFFRRead}, {"PRDFFR", ExtFormPredicateOne}, {"PRDFFRS", ExtFormPredicateFFRRead}, {"PWRFFR", ExtFormPredicateWrite}, {"PREV", ExtFormPredicateMove}, {"SETFFR", ExtFormNone}, {"PWHILEGE", ExtFormWhile}, {"PWHILEGT", ExtFormWhile}, {"PWHILEHI", ExtFormWhile}, {"PWHILEHS", ExtFormWhile}, {"PWHILELE", ExtFormWhile}, {"PWHILELO", ExtFormWhile}, {"PWHILELS", ExtFormWhile}, {"PWHILELT", ExtFormWhile}, {"PWHILERW", ExtFormWhile}, {"PWHILEWR", ExtFormWhile}, } { if _, ok := extInstructionQuiet(tt.mnem, tt.form); !ok { t.Errorf("the table lacks %s with the %s form", tt.mnem, tt.form) } } } // TestArm64ExtPredicateRejects pins the diagnostics the predicate forms // give the operands their classes cannot carry: the register ranges the // field widths imply, the arrangements the classes fix, and the read-back // constraint of the destination-shared shapes. func TestArm64ExtPredicateRejects(t *testing.T) { pb := func(r int) ExtOperand { return ExtPredicateSized(r, ExtArrB) } for _, tt := range []struct { name string mnem string form ExtForm ops []ExtOperand quote string }{ {"Pm beyond the three-bit field", "PAND", ExtFormPredicateLogical, []ExtOperand{pb(8), pb(2), ExtPredicate(1, ExtQualZeroing), pb(14)}, "outside P0-P7"}, {"governing predicate beyond the narrow field", "PAND", ExtFormPredicateLogical, []ExtOperand{pb(4), pb(2), ExtPredicate(8, ExtQualZeroing), pb(14)}, "outside P0-P7"}, {"wrong arrangement on the second source", "PAND", ExtFormPredicateLogical, []ExtOperand{pb(4), ExtPredicateSized(2, ExtArrS), ExtPredicate(1, ExtQualZeroing), pb(14)}, "want .B"}, {"bare governing predicate", "PAND", ExtFormPredicateLogical, []ExtOperand{pb(4), pb(2), ExtPredicate(1, ExtQualNone), pb(14)}, "zeroing qualifier"}, {"quadword arrangement", "PSEL", ExtFormPredicateSelect, []ExtOperand{ExtPredicateSized(4, ExtArrQ), ExtPredicateSized(2, ExtArrQ), ExtPredicate(1, ExtQualNone), ExtPredicateSized(14, ExtArrQ)}, "want .B"}, {"qualifier where PSEL wants none", "PSEL", ExtFormPredicateSelect, []ExtOperand{pb(4), pb(2), ExtPredicate(1, ExtQualZeroing), pb(14)}, "takes no qualifier"}, {"read-back operands disagree", "PBRKN", ExtFormPredicateLogicalDest, []ExtOperand{pb(4), pb(2), ExtPredicate(1, ExtQualZeroing), pb(9)}, "same register Pdm"}, {"merging qualifier on the zeroing break", "PBRKAS", ExtFormPredicateBreakZero, []ExtOperand{pb(5), ExtPredicate(9, ExtQualMerging), pb(4)}, "zeroing qualifier"}, {"governing predicate beyond the wide field", "PBRKA", ExtFormPredicateBreak, []ExtOperand{pb(5), ExtPredicate(16, ExtQualZeroing), pb(2)}, "outside P0-P15"}, {"permutations disagree on arrangement", "PTRN1", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicateSized(4, ExtArrD), ExtPredicateSized(2, ExtArrS)}, "want .D"}, {"bare permutation operand", "PUZP1", ExtFormPredicatePermute, []ExtOperand{ExtPredicateSized(5, ExtArrD), {Kind: ExtPReg, Reg: 4}, ExtPredicateSized(2, ExtArrD)}, "no arrangement suffix"}, {"read-back operands disagree on arrangement", "PPNEXT", ExtFormPredicateNext, []ExtOperand{ExtPredicateSized(5, ExtArrD), ExtPredicate(4, ExtQualNone), ExtPredicateSized(5, ExtArrS)}, "same register Pdn"}, {"qualifier on the bare source", "PPFIRST", ExtFormPredicateFirst, []ExtOperand{pb(5), ExtPredicate(9, ExtQualZeroing), pb(5)}, "takes no qualifier"}, {"PFIRST outside .B", "PPFIRST", ExtFormPredicateFirst, []ExtOperand{ExtPredicateSized(5, ExtArrS), ExtPredicate(9, ExtQualNone), ExtPredicateSized(5, ExtArrS)}, "want .B"}, {"merging qualifier on the FFR read", "PRDFFR", ExtFormPredicateFFRRead, []ExtOperand{ExtPredicate(14, ExtQualMerging), pb(0)}, "zeroing qualifier"}, {"wrong unpack destination arrangement", "PPUNPKHI", ExtFormPredicateUnpack, []ExtOperand{pb(14), ExtPredicateSized(0, ExtArrB)}, "want .H"}, {"qualifier on the tested predicate", "PPTEST", ExtFormPredicateTest, []ExtOperand{pb(14), ExtPredicate(0, ExtQualZeroing)}, "takes no qualifier"}, {"general register beyond R30", "PWHILELT", ExtFormWhile, []ExtOperand{ExtGeneral(31), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, "outside R0-R30"}, {"predicate where the register belongs", "PWHILELT", ExtFormWhile, []ExtOperand{pb(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, "wants a general register"}, {"counter predicate spelled plain", "PPTRUE", ExtFormPredicateCounter, []ExtOperand{ExtPredicateSized(6, ExtArrS)}, "predicate-as-counter register"}, {"counter below the counter range", "PPTRUE", ExtFormPredicateCounter, []ExtOperand{ExtCounterPredicate(7, ExtArrS)}, "outside PN8-PN15"}, {"operand where none belongs", "SETFFR", ExtFormNone, []ExtOperand{pb(13)}, "takes 0 operands"}, } { in := extInstruction(t, tt.mnem, tt.form) _, err := in.Encode(tt.ops) if err == nil { t.Errorf("%s: encode succeeded, want an error", tt.name) continue } if !strings.Contains(err.Error(), tt.quote) { t.Errorf("%s: error %q lacks %q", tt.name, err, tt.quote) } } } // extInstructionMeta finds the row whose name, form, governing-predicate // qualifier and fixed arrangement all match. func extInstructionMeta(t *testing.T, mnem string, form ExtForm, qual ExtQualifier, arr ExtArrangement) ExtInstr { t.Helper() for _, in := range Extensions(ARM64) { if in.Name == mnem && in.Form == form && in.PgQual == qual && in.Arr == arr { return in } } t.Fatalf("no extended %s with the %s form, %s qualifier and %s arrangement", mnem, form, qual, arr) return ExtInstr{} } // TestArm64ExtZGolden pins the SVE2.1 Z-alias families (unary and binary // predicated forms, immediate aliases, permutations, selects, splices, // compact and expand, the register-copy forms and MOVPRFX) against the // toolchain-generated corpus, the same provenance as the predicate family // above. The lookup matches the qualifier and arrangement metadata the // rows carry, because one mnemonic registers several rows over one form. func TestArm64ExtZGolden(t *testing.T) { for _, tt := range []struct { name string mnem string form ExtForm qual ExtQualifier arr ExtArrangement ops []ExtOperand want uint32 }{ {"ZABS Z7.D, P4.M, Z13.D", "ZABS", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d6b0ed}, {"ZABS Z7.D, P4.Z, Z13.D", "ZABS", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c6b0ed}, {"ZADD Z7.D, Z23.D, Z13.D", "ZADD", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x04e702ed}, {"ZAND Z7.D, Z6.D, Z23.D", "ZAND", ExtFormVectorsZm, 0, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrD), ExtVector(23, ExtArrD)}, 0x042730d7}, {"ZBIC Z7.D, Z6.D, Z23.D", "ZBIC", ExtFormVectorsZm, 0, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrD), ExtVector(23, ExtArrD)}, 0x04e730d7}, {"ZCLS Z7.D, P4.M, Z13.D", "ZCLS", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d8b0ed}, {"ZCLS Z7.D, P4.Z, Z13.D", "ZCLS", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c8b0ed}, {"ZCLZ Z7.D, P4.M, Z13.D", "ZCLZ", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d9b0ed}, {"ZCLZ Z7.D, P4.Z, Z13.D", "ZCLZ", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c9b0ed}, {"ZCNOT Z7.D, P4.M, Z13.D", "ZCNOT", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04dbb0ed}, {"ZCNOT Z7.D, P4.Z, Z13.D", "ZCNOT", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04cbb0ed}, {"ZCOMPACT Z7.D, P4, Z13.D", "ZCOMPACT", ExtFormZGov, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualNone), ExtVector(13, ExtArrD)}, 0x05e190ed}, {"ZCOMPACT Z7.D, P4, Z13.D", "ZCOMPACT", ExtFormZGov, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualNone), ExtVector(13, ExtArrD)}, 0x05e190ed}, {"ZEOR Z7.D, Z6.D, Z23.D", "ZEOR", ExtFormVectorsZm, 0, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrD), ExtVector(23, ExtArrD)}, 0x04a730d7}, {"ZEXPAND Z7.D, P4, Z13.D", "ZEXPAND", ExtFormZGov, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualNone), ExtVector(13, ExtArrD)}, 0x05f190ed}, {"ZMOVPRFX Z7.D, P4.Z, Z21.D", "ZMOVPRFX", ExtFormZUnary, ExtQualAny, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(21, ExtArrD)}, 0x04d030f5}, // The destination read back spells twice and encodes once, in the // destination slot alone: bits 16..20 are class bits, so a non-zero // Zdn must not reach them. {"ZADD Z15.B, Z5.B, P3.M, Z5.B", "ZADD", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(5, ExtArrB), ExtPredicate(3, ExtQualMerging), ExtVector(5, ExtArrB)}, 0x04000de5}, {"ZSUB Z20.D, Z13.D, P6.M, Z13.D", "ZSUB", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(20, ExtArrD), ExtVector(13, ExtArrD), ExtPredicate(6, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04c11a8d}, {"ZMOVPRFX Z11, Z6", "ZMOVPRFX", ExtFormZMoveBare, 0, ExtArrNone, []ExtOperand{{Kind: ExtZReg, Reg: 11}, {Kind: ExtZReg, Reg: 6}}, 0x0420bd66}, {"ZNEG Z7.D, P4.M, Z13.D", "ZNEG", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d7b0ed}, {"ZNEG Z7.D, P4.Z, Z13.D", "ZNEG", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c7b0ed}, {"ZNOT Z7.D, P4.M, Z13.D", "ZNOT", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04deb0ed}, {"ZNOT Z7.D, P4.Z, Z13.D", "ZNOT", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04ceb0ed}, {"ZORR Z7.D, Z6.D, Z23.D", "ZORR", ExtFormVectorsZm, 0, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrD), ExtVector(23, ExtArrD)}, 0x046730d7}, {"ZREV Z1.S, Z26.S", "ZREV", ExtFormZMove, 0, ExtArrNone, []ExtOperand{ExtVector(1, ExtArrS), ExtVector(26, ExtArrS)}, 0x05b8383a}, {"ZREVB Z7.D, P4.M, Z13.D", "ZREVB", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x05e490ed}, {"ZREVB Z7.D, P4.Z, Z13.D", "ZREVB", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x05e4b0ed}, {"ZREVD Z13.Q, P1.M, Z22.Q", "ZREVD", ExtFormZUnary, ExtQualMerging, ExtArrQ, []ExtOperand{ExtVector(13, ExtArrQ), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrQ)}, 0x052e85b6}, {"ZREVD Z13.Q, P1.Z, Z22.Q", "ZREVD", ExtFormZUnary, ExtQualZeroing, ExtArrQ, []ExtOperand{ExtVector(13, ExtArrQ), ExtPredicate(1, ExtQualZeroing), ExtVector(22, ExtArrQ)}, 0x052ea5b6}, {"ZREVH Z7.D, P4.M, Z13.D", "ZREVH", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x05e590ed}, {"ZREVH Z7.D, P4.Z, Z13.D", "ZREVH", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x05e5b0ed}, {"ZREVW Z13.D, P1.M, Z22.D", "ZREVW", ExtFormZUnary, ExtQualMerging, ExtArrD, []ExtOperand{ExtVector(13, ExtArrD), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrD)}, 0x05e685b6}, {"ZREVW Z13.D, P1.Z, Z22.D", "ZREVW", ExtFormZUnary, ExtQualZeroing, ExtArrD, []ExtOperand{ExtVector(13, ExtArrD), ExtPredicate(1, ExtQualZeroing), ExtVector(22, ExtArrD)}, 0x05e6a5b6}, {"ZSEL Z23.B, Z21.B, P14, Z2.B", "ZSEL", ExtFormZSelect, 0, ExtArrNone, []ExtOperand{ExtVector(23, ExtArrB), ExtVector(21, ExtArrB), ExtPredicate(14, ExtQualNone), ExtVector(2, ExtArrB)}, 0x0537faa2}, {"ZSQABS Z7.D, P4.M, Z13.D", "ZSQABS", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x44c8b0ed}, {"ZSQABS Z7.D, P4.Z, Z13.D", "ZSQABS", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x44cab0ed}, {"ZSQNEG Z7.D, P4.M, Z13.D", "ZSQNEG", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x44c9b0ed}, {"ZSQNEG Z7.D, P4.Z, Z13.D", "ZSQNEG", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x44cbb0ed}, {"ZSUB Z7.D, Z23.D, Z13.D", "ZSUB", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x04e706ed}, {"ZSUNPKHI Z15.B, Z0.H", "ZSUNPKHI", ExtFormZUnpack, 0, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrH)}, 0x057139e0}, {"ZSUNPKLO Z15.B, Z0.H", "ZSUNPKLO", ExtFormZUnpack, 0, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrH)}, 0x057039e0}, {"ZSXTB Z7.D, P4.M, Z13.D", "ZSXTB", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d0b0ed}, {"ZSXTB Z7.D, P4.Z, Z13.D", "ZSXTB", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c0b0ed}, {"ZSXTH Z7.D, P4.M, Z13.D", "ZSXTH", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d2b0ed}, {"ZSXTH Z7.D, P4.Z, Z13.D", "ZSXTH", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c2b0ed}, {"ZSXTW Z13.D, P1.M, Z22.D", "ZSXTW", ExtFormZUnary, ExtQualMerging, ExtArrD, []ExtOperand{ExtVector(13, ExtArrD), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrD)}, 0x04d4a5b6}, {"ZSXTW Z13.D, P1.Z, Z22.D", "ZSXTW", ExtFormZUnary, ExtQualZeroing, ExtArrD, []ExtOperand{ExtVector(13, ExtArrD), ExtPredicate(1, ExtQualZeroing), ExtVector(22, ExtArrD)}, 0x04c4a5b6}, {"ZTBX Z7.D, Z23.D, Z13.D", "ZTBX", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e72eed}, {"ZTBXQ Z7.D, Z23.D, Z13.D", "ZTBXQ", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e736ed}, {"ZTRN1 Z7.D, Z23.D, Z13.D", "ZTRN1", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e772ed}, {"ZTRN1 Z7.Q, Z6.Q, Z23.Q", "ZTRN1", ExtFormVectorsZm, 0, ExtArrQ, []ExtOperand{ExtVector(7, ExtArrQ), ExtVector(6, ExtArrQ), ExtVector(23, ExtArrQ)}, 0x05a718d7}, {"ZTRN2 Z7.D, Z23.D, Z13.D", "ZTRN2", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e776ed}, {"ZTRN2 Z7.Q, Z6.Q, Z23.Q", "ZTRN2", ExtFormVectorsZm, 0, ExtArrQ, []ExtOperand{ExtVector(7, ExtArrQ), ExtVector(6, ExtArrQ), ExtVector(23, ExtArrQ)}, 0x05a71cd7}, {"ZUUNPKHI Z15.B, Z0.H", "ZUUNPKHI", ExtFormZUnpack, 0, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrH)}, 0x057339e0}, {"ZUUNPKLO Z15.B, Z0.H", "ZUUNPKLO", ExtFormZUnpack, 0, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrH)}, 0x057239e0}, {"ZUXTB Z7.D, P4.M, Z13.D", "ZUXTB", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d1b0ed}, {"ZUXTB Z7.D, P4.Z, Z13.D", "ZUXTB", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c1b0ed}, {"ZUXTH Z7.D, P4.M, Z13.D", "ZUXTH", ExtFormZUnary, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04d3b0ed}, {"ZUXTH Z7.D, P4.Z, Z13.D", "ZUXTH", ExtFormZUnary, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrD)}, 0x04c3b0ed}, {"ZUXTW Z13.D, P1.M, Z22.D", "ZUXTW", ExtFormZUnary, ExtQualMerging, ExtArrD, []ExtOperand{ExtVector(13, ExtArrD), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrD)}, 0x04d5a5b6}, {"ZUXTW Z13.D, P1.Z, Z22.D", "ZUXTW", ExtFormZUnary, ExtQualZeroing, ExtArrD, []ExtOperand{ExtVector(13, ExtArrD), ExtPredicate(1, ExtQualZeroing), ExtVector(22, ExtArrD)}, 0x04c5a5b6}, {"ZUZP1 Z7.D, Z23.D, Z13.D", "ZUZP1", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e76aed}, {"ZUZP1 Z7.Q, Z6.Q, Z23.Q", "ZUZP1", ExtFormVectorsZm, 0, ExtArrQ, []ExtOperand{ExtVector(7, ExtArrQ), ExtVector(6, ExtArrQ), ExtVector(23, ExtArrQ)}, 0x05a708d7}, {"ZUZP2 Z7.D, Z23.D, Z13.D", "ZUZP2", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e76eed}, {"ZUZP2 Z7.Q, Z6.Q, Z23.Q", "ZUZP2", ExtFormVectorsZm, 0, ExtArrQ, []ExtOperand{ExtVector(7, ExtArrQ), ExtVector(6, ExtArrQ), ExtVector(23, ExtArrQ)}, 0x05a70cd7}, {"ZUZPQ1 Z7.D, Z23.D, Z13.D", "ZUZPQ1", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x44c7eaed}, {"ZUZPQ2 Z7.D, Z23.D, Z13.D", "ZUZPQ2", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x44c7eeed}, {"ZZIP1 Z7.D, Z23.D, Z13.D", "ZZIP1", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e762ed}, {"ZZIP1 Z7.Q, Z6.Q, Z23.Q", "ZZIP1", ExtFormVectorsZm, 0, ExtArrQ, []ExtOperand{ExtVector(7, ExtArrQ), ExtVector(6, ExtArrQ), ExtVector(23, ExtArrQ)}, 0x05a700d7}, {"ZZIP2 Z7.D, Z23.D, Z13.D", "ZZIP2", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x05e766ed}, {"ZZIP2 Z7.Q, Z6.Q, Z23.Q", "ZZIP2", ExtFormVectorsZm, 0, ExtArrQ, []ExtOperand{ExtVector(7, ExtArrQ), ExtVector(6, ExtArrQ), ExtVector(23, ExtArrQ)}, 0x05a704d7}, {"ZZIPQ1 Z7.D, Z23.D, Z13.D", "ZZIPQ1", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x44c7e2ed}, {"ZZIPQ2 Z7.D, Z23.D, Z13.D", "ZZIPQ2", ExtFormVectorsZm, 0, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x44c7e6ed}, {"ZDUP R2, Z10.D", "ZDUP", ExtFormZFromGeneral, 0, ExtArrD, []ExtOperand{ExtGeneral(2), ExtVector(10, ExtArrD)}, 0x05e0384a}, {"ZINSR R2, Z10.D", "ZINSR", ExtFormZFromGeneral, 0, ExtArrD, []ExtOperand{ExtGeneral(2), ExtVector(10, ExtArrD)}, 0x05e4384a}, {"ZADD $6, Z7.D, Z7.D", "ZADD", ExtFormZImmediateSource, 0, ExtArrNone, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(7, ExtArrD)}, 0x25e0c0c7}, {"ZSUB $6, Z7.D, Z7.D", "ZSUB", ExtFormZImmediateSource, 0, ExtArrNone, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(7, ExtArrD)}, 0x25e1c0c7}, {"ZSUBR $6, Z7.D, Z7.D", "ZSUBR", ExtFormZImmediateSource, 0, ExtArrNone, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(7, ExtArrD)}, 0x25e3c0c7}, {"ZLASTA Z10.D, P3, R15", "ZLASTA", ExtFormZLastReg, 0, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtGeneral(15)}, 0x05e0ad4f}, {"ZLASTB Z10.D, P3, R15", "ZLASTB", ExtFormZLastReg, 0, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtGeneral(15)}, 0x05e1ad4f}, } { in := extInstructionMeta(t, tt.mnem, tt.form, tt.qual, tt.arr) got, err := in.Encode(tt.ops) if err != nil { t.Errorf("%s: encode: %v", tt.name, err) continue } if want := hex.EncodeToString(extWordLE(tt.want)); hex.EncodeToString(got) != want { t.Errorf("%s:\n got %x\n want %s", tt.name, got, want) } } } // TestArm64ExtStage3Golden pins the stage-three families, the SVE2 crypto // group (the multi-precision carry steps, the SHA3 rotate, SM4 and AES), the // predicate counters and loop terminators (CNTP, the DECP and INCP steps, // the saturating variants and CTERM), the 32-bit while compares, and the SVE // reductions into a SIMD register (ANDV, EORV, ORV, SADDV, UADDV, the maxima // and minima, the floating-point sums and FADDA). Every row is one // arm64sveenc.s line and the want word is that line's own encoding, the // same provenance as the families above: the toolchain encoding table and // its generated corpus, both produced from Arm's official ISA description. func TestArm64ExtStage3Golden(t *testing.T) { for _, tt := range []struct { name string mnem string form ExtForm arr ExtArrangement ops []ExtOperand want uint32 }{ // The crypto family: Zm, Zn, Zd over a locked arrangement. {"ZADCLB Z7.D, Z23.D, Z13.D", "ZADCLB", ExtFormVectorsZm, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x4547d2ed}, {"ZADCLT Z7.D, Z23.D, Z13.D", "ZADCLT", ExtFormVectorsZm, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x4547d6ed}, {"ZSBCLB Z7.D, Z23.D, Z13.D", "ZSBCLB", ExtFormVectorsZm, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x45c7d2ed}, {"ZSBCLT Z7.D, Z23.D, Z13.D", "ZSBCLT", ExtFormVectorsZm, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x45c7d6ed}, {"ZRAX1 Z7.D, Z6.D, Z23.D", "ZRAX1", ExtFormVectorsZm, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrD), ExtVector(23, ExtArrD)}, 0x4527f4d7}, {"ZSM4EKEY Z7.S, Z6.S, Z23.S", "ZSM4EKEY", ExtFormVectorsZm, ExtArrS, []ExtOperand{ExtVector(7, ExtArrS), ExtVector(6, ExtArrS), ExtVector(23, ExtArrS)}, 0x4527f0d7}, {"ZSM4E Z7.S, Z6.S, Z6.S", "ZSM4E", ExtFormZReadBack, ExtArrS, []ExtOperand{ExtVector(7, ExtArrS), ExtVector(6, ExtArrS), ExtVector(6, ExtArrS)}, 0x4523e0e6}, {"ZAESD Z7.B, Z6.B, Z6.B", "ZAESD", ExtFormZReadBack, ExtArrB, []ExtOperand{ExtVector(7, ExtArrB), ExtVector(6, ExtArrB), ExtVector(6, ExtArrB)}, 0x4522e4e6}, {"ZAESE Z7.B, Z6.B, Z6.B", "ZAESE", ExtFormZReadBack, ExtArrB, []ExtOperand{ExtVector(7, ExtArrB), ExtVector(6, ExtArrB), ExtVector(6, ExtArrB)}, 0x4522e0e6}, {"ZAESIMC Z11.B, Z11.B", "ZAESIMC", ExtFormZSameReg, ExtArrB, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(11, ExtArrB)}, 0x4520e40b}, {"ZAESMC Z11.B, Z11.B", "ZAESMC", ExtFormZSameReg, ExtArrB, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(11, ExtArrB)}, 0x4520e00b}, // The terminators and counters. {"CTERMEQ ZR, R25", "CTERMEQ", ExtFormCTerm, ExtArrNone, []ExtOperand{ExtZeroRegister(), ExtGeneral(25)}, 0x25ff2320}, {"CTERMEQW ZR, R25", "CTERMEQW", ExtFormCTerm, ExtArrNone, []ExtOperand{ExtZeroRegister(), ExtGeneral(25)}, 0x25bf2320}, {"CTERMNE ZR, R25", "CTERMNE", ExtFormCTerm, ExtArrNone, []ExtOperand{ExtZeroRegister(), ExtGeneral(25)}, 0x25ff2330}, {"CTERMNEW ZR, R25", "CTERMNEW", ExtFormCTerm, ExtArrNone, []ExtOperand{ExtZeroRegister(), ExtGeneral(25)}, 0x25bf2330}, {"PCNTP P2.B, P14, R2", "PCNTP", ExtFormCountP, ExtArrNone, []ExtOperand{ExtPredicateSized(2, ExtArrB), ExtPredicateSized(14, ExtArrNone), ExtGeneral(2)}, 0x2520b842}, {"PFIRSTP P2.B, P14, R2", "PFIRSTP", ExtFormCountP, ExtArrNone, []ExtOperand{ExtPredicateSized(2, ExtArrB), ExtPredicateSized(14, ExtArrNone), ExtGeneral(2)}, 0x2521b842}, {"PLASTP P2.B, P14, R2", "PLASTP", ExtFormCountP, ExtArrNone, []ExtOperand{ExtPredicateSized(2, ExtArrB), ExtPredicateSized(14, ExtArrNone), ExtGeneral(2)}, 0x2522b842}, {"PDECP P14.S, ZR", "PDECP", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25ad89df}, {"ZDECP P14.S, Z26.S", "ZDECP", ExtFormCountPnVec, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtVector(26, ExtArrS)}, 0x25ad81da}, {"PINCP P14.S, ZR", "PINCP", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25ac89df}, {"PSQDECP P14.S, ZR", "PSQDECP", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25aa8ddf}, {"PSQINCP P14.S, ZR", "PSQINCP", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25a88ddf}, {"PUQDECP P14.S, ZR", "PUQDECP", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25ab8ddf}, {"PUQINCP P14.S, ZR", "PUQINCP", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25a98ddf}, {"PUQDECPW P14.S, ZR", "PUQDECPW", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25ab89df}, {"PUQINCPW P14.S, ZR", "PUQINCPW", ExtFormCountPn, ExtArrNone, []ExtOperand{ExtPredicateSized(14, ExtArrS), ExtZeroRegister()}, 0x25a989df}, {"PSQDECPW R8, P10.D, R8", "PSQDECPW", ExtFormCountPnW, ExtArrNone, []ExtOperand{ExtGeneral(8), ExtPredicateSized(10, ExtArrD), ExtGeneral(8)}, 0x25ea8948}, {"PSQINCPW R8, P10.D, R8", "PSQINCPW", ExtFormCountPnW, ExtArrNone, []ExtOperand{ExtGeneral(8), ExtPredicateSized(10, ExtArrD), ExtGeneral(8)}, 0x25e88948}, {"PWHILEGEW R2, R10, P10.H", "PWHILEGEW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562014a}, {"PWHILEGTW R2, R10, P10.H", "PWHILEGTW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562015a}, {"PWHILEHIW R2, R10, P10.H", "PWHILEHIW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562095a}, {"PWHILEHSW R2, R10, P10.H", "PWHILEHSW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562094a}, {"PWHILELEW R2, R10, P10.H", "PWHILELEW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562055a}, {"PWHILELOW R2, R10, P10.H", "PWHILELOW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x25620d4a}, {"PWHILELSW R2, R10, P10.H", "PWHILELSW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x25620d5a}, {"PWHILELTW R2, R10, P10.H", "PWHILELTW", ExtFormWhile, ExtArrNone, []ExtOperand{ExtGeneral(2), ExtGeneral(10), ExtPredicateSized(10, ExtArrH)}, 0x2562054a}, // The reductions. {"ZSADDVD Z6.B, P3, V2", "ZSADDVD", ExtFormReduce, ExtArrNone, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x04002cc2}, {"ZSADDVD Z6.D, P3, V2", "ZSADDVD", ExtFormReduce, ExtArrNone, []ExtOperand{ExtVector(6, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x04c02cc2}, {"ZUADDVD Z10.D, P3, V15", "ZUADDVD", ExtFormReduce, ExtArrNone, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04c12d4f}, {"ZUADDVD Z10.B, P3, V15", "ZUADDVD", ExtFormReduce, ExtArrNone, []ExtOperand{ExtVector(10, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04012d4f}, {"ZANDVB Z6.B, P3, V2", "ZANDVB", ExtFormReduce, ExtArrB, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x041a2cc2}, {"ZANDVH Z3.H, P1, V29", "ZANDVH", ExtFormReduce, ExtArrH, []ExtOperand{ExtVector(3, ExtArrH), ExtPredicateSized(1, ExtArrNone), ExtSIMD(29)}, 0x045a247d}, {"ZANDVS Z17.S, P1, V27", "ZANDVS", ExtFormReduce, ExtArrS, []ExtOperand{ExtVector(17, ExtArrS), ExtPredicateSized(1, ExtArrNone), ExtSIMD(27)}, 0x049a263b}, {"ZANDVD Z10.D, P3, V15", "ZANDVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04da2d4f}, {"ZEORVB Z6.B, P3, V2", "ZEORVB", ExtFormReduce, ExtArrB, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x04192cc2}, {"ZEORVD Z10.D, P3, V15", "ZEORVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04d92d4f}, {"ZORVB Z6.B, P3, V2", "ZORVB", ExtFormReduce, ExtArrB, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x04182cc2}, {"ZORVD Z10.D, P3, V15", "ZORVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04d82d4f}, {"ZSMAXVB Z6.B, P3, V2", "ZSMAXVB", ExtFormReduce, ExtArrB, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x04082cc2}, {"ZSMAXVH Z3.H, P1, V29", "ZSMAXVH", ExtFormReduce, ExtArrH, []ExtOperand{ExtVector(3, ExtArrH), ExtPredicateSized(1, ExtArrNone), ExtSIMD(29)}, 0x0448247d}, {"ZSMAXVS Z17.S, P1, V27", "ZSMAXVS", ExtFormReduce, ExtArrS, []ExtOperand{ExtVector(17, ExtArrS), ExtPredicateSized(1, ExtArrNone), ExtSIMD(27)}, 0x0488263b}, {"ZSMAXVD Z10.D, P3, V15", "ZSMAXVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04c82d4f}, {"ZSMINVB Z6.B, P3, V2", "ZSMINVB", ExtFormReduce, ExtArrB, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x040a2cc2}, {"ZSMINVD Z10.D, P3, V15", "ZSMINVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04ca2d4f}, {"ZUMAXVB Z6.B, P3, V2", "ZUMAXVB", ExtFormReduce, ExtArrB, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x04092cc2}, {"ZUMAXVD Z10.D, P3, V15", "ZUMAXVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04c92d4f}, {"ZUMINVB Z6.B, P3, V2", "ZUMINVB", ExtFormReduce, ExtArrB, []ExtOperand{ExtVector(6, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtSIMD(2)}, 0x040b2cc2}, {"ZUMINVD Z10.D, P3, V15", "ZUMINVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x04cb2d4f}, {"ZFADDVH Z3.H, P1, V29", "ZFADDVH", ExtFormReduce, ExtArrH, []ExtOperand{ExtVector(3, ExtArrH), ExtPredicateSized(1, ExtArrNone), ExtSIMD(29)}, 0x6540247d}, {"ZFADDVS Z17.S, P1, V27", "ZFADDVS", ExtFormReduce, ExtArrS, []ExtOperand{ExtVector(17, ExtArrS), ExtPredicateSized(1, ExtArrNone), ExtSIMD(27)}, 0x6580263b}, {"ZFADDVD Z10.D, P3, V15", "ZFADDVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x65c02d4f}, {"ZFMAXNMVH Z3.H, P1, V29", "ZFMAXNMVH", ExtFormReduce, ExtArrH, []ExtOperand{ExtVector(3, ExtArrH), ExtPredicateSized(1, ExtArrNone), ExtSIMD(29)}, 0x6544247d}, {"ZFMAXNMVD Z10.D, P3, V15", "ZFMAXNMVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x65c42d4f}, {"ZFMAXVH Z3.H, P1, V29", "ZFMAXVH", ExtFormReduce, ExtArrH, []ExtOperand{ExtVector(3, ExtArrH), ExtPredicateSized(1, ExtArrNone), ExtSIMD(29)}, 0x6546247d}, {"ZFMAXVD Z10.D, P3, V15", "ZFMAXVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x65c62d4f}, {"ZFMINNMVH Z3.H, P1, V29", "ZFMINNMVH", ExtFormReduce, ExtArrH, []ExtOperand{ExtVector(3, ExtArrH), ExtPredicateSized(1, ExtArrNone), ExtSIMD(29)}, 0x6545247d}, {"ZFMINNMVD Z10.D, P3, V15", "ZFMINNMVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x65c52d4f}, {"ZFMINVH Z3.H, P1, V29", "ZFMINVH", ExtFormReduce, ExtArrH, []ExtOperand{ExtVector(3, ExtArrH), ExtPredicateSized(1, ExtArrNone), ExtSIMD(29)}, 0x6547247d}, {"ZFMINVD Z10.D, P3, V15", "ZFMINVD", ExtFormReduce, ExtArrD, []ExtOperand{ExtVector(10, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtSIMD(15)}, 0x65c72d4f}, {"ZFADDAH Z8.H, V15, P2, V15", "ZFADDAH", ExtFormReduceReadBack, ExtArrH, []ExtOperand{ExtVector(8, ExtArrH), ExtSIMD(15), ExtPredicateSized(2, ExtArrNone), ExtSIMD(15)}, 0x6558290f}, {"ZFADDAS Z26.S, V30, P7, V30", "ZFADDAS", ExtFormReduceReadBack, ExtArrS, []ExtOperand{ExtVector(26, ExtArrS), ExtSIMD(30), ExtPredicateSized(7, ExtArrNone), ExtSIMD(30)}, 0x65983f5e}, {"ZFADDAD Z9.D, V10, P2, V10", "ZFADDAD", ExtFormReduceReadBack, ExtArrD, []ExtOperand{ExtVector(9, ExtArrD), ExtSIMD(10), ExtPredicateSized(2, ExtArrNone), ExtSIMD(10)}, 0x65d8292a}, } { in := extInstructionMeta(t, tt.mnem, tt.form, ExtQualNone, tt.arr) got, err := in.Encode(tt.ops) if err != nil { t.Errorf("%s: encode: %v", tt.name, err) continue } if want := hex.EncodeToString(extWordLE(tt.want)); hex.EncodeToString(got) != want { t.Errorf("%s:\n got %x\n want %s", tt.name, got, want) } } } // TestArm64ExtStage4Golden pins the SVE2.1 narrowing two-to-one family // (ZADDHNB and friends) against the toolchain-generated corpus, the same // provenance as the families above: every row is one arm64sveenc.s line and // the want word is that line's own encoding, with two extra vectors pinning // the widths the corpus line does not show (.H over .B, .D over .S). func TestArm64ExtStage4Golden(t *testing.T) { for _, tt := range []struct { name string mnem string form ExtForm qual ExtQualifier arr ExtArrangement ops []ExtOperand want uint32 }{ {"ZADDHNB Z22.S, Z10.S, Z8.H", "ZADDHNB", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b66148}, {"ZADDHNT Z22.S, Z10.S, Z8.H", "ZADDHNT", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b66548}, {"ZRADDHNB Z22.S, Z10.S, Z8.H", "ZRADDHNB", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b66948}, {"ZRADDHNT Z22.S, Z10.S, Z8.H", "ZRADDHNT", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b66d48}, {"ZRSUBHNB Z22.S, Z10.S, Z8.H", "ZRSUBHNB", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b67948}, {"ZRSUBHNT Z22.S, Z10.S, Z8.H", "ZRSUBHNT", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b67d48}, {"ZSUBHNB Z22.S, Z10.S, Z8.H", "ZSUBHNB", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b67148}, {"ZSUBHNT Z22.S, Z10.S, Z8.H", "ZSUBHNT", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(22, ExtArrS), ExtVector(10, ExtArrS), ExtVector(8, ExtArrH)}, 0x45b67548}, {"ZADDHNB Z8.H, Z10.H, Z11.B", "ZADDHNB", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(8, ExtArrH), ExtVector(10, ExtArrH), ExtVector(11, ExtArrB)}, 0x4568614b}, {"ZSUBHNT Z26.D, Z4.D, Z13.S", "ZSUBHNT", ExtFormNarrow, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(26, ExtArrD), ExtVector(4, ExtArrD), ExtVector(13, ExtArrS)}, 0x45fa748d}, // The pairwise and quadword-reduction classes. {"ZADDP Z15.B, Z0.B, P3.M, Z0.B", "ZADDP", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicate(3, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x4411ade0}, {"ZADDP Z9.S, Z2.S, P5.M, Z2.S", "ZADDP", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(9, ExtArrS), ExtVector(2, ExtArrS), ExtPredicate(5, ExtQualMerging), ExtVector(2, ExtArrS)}, 0x4491b522}, {"ZADDPT Z23.D, Z13.D, P1.M, Z13.D", "ZADDPT", ExtFormZPredicatedSource, ExtQualMerging, ExtArrD, []ExtOperand{ExtVector(23, ExtArrD), ExtVector(13, ExtArrD), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrD)}, 0x04c406ed}, {"ZADDPT Z7.D, Z6.D, Z23.D", "ZADDPT", ExtFormVectorsZm, ExtQualNone, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrD), ExtVector(23, ExtArrD)}, 0x04e708d7}, // The quadword reductions, one vector per class word, the corpus // line shared, plus a .D width the corpus line does not show. {"ZADDQV Z25.S, P3, V5.S4", "ZADDQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x04852f25}, {"ZADDQV Z9.D, P1, V7.D2", "ZADDQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(9, ExtArrD), ExtPredicateSized(1, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 7, Arr: ExtArrD}}, 0x04c52527}, {"ZANDQV Z25.S, P3, V5.S4", "ZANDQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x049e2f25}, {"ZEORQV Z25.S, P3, V5.S4", "ZEORQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x049d2f25}, {"ZORQV Z25.S, P3, V5.S4", "ZORQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x049c2f25}, {"ZSMAXQV Z25.S, P3, V5.S4", "ZSMAXQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x048c2f25}, {"ZSMINQV Z25.S, P3, V5.S4", "ZSMINQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x048e2f25}, {"ZUMAXQV Z25.S, P3, V5.S4", "ZUMAXQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x048d2f25}, {"ZUMINQV Z25.S, P3, V5.S4", "ZUMINQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x048f2f25}, {"ZFADDQV Z25.S, P3, V5.S4", "ZFADDQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x6490af25}, {"ZFMAXNMQV Z25.S, P3, V5.S4", "ZFMAXNMQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x6494af25}, {"ZFMAXQV Z25.S, P3, V5.S4", "ZFMAXQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x6496af25}, {"ZFMINNMQV Z25.S, P3, V5.S4", "ZFMINNMQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x6495af25}, {"ZFMINQV Z25.S, P3, V5.S4", "ZFMINQV", ExtFormQuadReduce, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(25, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtVReg, Reg: 5, Arr: ExtArrS}}, 0x6497af25}, // The shift-by-vector family. {"ZASR Z15.B, Z0.B, P3.M, Z0.B", "ZASR", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicate(3, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04108de0}, {"ZASR Z2.D, Z10.D, P3.M, Z10.D", "ZASR", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(2, ExtArrD), ExtVector(10, ExtArrD), ExtPredicate(3, ExtQualMerging), ExtVector(10, ExtArrD)}, 0x04d08c4a}, {"ZASR Z7.D, Z6.H, Z13.H", "ZASR", ExtFormShiftWide, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrH), ExtVector(13, ExtArrH)}, 0x046780cd}, {"ZASRR Z15.B, Z0.B, P3.M, Z0.B", "ZASRR", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicate(3, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04148de0}, {"ZLSL Z2.D, Z10.D, P3.M, Z10.D", "ZLSL", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(2, ExtArrD), ExtVector(10, ExtArrD), ExtPredicate(3, ExtQualMerging), ExtVector(10, ExtArrD)}, 0x04d38c4a}, {"ZLSL Z7.D, Z6.H, Z13.H", "ZLSL", ExtFormShiftWide, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrH), ExtVector(13, ExtArrH)}, 0x04678ccd}, {"ZLSLR Z15.B, Z0.B, P3.M, Z0.B", "ZLSLR", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicate(3, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04178de0}, {"ZLSR Z15.B, Z0.B, P3.M, Z0.B", "ZLSR", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicate(3, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04118de0}, {"ZLSR Z7.D, Z6.H, Z13.H", "ZLSR", ExtFormShiftWide, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(6, ExtArrH), ExtVector(13, ExtArrH)}, 0x046784cd}, {"ZLSRR Z15.B, Z0.B, P3.M, Z0.B", "ZLSRR", ExtFormZPredicatedSource, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicate(3, ExtQualMerging), ExtVector(0, ExtArrB)}, 0x04158de0}, // The three-source and bitwise combine families. {"ZBCAX Z23.D, Z13.D, Z21.D, Z21.D", "ZBCAX", ExtFormThreeSource, ExtQualNone, ExtArrD, []ExtOperand{ExtVector(23, ExtArrD), ExtVector(13, ExtArrD), ExtVector(21, ExtArrD), ExtVector(21, ExtArrD)}, 0x046d3af5}, {"ZEOR3 Z23.D, Z13.D, Z21.D, Z21.D", "ZEOR3", ExtFormThreeSource, ExtQualNone, ExtArrD, []ExtOperand{ExtVector(23, ExtArrD), ExtVector(13, ExtArrD), ExtVector(21, ExtArrD), ExtVector(21, ExtArrD)}, 0x042d3af5}, {"ZBSL Z23.D, Z13.D, Z21.D, Z21.D", "ZBSL", ExtFormThreeSource, ExtQualNone, ExtArrD, []ExtOperand{ExtVector(23, ExtArrD), ExtVector(13, ExtArrD), ExtVector(21, ExtArrD), ExtVector(21, ExtArrD)}, 0x042d3ef5}, {"ZBSL1N Z23.D, Z13.D, Z21.D, Z21.D", "ZBSL1N", ExtFormThreeSource, ExtQualNone, ExtArrD, []ExtOperand{ExtVector(23, ExtArrD), ExtVector(13, ExtArrD), ExtVector(21, ExtArrD), ExtVector(21, ExtArrD)}, 0x046d3ef5}, {"ZBSL2N Z23.D, Z13.D, Z21.D, Z21.D", "ZBSL2N", ExtFormThreeSource, ExtQualNone, ExtArrD, []ExtOperand{ExtVector(23, ExtArrD), ExtVector(13, ExtArrD), ExtVector(21, ExtArrD), ExtVector(21, ExtArrD)}, 0x04ad3ef5}, {"ZNBSL Z23.D, Z13.D, Z21.D, Z21.D", "ZNBSL", ExtFormThreeSource, ExtQualNone, ExtArrD, []ExtOperand{ExtVector(23, ExtArrD), ExtVector(13, ExtArrD), ExtVector(21, ExtArrD), ExtVector(21, ExtArrD)}, 0x04ed3ef5}, {"ZBDEP Z7.D, Z23.D, Z13.D", "ZBDEP", ExtFormVectorsZm, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x45c7b6ed}, {"ZBEXT Z7.D, Z23.D, Z13.D", "ZBEXT", ExtFormVectorsZm, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x45c7b2ed}, {"ZBGRP Z7.D, Z23.D, Z13.D", "ZBGRP", ExtFormVectorsZm, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x45c7baed}, {"ZEORBT Z7.D, Z23.D, Z13.D", "ZEORBT", ExtFormVectorsZm, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x45c792ed}, {"ZEORTB Z7.D, Z23.D, Z13.D", "ZEORTB", ExtFormVectorsZm, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(7, ExtArrD), ExtVector(23, ExtArrD), ExtVector(13, ExtArrD)}, 0x45c796ed}, // The BFloat16 arithmetic core, halfwords throughout. {"ZBF1CVT Z11.B, Z6.H", "ZBF1CVT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65083966}, {"ZBF1CVTLT Z11.B, Z6.H", "ZBF1CVTLT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65093966}, {"ZBF2CVT Z11.B, Z6.H", "ZBF2CVT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65083d66}, {"ZBF2CVTLT Z11.B, Z6.H", "ZBF2CVTLT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65093d66}, {"ZF1CVT Z11.B, Z6.H", "ZF1CVT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65083166}, {"ZF1CVTLT Z11.B, Z6.H", "ZF1CVTLT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65093166}, {"ZF2CVT Z11.B, Z6.H", "ZF2CVT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65083566}, {"ZF2CVTLT Z11.B, Z6.H", "ZF2CVTLT", ExtFormZUnpack, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(11, ExtArrB), ExtVector(6, ExtArrH)}, 0x65093566}, {"ZBFADD Z23.H, Z13.H, P1.M, Z13.H", "ZBFADD", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650086ed}, {"ZBFADD Z7.H, Z6.H, Z23.H", "ZBFADD", ExtFormVectorsZm, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrH)}, 0x650700d7}, {"ZBFCLAMP Z7.H, Z6.H, Z23.H", "ZBFCLAMP", ExtFormVectorsZm, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrH)}, 0x642724d7}, {"ZBFMAX Z23.H, Z13.H, P1.M, Z13.H", "ZBFMAX", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650686ed}, {"ZBFMAXNM Z23.H, Z13.H, P1.M, Z13.H", "ZBFMAXNM", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650486ed}, {"ZBFMIN Z23.H, Z13.H, P1.M, Z13.H", "ZBFMIN", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650786ed}, {"ZBFMINNM Z23.H, Z13.H, P1.M, Z13.H", "ZBFMINNM", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650586ed}, {"ZBFMUL Z23.H, Z13.H, P1.M, Z13.H", "ZBFMUL", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650286ed}, {"ZBFMUL Z7.H, Z6.H, Z23.H", "ZBFMUL", ExtFormVectorsZm, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrH)}, 0x650708d7}, {"ZBFSUB Z23.H, Z13.H, P1.M, Z13.H", "ZBFSUB", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650186ed}, {"ZBFSUB Z7.H, Z6.H, Z23.H", "ZBFSUB", ExtFormVectorsZm, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrH)}, 0x650704d7}, // The rest of the BFloat16 wall. {"ZBFCVT Z13.S, P1.M, Z22.H", "ZBFCVT", ExtFormConvert, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(13, ExtArrS), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrH)}, 0x658aa5b6}, {"ZBFCVT Z13.S, P1.Z, Z22.H", "ZBFCVT", ExtFormConvert, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(13, ExtArrS), ExtPredicate(1, ExtQualZeroing), ExtVector(22, ExtArrH)}, 0x649ac5b6}, {"ZBFDOT Z7.H, Z6.H, Z23.S", "ZBFDOT", ExtFormLongMul, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrS)}, 0x646780d7}, {"ZBFMLA Z23.H, Z13.H, P1.M, Z22.H", "ZBFMLA", ExtFormMulPred, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrH)}, 0x653705b6}, {"ZBFMLALB Z7.H, Z6.H, Z23.S", "ZBFMLALB", ExtFormLongMul, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrS)}, 0x64e780d7}, {"ZBFMMLA Z7.H, Z6.H, Z23.S", "ZBFMMLA", ExtFormLongMul, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrS)}, 0x6467e4d7}, {"ZBFSCALE Z23.H, Z13.H, P1.M, Z13.H", "ZBFSCALE", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650986ed}, // The multiple-structure loads and stores. {"ZLD2B (R6)(R14), P4.Z, [Z13.B, Z14.B]", "ZLD2B", ExtFormSveLoad, ExtQualNone, ExtArrB, []ExtOperand{ExtSveMemPair(6, 0, 14, false), ExtPredicate(4, ExtQualZeroing), ExtOperand{Kind: ExtZReg, Reg: 13, Arr: ExtArrB, List: 2}}, 0xa426d1cd}, {"ZLD4D (R6<<3)(R14), P4.Z, [Z13.D, Z14.D, Z15.D, Z16.D]", "ZLD4D", ExtFormSveLoad, ExtQualNone, ExtArrD, []ExtOperand{ExtSveMemPair(6, 3, 14, false), ExtPredicate(4, ExtQualZeroing), ExtOperand{Kind: ExtZReg, Reg: 13, Arr: ExtArrD, List: 4}}, 0xa5e6d1cd}, {"ZST2Q [Z8.Q, Z9.Q], P3, (R6<<4)(RSP)", "ZST2Q", ExtFormSveStore, ExtQualNone, ExtArrQ, []ExtOperand{ExtOperand{Kind: ExtZReg, Reg: 8, Arr: ExtArrQ, List: 2}, ExtPredicateSized(3, ExtArrNone), ExtSveMemPair(6, 4, 31, true)}, 0xe4660fe8}, // The rest of the BFloat16 wall. {"ZBFCVT Z13.S, P1.M, Z22.H", "ZBFCVT", ExtFormConvert, ExtQualMerging, ExtArrNone, []ExtOperand{ExtVector(13, ExtArrS), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrH)}, 0x658aa5b6}, {"ZBFCVT Z13.S, P1.Z, Z22.H", "ZBFCVT", ExtFormConvert, ExtQualZeroing, ExtArrNone, []ExtOperand{ExtVector(13, ExtArrS), ExtPredicate(1, ExtQualZeroing), ExtVector(22, ExtArrH)}, 0x649ac5b6}, {"ZBFDOT Z7.H, Z6.H, Z23.S", "ZBFDOT", ExtFormLongMul, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrS)}, 0x646780d7}, {"ZBFMLA Z23.H, Z13.H, P1.M, Z22.H", "ZBFMLA", ExtFormMulPred, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrH)}, 0x653705b6}, {"ZBFMLALB Z7.H, Z6.H, Z23.S", "ZBFMLALB", ExtFormLongMul, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrS)}, 0x64e780d7}, {"ZBFMMLA Z7.H, Z6.H, Z23.S", "ZBFMMLA", ExtFormLongMul, ExtQualNone, ExtArrH, []ExtOperand{ExtVector(7, ExtArrH), ExtVector(6, ExtArrH), ExtVector(23, ExtArrS)}, 0x6467e4d7}, {"ZBFSCALE Z23.H, Z13.H, P1.M, Z13.H", "ZBFSCALE", ExtFormZPredicatedSource, ExtQualMerging, ExtArrH, []ExtOperand{ExtVector(23, ExtArrH), ExtVector(13, ExtArrH), ExtPredicate(1, ExtQualMerging), ExtVector(13, ExtArrH)}, 0x650986ed}, // The last-active vector shape and the compares to a predicate. {"ZCLASTA Z15.B, Z0.B, P3, Z0.B", "ZCLASTA", ExtFormZPredicatedSource, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtVector(0, ExtArrB)}, 0x05288de0}, {"ZCLASTB Z15.B, Z0.B, P3, Z0.B", "ZCLASTB", ExtFormZPredicatedSource, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(15, ExtArrB), ExtVector(0, ExtArrB), ExtPredicateSized(3, ExtArrNone), ExtVector(0, ExtArrB)}, 0x05298de0}, {"ZCMPEQ Z0.H, Z2.H, P0.Z, P14.H", "ZCMPEQ", ExtFormCompare, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(0, ExtArrH), ExtVector(2, ExtArrH), ExtPredicate(0, ExtQualZeroing), ExtPredicateSized(14, ExtArrH)}, 0x2440a04e}, {"ZCMPEQ Z0.D, Z12.S, P0.Z, P14.S", "ZCMPEQ", ExtFormCompareWide, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(0, ExtArrD), ExtVector(12, ExtArrS), ExtPredicate(0, ExtQualZeroing), ExtPredicateSized(14, ExtArrS)}, 0x2480218e}, {"ZCMPHS Z0.H, Z2.H, P0.Z, P14.H", "ZCMPHS", ExtFormCompare, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(0, ExtArrH), ExtVector(2, ExtArrH), ExtPredicate(0, ExtQualZeroing), ExtPredicateSized(14, ExtArrH)}, 0x2440004e}, {"ZCMPNE Z0.D, Z12.S, P0.Z, P14.S", "ZCMPNE", ExtFormCompareWide, ExtQualNone, ExtArrNone, []ExtOperand{ExtVector(0, ExtArrD), ExtVector(12, ExtArrS), ExtPredicate(0, ExtQualZeroing), ExtPredicateSized(14, ExtArrS)}, 0x2480219e}, // The vector-length arithmetic. {"ADDPL $9, R11, RSP", "ADDPL", ExtFormVLArith, ExtQualNone, ExtArrNone, []ExtOperand{ExtImmediate(9), ExtGeneral(11), ExtStackPointer()}, 0x046b513f}, {"ADDVL $9, R11, RSP", "ADDVL", ExtFormVLArith, ExtQualNone, ExtArrNone, []ExtOperand{ExtImmediate(9), ExtGeneral(11), ExtStackPointer()}, 0x042b513f}, {"RDVL $1, R27", "RDVL", ExtFormVLRead, ExtQualNone, ExtArrNone, []ExtOperand{ExtImmediate(1), ExtGeneral(27)}, 0x04bf503b}, } { in := extInstructionMeta(t, tt.mnem, tt.form, tt.qual, tt.arr) got, err := in.Encode(tt.ops) if err != nil { t.Errorf("%s: encode: %v", tt.name, err) continue } if want := hex.EncodeToString(extWordLE(tt.want)); hex.EncodeToString(got) != want { t.Errorf("%s:\n got %x\n want %s", tt.name, got, want) } } } // extSveRow finds the gather/scatter row whose mnemonic, addressing mode, // base size, shift and list arrangement all match. func extSveRow(t *testing.T, mnem string, mode uint8, shift int, base, arr ExtArrangement) ExtInstr { t.Helper() for _, in := range Extensions(ARM64) { if in.Name == mnem && in.Form.Arity() == 3 && in.SveMode == mode && in.SveShift == shift && in.SveBase == base && in.Arr == arr { return in } } t.Fatalf("no extended %s with mode %d, shift %d, base %s and list %s", mnem, mode, shift, base, arr) return ExtInstr{} } // TestArm64ExtShiftImmGolden pins the shift-immediate classes against the // toolchain-generated corpus at the metadata layer: the narrowing and // widening three-vector shifts and the predicated saturating left shifts. // Every row is one arm64sveenc.s line and the want word is that line's own // encoding; the amount's tsz:imm3 split is derived in the encoders, right // shifts taking C = 2 x esize - amount over the destination's element size // and left shifts C = esize + amount over the source's (or the // destination's own, in the predicated class). func TestArm64ExtShiftImmGolden(t *testing.T) { for _, tt := range []struct { name string mnem string form ExtForm ops []ExtOperand want uint32 }{ // The narrowing family, one corpus line each over .S+.H. {"ZSHRNB $9, Z7.S, Z23.H", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453710f7}, {"ZSHRNT $9, Z7.S, Z23.H", "ZSHRNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453714f7}, {"ZRSHRNB $9, Z7.S, Z23.H", "ZRSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453718f7}, {"ZRSHRNT $9, Z7.S, Z23.H", "ZRSHRNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x45371cf7}, {"ZSQSHRNB $9, Z7.S, Z23.H", "ZSQSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453720f7}, {"ZSQSHRNT $9, Z7.S, Z23.H", "ZSQSHRNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453724f7}, {"ZSQRSHRNB $9, Z7.S, Z23.H", "ZSQRSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453728f7}, {"ZSQRSHRNT $9, Z7.S, Z23.H", "ZSQRSHRNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x45372cf7}, {"ZSQSHRUNB $9, Z7.S, Z23.H", "ZSQSHRUNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453700f7}, {"ZSQSHRUNT $9, Z7.S, Z23.H", "ZSQSHRUNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453704f7}, {"ZUQSHRNB $9, Z7.S, Z23.H", "ZUQSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453730f7}, {"ZUQSHRNT $9, Z7.S, Z23.H", "ZUQSHRNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453734f7}, {"ZUQRSHRNB $9, Z7.S, Z23.H", "ZUQRSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x453738f7}, {"ZUQRSHRNT $9, Z7.S, Z23.H", "ZUQRSHRNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, 0x45373cf7}, // The width extensions the corpus does not carry: .H+.B and .D+.S, // derived the same way and pinned to the words the fields give. {"ZSHRNB $8, Z6.H, Z22.B", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(8), ExtVector(6, ExtArrH), ExtVector(22, ExtArrB)}, 0x452810d6}, {"ZSQSHRNT $16, Z5.D, Z4.S", "ZSQSHRNT", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(16), ExtVector(5, ExtArrD), ExtVector(4, ExtArrS)}, 0x457024a4}, // The widening family, one corpus line each over .S+.D. {"ZSSHLLB $5, Z22.S, Z10.D", "ZSSHLLB", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(5), ExtVector(22, ExtArrS), ExtVector(10, ExtArrD)}, 0x4545a2ca}, {"ZSSHLLT $5, Z22.S, Z10.D", "ZSSHLLT", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(5), ExtVector(22, ExtArrS), ExtVector(10, ExtArrD)}, 0x4545a6ca}, {"ZUSHLLB $5, Z22.S, Z10.D", "ZUSHLLB", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(5), ExtVector(22, ExtArrS), ExtVector(10, ExtArrD)}, 0x4545aaca}, {"ZUSHLLT $5, Z22.S, Z10.D", "ZUSHLLT", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(5), ExtVector(22, ExtArrS), ExtVector(10, ExtArrD)}, 0x4545aeca}, {"ZSSHLLB $0, Z3.B, Z2.H", "ZSSHLLB", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(0), ExtVector(3, ExtArrB), ExtVector(2, ExtArrH)}, 0x4508a062}, // The predicated saturating left shifts, one corpus line each. {"ZSQSHL $6, Z23.B, P1.M, Z23.B", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, 0x040685d7}, {"ZSQSHLU $6, Z23.B, P1.M, Z23.B", "ZSQSHLU", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, 0x040f85d7}, {"ZUQSHL $6, Z23.B, P1.M, Z23.B", "ZUQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, 0x040785d7}, {"ZSQSHL $20, Z8.S, P4.M, Z8.S", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(20), ExtVector(8, ExtArrS), ExtPredicate(4, ExtQualMerging), ExtVector(8, ExtArrS)}, 0x04469288}, // The same-size right shifts, the accumulator and the extract. {"ZSRI $6, Z7.D, Z23.D", "ZSRI", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, 0x45daf0f7}, {"ZSSRA $6, Z7.D, Z23.D", "ZSSRA", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, 0x45dae0f7}, {"ZUSRA $6, Z7.D, Z23.D", "ZUSRA", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, 0x45dae4f7}, {"ZSRSRA $6, Z7.D, Z23.D", "ZSRSRA", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, 0x45dae8f7}, {"ZURSRA $6, Z7.D, Z23.D", "ZURSRA", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, 0x45daecf7}, {"ZASR $6, Z7.D, Z23.D", "ZASR", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, 0x04fa90f7}, {"ZASR $6, Z23.B, P1.M, Z23.B", "ZASR", ExtFormShiftImmPredRight, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, 0x04008557}, {"ZASRD $6, Z23.B, P1.M, Z23.B", "ZASRD", ExtFormShiftImmPredRight, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, 0x04048557}, {"ZXAR $6, Z23.B, Z21.B, Z21.B", "ZXAR", ExtFormShiftImmXar, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtVector(21, ExtArrB), ExtVector(21, ExtArrB)}, 0x042a36f5}, } { in := extInstructionMeta(t, tt.mnem, tt.form, 0, ExtArrNone) got, err := in.Encode(tt.ops) if err != nil { t.Errorf("%s: encode: %v", tt.name, err) continue } if want := hex.EncodeToString(extWordLE(tt.want)); hex.EncodeToString(got) != want { t.Errorf("%s:\n got %x\n want %s", tt.name, got, want) } } } // TestArm64ExtShiftImmRejects pins the diagnostics the shift-immediate // forms give: the element-step pairs the classes take, the amount ranges // and the read-back and qualifier rules of the predicated class. func TestArm64ExtShiftImmRejects(t *testing.T) { for _, tt := range []struct { name string mnem string form ExtForm ops []ExtOperand quote string }{ {"source not one step wide", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrD), ExtVector(23, ExtArrH)}, "one element step below .D"}, {"destination not one step narrow", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrS), ExtVector(23, ExtArrS)}, "one element step below"}, {"byte source", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(9), ExtVector(7, ExtArrB), ExtVector(23, ExtArrB)}, "want .H, .S or .D"}, {"amount over the destination element", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(17), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, "outside the range 1..16"}, {"amount zero on a right shift", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtImmediate(0), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, "outside the range 1..16"}, {"LSL spelling refused", "ZSHRNB", ExtFormShiftImmNarrow, []ExtOperand{ExtShiftedImmediate(9, 8), ExtVector(7, ExtArrS), ExtVector(23, ExtArrH)}, "takes no LSL shift"}, {"source not one step narrow", "ZSSHLLB", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(5), ExtVector(22, ExtArrS), ExtVector(10, ExtArrS)}, "one element step above .S"}, {"destination not one step wide", "ZSSHLLB", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(5), ExtVector(22, ExtArrS), ExtVector(10, ExtArrQ)}, "one element step above"}, {"amount over the source element", "ZSSHLLB", ExtFormShiftImmWide, []ExtOperand{ExtImmediate(32), ExtVector(22, ExtArrS), ExtVector(10, ExtArrD)}, "outside the range 0..31"}, {"zeroing qualifier", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualZeroing), ExtVector(23, ExtArrB)}, "/M"}, {"destination read-back mismatch", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(22, ExtArrB)}, "the same register Zdn"}, {"destination arrangement mismatch", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrH)}, "the same register Zdn"}, {"quadword has no size encoding", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrQ), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrQ)}, "no size encoding"}, {"amount over the element size", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(8), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, "outside the range 1..7"}, {"amount zero", "ZSQSHL", ExtFormShiftImmPred, []ExtOperand{ExtImmediate(0), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, "outside the range 1..7"}, {"same-size arrangements differ", "ZSRI", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(6), ExtVector(7, ExtArrB), ExtVector(23, ExtArrH)}, "must match"}, {"same-size amount zero", "ZSRI", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(0), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, "outside the range 1..63"}, {"same-size amount at the element size", "ZSRI", ExtFormShiftImmSame, []ExtOperand{ExtImmediate(64), ExtVector(7, ExtArrD), ExtVector(23, ExtArrD)}, "outside the range 1..63"}, {"predicated right amount at the element size", "ZASR", ExtFormShiftImmPredRight, []ExtOperand{ExtImmediate(8), ExtVector(23, ExtArrB), ExtPredicate(1, ExtQualMerging), ExtVector(23, ExtArrB)}, "outside the range 1..7"}, {"extract read-back mismatch", "ZXAR", ExtFormShiftImmXar, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtVector(21, ExtArrB), ExtVector(20, ExtArrB)}, "the same register Zdn"}, {"extract arrangements differ", "ZXAR", ExtFormShiftImmXar, []ExtOperand{ExtImmediate(6), ExtVector(23, ExtArrB), ExtVector(21, ExtArrH), ExtVector(21, ExtArrH)}, "must match"}, } { in := extInstruction(t, tt.mnem, tt.form) _, err := in.Encode(tt.ops) if err == nil { t.Errorf("%s: encode succeeded, want an error", tt.name) continue } if !strings.Contains(err.Error(), tt.quote) { t.Errorf("%s: error %q lacks %q", tt.name, err, tt.quote) } } } // TestArm64ExtGatherGolden pins the gather/scatter family against the // toolchain-generated corpus at the metadata layer: one row per addressing // mode, the want word that corpus line's own encoding. The asm-level // TestArm64AssembleExtensionGatherGolden pins every corpus line of the // scope end to end; these rows prove the forms and the operand builders // the registry exposes. func TestArm64ExtGatherGolden(t *testing.T) { for _, tt := range []struct { name string mnem string mode uint8 shift int base ExtArrangement arr ExtArrangement ops []ExtOperand want uint32 }{ {"ZLD1B (R6)(R14), P4.Z, [Z13.B]", "ZLD1B", extMemPair, 0, ExtArrNone, ExtArrB, []ExtOperand{ExtSveMemPair(6, 0, 14, false), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrB)}, 0xa40651cd}, {"ZLD1H (R6<<1)(R14), P4.Z, [Z13.H]", "ZLD1H", extMemPair, 1, ExtArrNone, ExtArrH, []ExtOperand{ExtSveMemPair(6, 1, 14, false), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrH)}, 0xa4a651cd}, {"ZLD1B (Z10.D)(R19), P3.Z, [Z15.D]", "ZLD1B", extMemVecOff, 0, ExtArrD, ExtArrD, []ExtOperand{ExtSveMemVector(10, ExtArrD, 0, 19), ExtPredicate(3, ExtQualZeroing), ExtVector(15, ExtArrD)}, 0xc44ace6f}, {"ZLD1D (Z23.D<<3)(R24), P1.Z, [Z22.D]", "ZLD1D", extMemVecOff, 3, ExtArrD, ExtArrD, []ExtOperand{ExtSveMemVector(23, ExtArrD, 3, 24), ExtPredicate(1, ExtQualZeroing), ExtVector(22, ExtArrD)}, 0xc5f7c716}, {"ZLD1H (Z4.S.UXTW<<1)(R3), P3.Z, [Z4.S]", "ZLD1H", extMemExt32, 1, ExtArrS, ExtArrS, []ExtOperand{ExtSveMemExtended(4, false, 1, 3), ExtPredicate(3, ExtQualZeroing), ExtVector(4, ExtArrS)}, 0x84a44c64}, {"ZLD1SB (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", "ZLD1SB", extMemExt32, 0, ExtArrS, ExtArrS, []ExtOperand{ExtSveMemExtended(4, false, 0, 3), ExtPredicate(3, ExtQualZeroing), ExtVector(4, ExtArrS)}, 0x84040c64}, {"ZLD1B 6(Z7.S), P4.Z, [Z13.S]", "ZLD1B", extMemImm, 0, ExtArrS, ExtArrS, []ExtOperand{ExtSveMemImmediate(7, ExtArrS, 6), ExtPredicate(4, ExtQualZeroing), ExtVector(13, ExtArrS)}, 0x8426d0ed}, {"ZLD1D 8(Z14.D), P6.Z, [Z6.D]", "ZLD1D", extMemImm, 3, ExtArrD, ExtArrD, []ExtOperand{ExtSveMemImmediate(14, ExtArrD, 8), ExtPredicate(6, ExtQualZeroing), ExtVector(6, ExtArrD)}, 0xc5a1d9c6}, {"ZLDFF1SW 12(Z0.D), P6.Z, [Z25.D]", "ZLDFF1SW", extMemImm, 2, ExtArrD, ExtArrD, []ExtOperand{ExtSveMemImmediate(0, ExtArrD, 12), ExtPredicate(6, ExtQualZeroing), ExtVector(25, ExtArrD)}, 0xc523b819}, {"ZST1B [Z7.D], P4, (R21)(R7)", "ZST1B", extMemPair, 0, ExtArrNone, ExtArrD, []ExtOperand{ExtVector(7, ExtArrD), ExtPredicateSized(4, ExtArrNone), ExtSveMemPair(21, 0, 7, false)}, 0xe47550e7}, {"ZST1D [Z8.D], P3, (Z6.D)(RSP)", "ZST1D", extMemVecOff, 0, ExtArrD, ExtArrD, []ExtOperand{ExtVector(8, ExtArrD), ExtPredicateSized(3, ExtArrNone), ExtOperand{Kind: ExtSveMem, Reg: 6, Arr: ExtArrD, Off: 31, Reg31: 2, BaseVec: true}}, 0xe586afe8}, {"ZST1W [Z16.D], P2, (Z5.D)", "ZST1W", extMemVecBase, 0, ExtArrD, ExtArrD, []ExtOperand{ExtVector(16, ExtArrD), ExtPredicateSized(2, ExtArrNone), ExtSveMemVector(5, ExtArrD, 0, -1)}, 0xe540a8b0}, {"ZST1H [Z8.S], P3, 6(Z15.S)", "ZST1H", extMemImm, 1, ExtArrS, ExtArrS, []ExtOperand{ExtVector(8, ExtArrS), ExtPredicateSized(3, ExtArrNone), ExtSveMemImmediate(15, ExtArrS, 6)}, 0xe4e3ade8}, } { mode := tt.mode in := extSveRow(t, tt.mnem, mode, tt.shift, tt.base, tt.arr) got, err := in.Encode(tt.ops) if err != nil { t.Errorf("%s: encode: %v", tt.name, err) continue } if want := hex.EncodeToString(extWordLE(tt.want)); hex.EncodeToString(got) != want { t.Errorf("%s:\n got %x\n want %s", tt.name, got, want) } } }