feat(arch): add the scalar FP16 memory forms to the amd64 extension layer

Assisted-by: GLM 5.3 Flash
This commit is contained in:
petrbalvin committed 2026-10-07 01:35:48 +02:00
1 parent 7d69dda874
commit d275dee3ae
3 files changed
+228 -20

No files matched your search

+139 -2
View File
@@ -264,6 +264,75 @@ var amd64GoldenRows = []amd64GoldenRow{
[]ExtOperand{ExtImmediate(0x7b), ExtXmm(29), ExtXmm(28), ExtXmm(30)},
"620314000af47b", "62 03 14 00 0a f4 7b vrndscalesh $0x7b,%xmm28,%xmm29,%xmm30"},
// The memory forms of the scalar moves and arithmetic, against the same
// listings' memory rows. The zero-displacement rows match the GNU
// source spellings outright and every base R8+ row exercises the EVEX.B
// high-base bit. The disp8 rows pin the bytes the listing lays down;
// binutils mainline encodes EVEX displacements with the APX disp8*N
// scaling, so its source spellings (0xfe for the m16 rows, 0x1fc0 for
// the m512 ones) are N times the plain SDM displacement those bytes
// carry, and the operand lists here hold the plain displacement. The
// rows with no GNU line are derived: the disp32 form the SDM ModR/M
// table defines and the source listings never emit plain, and the SIB
// byte the R12 base demands.
{"vmovsh load from r9", "VMOVSH",
[]ExtOperand{ExtMemory(9, 0), ExtXmm(30)},
"62457e081031", "62 45 7e 08 10 31 vmovsh (%r9),%xmm30"},
{"vmovsh load disp8", "VMOVSH",
[]ExtOperand{ExtMemory(1, 127), ExtXmm(30)},
"62657e0810717f", "62 65 7e 08 10 71 7f vmovsh 0xfe(%rcx),%xmm30 (Disp8(7f))"},
{"vmovsh store to r9", "VMOVSH",
[]ExtOperand{ExtXmm(30), ExtMemory(9, 0)},
"62457e081131", "62 45 7e 08 11 31 vmovsh %xmm30,(%r9)"},
{"vmovsh store disp8", "VMOVSH",
[]ExtOperand{ExtXmm(30), ExtMemory(1, 127)},
"62657e0811717f", "62 65 7e 08 11 71 7f vmovsh %xmm30,0xfe(%rcx) (Disp8(7f))"},
{"vmovsh store negative disp32", "VMOVSH",
[]ExtOperand{ExtXmm(30), ExtMemory(13, -200)},
"62457e0811b538ffffff", ""},
{"vmovw load from r9", "VMOVW",
[]ExtOperand{ExtMemory(9, 0), ExtXmm(30)},
"62457d086e31", "62 45 7d 08 6e 31 vmovw (%r9),%xmm30"},
{"vmovw load disp8", "VMOVW",
[]ExtOperand{ExtMemory(1, 127), ExtXmm(30)},
"62657d086e717f", "62 65 7d 08 6e 71 7f vmovw 0xfe(%rcx),%xmm30 (Disp8(7f))"},
{"vmovw store to r9", "VMOVW",
[]ExtOperand{ExtXmm(30), ExtMemory(9, 0)},
"62457d087e31", "62 45 7d 08 7e 31 vmovw %xmm30,(%r9)"},
{"vmovw store disp8", "VMOVW",
[]ExtOperand{ExtXmm(30), ExtMemory(1, 127)},
"62657d087e717f", "62 65 7d 08 7e 71 7f vmovw %xmm30,0xfe(%rcx) (Disp8(7f))"},
{"vaddsh memory source", "VADDSH",
[]ExtOperand{ExtXmm(29), ExtMemory(9, 0), ExtXmm(30)},
"624516005831", "62 45 16 00 58 31 vaddsh (%r9),%xmm29,%xmm30"},
{"vaddsh memory source disp8", "VADDSH",
[]ExtOperand{ExtXmm(29), ExtMemory(1, 127), ExtXmm(30)},
"6265160058717f", "62 65 16 00 58 71 7f vaddsh 0xfe(%rcx),%xmm29,%xmm30 (Disp8(7f))"},
{"vaddsh memory source disp32", "VADDSH",
[]ExtOperand{ExtXmm(29), ExtMemory(2, 8128), ExtXmm(30)},
"6265160058b2c01f0000", ""},
{"vsubsh memory source", "VSUBSH",
[]ExtOperand{ExtXmm(29), ExtMemory(9, 0), ExtXmm(30)},
"624516005c31", "62 45 16 00 5c 31 vsubsh (%r9),%xmm29,%xmm30"},
{"vmulsh memory source disp8", "VMULSH",
[]ExtOperand{ExtXmm(29), ExtMemory(1, 127), ExtXmm(30)},
"6265160059717f", "62 65 16 00 59 71 7f vmulsh 0xfe(%rcx),%xmm29,%xmm30 (Disp8(7f))"},
{"vdivsh memory source", "VDIVSH",
[]ExtOperand{ExtXmm(29), ExtMemory(9, 0), ExtXmm(30)},
"624516005e31", "62 45 16 00 5e 31 vdivsh (%r9),%xmm29,%xmm30"},
{"vminsh memory source disp8", "VMINSH",
[]ExtOperand{ExtXmm(29), ExtMemory(1, 127), ExtXmm(30)},
"626516005d717f", "62 65 16 00 5d 71 7f vminsh 0xfe(%rcx),%xmm29,%xmm30 (Disp8(7f))"},
{"vmaxsh memory source", "VMAXSH",
[]ExtOperand{ExtXmm(29), ExtMemory(9, 0), ExtXmm(30)},
"624516005f31", "62 45 16 00 5f 31 vmaxsh (%r9),%xmm29,%xmm30"},
{"vsqrtsh memory source", "VSQRTSH",
[]ExtOperand{ExtXmm(29), ExtMemory(9, 0), ExtXmm(30)},
"624516005131", "62 45 16 00 51 31 vsqrtsh (%r9),%xmm29,%xmm30"},
{"vsqrtsh memory source negative disp8", "VSQRTSH",
[]ExtOperand{ExtXmm(29), ExtMemory(2, -128), ExtXmm(30)},
"62651600517280", "62 65 16 87 51 72 80 vsqrtsh -0x100(%rdx),%xmm29,%xmm30 (Disp8(80); the GNU row adds {k7}{z})"},
// High registers in a 512-bit form exercise the EVEX extension bits:
// with both sources above 15 the B bar and X bar bits clear, while the
// destination zmm23 keeps R bar set in byte one (derived from the
@@ -386,6 +455,9 @@ func TestAmd64ExtTemplateIntegrity(t *testing.T) {
if in.Form.Arity() < 2 || in.Form.Arity() > 4 {
t.Errorf("%s: form %s carries an unusable arity %d", in.Name, in.Form, in.Form.Arity())
}
if in.Mem > in.Form.Arity() {
t.Errorf("%s: Mem names operand %d, outside the form's %d positions", in.Name, in.Mem, in.Form.Arity())
}
}
}
@@ -466,6 +538,27 @@ func TestAmd64ExtRejects(t *testing.T) {
{"mask beyond k7 on the compare", "VCMPSH",
[]ExtOperand{ExtImmediate(7), ExtXmm(28), ExtXmm(29), ExtMask(8)},
"outside 0-7"},
{"memory in the arithmetic's first source", "VADDSH",
[]ExtOperand{ExtMemory(9, 0), ExtXmm(28), ExtXmm(30)},
"wants an XMM register"},
{"memory in the arithmetic's destination", "VADDSH",
[]ExtOperand{ExtXmm(28), ExtXmm(29), ExtMemory(9, 0)},
"wants an XMM register"},
{"memory where the general register belongs", "VCVTSI2SH",
[]ExtOperand{ExtXmm(29), ExtMemory(9, 0), ExtXmm(30)},
"wants a 32-bit general register"},
{"memory as the compare's second source", "VCMPSH",
[]ExtOperand{ExtImmediate(7), ExtXmm(28), ExtMemory(9, 0), ExtMask(5)},
"wants an XMM register"},
{"memory as the intersect source", "VP2INTERSECTD",
[]ExtOperand{ExtZmm(2), ExtMemory(9, 0), ExtMask(0)},
"wants a ZMM register"},
{"memory as the convert's source", "VCVTSS2SH",
[]ExtOperand{ExtXmm(28), ExtMemory(9, 0), ExtXmm(30)},
"wants an XMM register"},
{"memory as the control byte", "VGETMANTSH",
[]ExtOperand{ExtMemory(9, 0), ExtXmm(28), ExtXmm(29), ExtXmm(30)},
"wants an immediate control byte"},
} {
in := amd64ExtInstr(t, tt.mnem, operandClass(t, tt.ops))
_, err := in.Encode(tt.ops)
@@ -486,6 +579,50 @@ func TestAmd64ExtRejects(t *testing.T) {
}
}
// TestAmd64ExtMemoryFormRejects covers the shapes the memory forms refuse:
// a register in the load's memory position, a memory operand in the store's
// register position, and the out-of-range bases and displacements. The
// rows resolve against the load and store entries themselves, which the
// name-and-class lookup cannot pick alone: the register forms of the same
// mnemonics share the class.
func TestAmd64ExtMemoryFormRejects(t *testing.T) {
load := func(in ExtInstr) bool { return in.Form == ExtFormAmdMemVec }
store := func(in ExtInstr) bool { return in.Form == ExtFormAmdVecMem }
for _, tt := range []struct {
name string
mnem string
pick func(ExtInstr) bool
ops []ExtOperand
quote string
}{
{"vector in the load's memory position", "VMOVSH", load,
[]ExtOperand{ExtXmm(29), ExtXmm(30)},
"wants a memory operand"},
{"memory in the store's register position", "VMOVSH", store,
[]ExtOperand{ExtMemory(9, 0), ExtMemory(1, 0)},
"wants an XMM register"},
{"vector in the store's memory position", "VMOVSH", store,
[]ExtOperand{ExtXmm(29), ExtXmm(30)},
"wants a memory operand"},
{"base beyond r15 on the load", "VMOVW", load,
[]ExtOperand{ExtMemory(16, 0), ExtXmm(30)},
"outside 0-15"},
{"displacement past the signed 32-bit range on the store", "VMOVW", store,
[]ExtOperand{ExtXmm(30), ExtMemory(8, 1<<32)},
"outside the signed 32-bit range"},
} {
in := amd64ExtInstr(t, tt.mnem, ExtXMM, tt.pick)
_, err := in.Encode(tt.ops)
if err == nil {
t.Errorf("%s: encode succeeded, want an error", tt.name)
continue
}
if !strings.Contains(err.Error(), tt.quote) {
t.Errorf("%s: error %q lacks %q", tt.name, err, tt.quote)
}
}
}
// operandClass names the vector class a row exercises, the key the entry
// lookup resolves with.
func operandClass(t *testing.T, ops []ExtOperand) ExtOperandKind {
@@ -554,7 +691,7 @@ func TestAmd64ExtArchBinding(t *testing.T) {
t.Errorf("Extensions(%s) carries %d instructions, want none", a, len(got))
}
}
if got := Extensions(AMD64); len(got) != 66 {
t.Errorf("the amd64 layer registers %d instructions, want 66", len(got))
if got := Extensions(AMD64); len(got) != 70 {
t.Errorf("the amd64 layer registers %d instructions, want 70", len(got))
}
}