feat(asm): encode the arm64 SVE gather loads and scatter stores
Assisted-by: GLM 5.3
This commit is contained in:
1 parent
6faf850793
commit
104bea036b
5 files changed
+1273
-2
No files matched your search
@@ -79,6 +79,20 @@ func arm64ExtStatement(mnem string, ops []*ast.Operand) (extops []arch.ExtOperan
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
// The gather/scatter destination list, [Z13.B]: one scalable vector
|
||||
// in brackets, its arrangement part of the instruction's identity.
|
||||
if strings.HasPrefix(text, "[") && strings.HasSuffix(text, "]") {
|
||||
if ext, ok := arm64ExtVector(strings.Trim(text, "[]")); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
}
|
||||
// The gather/scatter memory operand: a parenthesised register pair,
|
||||
// an immediate-offset base or a lone vector base.
|
||||
if ext, ok := arm64ExtSveMem(text); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
}
|
||||
if ext, ok := arm64ExtVector(text); ok {
|
||||
out = append(out, ext)
|
||||
continue
|
||||
@@ -285,6 +299,122 @@ func arm64ExtSIMD(text string) (arch.ExtOperand, bool) {
|
||||
return arch.ExtOperand{Kind: arch.ExtVReg, Reg: reg}, true
|
||||
}
|
||||
|
||||
// arm64ExtSveMem parses the gather/scatter memory operand off a normalised
|
||||
// operand text: the parenthesised pair (R6)(R14), (Z23.D<<1)(R24) and
|
||||
// (Z4.S.UXTW)(R3), the immediate-offset base 6(Z7.S), and the lone vector
|
||||
// base (Z5.D) of the stores. The second parenthesis accepts the
|
||||
// stack-pointer spelling RSP; the ranges and the mode's own rules are left
|
||||
// to the encoding, whose diagnostics name them.
|
||||
func arm64ExtSveMem(text string) (arch.ExtOperand, bool) {
|
||||
// The immediate-offset spelling: digits straight before the parenthesis.
|
||||
if i := strings.IndexByte(text, '('); i > 0 && i == strings.LastIndexByte(text, '(') {
|
||||
disp, err := strconv.ParseUint(text[:i], 10, 32)
|
||||
if err == nil && strings.HasSuffix(text, ")") {
|
||||
op, ok := arm64ExtSveMemGroup(text[i+1 : len(text)-1])
|
||||
if !ok {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
if !op.BaseVec || op.Extend != 0 || op.Shift != 0 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Imm = int64(disp)
|
||||
return op, true
|
||||
}
|
||||
}
|
||||
// The parenthesised forms: one group or two.
|
||||
rest, ok := strings.CutPrefix(text, "(")
|
||||
if !ok || !strings.HasSuffix(text, ")") {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
rest = rest[:len(rest)-1]
|
||||
first := rest
|
||||
op := arch.ExtOperand{Off: -1}
|
||||
if base, second, found := strings.Cut(rest, ")("); found {
|
||||
first = base
|
||||
off, ok := arm64ExtSveMemOffset(second)
|
||||
if !ok {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op = off
|
||||
}
|
||||
group, ok := arm64ExtSveMemGroup(first)
|
||||
if !ok {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
group.Off = op.Off
|
||||
group.Reg31 = op.Reg31
|
||||
return group, true
|
||||
}
|
||||
|
||||
// arm64ExtSveMemGroup parses one parenthesised memory register: R6, R6<<3,
|
||||
// Z23.D, Z23.D<<1, Z4.S.UXTW or Z7.D.SXTW. The general registers run
|
||||
// R0-R30 and the scalable vectors Z0-Z31 with an .S or .D element size and
|
||||
// an optional UXTW or SXTW extension; the ranges are left to the encoding.
|
||||
func arm64ExtSveMemGroup(text string) (arch.ExtOperand, bool) {
|
||||
op := arch.ExtOperand{Kind: arch.ExtSveMem, Off: -1}
|
||||
if base, shift, found := strings.Cut(text, "<<"); found {
|
||||
n, err := strconv.Atoi(shift)
|
||||
if err != nil || n < 0 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Shift = n
|
||||
text = base
|
||||
}
|
||||
parts := strings.Split(text, ".")
|
||||
switch parts[0][0] {
|
||||
case 'R':
|
||||
reg, err := strconv.Atoi(parts[0][1:])
|
||||
if err != nil || len(parts) != 1 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Reg = reg
|
||||
case 'Z':
|
||||
reg, err := strconv.Atoi(parts[0][1:])
|
||||
if err != nil || len(parts) < 2 || len(parts) > 3 {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
switch parts[1] {
|
||||
case "S":
|
||||
op.Arr = arch.ExtArrS
|
||||
case "D":
|
||||
op.Arr = arch.ExtArrD
|
||||
default:
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
op.Reg = reg
|
||||
op.BaseVec = true
|
||||
if len(parts) == 3 {
|
||||
switch parts[2] {
|
||||
case "UXTW":
|
||||
op.Extend = 1
|
||||
case "SXTW":
|
||||
op.Extend = 2
|
||||
default:
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
}
|
||||
default:
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
return op, true
|
||||
}
|
||||
|
||||
// arm64ExtSveMemOffset parses the second parenthesis of a gather/scatter
|
||||
// memory operand: a plain R0-R30 or the stack-pointer spelling RSP.
|
||||
func arm64ExtSveMemOffset(text string) (arch.ExtOperand, bool) {
|
||||
if text == "RSP" {
|
||||
return arch.ExtOperand{Off: 31, Reg31: 2}, true
|
||||
}
|
||||
if len(text) < 2 || text[0] != 'R' {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
reg, err := strconv.Atoi(text[1:])
|
||||
if err != nil {
|
||||
return arch.ExtOperand{}, false
|
||||
}
|
||||
return arch.ExtOperand{Off: reg}, true
|
||||
}
|
||||
|
||||
// arm64ExtRegDigits parses the digits and optional arrangement suffix of a
|
||||
// register spelling once the letter prefix is gone.
|
||||
func arm64ExtRegDigits(text string) (reg int, arr arch.ExtArrangement, ok bool) {
|
||||
|
||||
@@ -562,3 +562,212 @@ func TestArm64AssembleExtensionStage3Refusals(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionGatherGolden drives the gather/scatter family
|
||||
// through the full assembler: every corpus line of the scope the layer
|
||||
// covers, corpus text in, corpus word out. The scope is the plain,
|
||||
// sign-extended and first-fault loads and the stores over the core
|
||||
// addressing modes: the two-general-register pair, the vector base with a
|
||||
// general offset, the extended 32-bit offsets, the immediate offset on a
|
||||
// vector base and the lone vector base of the stores.
|
||||
func TestArm64AssembleExtensionGatherGolden(t *testing.T) {
|
||||
tests := []struct {
|
||||
stmt string
|
||||
want uint32
|
||||
}{
|
||||
{"ZLD1B (R6)(R14), P4.Z, [Z13.B]", 0xa40651cd},
|
||||
{"ZLD1B (R6)(R14), P4.Z, [Z13.H]", 0xa42651cd},
|
||||
{"ZLD1B (R6)(R14), P4.Z, [Z13.S]", 0xa44651cd},
|
||||
{"ZLD1B (R6)(R14), P4.Z, [Z13.D]", 0xa46651cd},
|
||||
{"ZLD1B (Z10.D)(R19), P3.Z, [Z15.D]", 0xc44ace6f},
|
||||
{"ZLD1B (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84044c64},
|
||||
{"ZLD1B (Z6.D)(R14), P4.Z, [Z13.D]", 0xc446d1cd},
|
||||
{"ZLD1D (R6<<3)(R14), P4.Z, [Z13.D]", 0xa5e651cd},
|
||||
{"ZLD1D (R6<<3)(R14), P4.Z, [Z13.Q]", 0xa58691cd},
|
||||
{"ZLD1D (Z23.D<<3)(R24), P1.Z, [Z22.D]", 0xc5f7c716},
|
||||
{"ZLD1D (Z10.D)(R19), P3.Z, [Z15.D]", 0xc5cace6f},
|
||||
{"ZLD1D (Z6.D<<3)(R14), P4.Z, [Z13.D]", 0xc5e6d1cd},
|
||||
{"ZLD1D (Z6.D)(R14), P4.Z, [Z13.D]", 0xc5c6d1cd},
|
||||
{"ZLD1H (R6<<1)(R14), P4.Z, [Z13.H]", 0xa4a651cd},
|
||||
{"ZLD1H (R6<<1)(R14), P4.Z, [Z13.S]", 0xa4c651cd},
|
||||
{"ZLD1H (R6<<1)(R14), P4.Z, [Z13.D]", 0xa4e651cd},
|
||||
{"ZLD1H (Z4.S.UXTW<<1)(R3), P3.Z, [Z4.S]", 0x84a44c64},
|
||||
{"ZLD1H (Z23.D<<1)(R24), P1.Z, [Z22.D]", 0xc4f7c716},
|
||||
{"ZLD1H (Z10.D)(R19), P3.Z, [Z15.D]", 0xc4cace6f},
|
||||
{"ZLD1H (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84844c64},
|
||||
{"ZLD1H (Z6.D<<1)(R14), P4.Z, [Z13.D]", 0xc4e6d1cd},
|
||||
{"ZLD1H (Z6.D)(R14), P4.Z, [Z13.D]", 0xc4c6d1cd},
|
||||
{"ZLD1SB (R6)(R14), P4.Z, [Z13.H]", 0xa5c651cd},
|
||||
{"ZLD1SB (R6)(R14), P4.Z, [Z13.S]", 0xa5a651cd},
|
||||
{"ZLD1SB (R6)(R14), P4.Z, [Z13.D]", 0xa58651cd},
|
||||
{"ZLD1SB (Z10.D)(R19), P3.Z, [Z15.D]", 0xc44a8e6f},
|
||||
{"ZLD1SB (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84040c64},
|
||||
{"ZLD1SB (Z6.D)(R14), P4.Z, [Z13.D]", 0xc44691cd},
|
||||
{"ZLD1SH (R6<<1)(R14), P4.Z, [Z13.S]", 0xa52651cd},
|
||||
{"ZLD1SH (R6<<1)(R14), P4.Z, [Z13.D]", 0xa50651cd},
|
||||
{"ZLD1SH (Z4.S.UXTW<<1)(R3), P3.Z, [Z4.S]", 0x84a40c64},
|
||||
{"ZLD1SH (Z23.D<<1)(R24), P1.Z, [Z22.D]", 0xc4f78716},
|
||||
{"ZLD1SH (Z10.D)(R19), P3.Z, [Z15.D]", 0xc4ca8e6f},
|
||||
{"ZLD1SH (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84840c64},
|
||||
{"ZLD1SH (Z6.D<<1)(R14), P4.Z, [Z13.D]", 0xc4e691cd},
|
||||
{"ZLD1SH (Z6.D)(R14), P4.Z, [Z13.D]", 0xc4c691cd},
|
||||
{"ZLD1SW (R6<<2)(R14), P4.Z, [Z13.D]", 0xa48651cd},
|
||||
{"ZLD1SW (Z23.D<<2)(R24), P1.Z, [Z22.D]", 0xc5778716},
|
||||
{"ZLD1SW (Z10.D)(R19), P3.Z, [Z15.D]", 0xc54a8e6f},
|
||||
{"ZLD1SW (Z6.D<<2)(R14), P4.Z, [Z13.D]", 0xc56691cd},
|
||||
{"ZLD1SW (Z6.D)(R14), P4.Z, [Z13.D]", 0xc54691cd},
|
||||
{"ZLD1W (R6<<2)(R14), P4.Z, [Z13.S]", 0xa54651cd},
|
||||
{"ZLD1W (R6<<2)(R14), P4.Z, [Z13.D]", 0xa56651cd},
|
||||
{"ZLD1W (R6<<2)(R14), P4.Z, [Z13.Q]", 0xa50691cd},
|
||||
{"ZLD1W (Z4.S.UXTW<<2)(R3), P3.Z, [Z4.S]", 0x85244c64},
|
||||
{"ZLD1W (Z23.D<<2)(R24), P1.Z, [Z22.D]", 0xc577c716},
|
||||
{"ZLD1W (Z10.D)(R19), P3.Z, [Z15.D]", 0xc54ace6f},
|
||||
{"ZLD1W (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x85044c64},
|
||||
{"ZLD1W (Z6.D<<2)(R14), P4.Z, [Z13.D]", 0xc566d1cd},
|
||||
{"ZLD1W (Z6.D)(R14), P4.Z, [Z13.D]", 0xc546d1cd},
|
||||
{"ZLDFF1B (R6)(R14), P4.Z, [Z13.B]", 0xa40671cd},
|
||||
{"ZLDFF1B (R6)(R14), P4.Z, [Z13.H]", 0xa42671cd},
|
||||
{"ZLDFF1B (R6)(R14), P4.Z, [Z13.S]", 0xa44671cd},
|
||||
{"ZLDFF1B (R6)(R14), P4.Z, [Z13.D]", 0xa46671cd},
|
||||
{"ZLDFF1B (Z10.D)(R19), P3.Z, [Z15.D]", 0xc44aee6f},
|
||||
{"ZLDFF1B (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84046c64},
|
||||
{"ZLDFF1B (Z6.D)(R14), P4.Z, [Z13.D]", 0xc446f1cd},
|
||||
{"ZLDFF1D (R6<<3)(R14), P4.Z, [Z13.D]", 0xa5e671cd},
|
||||
{"ZLDFF1D (Z23.D<<3)(R24), P1.Z, [Z22.D]", 0xc5f7e716},
|
||||
{"ZLDFF1D (Z10.D)(R19), P3.Z, [Z15.D]", 0xc5caee6f},
|
||||
{"ZLDFF1D (Z6.D<<3)(R14), P4.Z, [Z13.D]", 0xc5e6f1cd},
|
||||
{"ZLDFF1D (Z6.D)(R14), P4.Z, [Z13.D]", 0xc5c6f1cd},
|
||||
{"ZLDFF1H (R6<<1)(R14), P4.Z, [Z13.H]", 0xa4a671cd},
|
||||
{"ZLDFF1H (R6<<1)(R14), P4.Z, [Z13.S]", 0xa4c671cd},
|
||||
{"ZLDFF1H (R6<<1)(R14), P4.Z, [Z13.D]", 0xa4e671cd},
|
||||
{"ZLDFF1H (Z4.S.UXTW<<1)(R3), P3.Z, [Z4.S]", 0x84a46c64},
|
||||
{"ZLDFF1H (Z23.D<<1)(R24), P1.Z, [Z22.D]", 0xc4f7e716},
|
||||
{"ZLDFF1H (Z10.D)(R19), P3.Z, [Z15.D]", 0xc4caee6f},
|
||||
{"ZLDFF1H (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84846c64},
|
||||
{"ZLDFF1H (Z6.D<<1)(R14), P4.Z, [Z13.D]", 0xc4e6f1cd},
|
||||
{"ZLDFF1H (Z6.D)(R14), P4.Z, [Z13.D]", 0xc4c6f1cd},
|
||||
{"ZLDFF1SB (R6)(R14), P4.Z, [Z13.H]", 0xa5c671cd},
|
||||
{"ZLDFF1SB (R6)(R14), P4.Z, [Z13.S]", 0xa5a671cd},
|
||||
{"ZLDFF1SB (R6)(R14), P4.Z, [Z13.D]", 0xa58671cd},
|
||||
{"ZLDFF1SB (Z10.D)(R19), P3.Z, [Z15.D]", 0xc44aae6f},
|
||||
{"ZLDFF1SB (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84042c64},
|
||||
{"ZLDFF1SB (Z6.D)(R14), P4.Z, [Z13.D]", 0xc446b1cd},
|
||||
{"ZLDFF1SH (R6<<1)(R14), P4.Z, [Z13.S]", 0xa52671cd},
|
||||
{"ZLDFF1SH (R6<<1)(R14), P4.Z, [Z13.D]", 0xa50671cd},
|
||||
{"ZLDFF1SH (Z4.S.UXTW<<1)(R3), P3.Z, [Z4.S]", 0x84a42c64},
|
||||
{"ZLDFF1SH (Z23.D<<1)(R24), P1.Z, [Z22.D]", 0xc4f7a716},
|
||||
{"ZLDFF1SH (Z10.D)(R19), P3.Z, [Z15.D]", 0xc4caae6f},
|
||||
{"ZLDFF1SH (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x84842c64},
|
||||
{"ZLDFF1SH (Z6.D<<1)(R14), P4.Z, [Z13.D]", 0xc4e6b1cd},
|
||||
{"ZLDFF1SH (Z6.D)(R14), P4.Z, [Z13.D]", 0xc4c6b1cd},
|
||||
{"ZLDFF1SW (R6<<2)(R14), P4.Z, [Z13.D]", 0xa48671cd},
|
||||
{"ZLDFF1SW (Z23.D<<2)(R24), P1.Z, [Z22.D]", 0xc577a716},
|
||||
{"ZLDFF1SW (Z10.D)(R19), P3.Z, [Z15.D]", 0xc54aae6f},
|
||||
{"ZLDFF1SW (Z6.D<<2)(R14), P4.Z, [Z13.D]", 0xc566b1cd},
|
||||
{"ZLDFF1SW (Z6.D)(R14), P4.Z, [Z13.D]", 0xc546b1cd},
|
||||
{"ZLDFF1W (R6<<2)(R14), P4.Z, [Z13.S]", 0xa54671cd},
|
||||
{"ZLDFF1W (R6<<2)(R14), P4.Z, [Z13.D]", 0xa56671cd},
|
||||
{"ZLDFF1W (Z4.S.UXTW<<2)(R3), P3.Z, [Z4.S]", 0x85246c64},
|
||||
{"ZLDFF1W (Z23.D<<2)(R24), P1.Z, [Z22.D]", 0xc577e716},
|
||||
{"ZLDFF1W (Z10.D)(R19), P3.Z, [Z15.D]", 0xc54aee6f},
|
||||
{"ZLDFF1W (Z4.S.UXTW)(R3), P3.Z, [Z4.S]", 0x85046c64},
|
||||
{"ZLDFF1W (Z6.D<<2)(R14), P4.Z, [Z13.D]", 0xc566f1cd},
|
||||
{"ZLDFF1W (Z6.D)(R14), P4.Z, [Z13.D]", 0xc546f1cd},
|
||||
{"ZST1B [Z7.D], P4, (R21)(R7)", 0xe47550e7},
|
||||
{"ZST1B [Z6.D], P4, (Z21.D.UXTW)(R7)", 0xe41590e6},
|
||||
{"ZST1B [Z6.S], P4, (Z21.S.UXTW)(R7)", 0xe45590e6},
|
||||
{"ZST1B [Z8.D], P3, (Z6.D)(RSP)", 0xe406afe8},
|
||||
{"ZST1D [Z8.D], P3, (R6<<3)(RSP)", 0xe5e64fe8},
|
||||
{"ZST1D [Z8.Q], P3, (R6<<3)(RSP)", 0xe5c64fe8},
|
||||
{"ZST1D [Z6.D], P4, (Z21.D.UXTW<<3)(R7)", 0xe5b590e6},
|
||||
{"ZST1D [Z6.D], P4, (Z21.D.UXTW)(R7)", 0xe59590e6},
|
||||
{"ZST1D [Z8.D], P3, (Z6.D<<3)(RSP)", 0xe5a6afe8},
|
||||
{"ZST1D [Z8.D], P3, (Z6.D)(RSP)", 0xe586afe8},
|
||||
{"ZST1H [Z7.D], P4, (R21<<1)(R7)", 0xe4f550e7},
|
||||
{"ZST1H [Z6.S], P4, (Z21.S.UXTW<<1)(R7)", 0xe4f590e6},
|
||||
{"ZST1H [Z6.D], P4, (Z21.D.UXTW<<1)(R7)", 0xe4b590e6},
|
||||
{"ZST1H [Z6.D], P4, (Z21.D.UXTW)(R7)", 0xe49590e6},
|
||||
{"ZST1H [Z6.S], P4, (Z21.S.UXTW)(R7)", 0xe4d590e6},
|
||||
{"ZST1H [Z8.D], P3, (Z6.D<<1)(RSP)", 0xe4a6afe8},
|
||||
{"ZST1H [Z8.D], P3, (Z6.D)(RSP)", 0xe486afe8},
|
||||
{"ZST1W [Z7.D], P4, (R21<<2)(R7)", 0xe57550e7},
|
||||
{"ZST1W [Z8.Q], P3, (R6<<2)(RSP)", 0xe5064fe8},
|
||||
{"ZST1W [Z6.S], P4, (Z21.S.UXTW<<2)(R7)", 0xe57590e6},
|
||||
{"ZST1W [Z6.D], P4, (Z21.D.UXTW<<2)(R7)", 0xe53590e6},
|
||||
{"ZST1W [Z6.D], P4, (Z21.D.UXTW)(R7)", 0xe51590e6},
|
||||
{"ZST1W [Z6.S], P4, (Z21.S.UXTW)(R7)", 0xe55590e6},
|
||||
{"ZST1W [Z8.D], P3, (Z6.D<<2)(RSP)", 0xe526afe8},
|
||||
{"ZST1W [Z8.D], P3, (Z6.D)(RSP)", 0xe506afe8},
|
||||
{"ZLD1B 6(Z7.S), P4.Z, [Z13.S]", 0x8426d0ed},
|
||||
{"ZLD1B 6(Z7.D), P4.Z, [Z13.D]", 0xc426d0ed},
|
||||
{"ZLD1D 8(Z14.D), P6.Z, [Z6.D]", 0xc5a1d9c6},
|
||||
{"ZLD1H 6(Z7.S), P4.Z, [Z13.S]", 0x84a3d0ed},
|
||||
{"ZLD1H 6(Z7.D), P4.Z, [Z13.D]", 0xc4a3d0ed},
|
||||
{"ZLD1SB 6(Z7.S), P4.Z, [Z13.S]", 0x842690ed},
|
||||
{"ZLD1SB 6(Z7.D), P4.Z, [Z13.D]", 0xc42690ed},
|
||||
{"ZLD1SH 6(Z7.S), P4.Z, [Z13.S]", 0x84a390ed},
|
||||
{"ZLD1SH 6(Z7.D), P4.Z, [Z13.D]", 0xc4a390ed},
|
||||
{"ZLD1SW 12(Z0.D), P6.Z, [Z25.D]", 0xc5239819},
|
||||
{"ZLD1W 12(Z0.S), P6.Z, [Z25.S]", 0x8523d819},
|
||||
{"ZLD1W 12(Z0.D), P6.Z, [Z25.D]", 0xc523d819},
|
||||
{"ZLDFF1B 6(Z7.S), P4.Z, [Z13.S]", 0x8426f0ed},
|
||||
{"ZLDFF1B 6(Z7.D), P4.Z, [Z13.D]", 0xc426f0ed},
|
||||
{"ZLDFF1D 8(Z14.D), P6.Z, [Z6.D]", 0xc5a1f9c6},
|
||||
{"ZLDFF1H 6(Z7.S), P4.Z, [Z13.S]", 0x84a3f0ed},
|
||||
{"ZLDFF1H 6(Z7.D), P4.Z, [Z13.D]", 0xc4a3f0ed},
|
||||
{"ZLDFF1SB 6(Z7.S), P4.Z, [Z13.S]", 0x8426b0ed},
|
||||
{"ZLDFF1SB 6(Z7.D), P4.Z, [Z13.D]", 0xc426b0ed},
|
||||
{"ZLDFF1SH 6(Z7.S), P4.Z, [Z13.S]", 0x84a3b0ed},
|
||||
{"ZLDFF1SH 6(Z7.D), P4.Z, [Z13.D]", 0xc4a3b0ed},
|
||||
{"ZLDFF1SW 12(Z0.D), P6.Z, [Z25.D]", 0xc523b819},
|
||||
{"ZLDFF1W 12(Z0.S), P6.Z, [Z25.S]", 0x8523f819},
|
||||
{"ZLDFF1W 12(Z0.D), P6.Z, [Z25.D]", 0xc523f819},
|
||||
{"ZST1B [Z8.S], P3, 6(Z15.S)", 0xe466ade8},
|
||||
{"ZST1B [Z8.D], P3, 6(Z15.D)", 0xe446ade8},
|
||||
{"ZST1D [Z16.D], P2, (Z5.D)", 0xe5c0a8b0},
|
||||
{"ZST1H [Z8.S], P3, 6(Z15.S)", 0xe4e3ade8},
|
||||
{"ZST1H [Z8.D], P3, 6(Z15.D)", 0xe4c3ade8},
|
||||
{"ZST1W [Z16.S], P2, (Z5.S)", 0xe560a8b0},
|
||||
{"ZST1W [Z16.D], P2, (Z5.D)", 0xe540a8b0},
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TestArm64AssembleExtensionGatherRefusals pins the diagnostics the
|
||||
// gather/scatter statements get from the layer: the addressing-mode
|
||||
// mismatches, the locked list arrangements, the zeroing qualifier of the
|
||||
// loads against the bare predicates of the stores, and the immediate
|
||||
// scaling.
|
||||
func TestArm64AssembleExtensionGatherRefusals(t *testing.T) {
|
||||
tests := []struct {
|
||||
stmt string
|
||||
want string
|
||||
}{
|
||||
{"ZLD1B (R6<<1)(R14), P4.Z, [Z13.B]", "scaled by <<0"},
|
||||
{"ZLD1B (Z6.D)(R14), P4.Z, [Z13.B]", "wants two general registers"},
|
||||
{"ZLD1B (Z6.S)(R14), P4.Z, [Z13.S]", "wants two general registers"},
|
||||
{"ZLD1B (R6)(R14), P4/M, [Z13.B]", "wants the zeroing qualifier"},
|
||||
{"ZLD1B (R6)(R14), P9.Z, [Z13.B]", "outside P0-P7"},
|
||||
{"ZLD1B (R6)(ZR), P4.Z, [Z13.B]", "is not an extended-layer operand"},
|
||||
{"ZLD1B (RSP)(R14), P4.Z, [Z13.B]", "is not an extended-layer operand"},
|
||||
{"ZLD1D 12(Z14.D), P6.Z, [Z6.D]", "wants two general registers"},
|
||||
{"ZLD1D 264(Z14.D), P6.Z, [Z6.D]", "wants two general registers"},
|
||||
{"ZST1B [Z7.D], P4/Z, (R21)(R7)", "takes no qualifier"},
|
||||
{"ZST1B [Z7.S], P4, (R21)(R7)", "carries arrangement .S, want .D"},
|
||||
{"ZST1B [Z7.D], P4, (Z21.S)(R7)", "wants two general registers"},
|
||||
}
|
||||
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)
|
||||
}
|
||||
}
|
||||
}
|
||||
+22
-2
@@ -360,12 +360,32 @@ func TestExtensionNamesARM64(t *testing.T) {
|
||||
"ZFADDAH",
|
||||
"ZFADDAS",
|
||||
"ZFADDAD",
|
||||
// The gather loads and scatter stores: plain, sign-extended and
|
||||
// first-fault loads, and the stores, in first-occurrence order.
|
||||
"ZLD1B",
|
||||
"ZLD1D",
|
||||
"ZLD1H",
|
||||
"ZLD1SB",
|
||||
"ZLD1SH",
|
||||
"ZLD1SW",
|
||||
"ZLD1W",
|
||||
"ZLDFF1B",
|
||||
"ZLDFF1D",
|
||||
"ZLDFF1H",
|
||||
"ZLDFF1SB",
|
||||
"ZLDFF1SH",
|
||||
"ZLDFF1SW",
|
||||
"ZLDFF1W",
|
||||
"ZST1B",
|
||||
"ZST1D",
|
||||
"ZST1H",
|
||||
"ZST1W",
|
||||
}
|
||||
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 != 251 {
|
||||
t.Errorf("the family registers %d instructions, want 251", n)
|
||||
if n := len(arch.Extensions(arch.ARM64)); n != 381 {
|
||||
t.Errorf("the family registers %d instructions, want 381", n)
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user