feat(arch): the shift-immediate tsz:imm3 scheme
Assisted-by: GLM 5.3 Flash
This commit is contained in:
1 parent
718181e7a7
commit
eda8b16c5f
4 files changed
+555
-2
No files matched your search
@@ -134,6 +134,12 @@ func (a ExtArrangement) Width() int {
|
||||
}
|
||||
}
|
||||
|
||||
// elemBits returns the arrangement's element size in bits, the scale the
|
||||
// shift-immediate classes encode their amounts against.
|
||||
func (a ExtArrangement) elemBits() int {
|
||||
return a.Width() * 8
|
||||
}
|
||||
|
||||
// sizeBits maps the arrangement onto the two-bit size field the integer SVE
|
||||
// classes carry at bits 23..22: 00=B, 01=H, 10=S, 11=D. ok is false for the
|
||||
// arrangements no such class accepts (.Q and the bare spelling).
|
||||
@@ -407,6 +413,18 @@ var (
|
||||
extFieldPnc = ExtField{0, 3} // predicate-as-counter destination PN8-PN15, field holds reg-8
|
||||
extFieldPn4 = ExtField{5, 4} // predicate source P0-P15 at bits 8..5 (counter family)
|
||||
extFieldImm6 = ExtField{5, 6} // the signed imm6 of the vector-length arithmetic
|
||||
// The tsz:imm3 shift-immediate fields: the amount rides a 5..7-bit
|
||||
// integer C, split imm3 (the low three bits), a two-bit tsz chunk and
|
||||
// a one- or two-bit tsz top. The three-vector classes split into
|
||||
// bits 18..16, 20..19 and 22; the predicated class into bits 7..5,
|
||||
// 9..8 and 23..22. The tsz chunks are the arrangement's own spelling
|
||||
// and stand in for the size field these classes do not carry.
|
||||
extFieldImm3T16 = ExtField{16, 3} // the low three bits of C, three-vector classes
|
||||
extFieldTszM19 = ExtField{19, 2} // the middle tsz chunk of the three-vector classes
|
||||
extFieldTszH22 = ExtField{22, 1} // the top tsz bit of the three-vector classes
|
||||
extFieldImm3T5 = ExtField{5, 3} // the low three bits of C, predicated class
|
||||
extFieldTszM8 = ExtField{8, 2} // the middle tsz chunk of the predicated class
|
||||
extFieldTszH22W = ExtField{22, 2} // the top tsz chunk of the predicated class
|
||||
)
|
||||
|
||||
// ExtForm enumerates the operand shapes the extension layer defines, in Plan
|
||||
@@ -742,6 +760,31 @@ const (
|
||||
// destination slot, and the predicate's arrangement feeds the size
|
||||
// field.
|
||||
ExtFormCountPnVec
|
||||
// ExtFormShiftImmPred is the predicated shift by immediate, ZSQSHL
|
||||
// $6, Z23.B, P1.M, Z23.B. Operands: imm, Zdn.T, Pg/M, Zdn.T, the
|
||||
// destination spelled twice and encoded once. The amount rides the
|
||||
// class's tsz:imm3 fields: C = esize + amount, split imm3 into bits
|
||||
// 7..5, the low tsz pair into bits 9..8 and the top tsz pair into
|
||||
// bits 23..22, where the tsz bits are the arrangement's own spelling
|
||||
// and double as its size encoding; no separate size field exists.
|
||||
// The amount runs 1..esize-1 and the merging qualifier is the only
|
||||
// one the class spells.
|
||||
ExtFormShiftImmPred
|
||||
// ExtFormShiftImmNarrow is the three-vector narrowing shift by
|
||||
// immediate, ZSHRNB $9, Z7.S, Z23.H: a right shift of the wide source
|
||||
// whose result the narrow destination keeps, one element step down
|
||||
// (.H+.B, .S+.H, .D+.S). Operands: imm, Zn.Tb, Zd.T. C = 2 x esize
|
||||
// - amount over the destination's element size, split imm3 into bits
|
||||
// 18..16, the low tsz pair into bits 20..19 and the top tsz bit into
|
||||
// bit 22; the amount runs 1..esize.
|
||||
ExtFormShiftImmNarrow
|
||||
// ExtFormShiftImmWide is the three-vector widening shift by
|
||||
// immediate, ZSSHLLB $5, Z22.S, Z10.D: a left shift of the narrow
|
||||
// source into a destination one element step up (.B+.H, .H+.S,
|
||||
// .S+.D). Operands: imm, Zn.Tb, Zd.T. C = esize + amount over the
|
||||
// source's element size, split like the narrowing class; the amount
|
||||
// runs 0..esize-1.
|
||||
ExtFormShiftImmWide
|
||||
)
|
||||
|
||||
// Arity returns the operand count the form takes.
|
||||
@@ -780,6 +823,10 @@ func (f ExtForm) Arity() int {
|
||||
return 2
|
||||
case ExtFormCountPnVec:
|
||||
return 2
|
||||
case ExtFormShiftImmPred:
|
||||
return 4
|
||||
case ExtFormShiftImmNarrow, ExtFormShiftImmWide:
|
||||
return 3
|
||||
case ExtFormReduceReadBack:
|
||||
return 4
|
||||
case ExtFormSveLoad, ExtFormSveStore, ExtFormNarrow, ExtFormQuadReduce, ExtFormShiftWide,
|
||||
@@ -848,6 +895,10 @@ func (f ExtForm) Kinds() []ExtOperandKind {
|
||||
return []ExtOperandKind{ExtPReg, ExtGReg}
|
||||
case ExtFormCountPnVec:
|
||||
return []ExtOperandKind{ExtPReg, ExtZReg}
|
||||
case ExtFormShiftImmPred:
|
||||
return []ExtOperandKind{ExtImm, ExtZReg, ExtPReg, ExtZReg}
|
||||
case ExtFormShiftImmNarrow, ExtFormShiftImmWide:
|
||||
return []ExtOperandKind{ExtImm, ExtZReg, ExtZReg}
|
||||
case ExtFormCountPnW:
|
||||
return []ExtOperandKind{ExtGReg, ExtPReg, ExtGReg}
|
||||
case ExtFormReduce:
|
||||
@@ -984,6 +1035,12 @@ func (f ExtForm) String() string {
|
||||
return "counter step, result dropped"
|
||||
case ExtFormCountPnVec:
|
||||
return "counter step on a vector"
|
||||
case ExtFormShiftImmPred:
|
||||
return "predicated shift by immediate"
|
||||
case ExtFormShiftImmNarrow:
|
||||
return "narrowing shift by immediate"
|
||||
case ExtFormShiftImmWide:
|
||||
return "widening shift by immediate"
|
||||
case ExtFormCountPnW:
|
||||
return "counter step to a register"
|
||||
case ExtFormReduce:
|
||||
@@ -1260,6 +1317,12 @@ func (in ExtInstr) Encode(ops []ExtOperand) ([]byte, error) {
|
||||
return in.encodeCountPn(ops)
|
||||
case ExtFormCountPnVec:
|
||||
return in.encodeCountPnVec(ops)
|
||||
case ExtFormShiftImmPred:
|
||||
return in.encodeShiftImmPred(ops)
|
||||
case ExtFormShiftImmNarrow:
|
||||
return in.encodeShiftImmNarrow(ops)
|
||||
case ExtFormShiftImmWide:
|
||||
return in.encodeShiftImmWide(ops)
|
||||
case ExtFormCountPnW:
|
||||
return in.encodeCountPnW(ops)
|
||||
case ExtFormReduce:
|
||||
@@ -2393,6 +2456,139 @@ func (in ExtInstr) encodeCountPnVec(ops []ExtOperand) ([]byte, error) {
|
||||
return extWordLE(word), nil
|
||||
}
|
||||
|
||||
// shiftImmAmount validates the immediate shift operand against the closed
|
||||
// range lo..hi and refuses the LSL spelling, which belongs to the
|
||||
// immediate-constant classes and not to the shift-immediate ones.
|
||||
func (in ExtInstr) shiftImmAmount(op ExtOperand, position, lo, hi int) (int, error) {
|
||||
if op.Kind != ExtImm {
|
||||
return 0, fmt.Errorf("%s: operand %d wants an immediate, got %s", in.Name, position, op.Kind)
|
||||
}
|
||||
if op.HasShift {
|
||||
return 0, fmt.Errorf("%s: the shift-immediate class takes no LSL shift", in.Name)
|
||||
}
|
||||
v := int(op.Imm)
|
||||
if v < lo || v > hi {
|
||||
return 0, fmt.Errorf("%s: shift amount %d is outside the range %d..%d in this class",
|
||||
in.Name, v, lo, hi)
|
||||
}
|
||||
return v, nil
|
||||
}
|
||||
|
||||
// encodeShiftImmPred fills the predicated shift by immediate: imm, Zdn.T,
|
||||
// Pg/M, Zdn.T, the destination spelled twice and encoded once. The amount
|
||||
// rides the class's tsz:imm3 fields: C = esize + amount, split imm3 into
|
||||
// bits 7..5, the low tsz pair into bits 9..8 and the top tsz pair into
|
||||
// bits 23..22, where the tsz bits spell the arrangement and stand in for
|
||||
// the size field the class does not carry.
|
||||
func (in ExtInstr) encodeShiftImmPred(ops []ExtOperand) ([]byte, error) {
|
||||
imm, zdn, pg, zdn2 := ops[0], ops[1], ops[2], ops[3]
|
||||
if err := in.zVector(zdn, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if _, ok := zdn.Arr.sizeBits(); !ok {
|
||||
return nil, fmt.Errorf("%s: arrangement %s has no size encoding in this class",
|
||||
in.Name, zdn.Arr)
|
||||
}
|
||||
esize := zdn.Arr.elemBits()
|
||||
v, err := in.shiftImmAmount(imm, 1, 1, esize-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if err := in.predicateOperand(pg, 3, 0, 15, ExtArrNone); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if pg.Qual != ExtQualMerging {
|
||||
return nil, fmt.Errorf("%s: operand 3 wants the merging qualifier /M, got %q",
|
||||
in.Name, pg.Qual)
|
||||
}
|
||||
if err := in.zVector(zdn2, 4); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if zdn2.Reg != zdn.Reg || zdn2.Arr != zdn.Arr {
|
||||
return nil, fmt.Errorf("%s: operands 2 and 4 are the same register Zdn, got Z%d and Z%d",
|
||||
in.Name, zdn.Reg, zdn2.Reg)
|
||||
}
|
||||
c := esize + v
|
||||
word := in.Word
|
||||
word = extSet(word, extFieldImm3T5, uint32(c))
|
||||
word = extSet(word, extFieldTszM8, uint32(c>>3))
|
||||
word = extSet(word, extFieldTszH22W, uint32(c>>5))
|
||||
word = extSet(word, extFieldRd, uint32(zdn.Reg))
|
||||
word = extSet(word, extFieldPgW, uint32(pg.Reg))
|
||||
return extWordLE(word), nil
|
||||
}
|
||||
|
||||
// encodeShiftImmNarrow fills the three-vector narrowing shift by immediate:
|
||||
// imm, Zn.Tb, Zd.T, a right shift of the wide source whose result the
|
||||
// destination one element step down keeps (.H+.B, .S+.H, .D+.S). The
|
||||
// amount runs 1..esize over the destination's element size and C = 2 x
|
||||
// esize - amount, split imm3 into bits 18..16, the low tsz pair into bits
|
||||
// 20..19 and the top tsz bit into bit 22.
|
||||
func (in ExtInstr) encodeShiftImmNarrow(ops []ExtOperand) ([]byte, error) {
|
||||
imm, zn, zd := ops[0], ops[1], ops[2]
|
||||
if err := in.zVector(zn, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if zn.Arr < ExtArrH || zn.Arr > ExtArrD {
|
||||
return nil, fmt.Errorf("%s: operand 2 carries arrangement %s, want .H, .S or .D", in.Name, zn.Arr)
|
||||
}
|
||||
if err := in.zVector(zd, 3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if zd.Arr != zn.Arr-1 {
|
||||
return nil, fmt.Errorf("%s: operand 3 carries arrangement %s, want one element step below %s",
|
||||
in.Name, zd.Arr, zn.Arr)
|
||||
}
|
||||
esize := zd.Arr.elemBits()
|
||||
v, err := in.shiftImmAmount(imm, 1, 1, esize)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := 2*esize - v
|
||||
word := in.Word
|
||||
word = extSet(word, extFieldImm3T16, uint32(c))
|
||||
word = extSet(word, extFieldTszM19, uint32(c>>3))
|
||||
word = extSet(word, extFieldTszH22, uint32(c>>5))
|
||||
word = extSet(word, extFieldRn, uint32(zn.Reg))
|
||||
word = extSet(word, extFieldRd, uint32(zd.Reg))
|
||||
return extWordLE(word), nil
|
||||
}
|
||||
|
||||
// encodeShiftImmWide fills the three-vector widening shift by immediate:
|
||||
// imm, Zn.Tb, Zd.T, a left shift of the narrow source into a destination
|
||||
// one element step up (.B+.H, .H+.S, .S+.D). The amount runs
|
||||
// 0..esize-1 over the source's element size and C = esize + amount, split
|
||||
// like the narrowing class.
|
||||
func (in ExtInstr) encodeShiftImmWide(ops []ExtOperand) ([]byte, error) {
|
||||
imm, zn, zd := ops[0], ops[1], ops[2]
|
||||
if err := in.zVector(zn, 2); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if zn.Arr < ExtArrB || zn.Arr > ExtArrS {
|
||||
return nil, fmt.Errorf("%s: operand 2 carries arrangement %s, want .B, .H or .S", in.Name, zn.Arr)
|
||||
}
|
||||
if err := in.zVector(zd, 3); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if zd.Arr != zn.Arr+1 {
|
||||
return nil, fmt.Errorf("%s: operand 3 carries arrangement %s, want one element step above %s",
|
||||
in.Name, zd.Arr, zn.Arr)
|
||||
}
|
||||
esize := zn.Arr.elemBits()
|
||||
v, err := in.shiftImmAmount(imm, 1, 0, esize-1)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
c := esize + v
|
||||
word := in.Word
|
||||
word = extSet(word, extFieldImm3T16, uint32(c))
|
||||
word = extSet(word, extFieldTszM19, uint32(c>>3))
|
||||
word = extSet(word, extFieldTszH22, uint32(c>>5))
|
||||
word = extSet(word, extFieldRn, uint32(zn.Reg))
|
||||
word = extSet(word, extFieldRd, uint32(zd.Reg))
|
||||
return extWordLE(word), nil
|
||||
}
|
||||
|
||||
// encodeCountPnW fills the predicate-counter step with a scalar result:
|
||||
// Rd, Pn.T, Rd, the destination spelled twice. The predicate occupies the
|
||||
// four-bit field at bits 8..5 and its arrangement feeds the size field.
|
||||
@@ -4853,6 +5049,80 @@ var arm64Extensions = []ExtInstr{
|
||||
Word: 0xe540a000, Form: ExtFormSveStore, Arr: ExtArrD, Feature: ExtFeatureSVE,
|
||||
SveMode: extMemVecBase, SveShift: 0, SveBase: ExtArrD,
|
||||
Ref: "ARM DDI 0487J: gather/scatter (vector base alone); inst_gen.go + arm64sveenc.s"},
|
||||
// The shift-immediate classes: the SVE2 narrowing and widening
|
||||
// three-vector shifts and the predicated saturating left shifts. The
|
||||
// amount rides the class's tsz:imm3 fields, whose tsz bits double as
|
||||
// the arrangement spelling: right shifts take C = 2 x esize - amount
|
||||
// over the destination's element size, left shifts C = esize + amount
|
||||
// over the source's (or the destination's own, in the predicated
|
||||
// class), and C splits imm3, a two-bit tsz chunk and a one- or
|
||||
// two-bit tsz top. Provenance as above: the toolchain encoding table
|
||||
// and its generated corpus, both produced from Arm's official ISA
|
||||
// description, and the golden test pins every corpus line of the
|
||||
// covered classes.
|
||||
{Name: "ZSQSHRUNB", Summary: "Shift right narrowing, unsigned results from signed, bottom",
|
||||
Word: 0x45200000, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQSHRUN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSQSHRUNT", Summary: "Shift right narrowing, unsigned results from signed, top",
|
||||
Word: 0x45200400, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQSHRUN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSHRNB", Summary: "Shift right narrowing by immediate, bottom",
|
||||
Word: 0x45201000, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSHRNT", Summary: "Shift right narrowing by immediate, top",
|
||||
Word: 0x45201400, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZRSHRNB", Summary: "Rounding shift right narrowing by immediate, bottom",
|
||||
Word: 0x45201800, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: RSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZRSHRNT", Summary: "Rounding shift right narrowing by immediate, top",
|
||||
Word: 0x45201c00, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: RSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSQSHRNB", Summary: "Saturating signed shift right narrowing by immediate, bottom",
|
||||
Word: 0x45202000, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSQSHRNT", Summary: "Saturating signed shift right narrowing by immediate, top",
|
||||
Word: 0x45202400, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSQRSHRNB", Summary: "Saturating rounding signed shift right narrowing by immediate, bottom",
|
||||
Word: 0x45202800, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQRSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSQRSHRNT", Summary: "Saturating rounding signed shift right narrowing by immediate, top",
|
||||
Word: 0x45202c00, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQRSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZUQSHRNB", Summary: "Saturating unsigned shift right narrowing by immediate, bottom",
|
||||
Word: 0x45203000, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: UQSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZUQSHRNT", Summary: "Saturating unsigned shift right narrowing by immediate, top",
|
||||
Word: 0x45203400, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: UQSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZUQRSHRNB", Summary: "Saturating rounding unsigned shift right narrowing by immediate, bottom",
|
||||
Word: 0x45203800, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: UQRSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZUQRSHRNT", Summary: "Saturating rounding unsigned shift right narrowing by immediate, top",
|
||||
Word: 0x45203c00, Form: ExtFormShiftImmNarrow, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: UQRSHRN (narrowing, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSSHLLB", Summary: "Signed shift left widening by immediate, bottom",
|
||||
Word: 0x4500a000, Form: ExtFormShiftImmWide, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SSHLL (widening, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSSHLLT", Summary: "Signed shift left widening by immediate, top",
|
||||
Word: 0x4500a400, Form: ExtFormShiftImmWide, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SSHLL (widening, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZUSHLLB", Summary: "Unsigned shift left widening by immediate, bottom",
|
||||
Word: 0x4500a800, Form: ExtFormShiftImmWide, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: USHLL (widening, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZUSHLLT", Summary: "Unsigned shift left widening by immediate, top",
|
||||
Word: 0x4500ac00, Form: ExtFormShiftImmWide, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: USHLL (widening, immediate); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSQSHL", Summary: "Saturating signed shift left by immediate, over a governing predicate",
|
||||
Word: 0x04068000, Form: ExtFormShiftImmPred, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQSHL (immediate, predicated); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZSQSHLU", Summary: "Saturating signed shift left by immediate, unsigned bases, over a governing predicate",
|
||||
Word: 0x040f8000, Form: ExtFormShiftImmPred, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: SQSHLU (immediate, predicated); inst_gen.go + arm64sveenc.s"},
|
||||
{Name: "ZUQSHL", Summary: "Saturating unsigned shift left by immediate, over a governing predicate",
|
||||
Word: 0x04078000, Form: ExtFormShiftImmPred, Feature: ExtFeatureSVE2,
|
||||
Ref: "ARM DDI 0487J SVE2: UQSHL (immediate, predicated); inst_gen.go + arm64sveenc.s"},
|
||||
}
|
||||
|
||||
// Extensions returns the extended-instruction layer registered for a, outside
|
||||
|
||||
@@ -1683,6 +1683,184 @@ func extSveRow(t *testing.T, mnem string, mode uint8, shift int, base, arr ExtAr
|
||||
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},
|
||||
} {
|
||||
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"},
|
||||
} {
|
||||
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
|
||||
|
||||
@@ -956,3 +956,84 @@ func TestArm64AssembleExtensionGatherRefusals(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionShiftImmGolden drives the shift-immediate
|
||||
// classes through the full assembler: every corpus line of the three
|
||||
// families, corpus text in, corpus word out. The narrowing and widening
|
||||
// three-vector shifts and the predicated saturating left shifts carry the
|
||||
// amount in the class's tsz:imm3 fields, whose tsz bits double as the
|
||||
// arrangement spelling.
|
||||
func TestArm64AssembleExtensionShiftImmGolden(t *testing.T) {
|
||||
tests := []struct {
|
||||
stmt string
|
||||
want uint32
|
||||
}{
|
||||
{"ZSHRNB $9, Z7.S, Z23.H", 0x453710f7},
|
||||
{"ZSHRNT $9, Z7.S, Z23.H", 0x453714f7},
|
||||
{"ZRSHRNB $9, Z7.S, Z23.H", 0x453718f7},
|
||||
{"ZRSHRNT $9, Z7.S, Z23.H", 0x45371cf7},
|
||||
{"ZSQSHRNB $9, Z7.S, Z23.H", 0x453720f7},
|
||||
{"ZSQSHRNT $9, Z7.S, Z23.H", 0x453724f7},
|
||||
{"ZSQRSHRNB $9, Z7.S, Z23.H", 0x453728f7},
|
||||
{"ZSQRSHRNT $9, Z7.S, Z23.H", 0x45372cf7},
|
||||
{"ZSQSHRUNB $9, Z7.S, Z23.H", 0x453700f7},
|
||||
{"ZSQSHRUNT $9, Z7.S, Z23.H", 0x453704f7},
|
||||
{"ZUQSHRNB $9, Z7.S, Z23.H", 0x453730f7},
|
||||
{"ZUQSHRNT $9, Z7.S, Z23.H", 0x453734f7},
|
||||
{"ZUQRSHRNB $9, Z7.S, Z23.H", 0x453738f7},
|
||||
{"ZUQRSHRNT $9, Z7.S, Z23.H", 0x45373cf7},
|
||||
{"ZSSHLLB $5, Z22.S, Z10.D", 0x4545a2ca},
|
||||
{"ZSSHLLT $5, Z22.S, Z10.D", 0x4545a6ca},
|
||||
{"ZUSHLLB $5, Z22.S, Z10.D", 0x4545aaca},
|
||||
{"ZUSHLLT $5, Z22.S, Z10.D", 0x4545aeca},
|
||||
{"ZSQSHL $6, Z23.B, P1.M, Z23.B", 0x040685d7},
|
||||
{"ZSQSHLU $6, Z23.B, P1.M, Z23.B", 0x040f85d7},
|
||||
{"ZUQSHL $6, Z23.B, P1.M, Z23.B", 0x040785d7},
|
||||
// Width extensions beyond the corpus lines.
|
||||
{"ZSHRNB $8, Z6.H, Z22.B", 0x452810d6},
|
||||
{"ZSQSHRNT $16, Z5.D, Z4.S", 0x457024a4},
|
||||
{"ZSSHLLB $0, Z3.B, Z2.H", 0x4508a062},
|
||||
{"ZSQSHL $20, Z8.S, P4.M, Z8.S", 0x04469288},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
words := assembleArm64Words(t, arm64ExtProbeHead+"\t"+tt.stmt+"\n\tRET\n")
|
||||
if len(words) != 2 {
|
||||
t.Fatalf("%s: got %d words, want the statement and RET", tt.stmt, len(words))
|
||||
}
|
||||
if words[0] != tt.want {
|
||||
t.Errorf("%s:\n got %08x\n want %08x", tt.stmt, words[0], tt.want)
|
||||
}
|
||||
if words[1] != 0xd65f03c0 {
|
||||
t.Errorf("%s: RET encoded %08x", tt.stmt, words[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionShiftImmRefusals pins the diagnostics the
|
||||
// shift-immediate statements get from the layer: the element-step pairs
|
||||
// the classes take, the amount ranges and the read-back and qualifier
|
||||
// rules of the predicated class.
|
||||
func TestArm64AssembleExtensionShiftImmRefusals(t *testing.T) {
|
||||
tests := []struct {
|
||||
stmt string
|
||||
want string
|
||||
}{
|
||||
{"ZSHRNB $9, Z7.S, Z23.S", "one element step below"},
|
||||
{"ZSHRNB $9, Z7.S, Z23.B", "one element step below"},
|
||||
{"ZSHRNB $17, Z7.S, Z23.H", "outside the range 1..16"},
|
||||
{"ZSHRNB $0, Z7.S, Z23.H", "outside the range 1..16"},
|
||||
{"ZSHRNB $9, LSL #8, Z7.S, Z23.H", "takes no LSL shift"},
|
||||
{"ZSSHLLB $32, Z22.S, Z10.D", "outside the range 0..31"},
|
||||
{"ZSSHLLB $5, Z22.S, Z10.Q", "one element step above .S"},
|
||||
{"ZSQSHL $6, Z23.B, P1.Z, Z23.B", "/M"},
|
||||
{"ZSQSHL $6, Z23.B, P1.M, Z22.B", "the same register Zdn"},
|
||||
{"ZSQSHL $6, Z23.Q, P1.M, Z23.Q", "no size encoding"},
|
||||
{"ZSQSHL $8, Z23.B, P1.M, Z23.B", "outside the range 1..7"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
got := assembleArm64SrcError(t, arm64ExtProbeHead+"\t"+tt.stmt+"\n\tRET\n")
|
||||
if !strings.Contains(got, tt.want) {
|
||||
t.Errorf("%s: error %q does not name %q", tt.stmt, got, tt.want)
|
||||
}
|
||||
}
|
||||
}
|
||||
+26
-2
@@ -492,12 +492,36 @@ func TestExtensionNamesARM64(t *testing.T) {
|
||||
"ZST1D",
|
||||
"ZST1H",
|
||||
"ZST1W",
|
||||
// The shift-immediate classes: the narrowing and widening
|
||||
// three-vector shifts and the predicated saturating left shifts,
|
||||
// in first-occurrence order.
|
||||
"ZSQSHRUNB",
|
||||
"ZSQSHRUNT",
|
||||
"ZSHRNB",
|
||||
"ZSHRNT",
|
||||
"ZRSHRNB",
|
||||
"ZRSHRNT",
|
||||
"ZSQSHRNB",
|
||||
"ZSQSHRNT",
|
||||
"ZSQRSHRNB",
|
||||
"ZSQRSHRNT",
|
||||
"ZUQSHRNB",
|
||||
"ZUQSHRNT",
|
||||
"ZUQRSHRNB",
|
||||
"ZUQRSHRNT",
|
||||
"ZSSHLLB",
|
||||
"ZSSHLLT",
|
||||
"ZUSHLLB",
|
||||
"ZUSHLLT",
|
||||
"ZSQSHL",
|
||||
"ZSQSHLU",
|
||||
"ZUQSHL",
|
||||
}
|
||||
got := ExtensionNames(arch.ARM64)
|
||||
if strings.Join(got, ",") != strings.Join(want, ",") {
|
||||
t.Errorf("ExtensionNames(ARM64) = %v, want %v", got, want)
|
||||
}
|
||||
if n := len(arch.Extensions(arch.ARM64)); n != 507 {
|
||||
t.Errorf("the family registers %d instructions, want 507", n)
|
||||
if n := len(arch.Extensions(arch.ARM64)); n != 528 {
|
||||
t.Errorf("the family registers %d instructions, want 528", n)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user