style: replace em and en dashes across sources
This commit is contained in:
+82
-82
@@ -9,10 +9,10 @@ import (
|
||||
)
|
||||
|
||||
// This file implements EVEX (AVX-512) instruction encoding: the four-byte
|
||||
// EVEX prefix with 5-bit vector register fields (Z0–Z31, X/Y 16–31), the
|
||||
// EVEX prefix with 5-bit vector register fields (Z0-Z31, X/Y 16-31), the
|
||||
// compressed disp8×N displacement, and the operand shapes the go-flac
|
||||
// AVX-512 kernels use plus the common floating-point and conversion set.
|
||||
// Masking follows the Go assembler's spelling: an explicit K1–K7 operand
|
||||
// Masking follows the Go assembler's spelling: an explicit K1-K7 operand
|
||||
// anywhere among the operands (merging) plus a ".Z" mnemonic suffix for
|
||||
// zeroing. K-register operands (mask destinations, KMOVW, KTESTW) are
|
||||
// supported too.
|
||||
@@ -36,7 +36,7 @@ type evexSpec struct {
|
||||
// are taken from the Go assembler's opcode tables, which are authoritative
|
||||
// for byte-for-byte agreement.
|
||||
var evexTable = map[string]evexSpec{
|
||||
// EVEX.128/256/512.66.0F — integer arithmetic / logic, NDS form.
|
||||
// EVEX.128/256/512.66.0F, integer arithmetic / logic, NDS form.
|
||||
"VPADDD": {1, 0xFE, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPADDQ": {1, 0xD4, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPSUBD": {1, 0xFA, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
@@ -48,25 +48,25 @@ var evexTable = map[string]evexSpec{
|
||||
"VPCMPEQD": {1, 0x76, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VFMADD231PD": {2, 0xB8, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.128/256/512.66.0F.W1 — packed double arithmetic.
|
||||
// EVEX.128/256/512.66.0F.W1, packed double arithmetic.
|
||||
"VADDPD": {1, 0x58, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VMULPD": {1, 0x59, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VSUBPD": {1, 0x5C, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VDIVPD": {1, 0x5E, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VMINPD": {1, 0x5D, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VMAXPD": {1, 0x5F, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.0F.W0 — packed single arithmetic.
|
||||
// EVEX.128/256/512.0F.W0, packed single arithmetic.
|
||||
"VADDPS": {1, 0x58, 0, 0, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VMULPS": {1, 0x59, 0, 0, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VSUBPS": {1, 0x5C, 0, 0, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VDIVPS": {1, 0x5E, 0, 0, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VMINPS": {1, 0x5D, 0, 0, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VMAXPS": {1, 0x5F, 0, 0, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.66.0F.W1 — packed double unpack.
|
||||
// EVEX.128/256/512.66.0F.W1, packed double unpack.
|
||||
"VUNPCKLPD": {1, 0x14, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VUNPCKHPD": {1, 0x15, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.128.F2.0F.W1 — scalar double arithmetic (the packed opcodes with
|
||||
// EVEX.128.F2.0F.W1, scalar double arithmetic (the packed opcodes with
|
||||
// an F2 pp; the EVEX forms exist for masked and zeroing use). The
|
||||
// memory operand is a single double, so disp8×N = 8.
|
||||
"VADDSD": {1, 0x58, 1, 3, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
@@ -76,7 +76,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VMINSD": {1, 0x5D, 1, 3, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
"VMAXSD": {1, 0x5F, 1, 3, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
|
||||
// EVEX.128.F3.0F.W0 — scalar single arithmetic (disp8×N = 4).
|
||||
// EVEX.128.F3.0F.W0, scalar single arithmetic (disp8×N = 4).
|
||||
"VADDSS": {1, 0x58, 0, 2, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
"VSUBSS": {1, 0x5C, 0, 2, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
"VMULSS": {1, 0x59, 0, 2, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
@@ -84,38 +84,38 @@ var evexTable = map[string]evexSpec{
|
||||
"VMINSS": {1, 0x5D, 0, 2, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
"VMAXSS": {1, 0x5F, 0, 2, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
|
||||
// EVEX.512.66.0F3A — align (NDS + imm8).
|
||||
// EVEX.512.66.0F3A, align (NDS + imm8).
|
||||
"VALIGND": {3, 0x03, 0, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.128/256/512.66.0F — immediate shift (VPSRAD /4).
|
||||
// EVEX.128/256/512.66.0F, immediate shift (VPSRAD /4).
|
||||
"VPSRAD": {1, 0x72, 0, 1, 4, vexShiftImm, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.66.0F.W1 — variable shift with an XMM count (VPSRAQ;
|
||||
// EVEX.128/256/512.66.0F.W1, variable shift with an XMM count (VPSRAQ;
|
||||
// the W bit distinguishes it from VPSRAD's E2 form).
|
||||
"VPSRAQ": {1, 0xE2, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.128/256/512.F3.0F.W1 — signed qword to packed double (reg=dst,
|
||||
// EVEX.128/256/512.F3.0F.W1, signed qword to packed double (reg=dst,
|
||||
// rm=src, no vvvv).
|
||||
"VCVTQQ2PD": {1, 0xE6, 1, 2, -1, vexRM, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.F2.0F.W1 — duplicate the low double (reg=dst,
|
||||
// EVEX.128/256/512.F2.0F.W1, duplicate the low double (reg=dst,
|
||||
// rm=src, no vvvv): a 128-bit destination reads a single double from
|
||||
// memory (disp8×8), the wider ones read the full operand.
|
||||
"VMOVDDUP": {1, 0x12, 1, 3, -1, vexRM, [3]int{8, 32, 64}},
|
||||
// EVEX.128/256/512.0F.W0 — signed dword to packed single (reg=dst,
|
||||
// rm=src, no vvvv, no mandatory prefix — as in the VEX form).
|
||||
// EVEX.128/256/512.0F.W0, signed dword to packed single (reg=dst,
|
||||
// rm=src, no vvvv, no mandatory prefix, as in the VEX form).
|
||||
"VCVTDQ2PS": {1, 0x5B, 0, 0, -1, vexRM, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.0F.W0 — packed single to packed double: the
|
||||
// EVEX.128/256/512.0F.W0, packed single to packed double: the
|
||||
// destination is twice the source width and sets the length; disp8×N
|
||||
// follows the narrow memory source. No F3 prefix: the Go assembler
|
||||
// emits this instruction with pp = 00 (Intel's maps would call that
|
||||
// undefined) and gasm reproduces the Go assembler's bytes — its machine
|
||||
// undefined) and gasm reproduces the Go assembler's bytes, its machine
|
||||
// code is the oracle, not the manual.
|
||||
"VCVTPS2PD": {1, 0x5A, 0, 0, -1, vexRM, [3]int{8, 16, 32}},
|
||||
// EVEX.128/256/512.F3.0F.W0 — signed dword to packed double (the EVEX
|
||||
// EVEX.128/256/512.F3.0F.W0, signed dword to packed double (the EVEX
|
||||
// form of the VEX instruction; the destination sets the length, disp8×N
|
||||
// follows the narrow memory source).
|
||||
"VCVTDQ2PD": {1, 0xE6, 0, 2, -1, vexRM, [3]int{8, 16, 32}},
|
||||
// EVEX packed double → dword conversions: the source is the wide
|
||||
// operand and the mnemonic fixes the length — the bare names are
|
||||
// operand and the mnemonic fixes the length, the bare names are
|
||||
// 512-bit only (ZMM source, XMM destination), the X/Y spellings are
|
||||
// EVEX-128/256. Exactly one slot of n is valid; it names the vector
|
||||
// length (and the disp8×N multiplier) a register or memory source
|
||||
@@ -127,7 +127,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VCVTTPD2DQX": {1, 0xE6, 1, 1, -1, vexRMSrcLen, [3]int{16, 0, 0}},
|
||||
"VCVTTPD2DQY": {1, 0xE6, 1, 1, -1, vexRMSrcLen, [3]int{0, 32, 0}},
|
||||
|
||||
// EVEX.66.0F3A — ternary logic and lane shuffles (NDS + imm8).
|
||||
// EVEX.66.0F3A, ternary logic and lane shuffles (NDS + imm8).
|
||||
"VPTERNLOGD": {3, 0x25, 0, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
"VPTERNLOGQ": {3, 0x25, 1, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
"VSHUFI32X4": {3, 0x43, 0, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
@@ -136,11 +136,11 @@ var evexTable = map[string]evexSpec{
|
||||
"VSHUFF64X2": {3, 0x23, 1, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
"VPALIGNR": {3, 0x0F, 0, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F — the EVEX forms of the VEX two-source shuffle.
|
||||
// EVEX.66.0F, the EVEX forms of the VEX two-source shuffle.
|
||||
"VSHUFPD": {1, 0xC6, 1, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
"VSHUFPS": {1, 0xC6, 0, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F3A — lane insert ($imm, xsrc, zsrc1, zdst).
|
||||
// EVEX.66.0F3A, lane insert ($imm, xsrc, zsrc1, zdst).
|
||||
"VINSERTF32X4": {3, 0x18, 0, 1, -1, vexNDS3Imm, [3]int{0, 16, 32}},
|
||||
"VINSERTF32X8": {3, 0x1A, 0, 1, -1, vexNDS3Imm, [3]int{0, 0, 32}},
|
||||
"VINSERTF64X2": {3, 0x18, 1, 1, -1, vexNDS3Imm, [3]int{0, 16, 32}},
|
||||
@@ -150,7 +150,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VINSERTI64X2": {3, 0x38, 1, 1, -1, vexNDS3Imm, [3]int{0, 16, 32}},
|
||||
"VINSERTI64X4": {3, 0x3A, 1, 1, -1, vexNDS3Imm, [3]int{0, 0, 32}},
|
||||
|
||||
// EVEX.66.0F3A — lane extract (reg=source, rm=XMM/YMM destination,
|
||||
// EVEX.66.0F3A, lane extract (reg=source, rm=XMM/YMM destination,
|
||||
// imm8).
|
||||
"VEXTRACTF32X4": {3, 0x19, 0, 1, -1, vexExtract, [3]int{0, 16, 16}},
|
||||
"VEXTRACTF32X8": {3, 0x1B, 0, 1, -1, vexExtract, [3]int{0, 0, 32}},
|
||||
@@ -159,14 +159,14 @@ var evexTable = map[string]evexSpec{
|
||||
"VEXTRACTI32X8": {3, 0x3B, 0, 1, -1, vexExtract, [3]int{0, 0, 32}},
|
||||
"VEXTRACTI64X2": {3, 0x39, 1, 1, -1, vexExtract, [3]int{0, 16, 16}},
|
||||
|
||||
// EVEX.66.0F — compare with an opmask destination ($imm, src2, src1,
|
||||
// EVEX.66.0F, compare with an opmask destination ($imm, src2, src1,
|
||||
// kdst): NDS3Imm with the K register in the reg field.
|
||||
"VCMPPD": {1, 0xC2, 1, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
"VCMPPS": {1, 0xC2, 0, 0, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
"VCMPSD": {1, 0xC2, 1, 3, -1, vexNDS3Imm, [3]int{8, 8, 8}},
|
||||
"VCMPSS": {1, 0xC2, 0, 2, -1, vexNDS3Imm, [3]int{4, 4, 4}},
|
||||
|
||||
// EVEX.66.0F3A — integer compares with an opmask destination, the same
|
||||
// EVEX.66.0F3A, integer compares with an opmask destination, the same
|
||||
// NDS3Imm-with-k-reg shape as the floating-point compares; W selects the
|
||||
// operand width (byte/word vs dword/qword), the opcode the signedness.
|
||||
// The memory form takes a full vector, so disp8×N is 16/32/64.
|
||||
@@ -179,7 +179,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VPCMPQ": {3, 0x1F, 1, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
"VPCMPUQ": {3, 0x1E, 1, 1, -1, vexNDS3Imm, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F38 — permutes (NDS form).
|
||||
// EVEX.66.0F38, permutes (NDS form).
|
||||
"VPERMB": {2, 0x8D, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMW": {2, 0x8D, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMI2D": {2, 0x76, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
@@ -188,7 +188,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VPERMT2Q": {2, 0x7E, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMT2PD": {2, 0x7F, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F — the wider integer set (NDS form).
|
||||
// EVEX.66.0F, the wider integer set (NDS form).
|
||||
"VPMADDWD": {1, 0xF5, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPMULHUW": {1, 0xE4, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPMADDUBSW": {2, 0x04, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
@@ -199,34 +199,34 @@ var evexTable = map[string]evexSpec{
|
||||
"VPACKSSDW": {1, 0x6B, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPACKUSDW": {2, 0x2B, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F38 — absolute values and replicating moves (reg=dst,
|
||||
// EVEX.66.0F38, absolute values and replicating moves (reg=dst,
|
||||
// rm=src).
|
||||
"VPABSB": {2, 0x1C, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VPABSW": {2, 0x1D, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VPABSD": {2, 0x1E, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VPABSQ": {2, 0x1F, 1, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
// EVEX.F3.0F — replicate even/odd singles.
|
||||
// EVEX.F3.0F, replicate even/odd singles.
|
||||
"VMOVSLDUP": {1, 0x12, 0, 2, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VMOVSHDUP": {1, 0x16, 0, 2, -1, vexRM, [3]int{16, 32, 64}},
|
||||
// EVEX.66.0F38 — sign/zero-extending moves; the memory source is the
|
||||
// EVEX.66.0F38, sign/zero-extending moves; the memory source is the
|
||||
// narrow half (here byte to word).
|
||||
"VPMOVSXBW": {2, 0x20, 0, 1, -1, vexRM, [3]int{8, 16, 32}},
|
||||
"VPMOVZXBW": {2, 0x30, 0, 1, -1, vexRM, [3]int{8, 16, 32}},
|
||||
// EVEX.66.0F — packed single conversions (reg=dst, rm=src).
|
||||
// EVEX.66.0F, packed single conversions (reg=dst, rm=src).
|
||||
"VCVTPS2DQ": {1, 0x5B, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VCVTTPS2DQ": {1, 0x5B, 0, 2, -1, vexRM, [3]int{16, 32, 64}},
|
||||
// EVEX.66.0F38 — broadcast a single/double to all lanes (reg=dst,
|
||||
// EVEX.66.0F38, broadcast a single/double to all lanes (reg=dst,
|
||||
// rm=scalar memory; disp8×N is the element size).
|
||||
"VBROADCASTSS": {2, 0x18, 0, 1, -1, vexRM, [3]int{4, 4, 4}},
|
||||
"VBROADCASTSD": {2, 0x19, 1, 1, -1, vexRM, [3]int{0, 8, 8}},
|
||||
|
||||
// EVEX.66.0F38 — expand loads (rm → vector register destination).
|
||||
// EVEX.66.0F38, expand loads (rm → vector register destination).
|
||||
"VEXPANDPD": {2, 0x88, 1, 1, -1, vexRM, [3]int{8, 8, 8}},
|
||||
"VEXPANDPS": {2, 0x88, 0, 1, -1, vexRM, [3]int{4, 4, 4}},
|
||||
"VPEXPANDD": {2, 0x89, 0, 1, -1, vexRM, [3]int{4, 4, 4}},
|
||||
"VPEXPANDQ": {2, 0x89, 1, 1, -1, vexRM, [3]int{8, 8, 8}},
|
||||
|
||||
// EVEX.66.0F38 — compress stores (vector register source → rm), and the
|
||||
// EVEX.66.0F38, compress stores (vector register source → rm), and the
|
||||
// remaining narrowing stores.
|
||||
"VCOMPRESSPD": {2, 0x8A, 1, 1, -1, vexRMRev, [3]int{8, 8, 8}},
|
||||
"VCOMPRESSPS": {2, 0x8A, 0, 1, -1, vexRMRev, [3]int{4, 4, 4}},
|
||||
@@ -235,7 +235,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VPMOVWB": {2, 0x30, 0, 2, -1, vexRMRev, [3]int{8, 16, 32}},
|
||||
"VPMOVQB": {2, 0x32, 0, 2, -1, vexRMRev, [3]int{2, 4, 8}},
|
||||
|
||||
// EVEX.66.0F — rotates (immediate form: /0 right, /1 left).
|
||||
// EVEX.66.0F, rotates (immediate form: /0 right, /1 left).
|
||||
"VPRORD": {1, 0x72, 0, 1, 0, vexShiftImm, [3]int{16, 32, 64}},
|
||||
"VPRORQ": {1, 0x72, 1, 1, 0, vexShiftImm, [3]int{16, 32, 64}},
|
||||
"VPROLD": {1, 0x72, 0, 1, 1, vexShiftImm, [3]int{16, 32, 64}},
|
||||
@@ -248,14 +248,14 @@ var evexTable = map[string]evexSpec{
|
||||
"VPSRLQ": {1, 0x73, 1, 1, 2, vexShiftImm, [3]int{16, 32, 64}},
|
||||
"VPSLLQ": {1, 0x73, 1, 1, 6, vexShiftImm, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F38 — floating-point helpers, packed (reg=dst, rm=src).
|
||||
// EVEX.66.0F38, floating-point helpers, packed (reg=dst, rm=src).
|
||||
"VRCP14PD": {2, 0x4C, 1, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VRCP14PS": {2, 0x4C, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VRSQRT14PD": {2, 0x4E, 1, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VRSQRT14PS": {2, 0x4E, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VGETEXPPD": {2, 0x42, 1, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VGETEXPPS": {2, 0x42, 0, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
// EVEX.66.0F38 — floating-point helpers, scalar (NDS form: src2 is
|
||||
// EVEX.66.0F38, floating-point helpers, scalar (NDS form: src2 is
|
||||
// rm, src1 is vvvv, the XMM destination is reg). Like the scalar 0F3A
|
||||
// forms, these take the 66 prefix; W selects double/single.
|
||||
"VRCP14SD": {2, 0x4D, 1, 1, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
@@ -264,13 +264,13 @@ var evexTable = map[string]evexSpec{
|
||||
"VRSQRT14SS": {2, 0x4F, 0, 1, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
"VGETEXPSD": {2, 0x43, 1, 1, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
"VGETEXPSS": {2, 0x43, 0, 1, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
// EVEX.66.0F38 — scale by a power of two (NDS form).
|
||||
// EVEX.66.0F38, scale by a power of two (NDS form).
|
||||
"VSCALEFPD": {2, 0x2C, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VSCALEFPS": {2, 0x2C, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VSCALEFSD": {2, 0x2D, 1, 1, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
"VSCALEFSS": {2, 0x2D, 0, 1, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
|
||||
// EVEX.66.0F3A — packed round/getmant/reduce ($imm, src, dst: reg=dst,
|
||||
// EVEX.66.0F3A, packed round/getmant/reduce ($imm, src, dst: reg=dst,
|
||||
// rm=src, imm8).
|
||||
"VRNDSCALEPD": {3, 0x09, 1, 1, -1, vexImmRM, [3]int{16, 32, 64}},
|
||||
"VRNDSCALEPS": {3, 0x08, 0, 1, -1, vexImmRM, [3]int{16, 32, 64}},
|
||||
@@ -278,7 +278,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VGETMANTPS": {3, 0x26, 0, 1, -1, vexImmRM, [3]int{16, 32, 64}},
|
||||
"VREDUCEPD": {3, 0x56, 1, 1, -1, vexImmRM, [3]int{16, 32, 64}},
|
||||
"VREDUCEPS": {3, 0x56, 0, 1, -1, vexImmRM, [3]int{16, 32, 64}},
|
||||
// EVEX.66.0F3A — scalar round/getmant/reduce and fixup/range (NDS +
|
||||
// EVEX.66.0F3A, scalar round/getmant/reduce and fixup/range (NDS +
|
||||
// imm8: $imm, src2, src1, dst). The scalar 0F3A forms all take the 66
|
||||
// prefix; W selects double/single.
|
||||
"VRNDSCALESD": {3, 0x0B, 1, 1, -1, vexNDS3Imm, [3]int{8, 8, 8}},
|
||||
@@ -296,7 +296,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VRANGESD": {3, 0x51, 1, 1, -1, vexNDS3Imm, [3]int{8, 8, 8}},
|
||||
"VRANGESS": {3, 0x51, 0, 1, -1, vexNDS3Imm, [3]int{4, 4, 4}},
|
||||
|
||||
// EVEX.66.0F3A — floating-point class test ($imm, src, kdst): the
|
||||
// EVEX.66.0F3A, floating-point class test ($imm, src, kdst): the
|
||||
// reg field carries the opmask destination. The packed forms carry an
|
||||
// explicit length in the mnemonic (X/Y/Z).
|
||||
"VFPCLASSPDX": {3, 0x66, 1, 1, -1, vexImmRM, [3]int{16, 0, 0}},
|
||||
@@ -308,7 +308,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VFPCLASSSD": {3, 0x67, 1, 1, -1, vexImmRM, [3]int{8, 0, 0}},
|
||||
"VFPCLASSSS": {3, 0x67, 0, 1, -1, vexImmRM, [3]int{4, 0, 0}},
|
||||
|
||||
// EVEX — the remaining conversions. VCVTQQ2PS narrows (the 512-bit
|
||||
// EVEX, the remaining conversions. VCVTQQ2PS narrows (the 512-bit
|
||||
// source sets the length); the rest follow the destination.
|
||||
"VCVTQQ2PS": {1, 0x5B, 1, 0, -1, vexRMSrcLen, [3]int{0, 0, 64}},
|
||||
"VCVTPD2QQ": {1, 0x7B, 1, 1, -1, vexRM, [3]int{16, 32, 64}},
|
||||
@@ -316,13 +316,13 @@ var evexTable = map[string]evexSpec{
|
||||
"VCVTPS2QQ": {1, 0x7B, 0, 1, -1, vexRM, [3]int{8, 16, 32}},
|
||||
"VCVTUDQ2PD": {1, 0x7A, 0, 2, -1, vexRM, [3]int{8, 16, 32}},
|
||||
"VCVTUDQ2PS": {1, 0x7A, 0, 0, -1, vexRM, [3]int{8, 16, 32}},
|
||||
// EVEX.66.0F38 — half-precision convert (half-width source).
|
||||
// EVEX.66.0F38, half-precision convert (half-width source).
|
||||
"VCVTPH2PS": {2, 0x13, 0, 1, -1, vexRM, [3]int{8, 16, 32}},
|
||||
// EVEX.66.0F3A — half-precision convert back ($imm, src, dst: reg=src,
|
||||
// rm=dst, imm8 — the extract layout).
|
||||
// EVEX.66.0F3A, half-precision convert back ($imm, src, dst: reg=src,
|
||||
// rm=dst, imm8, the extract layout).
|
||||
"VCVTPS2PH": {3, 0x1D, 0, 1, -1, vexExtract, [3]int{8, 16, 32}},
|
||||
|
||||
// EVEX — unsigned and truncating conversions. The PD sources are the
|
||||
// EVEX, unsigned and truncating conversions. The PD sources are the
|
||||
// wide operand (the bare names are 512-bit only, the X/Y spellings fix
|
||||
// the length); the PS/UQQ destinations are wide and follow the
|
||||
// destination.
|
||||
@@ -349,7 +349,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VCVTQQ2PSX": {1, 0x5B, 1, 0, -1, vexRMSrcLen, [3]int{16, 0, 0}},
|
||||
"VCVTQQ2PSY": {1, 0x5B, 1, 0, -1, vexRMSrcLen, [3]int{0, 32, 0}},
|
||||
|
||||
// EVEX.66.0F38 — the remaining sign/zero-extending moves (narrow
|
||||
// EVEX.66.0F38, the remaining sign/zero-extending moves (narrow
|
||||
// source; disp8×N follows its size).
|
||||
"VPMOVSXBD": {2, 0x21, 0, 1, -1, vexRM, [3]int{4, 8, 16}},
|
||||
"VPMOVSXBQ": {2, 0x22, 0, 1, -1, vexRM, [3]int{2, 4, 8}},
|
||||
@@ -361,7 +361,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VPMOVZXWQ": {2, 0x34, 0, 1, -1, vexRM, [3]int{4, 8, 16}},
|
||||
"VPMOVZXDQ": {2, 0x35, 0, 1, -1, vexRM, [3]int{8, 16, 32}},
|
||||
|
||||
// EVEX.F3.0F38 — the remaining narrowing stores (vector source in reg,
|
||||
// EVEX.F3.0F38, the remaining narrowing stores (vector source in reg,
|
||||
// narrow destination in r/m): signed, unsigned and the D/Q truncations.
|
||||
"VPMOVSDB": {2, 0x21, 0, 2, -1, vexRMRev, [3]int{4, 8, 16}},
|
||||
"VPMOVSQB": {2, 0x22, 0, 2, -1, vexRMRev, [3]int{2, 4, 8}},
|
||||
@@ -378,7 +378,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VPMOVDB": {2, 0x31, 0, 2, -1, vexRMRev, [3]int{4, 8, 16}},
|
||||
"VPMOVQW": {2, 0x34, 0, 2, -1, vexRMRev, [3]int{4, 8, 16}},
|
||||
|
||||
// EVEX.F3.0F38 — mask/vector conversions: M2* moves an opmask register
|
||||
// EVEX.F3.0F38, mask/vector conversions: M2* moves an opmask register
|
||||
// into a vector (rm = K source, reg = vector destination), *2M does the
|
||||
// reverse (reg = K destination, rm = vector source, the length follows
|
||||
// the vector).
|
||||
@@ -391,7 +391,7 @@ var evexTable = map[string]evexSpec{
|
||||
"VPMOVD2M": {2, 0x39, 0, 2, -1, vexRM, [3]int{16, 32, 64}},
|
||||
"VPMOVQ2M": {2, 0x39, 1, 2, -1, vexRM, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX — scalar conversions between vector and general-purpose
|
||||
// EVEX, scalar conversions between vector and general-purpose
|
||||
// registers. Vector to GPR (two operands: vec/mem source, GPR
|
||||
// destination, vvvv unused): the signed and truncated pair, and the
|
||||
// unsigned forms (EVEX only).
|
||||
@@ -421,22 +421,22 @@ var evexTable = map[string]evexSpec{
|
||||
"VCVTUSI2SDQ": {1, 0x7B, 1, 3, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
"VCVTUSI2SSL": {1, 0x7B, 0, 2, -1, vexNDS3, [3]int{4, 4, 4}},
|
||||
"VCVTUSI2SSQ": {1, 0x7B, 1, 2, -1, vexNDS3, [3]int{8, 8, 8}},
|
||||
// EVEX.128/256/512.66.0F38.W0 — sign-extend dwords to qwords; the memory
|
||||
// EVEX.128/256/512.66.0F38.W0, sign-extend dwords to qwords; the memory
|
||||
// operand is the narrow source, so disp8×N follows its size (8/16/32 for
|
||||
// the xmm/ymm/zmm destination lengths).
|
||||
"VPMOVSXDQ": {2, 0x25, 0, 1, -1, vexRM, [3]int{8, 16, 32}},
|
||||
|
||||
// EVEX.512.66.0F3A.W1 — lane extract (reg=ZMM source, rm=YMM/memory
|
||||
// EVEX.512.66.0F3A.W1, lane extract (reg=ZMM source, rm=YMM/memory
|
||||
// destination, imm8).
|
||||
"VEXTRACTI64X4": {3, 0x3B, 1, 1, -1, vexExtract, [3]int{0, 0, 32}},
|
||||
"VEXTRACTF64X4": {3, 0x1B, 1, 1, -1, vexExtract, [3]int{0, 0, 32}},
|
||||
|
||||
// EVEX.66.0F38 — more integer NDS forms (W distinguishes D/Q).
|
||||
// EVEX.66.0F38, more integer NDS forms (W distinguishes D/Q).
|
||||
"VPMULLD": {2, 0x40, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPMULLQ": {2, 0x40, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
"VPERMD": {2, 0x36, 0, 1, -1, vexNDS3, [3]int{0, 32, 64}},
|
||||
|
||||
// EVEX.128/256/512 — the wider integer set (AVX-512 F/BW): byte/word
|
||||
// EVEX.128/256/512, the wider integer set (AVX-512 F/BW): byte/word
|
||||
// arithmetic, the bitwise ops with D/Q suffixes, min/max, averages and
|
||||
// variable shifts. All NDS form; W distinguishes element size.
|
||||
"VPADDB": {1, 0xFC, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
@@ -474,21 +474,21 @@ var evexTable = map[string]evexSpec{
|
||||
"VPSRAVQ": {2, 0x46, 1, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX forms of instructions that also exist in VEX (selected when a ZMM
|
||||
// or K register, or indices 16–31, demand EVEX).
|
||||
// or K register, or indices 16-31, demand EVEX).
|
||||
"VPSHUFD": {1, 0x70, 0, 1, -1, vexImmRM, [3]int{16, 32, 64}},
|
||||
"VPSHUFB": {2, 0x00, 0, 1, -1, vexNDS3, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.66.0F — immediate shift (VPSLLD /6).
|
||||
// EVEX.66.0F, immediate shift (VPSLLD /6).
|
||||
"VPSLLD": {1, 0x72, 0, 1, 6, vexShiftImm, [3]int{16, 32, 64}},
|
||||
|
||||
// EVEX.F3.0F38.W0 — narrowing stores: reg = wide source, rm = narrow
|
||||
// EVEX.F3.0F38.W0, narrowing stores: reg = wide source, rm = narrow
|
||||
// destination (VPMOVDW dword→word, VPMOVQD qword→dword).
|
||||
"VPMOVDW": {2, 0x33, 0, 2, -1, vexRMRev, [3]int{8, 16, 32}},
|
||||
"VPMOVQD": {2, 0x35, 0, 2, -1, vexRMRev, [3]int{8, 16, 32}},
|
||||
}
|
||||
|
||||
// evexBcastSpec describes an EVEX broadcast (VPBROADCASTD/Q): the opcode
|
||||
// depends on the source kind — a GPR source uses opReg, a memory source uses
|
||||
// depends on the source kind, a GPR source uses opReg, a memory source uses
|
||||
// opMem with a disp8×N of n.
|
||||
type evexBcastSpec struct {
|
||||
mapSel int
|
||||
@@ -499,10 +499,10 @@ type evexBcastSpec struct {
|
||||
}
|
||||
|
||||
var evexBcastTable = map[string]evexBcastSpec{
|
||||
// EVEX.128/256/512.66.0F38 — broadcast a dword/qword to all lanes.
|
||||
// EVEX.128/256/512.66.0F38, broadcast a dword/qword to all lanes.
|
||||
"VPBROADCASTD": {2, 0x7C, 0x58, 0, 4},
|
||||
"VPBROADCASTQ": {2, 0x7C, 0x59, 1, 8},
|
||||
// EVEX.128/256/512.66.0F38 — broadcast a byte/word (GPR or memory
|
||||
// EVEX.128/256/512.66.0F38, broadcast a byte/word (GPR or memory
|
||||
// source) to all lanes.
|
||||
"VPBROADCASTB": {2, 0x7A, 0x78, 0, 1},
|
||||
"VPBROADCASTW": {2, 0x7B, 0x79, 0, 2},
|
||||
@@ -521,26 +521,26 @@ type evexMoveSpec struct {
|
||||
|
||||
// evexMoveTable maps an upper-case EVEX move mnemonic to its encoding.
|
||||
var evexMoveTable = map[string]evexMoveSpec{
|
||||
// EVEX.128/256/512.F3.0F.W0 — unaligned integer move.
|
||||
// EVEX.128/256/512.F3.0F.W0, unaligned integer move.
|
||||
"VMOVDQU32": {1, 2, 0x6F, 0x7F, 0, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.F3.0F.W1 — unaligned qword move.
|
||||
// EVEX.128/256/512.F3.0F.W1, unaligned qword move.
|
||||
"VMOVDQU64": {1, 2, 0x6F, 0x7F, 1, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.F2.0F.W0 — unaligned byte move (byte/word moves use the
|
||||
// EVEX.128/256/512.F2.0F.W0, unaligned byte move (byte/word moves use the
|
||||
// F2 prefix, dword/qword moves F3; the element size only changes the tuple
|
||||
// semantics).
|
||||
"VMOVDQU8": {1, 3, 0x6F, 0x7F, 0, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.F2.0F.W1 — unaligned word move (shares the qword
|
||||
// EVEX.128/256/512.F2.0F.W1, unaligned word move (shares the qword
|
||||
// encoding).
|
||||
"VMOVDQU16": {1, 3, 0x6F, 0x7F, 1, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.66.0F.W1 — unaligned packed double move.
|
||||
// EVEX.128/256/512.66.0F.W1, unaligned packed double move.
|
||||
"VMOVUPD": {1, 1, 0x10, 0x11, 1, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512 — aligned packed moves.
|
||||
// EVEX.128/256/512, aligned packed moves.
|
||||
"VMOVAPS": {1, 0, 0x28, 0x29, 0, [3]int{16, 32, 64}},
|
||||
"VMOVAPD": {1, 1, 0x28, 0x29, 1, [3]int{16, 32, 64}},
|
||||
// EVEX.128/256/512.66.0F — aligned integer moves.
|
||||
// EVEX.128/256/512.66.0F, aligned integer moves.
|
||||
"VMOVDQA32": {1, 1, 0x6F, 0x7F, 0, [3]int{16, 32, 64}},
|
||||
"VMOVDQA64": {1, 1, 0x6F, 0x7F, 1, [3]int{16, 32, 64}},
|
||||
// EVEX.128.F3.0F.W0 — scalar single move, memory operands (the
|
||||
// EVEX.128.F3.0F.W0, scalar single move, memory operands (the
|
||||
// three-operand register form is not supported).
|
||||
"VMOVSS": {1, 2, 0x10, 0x11, 0, [3]int{4, 4, 4}},
|
||||
}
|
||||
@@ -559,7 +559,7 @@ func isEvex(mnemUpper string) bool {
|
||||
|
||||
// evexRequired reports whether the operands force the EVEX encoding of a
|
||||
// mnemonic that also has a VEX form: ZMM and K registers do, and so do
|
||||
// register indices 16–31, which only EVEX can represent (X16–Y31 exist
|
||||
// register indices 16-31, which only EVEX can represent (X16-Y31 exist
|
||||
// solely under AVX-512).
|
||||
func evexRequired(upper string, ops []Operand) bool {
|
||||
_, inVex := vexTable[upper]
|
||||
@@ -578,7 +578,7 @@ func evexRequired(upper string, ops []Operand) bool {
|
||||
// evexSuffix carries the EVEX mnemonic suffixes the Go assembler accepts:
|
||||
// zeroing (.Z), a rounding mode (.RN_SAE, .RD_SAE, .RU_SAE, .RZ_SAE),
|
||||
// suppress-all-exceptions (.SAE) and memory broadcast (.BCST). Masking is
|
||||
// not a suffix — Go writes it as an explicit K operand.
|
||||
// not a suffix, Go writes it as an explicit K operand.
|
||||
type evexSuffix struct {
|
||||
zeroing bool
|
||||
sae bool
|
||||
@@ -668,7 +668,7 @@ var evexRound = map[string]bool{
|
||||
}
|
||||
|
||||
// evexBcstN maps an instruction accepting .BCST to the broadcast element
|
||||
// size — the disp8×N multiplier for its memory operand.
|
||||
// size, the disp8×N multiplier for its memory operand.
|
||||
var evexBcstN = map[string]int{
|
||||
"VADDPD": 8, "VSUBPD": 8, "VMULPD": 8, "VDIVPD": 8,
|
||||
"VMINPD": 8, "VMAXPD": 8,
|
||||
@@ -689,7 +689,7 @@ var evexBcstN = map[string]int{
|
||||
"VCVTTPD2QQ": 8, "VCVTTPS2QQ": 4, "VCVTUQQ2PD": 8, "VCVTUQQ2PS": 8,
|
||||
}
|
||||
|
||||
// splitMask extracts an explicit mask register (K1–K7) from the operand list,
|
||||
// splitMask extracts an explicit mask register (K1-K7) from the operand list,
|
||||
// returning the remaining operands and the mask index. K0 is not a usable
|
||||
// mask (aaa = 0 means "no mask"), matching the assembler.
|
||||
func splitMask(ops []Operand) ([]Operand, int, error) {
|
||||
@@ -712,7 +712,7 @@ func splitMask(ops []Operand) ([]Operand, int, error) {
|
||||
}
|
||||
|
||||
// encodeEvex encodes an EVEX instruction with operands in Plan 9 order. The
|
||||
// mask, when present, is an explicit K1–K7 operand anywhere among the
|
||||
// mask, when present, is an explicit K1-K7 operand anywhere among the
|
||||
// operands; the mnemonic suffix carries zeroing, rounding/SAE and
|
||||
// broadcast.
|
||||
func (e *enc) encodeEvex(mnemUpper string, ops []Operand, sfx evexSuffix) error {
|
||||
@@ -1042,7 +1042,7 @@ func (e *enc) encodeEvexMove(mnem string, ms evexMoveSpec, ops []Operand, mask i
|
||||
}
|
||||
|
||||
// encodeEvexRMSrcLen encodes a length-narrowing conversion: OP src, dst with
|
||||
// the destination always XMM and the length fixed by the mnemonic — the
|
||||
// the destination always XMM and the length fixed by the mnemonic, the
|
||||
// single valid slot of spec.n names the vector length (and the disp8×N
|
||||
// multiplier) a register or memory source encodes.
|
||||
func (e *enc) encodeEvexRMSrcLen(spec evexSpec, ops []Operand, mask int, sfx evexSuffix) error {
|
||||
@@ -1061,7 +1061,7 @@ func (e *enc) encodeEvexRMSrcLen(spec evexSpec, ops []Operand, mask int, sfx eve
|
||||
return e.emitEvexFields(spec, ll, dstReg.idx, -1, src, mask, sfx)
|
||||
}
|
||||
|
||||
// soleLen returns the vector-length index of the single valid slot of n —
|
||||
// soleLen returns the vector-length index of the single valid slot of n
|
||||
// the length a length-fixed mnemonic (the EVEX conversion spellings) encodes
|
||||
// regardless of its operands.
|
||||
func soleLen(n [3]int) (int, error) {
|
||||
@@ -1131,8 +1131,8 @@ func (e *enc) encodeEvexBcast(bs evexBcastSpec, ops []Operand, mask int, sfx eve
|
||||
|
||||
// emitEvexFields emits the EVEX prefix, opcode, ModR/M, SIB and displacement
|
||||
// (disp8×N compressed) for the given precomputed fields. regIdx is the
|
||||
// unextended reg-field register index, or a /digit (0–7); vvvvIdx is the
|
||||
// vvvv register index, or -1 when unused. mask (K1–K7, 0 = unmasked) and
|
||||
// unextended reg-field register index, or a /digit (0-7); vvvvIdx is the
|
||||
// vvvv register index, or -1 when unused. mask (K1-K7, 0 = unmasked) and
|
||||
// zeroing fill the aaa and z bits of the P2 byte.
|
||||
func (e *enc) emitEvexFields(spec evexSpec, ll, regIdx, vvvvIdx int, rm Operand, mask int, sfx evexSuffix) error {
|
||||
if ll > 2 {
|
||||
@@ -1324,7 +1324,7 @@ func isScatter(upper string) bool {
|
||||
}
|
||||
|
||||
// vsibLen validates a VSIB memory operand (the index must be a vector
|
||||
// register) and returns it with the vector length the index selects — the
|
||||
// register) and returns it with the vector length the index selects, the
|
||||
// EVEX L'L field follows the index register, not the data register.
|
||||
func vsibLen(op Operand, what string) (Mem, int, error) {
|
||||
m, ok := op.(Mem)
|
||||
@@ -1383,7 +1383,7 @@ func (e *enc) encodeGather(upper string, gs gatherSpec, ops []Operand, sfx evexS
|
||||
return e.emitVexFields(spec, dst.vecLenBit(), dst.idx&7, rBit, 15-maskReg.idx, vsib)
|
||||
}
|
||||
|
||||
// encodeScatter encodes a scatter (EVEX only): OP src, K, vsib — reg = src,
|
||||
// encodeScatter encodes a scatter (EVEX only): OP src, K, vsib, reg = src,
|
||||
// rm = the VSIB memory operand, the K mask in aaa and L following the VSIB
|
||||
// index.
|
||||
func (e *enc) encodeScatter(upper string, ss gatherSpec, ops []Operand, sfx evexSuffix) error {
|
||||
@@ -1411,15 +1411,15 @@ func (e *enc) encodeScatter(upper string, ss gatherSpec, ops []Operand, sfx evex
|
||||
|
||||
// evexKOperand lists the instructions whose K register is a genuine operand
|
||||
// (the source or destination of a mask/vector conversion) rather than a
|
||||
// mask modifier — the M2 and 2M conversions. They take no masking.
|
||||
// mask modifier, the M2 and 2M conversions. They take no masking.
|
||||
var evexKOperand = map[string]bool{
|
||||
"VPMOVM2B": true, "VPMOVM2W": true, "VPMOVM2D": true, "VPMOVM2Q": true,
|
||||
"VPMOVB2M": true, "VPMOVW2M": true, "VPMOVD2M": true, "VPMOVQ2M": true,
|
||||
}
|
||||
|
||||
// kmovSpec describes a KMOV width: the opcode depends on the operand
|
||||
// direction — kk (k/mem → K is 90, k → k uses the same), kmem (K → mem),
|
||||
// gprk (GPR/mem → K), kgpr (K → GPR) — and the GPR forms carry a mandatory
|
||||
// direction, kk (k/mem → K is 90, k → k uses the same), kmem (K → mem),
|
||||
// gprk (GPR/mem → K), kgpr (K → GPR), and the GPR forms carry a mandatory
|
||||
// prefix and W for the wider widths.
|
||||
type kmovSpec struct {
|
||||
kk, kmem, gprk, kgpr byte
|
||||
|
||||
Reference in New Issue
Block a user