1055 lines
43 KiB
Go
1055 lines
43 KiB
Go
// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
|
|
// SPDX-License-Identifier: BSD-3-Clause
|
|
|
|
package asm
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"strings"
|
|
"testing"
|
|
|
|
"sourcedock.dev/petrbalvin/gasm-sdk/parser"
|
|
)
|
|
|
|
// assembleArm64Words parses src, assembles it for arm64 and returns the
|
|
// first function's body as little-endian instruction words. Every statement
|
|
// must encode: a failure is the test's.
|
|
func assembleArm64Words(t *testing.T, src string) []uint32 {
|
|
t.Helper()
|
|
f, errs := parser.Parse("ext_arm64.s", src)
|
|
if len(errs) > 0 {
|
|
t.Fatalf("parse: %v", errs)
|
|
}
|
|
img, err := AssembleFileARM64(f)
|
|
if err != nil {
|
|
t.Fatalf("assemble: %v", err)
|
|
}
|
|
if len(img.Funcs) != 1 {
|
|
t.Fatalf("got %d functions, want 1", len(img.Funcs))
|
|
}
|
|
body := img.Code[img.Funcs[0].Offset:][:img.Funcs[0].Size]
|
|
if len(body)%4 != 0 {
|
|
t.Fatalf("body is %d bytes, not a whole number of instructions", len(body))
|
|
}
|
|
words := make([]uint32, 0, len(body)/4)
|
|
for i := 0; i < len(body); i += 4 {
|
|
words = append(words, binary.LittleEndian.Uint32(body[i:]))
|
|
}
|
|
return words
|
|
}
|
|
|
|
// assembleArm64SrcError parses and assembles src and returns the assembler's
|
|
// error text.
|
|
func assembleArm64SrcError(t *testing.T, src string) string {
|
|
t.Helper()
|
|
f, errs := parser.Parse("ext_arm64.s", src)
|
|
if len(errs) > 0 {
|
|
t.Fatalf("parse: %v", errs)
|
|
}
|
|
_, err := AssembleFileARM64(f)
|
|
if err == nil {
|
|
t.Fatal("assembled, want an error")
|
|
}
|
|
return err.Error()
|
|
}
|
|
|
|
const arm64ExtProbeHead = "#include \"textflag.h\"\nTEXT ·t(SB), NOSPLIT, $0\n"
|
|
|
|
// TestArm64AssembleExtensionGolden drives the wired layer through the full
|
|
// assembler: text in, instruction word out. Each want is the encoding the
|
|
// ARM Architecture Reference Manual's field layout gives for the statement:
|
|
// the fixed class word, the size field from the arrangement, and the
|
|
// register and immediate fields in the class's own places. The arch-level
|
|
// golden vectors in arch/arm64_ext_test.go pin the same bytes at the
|
|
// metadata layer; these pin the text-to-bytes path.
|
|
func TestArm64AssembleExtensionGolden(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want uint32
|
|
}{
|
|
// Unpredicated three-vector: Zn, Zm, Zd, one shared arrangement.
|
|
{"ADD Z1.S, Z2.S, Z0.S", 0x04a20020},
|
|
{"ADD Z0.B, Z1.B, Z2.B", 0x04210002},
|
|
{"SUB Z31.D, Z30.D, Z29.D", 0x04fe07fd},
|
|
{"SQADD Z5.H, Z6.H, Z7.H", 0x046610a7},
|
|
{"UQADD Z8.S, Z9.S, Z10.S", 0x04a9150a},
|
|
{"SQSUB Z5.H, Z6.H, Z7.H", 0x046618a7},
|
|
{"UQSUB Z8.S, Z9.S, Z10.S", 0x04a91d0a},
|
|
{"MUL Z0.B, Z1.B, Z2.B", 0x04216002},
|
|
{"SMULH Z11.D, Z12.D, Z13.D", 0x04ec696d},
|
|
{"UMULH Z0.B, Z1.B, Z2.B", 0x04216c02},
|
|
// Governed destructive, merging: Zm, Pg/M, Zdn; the governing
|
|
// predicate is a 3-bit field, so P0-P7 alone.
|
|
{"ADD Z1.S, P0/M, Z0.S", 0x04800020},
|
|
{"SUBR Z1.S, P7/M, Z0.S", 0x04831c20},
|
|
{"MUL Z3.D, P2/M, Z5.D", 0x04d00865},
|
|
{"SUBR Z0.B, P5/M, Z31.B", 0x0403141f},
|
|
// Immediate classes: imm{, LSL #8}, Zdn. A bare multiple of 256
|
|
// derives the shift bit, the spelling the layer canonicalises.
|
|
{"ADD $255, Z0.S", 0x25a0dfe0},
|
|
{"ADD $65280, Z0.H", 0x2560ffe0},
|
|
{"ADD $255, LSL #8, Z0.S", 0x25a0ffe0},
|
|
{"ADD $(255<<8), Z0.S", 0x25a0ffe0},
|
|
{"MUL $-128, Z0.B", 0x2530d000},
|
|
}
|
|
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])
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionRefusals pins the diagnostics a pinned statement
|
|
// gets from the layer instead of a scalar path's register complaint.
|
|
func TestArm64AssembleExtensionRefusals(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want string
|
|
}{
|
|
{"ADD Z0, Z1.S, Z2.S", "carries no arrangement suffix"},
|
|
{"ADD Z33.S, Z1.S, Z2.S", "outside Z0-Z31"},
|
|
{"ADD Z1.S, P0/Z, Z0.S", "/M"},
|
|
{"ADD Z1.S, P9/M, Z0.S", "outside P0-P7"},
|
|
{"ADD $300, Z0.S", "immediate 300"},
|
|
{"ADD $255<<8, Z0.S", "not an immediate the layer can read"},
|
|
{"ADD Z1.S, P0/M, R0", "wants a scalable vector register"},
|
|
{"ADD Z1.S, P0/B, Z0.S", "not an extended-layer operand"},
|
|
{"MUL $200, Z0.B", "outside the signed 8-bit range"},
|
|
{"ADD Z1.S, LSL #8, Z0.S", "LSL belongs straight after an immediate"},
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionPredicateGolden drives the predicate family
|
|
// through the full assembler: corpus spellings in, corpus words out. The
|
|
// want words are the same arm64sveenc.s lines the arch-level golden test
|
|
// pins; these prove the text-to-bytes path parses the dot and slash
|
|
// qualifiers, the general registers and the counter spelling the statements
|
|
// write.
|
|
func TestArm64AssembleExtensionPredicateGolden(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want uint32
|
|
}{
|
|
// The logical operations, .B alone, the governing predicate with the
|
|
// zeroing qualifier in its dot spelling.
|
|
{"PAND P4.B, P2.B, P1.Z, P14.B", 0x2504444e},
|
|
{"PANDS P4.B, P2.B, P1.Z, P14.B", 0x2544444e},
|
|
{"PBIC P4.B, P2.B, P1.Z, P14.B", 0x2504445e},
|
|
{"PEOR P4.B, P2.B, P1.Z, P14.B", 0x2504464e},
|
|
{"PNAND P4.B, P2.B, P1.Z, P14.B", 0x2584465e},
|
|
{"PORR P4.B, P2.B, P1.Z, P14.B", 0x2584444e},
|
|
// The slash qualifier spells the same operand the dot spelling does.
|
|
{"PAND P4.B, P2.B, P1/Z, P14.B", 0x2504444e},
|
|
// The select and the breaks.
|
|
{"PSEL P4.B, P2.B, P1, P14.B", 0x2504465e},
|
|
{"PBRKA P5.B, P9.Z, P2.B", 0x251064a2},
|
|
{"PBRKAS P5.B, P9.Z, P4.B", 0x255064a4},
|
|
{"PBRKN P4.B, P2.B, P1.Z, P4.B", 0x25184444},
|
|
{"PBRKPA P4.B, P2.B, P1.Z, P14.B", 0x2504c44e},
|
|
// The permutations carry the arrangement into the size field.
|
|
{"PTRN1 P5.D, P4.D, P2.D", 0x05e55082},
|
|
{"PUZP2 P5.D, P4.D, P2.D", 0x05e54c82},
|
|
{"PZIP1 P5.H, P4.H, P2.H", 0x05654082},
|
|
// The singles and the first-fault group.
|
|
{"PPFALSE P13.B", 0x2518e40d},
|
|
{"PPFIRST P5.B, P9, P5.B", 0x2558c125},
|
|
{"PPNEXT P5.D, P4, P5.D", 0x25d9c485},
|
|
{"PPTEST P14.B, P0", 0x2550c1c0},
|
|
{"PPUNPKHI P14.B, P0.H", 0x053141c0},
|
|
{"PRDFFR P13.B", 0x2519f00d},
|
|
{"PRDFFR P14.Z, P0.B", 0x2518f1c0},
|
|
{"PRDFFRS P14.Z, P0.B", 0x2558f1c0},
|
|
{"PWRFFR P13.B", 0x252891a0},
|
|
{"PREV P14.S, P13.S", 0x05b441cd},
|
|
{"SETFFR", 0x252c9000},
|
|
// The while compares: general registers in, a sized predicate out.
|
|
{"PWHILEGE R2, R10, P10.H", 0x2562114a},
|
|
{"PWHILELT R2, R10, P10.H", 0x2562154a},
|
|
{"PWHILELS R2, R10, P10.B", 0x25221d5a},
|
|
{"PWHILERW R2, R10, P10.H", 0x2562315a},
|
|
}
|
|
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])
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionPredicateRefusals pins the diagnostics the
|
|
// predicate statements get from the layer.
|
|
func TestArm64AssembleExtensionPredicateRefusals(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want string
|
|
}{
|
|
{"PAND P4.B, P2.B, P1.M, P14.B", "zeroing qualifier"},
|
|
{"PAND P4.B, P2.B, P9.Z, P14.B", "outside P0-P7"},
|
|
{"PAND P8.B, P2.B, P1.Z, P14.B", "outside P0-P7"},
|
|
{"PAND P4.S, P2.B, P1.Z, P14.B", "want .B"},
|
|
{"PBRKN P4.B, P2.B, P1.Z, P9.B", "same register Pdm"},
|
|
{"PBRKAS P5.B, P9.M, P4.B", "zeroing qualifier"},
|
|
{"PSEL P4.B, P2.B, P1.Z, P14.B", "takes no qualifier"},
|
|
{"PTRN1 P5.D, P4.S, P2.D", "want .D"},
|
|
{"PPFALSE P13.S", "want .B"},
|
|
{"PPTRUE P6.S", "predicate-as-counter register"},
|
|
{"PPTRUE PN6.S", "outside PN8-PN15"},
|
|
{"PWHILELT R2, R31, P10.H", "outside R0-R30"},
|
|
{"PWHILELT R2, R10, P10.Q", "no size encoding"},
|
|
{"SETFFR P0.B", "takes 0 operands"},
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionPredicateLeavesScalarsAlone pins the non-
|
|
// invasion promise across the new operand kinds: general-register
|
|
// statements whose mnemonics the layer also carries for predicates keep
|
|
// their scalar behaviour whenever no vector, predicate or counter operand
|
|
// appears.
|
|
func TestArm64AssembleExtensionPredicateLeavesScalarsAlone(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want uint32
|
|
}{
|
|
{"ADD R0, R1, R2", 0x8b000022},
|
|
{"SUB R0, R1, R2", 0xcb000022},
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionPredicateLabelOffsets proves pass 1 and pass 2
|
|
// agree on a function mixing the predicate family with the vector family:
|
|
// PWHILELT (4 bytes) and SETFFR (4 bytes) shift the label by exactly the
|
|
// words pass 2 lays down.
|
|
func TestArm64AssembleExtensionPredicateLabelOffsets(t *testing.T) {
|
|
src := arm64ExtProbeHead + `
|
|
PWHILELT R2, R10, P10.H
|
|
loop:
|
|
SETFFR
|
|
B loop
|
|
PPFALSE P13.B
|
|
RET
|
|
`
|
|
words := assembleArm64Words(t, src)
|
|
want := []uint32{0x2562154a, 0x252c9000, 0x17ffffff, 0x2518e40d, 0xd65f03c0}
|
|
if len(words) != len(want) {
|
|
t.Fatalf("got %d words, want %d", len(words), len(want))
|
|
}
|
|
for i := range want {
|
|
if words[i] != want[i] {
|
|
t.Errorf("word %d: got %08x, want %08x", i, words[i], want[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionLabelOffsets proves pass 1 and pass 2 agree on a
|
|
// function that mixes the layer with ordinary statements: the label after an
|
|
// SVE instruction lands on the 4 bytes the encoder laid down, and the branch
|
|
// back to it encodes the distance in words.
|
|
func TestArm64AssembleExtensionLabelOffsets(t *testing.T) {
|
|
src := arm64ExtProbeHead + `
|
|
ADD Z0.S, Z1.S, Z2.S
|
|
loop:
|
|
ADD $255, Z0.S
|
|
B loop
|
|
MUL $-128, Z0.B
|
|
RET
|
|
`
|
|
words := assembleArm64Words(t, src)
|
|
want := []uint32{0x04a10002, 0x25a0dfe0, 0x17ffffff, 0x2530d000, 0xd65f03c0}
|
|
if len(words) != len(want) {
|
|
t.Fatalf("got %d words, want %d", len(words), len(want))
|
|
}
|
|
for i := range want {
|
|
if words[i] != want[i] {
|
|
t.Errorf("word %d: got %08x, want %08x", i, words[i], want[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionLeavesScalarsAlone pins the non-invasion
|
|
// promise: statements whose operands the scalar paths already read keep
|
|
// their exact encodings, scalar and NEON alike, with the layer wired in.
|
|
func TestArm64AssembleExtensionLeavesScalarsAlone(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want uint32
|
|
}{
|
|
{"ADD R0, R1, R2", 0x8b000022},
|
|
{"ADD $255, R0", 0x9103fc00},
|
|
{"SUB R0, R1, R2", 0xcb000022},
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionStage2Golden drives the SVE2.1 Z-alias
|
|
// statements through the full assembler: corpus text in, corpus word out.
|
|
// The statements carry the spellings the layer reads: dot and slash
|
|
// qualifiers, bare predicates, bare vectors, general registers and the
|
|
// immediate-with-source alias.
|
|
func TestArm64AssembleExtensionStage2Golden(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want uint32
|
|
}{
|
|
{"ZABS Z7.D, P4.M, Z13.D", 0x04d6b0ed},
|
|
{"ZABS Z7.D, P4.Z, Z13.D", 0x04c6b0ed},
|
|
// The destination read back encodes once, in the destination slot
|
|
// alone: a non-zero Zdn must stay clear of the class bits.
|
|
{"ZADD Z15.B, Z5.B, P3.M, Z5.B", 0x04000de5},
|
|
{"ZSUB Z20.D, Z13.D, P6.M, Z13.D", 0x04c11a8d},
|
|
{"ZADD Z15.B, Z0.B, P3.M, Z0.B", 0x04000de0},
|
|
{"ZADD Z7.D, Z23.D, Z13.D", 0x04e702ed},
|
|
{"ZAND Z15.B, Z0.B, P3.M, Z0.B", 0x041a0de0},
|
|
{"ZAND Z7.D, Z6.D, Z23.D", 0x042730d7},
|
|
{"ZBIC Z15.B, Z0.B, P3.M, Z0.B", 0x041b0de0},
|
|
{"ZBIC Z7.D, Z6.D, Z23.D", 0x04e730d7},
|
|
{"ZCLS Z7.D, P4.M, Z13.D", 0x04d8b0ed},
|
|
{"ZCLS Z7.D, P4.Z, Z13.D", 0x04c8b0ed},
|
|
{"ZCLZ Z7.D, P4.M, Z13.D", 0x04d9b0ed},
|
|
{"ZCLZ Z7.D, P4.Z, Z13.D", 0x04c9b0ed},
|
|
{"ZCNOT Z7.D, P4.M, Z13.D", 0x04dbb0ed},
|
|
{"ZCNOT Z7.D, P4.Z, Z13.D", 0x04cbb0ed},
|
|
{"ZCOMPACT Z7.D, P4, Z13.D", 0x05e190ed},
|
|
{"ZCOMPACT Z7.D, P4, Z13.D", 0x05e190ed},
|
|
{"ZEOR Z15.B, Z0.B, P3.M, Z0.B", 0x04190de0},
|
|
{"ZEOR Z7.D, Z6.D, Z23.D", 0x04a730d7},
|
|
{"ZEXPAND Z7.D, P4, Z13.D", 0x05f190ed},
|
|
{"ZMOVPRFX Z7.D, P4.Z, Z21.D", 0x04d030f5},
|
|
{"ZMOVPRFX Z11, Z6", 0x0420bd66},
|
|
{"ZNEG Z7.D, P4.M, Z13.D", 0x04d7b0ed},
|
|
{"ZNEG Z7.D, P4.Z, Z13.D", 0x04c7b0ed},
|
|
{"ZNOT Z7.D, P4.M, Z13.D", 0x04deb0ed},
|
|
{"ZNOT Z7.D, P4.Z, Z13.D", 0x04ceb0ed},
|
|
{"ZORR Z15.B, Z0.B, P3.M, Z0.B", 0x04180de0},
|
|
{"ZORR Z7.D, Z6.D, Z23.D", 0x046730d7},
|
|
{"ZREV Z1.S, Z26.S", 0x05b8383a},
|
|
{"ZREVB Z7.D, P4.M, Z13.D", 0x05e490ed},
|
|
{"ZREVB Z7.D, P4.Z, Z13.D", 0x05e4b0ed},
|
|
{"ZREVD Z13.Q, P1.M, Z22.Q", 0x052e85b6},
|
|
{"ZREVD Z13.Q, P1.Z, Z22.Q", 0x052ea5b6},
|
|
{"ZREVH Z7.D, P4.M, Z13.D", 0x05e590ed},
|
|
{"ZREVH Z7.D, P4.Z, Z13.D", 0x05e5b0ed},
|
|
{"ZREVW Z13.D, P1.M, Z22.D", 0x05e685b6},
|
|
{"ZREVW Z13.D, P1.Z, Z22.D", 0x05e6a5b6},
|
|
{"ZSEL Z23.B, Z21.B, P14, Z2.B", 0x0537faa2},
|
|
{"ZSQABS Z7.D, P4.M, Z13.D", 0x44c8b0ed},
|
|
{"ZSQABS Z7.D, P4.Z, Z13.D", 0x44cab0ed},
|
|
{"ZSQNEG Z7.D, P4.M, Z13.D", 0x44c9b0ed},
|
|
{"ZSQNEG Z7.D, P4.Z, Z13.D", 0x44cbb0ed},
|
|
{"ZSUB Z15.B, Z0.B, P3.M, Z0.B", 0x04010de0},
|
|
{"ZSUB Z7.D, Z23.D, Z13.D", 0x04e706ed},
|
|
{"ZSUBR Z15.B, Z0.B, P3.M, Z0.B", 0x04030de0},
|
|
{"ZSUNPKHI Z15.B, Z0.H", 0x057139e0},
|
|
{"ZSUNPKLO Z15.B, Z0.H", 0x057039e0},
|
|
{"ZSXTB Z7.D, P4.M, Z13.D", 0x04d0b0ed},
|
|
{"ZSXTB Z7.D, P4.Z, Z13.D", 0x04c0b0ed},
|
|
{"ZSXTH Z7.D, P4.M, Z13.D", 0x04d2b0ed},
|
|
{"ZSXTH Z7.D, P4.Z, Z13.D", 0x04c2b0ed},
|
|
{"ZSXTW Z13.D, P1.M, Z22.D", 0x04d4a5b6},
|
|
{"ZSXTW Z13.D, P1.Z, Z22.D", 0x04c4a5b6},
|
|
{"ZTBX Z7.D, Z23.D, Z13.D", 0x05e72eed},
|
|
{"ZTBXQ Z7.D, Z23.D, Z13.D", 0x05e736ed},
|
|
{"ZTRN1 Z7.D, Z23.D, Z13.D", 0x05e772ed},
|
|
{"ZTRN1 Z7.Q, Z6.Q, Z23.Q", 0x05a718d7},
|
|
{"ZTRN2 Z7.D, Z23.D, Z13.D", 0x05e776ed},
|
|
{"ZTRN2 Z7.Q, Z6.Q, Z23.Q", 0x05a71cd7},
|
|
{"ZUUNPKHI Z15.B, Z0.H", 0x057339e0},
|
|
{"ZUUNPKLO Z15.B, Z0.H", 0x057239e0},
|
|
{"ZUXTB Z7.D, P4.M, Z13.D", 0x04d1b0ed},
|
|
{"ZUXTB Z7.D, P4.Z, Z13.D", 0x04c1b0ed},
|
|
{"ZUXTH Z7.D, P4.M, Z13.D", 0x04d3b0ed},
|
|
{"ZUXTH Z7.D, P4.Z, Z13.D", 0x04c3b0ed},
|
|
{"ZUXTW Z13.D, P1.M, Z22.D", 0x04d5a5b6},
|
|
{"ZUXTW Z13.D, P1.Z, Z22.D", 0x04c5a5b6},
|
|
{"ZUZP1 Z7.D, Z23.D, Z13.D", 0x05e76aed},
|
|
{"ZUZP1 Z7.Q, Z6.Q, Z23.Q", 0x05a708d7},
|
|
{"ZUZP2 Z7.D, Z23.D, Z13.D", 0x05e76eed},
|
|
{"ZUZP2 Z7.Q, Z6.Q, Z23.Q", 0x05a70cd7},
|
|
{"ZUZPQ1 Z7.D, Z23.D, Z13.D", 0x44c7eaed},
|
|
{"ZUZPQ2 Z7.D, Z23.D, Z13.D", 0x44c7eeed},
|
|
{"ZZIP1 Z7.D, Z23.D, Z13.D", 0x05e762ed},
|
|
{"ZZIP1 Z7.Q, Z6.Q, Z23.Q", 0x05a700d7},
|
|
{"ZZIP2 Z7.D, Z23.D, Z13.D", 0x05e766ed},
|
|
{"ZZIP2 Z7.Q, Z6.Q, Z23.Q", 0x05a704d7},
|
|
{"ZZIPQ1 Z7.D, Z23.D, Z13.D", 0x44c7e2ed},
|
|
{"ZZIPQ2 Z7.D, Z23.D, Z13.D", 0x44c7e6ed},
|
|
{"ZDUP R2, Z10.D", 0x05e0384a},
|
|
{"ZINSR R2, Z10.D", 0x05e4384a},
|
|
{"ZADD $6, Z7.D, Z7.D", 0x25e0c0c7},
|
|
{"ZSUB $6, Z7.D, Z7.D", 0x25e1c0c7},
|
|
{"ZSUBR $6, Z7.D, Z7.D", 0x25e3c0c7},
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionStage3Golden drives the stage-three families
|
|
// through the full assembler: corpus text in, corpus word out. The
|
|
// statements carry the spellings the layer reads: the read-back crypto
|
|
// destinations, the ZR of the dropped counter results, the bare governing
|
|
// predicates and the V destinations of the reductions.
|
|
func TestArm64AssembleExtensionStage3Golden(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want uint32
|
|
}{
|
|
// The crypto family.
|
|
{"ZADCLB Z7.D, Z23.D, Z13.D", 0x4547d2ed},
|
|
{"ZADCLT Z7.D, Z23.D, Z13.D", 0x4547d6ed},
|
|
{"ZSBCLB Z7.D, Z23.D, Z13.D", 0x45c7d2ed},
|
|
{"ZSBCLT Z7.D, Z23.D, Z13.D", 0x45c7d6ed},
|
|
{"ZRAX1 Z7.D, Z6.D, Z23.D", 0x4527f4d7},
|
|
{"ZSM4EKEY Z7.S, Z6.S, Z23.S", 0x4527f0d7},
|
|
{"ZSM4E Z7.S, Z6.S, Z6.S", 0x4523e0e6},
|
|
{"ZAESD Z7.B, Z6.B, Z6.B", 0x4522e4e6},
|
|
{"ZAESE Z7.B, Z6.B, Z6.B", 0x4522e0e6},
|
|
{"ZAESIMC Z11.B, Z11.B", 0x4520e40b},
|
|
{"ZAESMC Z11.B, Z11.B", 0x4520e00b},
|
|
// The terminators and counters.
|
|
{"CTERMEQ ZR, R25", 0x25ff2320},
|
|
{"CTERMEQW ZR, R25", 0x25bf2320},
|
|
{"CTERMNE ZR, R25", 0x25ff2330},
|
|
{"CTERMNEW ZR, R25", 0x25bf2330},
|
|
{"CTERMEQ R0, R25", 0x25e02320},
|
|
{"PCNTP P2.B, P14, R2", 0x2520b842},
|
|
{"PFIRSTP P2.B, P14, R2", 0x2521b842},
|
|
{"PLASTP P2.B, P14, R2", 0x2522b842},
|
|
{"PDECP P14.S, ZR", 0x25ad89df},
|
|
{"ZDECP P14.S, Z26.S", 0x25ad81da},
|
|
{"PINCP P14.S, ZR", 0x25ac89df},
|
|
{"PSQDECP P14.S, ZR", 0x25aa8ddf},
|
|
{"PSQINCP P14.S, ZR", 0x25a88ddf},
|
|
{"PUQDECP P14.S, ZR", 0x25ab8ddf},
|
|
{"PUQINCP P14.S, ZR", 0x25a98ddf},
|
|
{"PUQDECPW P14.S, ZR", 0x25ab89df},
|
|
{"PUQINCPW P14.S, ZR", 0x25a989df},
|
|
{"PSQDECPW R8, P10.D, R8", 0x25ea8948},
|
|
{"PSQINCPW R8, P10.D, R8", 0x25e88948},
|
|
{"PWHILEGEW R2, R10, P10.H", 0x2562014a},
|
|
{"PWHILEGTW R2, R10, P10.H", 0x2562015a},
|
|
{"PWHILEHIW R2, R10, P10.H", 0x2562095a},
|
|
{"PWHILEHSW R2, R10, P10.H", 0x2562094a},
|
|
{"PWHILELEW R2, R10, P10.H", 0x2562055a},
|
|
{"PWHILELOW R2, R10, P10.H", 0x25620d4a},
|
|
{"PWHILELSW R2, R10, P10.H", 0x25620d5a},
|
|
{"PWHILELTW R2, R10, P10.H", 0x2562054a},
|
|
// The reductions.
|
|
{"ZSADDVD Z6.B, P3, V2", 0x04002cc2},
|
|
{"ZUADDVD Z10.D, P3, V15", 0x04c12d4f},
|
|
{"ZANDVB Z6.B, P3, V2", 0x041a2cc2},
|
|
{"ZANDVH Z3.H, P1, V29", 0x045a247d},
|
|
{"ZANDVS Z17.S, P1, V27", 0x049a263b},
|
|
{"ZANDVD Z10.D, P3, V15", 0x04da2d4f},
|
|
{"ZEORVB Z6.B, P3, V2", 0x04192cc2},
|
|
{"ZEORVD Z10.D, P3, V15", 0x04d92d4f},
|
|
{"ZORVB Z6.B, P3, V2", 0x04182cc2},
|
|
{"ZORVD Z10.D, P3, V15", 0x04d82d4f},
|
|
{"ZSMAXVB Z6.B, P3, V2", 0x04082cc2},
|
|
{"ZSMAXVH Z3.H, P1, V29", 0x0448247d},
|
|
{"ZSMAXVS Z17.S, P1, V27", 0x0488263b},
|
|
{"ZSMAXVD Z10.D, P3, V15", 0x04c82d4f},
|
|
{"ZSMINVB Z6.B, P3, V2", 0x040a2cc2},
|
|
{"ZSMINVD Z10.D, P3, V15", 0x04ca2d4f},
|
|
{"ZUMAXVB Z6.B, P3, V2", 0x04092cc2},
|
|
{"ZUMAXVD Z10.D, P3, V15", 0x04c92d4f},
|
|
{"ZUMINVB Z6.B, P3, V2", 0x040b2cc2},
|
|
{"ZUMINVD Z10.D, P3, V15", 0x04cb2d4f},
|
|
{"ZFADDVH Z3.H, P1, V29", 0x6540247d},
|
|
{"ZFADDVS Z17.S, P1, V27", 0x6580263b},
|
|
{"ZFADDVD Z10.D, P3, V15", 0x65c02d4f},
|
|
{"ZFMAXNMVH Z3.H, P1, V29", 0x6544247d},
|
|
{"ZFMAXNMVD Z10.D, P3, V15", 0x65c42d4f},
|
|
{"ZFMAXVH Z3.H, P1, V29", 0x6546247d},
|
|
{"ZFMAXVD Z10.D, P3, V15", 0x65c62d4f},
|
|
{"ZFMINNMVH Z3.H, P1, V29", 0x6545247d},
|
|
{"ZFMINNMVD Z10.D, P3, V15", 0x65c52d4f},
|
|
{"ZFMINVH Z3.H, P1, V29", 0x6547247d},
|
|
{"ZFMINVD Z10.D, P3, V15", 0x65c72d4f},
|
|
{"ZFADDAH Z8.H, V15, P2, V15", 0x6558290f},
|
|
{"ZFADDAS Z26.S, V30, P7, V30", 0x65983f5e},
|
|
{"ZFADDAD Z9.D, V10, P2, V10", 0x65d8292a},
|
|
}
|
|
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])
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionStage3Refusals pins the diagnostics the
|
|
// stage-three statements get from the layer: the read-back mismatches, the
|
|
// locked arrangements, the dropped-result zero register and the narrow
|
|
// governing predicates.
|
|
func TestArm64AssembleExtensionStage3Refusals(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want string
|
|
}{
|
|
{"ZSM4E Z7.S, Z6.S, Z5.S", "the same register Zd"},
|
|
{"ZSM4E Z7.D, Z6.D, Z6.D", "want .S"},
|
|
{"ZAESIMC Z11.B, Z12.B", "the same register Zd"},
|
|
{"ZADCLB Z7.S, Z23.S, Z13.S", "want .D"},
|
|
{"CTERMEQ RSP, R25", "wants ZR here"},
|
|
{"CTERMEQ R31, R25", "outside R0-R30"},
|
|
{"PCNTP P2.B, P14, R31", "outside R0-R30"},
|
|
{"PCNTP P2.Q, P14, R2", "no size encoding"},
|
|
{"PDECP P14.S, R0", "spelled ZR"},
|
|
{"PDECP P14.Q, ZR", "no size encoding"},
|
|
{"PSQDECPW R8, P10.D, R9", "the same register"},
|
|
{"ZSADDVD Z6.B, P9, V2", "outside P0-P7"},
|
|
{"ZSADDVD Z6.B, P3/M, V2", "takes no qualifier"},
|
|
{"ZSADDVD Z6.B, P3, V32", "outside V0-V31"},
|
|
{"ZSADDVD Z6.B, P3, R2", "wants a SIMD register"},
|
|
{"ZANDVB Z6.S, P3, V2", "want .B"},
|
|
{"ZFADDAD Z9.D, V10, P2, V11", "the same register Vd"},
|
|
{"PWHILEGEW R2, R10, P10.H", ""},
|
|
}
|
|
for _, tt := range tests {
|
|
if tt.want == "" {
|
|
continue
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionStage4Golden drives the SVE2.1 narrowing
|
|
// two-to-one family through the full assembler: corpus text in, corpus word
|
|
// out, with the two width extensions the arch-level golden test pins.
|
|
func TestArm64AssembleExtensionStage4Golden(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want uint32
|
|
}{
|
|
{"ZADDHNB Z22.S, Z10.S, Z8.H", 0x45b66148},
|
|
{"ZADDHNT Z22.S, Z10.S, Z8.H", 0x45b66548},
|
|
{"ZRADDHNB Z22.S, Z10.S, Z8.H", 0x45b66948},
|
|
{"ZRADDHNT Z22.S, Z10.S, Z8.H", 0x45b66d48},
|
|
{"ZRSUBHNB Z22.S, Z10.S, Z8.H", 0x45b67948},
|
|
{"ZRSUBHNT Z22.S, Z10.S, Z8.H", 0x45b67d48},
|
|
{"ZSUBHNB Z22.S, Z10.S, Z8.H", 0x45b67148},
|
|
{"ZSUBHNT Z22.S, Z10.S, Z8.H", 0x45b67548},
|
|
{"ZADDHNB Z8.H, Z10.H, Z11.B", 0x4568614b},
|
|
{"ZSUBHNT Z26.D, Z4.D, Z13.S", 0x45fa748d},
|
|
// The pairwise and quadword-reduction classes: corpus lines plus a
|
|
// width extension each.
|
|
{"ZADDP Z15.B, Z0.B, P3.M, Z0.B", 0x4411ade0},
|
|
{"ZADDP Z9.S, Z2.S, P5.M, Z2.S", 0x4491b522},
|
|
{"ZADDPT Z23.D, Z13.D, P1.M, Z13.D", 0x04c406ed},
|
|
{"ZADDPT Z7.D, Z6.D, Z23.D", 0x04e708d7},
|
|
{"ZADDQV Z25.S, P3, V5.S4", 0x04852f25},
|
|
{"ZADDQV Z9.D, P1, V7.D2", 0x04c52527},
|
|
{"ZANDQV Z25.S, P3, V5.S4", 0x049e2f25},
|
|
{"ZEORQV Z25.S, P3, V5.S4", 0x049d2f25},
|
|
{"ZORQV Z25.S, P3, V5.S4", 0x049c2f25},
|
|
{"ZSMAXQV Z25.S, P3, V5.S4", 0x048c2f25},
|
|
{"ZSMINQV Z25.S, P3, V5.S4", 0x048e2f25},
|
|
{"ZUMAXQV Z25.S, P3, V5.S4", 0x048d2f25},
|
|
{"ZUMINQV Z25.S, P3, V5.S4", 0x048f2f25},
|
|
{"ZFADDQV Z25.S, P3, V5.S4", 0x6490af25},
|
|
{"ZFMAXNMQV Z25.S, P3, V5.S4", 0x6494af25},
|
|
{"ZFMAXQV Z25.S, P3, V5.S4", 0x6496af25},
|
|
{"ZFMINNMQV Z25.S, P3, V5.S4", 0x6495af25},
|
|
{"ZFMINQV Z25.S, P3, V5.S4", 0x6497af25},
|
|
// The shift-by-vector family.
|
|
{"ZASR Z15.B, Z0.B, P3.M, Z0.B", 0x04108de0},
|
|
{"ZASR Z2.D, Z10.D, P3.M, Z10.D", 0x04d08c4a},
|
|
{"ZASR Z7.D, Z6.H, Z13.H", 0x046780cd},
|
|
{"ZASRR Z15.B, Z0.B, P3.M, Z0.B", 0x04148de0},
|
|
{"ZLSL Z2.D, Z10.D, P3.M, Z10.D", 0x04d38c4a},
|
|
{"ZLSL Z7.D, Z6.H, Z13.H", 0x04678ccd},
|
|
{"ZLSLR Z15.B, Z0.B, P3.M, Z0.B", 0x04178de0},
|
|
{"ZLSR Z15.B, Z0.B, P3.M, Z0.B", 0x04118de0},
|
|
{"ZLSR Z7.D, Z6.H, Z13.H", 0x046784cd},
|
|
{"ZLSRR Z15.B, Z0.B, P3.M, Z0.B", 0x04158de0},
|
|
// The three-source and bitwise combine families.
|
|
{"ZBCAX Z23.D, Z13.D, Z21.D, Z21.D", 0x046d3af5},
|
|
{"ZEOR3 Z23.D, Z13.D, Z21.D, Z21.D", 0x042d3af5},
|
|
{"ZBSL Z23.D, Z13.D, Z21.D, Z21.D", 0x042d3ef5},
|
|
{"ZBSL1N Z23.D, Z13.D, Z21.D, Z21.D", 0x046d3ef5},
|
|
{"ZBSL2N Z23.D, Z13.D, Z21.D, Z21.D", 0x04ad3ef5},
|
|
{"ZNBSL Z23.D, Z13.D, Z21.D, Z21.D", 0x04ed3ef5},
|
|
{"ZBDEP Z7.D, Z23.D, Z13.D", 0x45c7b6ed},
|
|
{"ZBEXT Z7.D, Z23.D, Z13.D", 0x45c7b2ed},
|
|
{"ZBGRP Z7.D, Z23.D, Z13.D", 0x45c7baed},
|
|
{"ZEORBT Z7.D, Z23.D, Z13.D", 0x45c792ed},
|
|
{"ZEORTB Z7.D, Z23.D, Z13.D", 0x45c796ed},
|
|
// The BFloat16 arithmetic core, halfwords throughout.
|
|
{"ZBF1CVT Z11.B, Z6.H", 0x65083966},
|
|
{"ZBF1CVTLT Z11.B, Z6.H", 0x65093966},
|
|
{"ZBF2CVT Z11.B, Z6.H", 0x65083d66},
|
|
{"ZBF2CVTLT Z11.B, Z6.H", 0x65093d66},
|
|
{"ZF1CVT Z11.B, Z6.H", 0x65083166},
|
|
{"ZF1CVTLT Z11.B, Z6.H", 0x65093166},
|
|
{"ZF2CVT Z11.B, Z6.H", 0x65083566},
|
|
{"ZF2CVTLT Z11.B, Z6.H", 0x65093566},
|
|
{"ZBFADD Z23.H, Z13.H, P1.M, Z13.H", 0x650086ed},
|
|
{"ZBFADD Z7.H, Z6.H, Z23.H", 0x650700d7},
|
|
{"ZBFCLAMP Z7.H, Z6.H, Z23.H", 0x642724d7},
|
|
{"ZBFMAX Z23.H, Z13.H, P1.M, Z13.H", 0x650686ed},
|
|
{"ZBFMAXNM Z23.H, Z13.H, P1.M, Z13.H", 0x650486ed},
|
|
{"ZBFMIN Z23.H, Z13.H, P1.M, Z13.H", 0x650786ed},
|
|
{"ZBFMINNM Z23.H, Z13.H, P1.M, Z13.H", 0x650586ed},
|
|
{"ZBFMUL Z23.H, Z13.H, P1.M, Z13.H", 0x650286ed},
|
|
{"ZBFMUL Z7.H, Z6.H, Z23.H", 0x650708d7},
|
|
{"ZBFSUB Z23.H, Z13.H, P1.M, Z13.H", 0x650186ed},
|
|
{"ZBFSUB Z7.H, Z6.H, Z23.H", 0x650704d7},
|
|
// The rest of the BFloat16 wall.
|
|
{"ZBFCVT Z13.S, P1.M, Z22.H", 0x658aa5b6},
|
|
{"ZBFCVT Z13.S, P1.Z, Z22.H", 0x649ac5b6},
|
|
{"ZBFCVTNT Z13.S, P1.M, Z22.H", 0x648aa5b6},
|
|
{"ZBFDOT Z7.H, Z6.H, Z23.S", 0x646780d7},
|
|
{"ZBFMLA Z23.H, Z13.H, P1.M, Z22.H", 0x653705b6},
|
|
{"ZBFMLALB Z7.H, Z6.H, Z23.S", 0x64e780d7},
|
|
{"ZBFMLALT Z7.H, Z6.H, Z23.S", 0x64e784d7},
|
|
{"ZBFMLS Z23.H, Z13.H, P1.M, Z22.H", 0x653725b6},
|
|
{"ZBFMLSLB Z7.H, Z6.H, Z23.S", 0x64e7a0d7},
|
|
{"ZBFMLSLT Z7.H, Z6.H, Z23.S", 0x64e7a4d7},
|
|
{"ZBFMMLA Z7.H, Z6.H, Z23.S", 0x6467e4d7},
|
|
{"ZBFSCALE Z23.H, Z13.H, P1.M, Z13.H", 0x650986ed},
|
|
// The multiple-structure loads and stores.
|
|
{"ZLD2B (R6)(R14), P4.Z, [Z13.B, Z14.B]", 0xa426d1cd},
|
|
{"ZLD2H (R6<<1)(R14), P4.Z, [Z13.H, Z14.H]", 0xa4a6d1cd},
|
|
{"ZLD2Q (R6<<4)(R14), P4.Z, [Z13.Q, Z14.Q]", 0xa4a691cd},
|
|
{"ZLD3W (R6<<2)(R14), P4.Z, [Z13.S, Z14.S, Z15.S]", 0xa546d1cd},
|
|
{"ZLD4B (R6)(R14), P4.Z, [Z13.B, Z14.B, Z15.B, Z16.B]", 0xa466d1cd},
|
|
{"ZLD4D (R6<<3)(R14), P4.Z, [Z13.D, Z14.D, Z15.D, Z16.D]", 0xa5e6d1cd},
|
|
{"ZST2B [Z8.B, Z9.B], P3, (R6)(RSP)", 0xe4266fe8},
|
|
{"ZST2Q [Z8.Q, Z9.Q], P3, (R6<<4)(RSP)", 0xe4660fe8},
|
|
{"ZST3D [Z8.D, Z9.D, Z10.D], P3, (R6<<3)(RSP)", 0xe5c66fe8},
|
|
{"ZST4Q [Z8.Q, Z9.Q, Z10.Q, Z11.Q], P3, (R6<<4)(RSP)", 0xe4e60fe8},
|
|
// The rest of the BFloat16 wall.
|
|
{"ZBFCVT Z13.S, P1.M, Z22.H", 0x658aa5b6},
|
|
{"ZBFCVT Z13.S, P1.Z, Z22.H", 0x649ac5b6},
|
|
{"ZBFCVTNT Z13.S, P1.M, Z22.H", 0x648aa5b6},
|
|
{"ZBFDOT Z7.H, Z6.H, Z23.S", 0x646780d7},
|
|
{"ZBFMLA Z23.H, Z13.H, P1.M, Z22.H", 0x653705b6},
|
|
{"ZBFMLALB Z7.H, Z6.H, Z23.S", 0x64e780d7},
|
|
{"ZBFMLALT Z7.H, Z6.H, Z23.S", 0x64e784d7},
|
|
{"ZBFMLS Z23.H, Z13.H, P1.M, Z22.H", 0x653725b6},
|
|
{"ZBFMLSLB Z7.H, Z6.H, Z23.S", 0x64e7a0d7},
|
|
{"ZBFMLSLT Z7.H, Z6.H, Z23.S", 0x64e7a4d7},
|
|
{"ZBFMMLA Z7.H, Z6.H, Z23.S", 0x6467e4d7},
|
|
{"ZBFSCALE Z23.H, Z13.H, P1.M, Z13.H", 0x650986ed},
|
|
// The last-active vector shape and the compares to a predicate.
|
|
{"ZCLASTA Z15.B, Z0.B, P3, Z0.B", 0x05288de0},
|
|
{"ZCLASTB Z15.B, Z0.B, P3, Z0.B", 0x05298de0},
|
|
{"ZCMPEQ Z0.H, Z2.H, P0.Z, P14.H", 0x2440a04e},
|
|
{"ZCMPEQ Z0.D, Z12.S, P0.Z, P14.S", 0x2480218e},
|
|
{"ZCMPHS Z0.H, Z2.H, P0.Z, P14.H", 0x2440004e},
|
|
{"ZCMPNE Z0.D, Z12.S, P0.Z, P14.S", 0x2480219e},
|
|
// The vector-length arithmetic.
|
|
{"ADDPL $9, R11, RSP", 0x046b513f},
|
|
{"ADDVL $9, R11, RSP", 0x042b513f},
|
|
{"RDVL $1, R27", 0x04bf503b},
|
|
}
|
|
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])
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestArm64AssembleExtensionStage4Refusals pins the diagnostics the
|
|
// narrowing, pairwise and quadword-reduction statements get from the layer:
|
|
// the arrangement pair the single size field over-determines, the locked
|
|
// pairwise top arrangement and the accumulator's bare predicate.
|
|
func TestArm64AssembleExtensionStage4Refusals(t *testing.T) {
|
|
tests := []struct {
|
|
stmt string
|
|
want string
|
|
}{
|
|
{"ZADDHNB Z22.B, Z10.B, Z8.H", "want .H, .S or .D"},
|
|
{"ZADDHNB Z22.S, Z10.H, Z8.H", "must match"},
|
|
{"ZADDHNB Z22.S, Z10.S, Z8.S", "want .H"},
|
|
{"ZADDHNB Z22.D, Z10.D, Z8.H", "want .S"},
|
|
{"ZADDHNB Z22.Q, Z10.Q, Z8.D", "want .H, .S or .D"},
|
|
{"ZADDHNB Z22.S, Z10.S, Z8", "carries no arrangement suffix"},
|
|
{"ZADDP Z15.B, Z0.B, P3.Z, Z0.B", "/M qualifier"},
|
|
{"ZADDPT Z7.S, Z6.S, Z23.S", "want .D"},
|
|
{"ZADDQV Z25.S, P9, V5.S4", "outside P0-P7"},
|
|
{"ZADDQV Z25.S, P3/M, V5.S4", "takes no qualifier"},
|
|
{"ZADDQV Z25.S, P3, V5", "no quadword suffix"},
|
|
{"ZADDQV Z25.S, P3, V5.D2", "carries arrangement .D, want .S"},
|
|
// The multiple-structure lists.
|
|
{"ZLD3B (R6)(R14), P4.Z, [Z13.B, Z14.B]", "is not an extended-layer operand"},
|
|
{"ZLD2B (R6)(R14), P4.Z, [Z13.B, Z15.B]", "is not an extended-layer operand"},
|
|
{"ZLD2B (R6)(R14), P4.Z, [Z13.B, Z14.S]", "is not an extended-layer operand"},
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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},
|
|
// The same-size right shifts, the accumulator and the extract.
|
|
{"ZSRI $6, Z7.D, Z23.D", 0x45daf0f7},
|
|
{"ZSSRA $6, Z7.D, Z23.D", 0x45dae0f7},
|
|
{"ZUSRA $6, Z7.D, Z23.D", 0x45dae4f7},
|
|
{"ZSRSRA $6, Z7.D, Z23.D", 0x45dae8f7},
|
|
{"ZURSRA $6, Z7.D, Z23.D", 0x45daecf7},
|
|
{"ZASR $6, Z7.D, Z23.D", 0x04fa90f7},
|
|
{"ZASR $6, Z23.B, P1.M, Z23.B", 0x04008557},
|
|
{"ZASRD $6, Z23.B, P1.M, Z23.B", 0x04048557},
|
|
{"ZXAR $6, Z23.B, Z21.B, Z21.B", 0x042a36f5},
|
|
}
|
|
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"},
|
|
{"ZSRI $6, Z7.B, Z23.H", "must match"},
|
|
{"ZSRI $0, Z7.D, Z23.D", "outside the range 1..63"},
|
|
{"ZASR $8, Z23.B, P1.M, Z23.B", "outside the range 1..7"},
|
|
{"ZXAR $6, Z23.B, Z21.B, Z20.B", "the same register Zdn"},
|
|
{"ZXAR $6, Z23.B, Z21.H, Z21.H", "must match"},
|
|
}
|
|
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)
|
|
}
|
|
}
|
|
}
|