Files
gasm-sdk/asm/rendered_text_test.go
T
petrbalvin e7a1c20467 fix(asm): prefix MOVQ2DQ with F3
The two bank-crossing quadword moves take the mandatory prefix by
direction: the toolchain renders F3 0F D6 as MOVQ2DQ with the MMX
source and F2 0F D6 as MOVDQ2Q with the XMM source, and the encoder
emitted F2 for both, so MOVQ2DQ encoded MOVDQ2Q.

Assisted-by: GLM 5.3 Flash
2026-10-07 02:12:21 +02:00

52 lines
1.6 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
package asm
import (
"encoding/hex"
"strings"
"testing"
"sourcedock.dev/petrbalvin/gasm-sdk/parser"
)
// TestRenderedTextEncodes pins the encoder against the disassembler's
// renderings: every line here is a text the toolchain's own decoder prints
// for bytes its assembler produced (the disasm package's parity fixtures),
// so assembling the printed text must reproduce those bytes. Each row was
// read back through the toolchain's decoder; the hex is the fixture's.
func TestRenderedTextEncodes(t *testing.T) {
for _, tt := range []struct {
text string
want string
}{
// The segment-absolute rendering lowers to the FS-prefixed disp32
// absolute, exactly what the 0(FS) spelling encodes.
{"MOVQ FS:0, DX", "64488b142500000000"},
// The bank-crossing quadword move takes the prefix by direction: the
// MMX source carries F3, the XMM source F2.
{"MOVQ2DQ M2, X11", "f3440fd6da"},
} {
src := "TEXT \u00b7k(SB), NOSPLIT, $0\n\t" + tt.text + "\n\tRET\n"
f, errs := parser.Parse("k.s", src)
if len(errs) > 0 {
t.Errorf("%s: parse: %v", tt.text, errs[0])
continue
}
img, err := AssembleFile(f)
if err != nil {
t.Errorf("%s: assemble: %v", tt.text, err)
continue
}
fn := img.Funcs[0]
code := img.Code[fn.Offset : fn.Offset+fn.Size]
// The no-fallthrough rule appends the RET; the pinned instruction is
// the prefix.
got := hex.EncodeToString(code)
if !strings.HasPrefix(got, tt.want) {
t.Errorf("%s: bytes %s, want prefix %s", tt.text, got, tt.want)
}
}
}