style: purge em dashes from the produced text

Assisted-by: GLM 5.3 Flash
This commit is contained in:
2026-09-16 23:12:31 +02:00
parent 6a7317d141
commit 0078f7be5c
25 changed files with 67 additions and 67 deletions
+1 -1
View File
@@ -166,6 +166,6 @@ recipe.
## Licence ## Licence
BSD-3-Clause — see [LICENSE](LICENSE). BSD-3-Clause; see [LICENSE](LICENSE).
Copyright © 2026 [Petr Balvín](https://petrbalvin.org) Copyright © 2026 [Petr Balvín](https://petrbalvin.org)
+2 -2
View File
@@ -202,8 +202,8 @@ TEXT ·withframe(SB), NOSPLIT, $16-16
} }
// TestAssembleVexKernel assembles the horizontal-sum reduction the go-flac // TestAssembleVexKernel assembles the horizontal-sum reduction the go-flac
// kernels end with — exercising the VEX moves, shuffle and extract forms // kernels end with; exercising the VEX moves, shuffle and extract forms
// through the full parser → encoder path — and checks the output is // through the full parser → encoder path; and checks the output is
// byte-identical to the Go assembler's. // byte-identical to the Go assembler's.
func TestAssembleVexKernel(t *testing.T) { func TestAssembleVexKernel(t *testing.T) {
fn := firstText(t, ` fn := firstText(t, `
+1 -1
View File
@@ -52,7 +52,7 @@ func elfTestImage(t *testing.T) *Image {
} }
// TestAssembleFileExternals checks that a reference to a symbol no GLOBL // TestAssembleFileExternals checks that a reference to a symbol no GLOBL
// defines is recorded as an external relocation instead of failing — the // defines is recorded as an external relocation instead of failing; the
// raw image leaves the displacement zero, the object emitters carry it. // raw image leaves the displacement zero, the object emitters carry it.
func TestAssembleFileExternals(t *testing.T) { func TestAssembleFileExternals(t *testing.T) {
img := elfTestImage(t) img := elfTestImage(t)
+2 -2
View File
@@ -230,7 +230,7 @@ func TestSSEMoveGroundTruth(t *testing.T) {
// TestGoFlacScalarTail encodes the scalar tail of an analyze kernel to confirm // TestGoFlacScalarTail encodes the scalar tail of an analyze kernel to confirm
// the encoder handles a realistic instruction sequence. // the encoder handles a realistic instruction sequence.
func TestGoFlacScalarTail(t *testing.T) { func TestGoFlacScalarTail(t *testing.T) {
// MOVQ swin_base+0(FP), SI — modelled as MOVQ disp(reg), reg. // MOVQ swin_base+0(FP), SI; modelled as MOVQ disp(reg), reg.
checkSyntax(t, "mov rsi, qword ptr [rax+0x10]", "MOVQ", Ptr(AX, 0x10, 8), SI) checkSyntax(t, "mov rsi, qword ptr [rax+0x10]", "MOVQ", Ptr(AX, 0x10, 8), SI)
checkSyntax(t, "lea r9, ptr [rsi+4*rbx]", "LEAQ", Idx(SI, BX, 4, 0, 8), Reg{idx: 9, size: 8}) checkSyntax(t, "lea r9, ptr [rsi+4*rbx]", "LEAQ", Idx(SI, BX, 4, 0, 8), Reg{idx: 9, size: 8})
checkSyntax(t, "and r10, -0x8", "ANDQ", Imm(-8), Reg{idx: 10, size: 8}) checkSyntax(t, "and r10, -0x8", "ANDQ", Imm(-8), Reg{idx: 10, size: 8})
@@ -421,7 +421,7 @@ func TestSSEShuffleGroundTruth(t *testing.T) {
} }
// TestMOVQXMMGroundTruth pins the SSE2 packed-quadword move encodings: // TestMOVQXMMGroundTruth pins the SSE2 packed-quadword move encodings:
// loads and register moves on F3 0F 7E, stores on 66 0F D6 — the forms // loads and register moves on F3 0F 7E, stores on 66 0F D6; the forms
// the GPR-move fallback silently corrupted. // the GPR-move fallback silently corrupted.
func TestMOVQXMMGroundTruth(t *testing.T) { func TestMOVQXMMGroundTruth(t *testing.T) {
cases := []struct { cases := []struct {
+13 -13
View File
@@ -16,7 +16,7 @@ import (
// kernels use: NDS arithmetic, immediate and variable shifts, shuffles with // kernels use: NDS arithmetic, immediate and variable shifts, shuffles with
// an immediate, lane extracts, narrowing stores, broadcasts from a GPR or // an immediate, lane extracts, narrowing stores, broadcasts from a GPR or
// memory, mask destinations, mask moves, disp8×N compression and the 5-bit // memory, mask destinations, mask moves, disp8×N compression and the 5-bit
// register fields (X/Y 16–31, Z 0–31). // register fields (X/Y 16-31, Z 0-31).
func TestEvexGroundTruth(t *testing.T) { func TestEvexGroundTruth(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
@@ -58,7 +58,7 @@ func TestEvexGroundTruth(t *testing.T) {
{"VMOVDQU32 16(SI)(R15*4),Z4", "VMOVDQU32", []Operand{Idx(SI, vreg(t, "R15"), 4, 16, 64), vreg(t, "Z4")}, "62b17e486fa4be10000000"}, {"VMOVDQU32 16(SI)(R15*4),Z4", "VMOVDQU32", []Operand{Idx(SI, vreg(t, "R15"), 4, 16, 64), vreg(t, "Z4")}, "62b17e486fa4be10000000"},
{"VMOVDQU32 Z0,4(SI)(AX*1)", "VMOVDQU32", []Operand{vreg(t, "Z0"), Idx(SI, AX, 1, 4, 64)}, "62f17e487f840604000000"}, {"VMOVDQU32 Z0,4(SI)(AX*1)", "VMOVDQU32", []Operand{vreg(t, "Z0"), Idx(SI, AX, 1, 4, 64)}, "62f17e487f840604000000"},
{"VMOVDQU32 Z3,(DI)(R15*4)", "VMOVDQU32", []Operand{vreg(t, "Z3"), Idx(DI, vreg(t, "R15"), 4, 0, 64)}, "62b17e487f1cbf"}, {"VMOVDQU32 Z3,(DI)(R15*4)", "VMOVDQU32", []Operand{vreg(t, "Z3"), Idx(DI, vreg(t, "R15"), 4, 0, 64)}, "62b17e487f1cbf"},
// VMOVDQU64 — the W1 qword variant. // VMOVDQU64; the W1 qword variant.
{"VMOVDQU64 (SI)(R15*4),Z3", "VMOVDQU64", []Operand{Idx(SI, vreg(t, "R15"), 4, 0, 64), vreg(t, "Z3")}, "62b1fe486f1cbe"}, {"VMOVDQU64 (SI)(R15*4),Z3", "VMOVDQU64", []Operand{Idx(SI, vreg(t, "R15"), 4, 0, 64), vreg(t, "Z3")}, "62b1fe486f1cbe"},
{"VMOVDQU64 Z0,4(SI)(AX*1)", "VMOVDQU64", []Operand{vreg(t, "Z0"), Idx(SI, AX, 1, 4, 64)}, "62f1fe487f840604000000"}, {"VMOVDQU64 Z0,4(SI)(AX*1)", "VMOVDQU64", []Operand{vreg(t, "Z0"), Idx(SI, AX, 1, 4, 64)}, "62f1fe487f840604000000"},
{"VMOVDQU64 Z1,Z2", "VMOVDQU64", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f1fe487fca"}, {"VMOVDQU64 Z1,Z2", "VMOVDQU64", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f1fe487fca"},
@@ -77,7 +77,7 @@ func TestEvexGroundTruth(t *testing.T) {
{"VPSHUFB Z1,Z2,Z3", "VPSHUFB", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f26d4800d9"}, {"VPSHUFB Z1,Z2,Z3", "VPSHUFB", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f26d4800d9"},
{"VMOVDQU8 Z1,Z2", "VMOVDQU8", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f17f487fca"}, {"VMOVDQU8 Z1,Z2", "VMOVDQU8", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f17f487fca"},
{"VMOVDQU16 Z1,Z2", "VMOVDQU16", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f1ff487fca"}, {"VMOVDQU16 Z1,Z2", "VMOVDQU16", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f1ff487fca"},
// Indices 16–31: rm[4] rides in X̄ for register operands. // Indices 16-31: rm[4] rides in X̄ for register operands.
{"VPSHUFD $1,X16,X17", "VPSHUFD", []Operand{Imm(1), vreg(t, "X16"), vreg(t, "X17")}, "62a17d0870c801"}, {"VPSHUFD $1,X16,X17", "VPSHUFD", []Operand{Imm(1), vreg(t, "X16"), vreg(t, "X17")}, "62a17d0870c801"},
{"VMOVUPD (DI),Z14", "VMOVUPD", []Operand{Ptr(DI, 0, 64), vreg(t, "Z14")}, "6271fd481037"}, {"VMOVUPD (DI),Z14", "VMOVUPD", []Operand{Ptr(DI, 0, 64), vreg(t, "Z14")}, "6271fd481037"},
{"VMOVUPD 64(DI),Z14", "VMOVUPD", []Operand{Ptr(DI, 64, 64), vreg(t, "Z14")}, "6271fd48107701"}, {"VMOVUPD 64(DI),Z14", "VMOVUPD", []Operand{Ptr(DI, 64, 64), vreg(t, "Z14")}, "6271fd48107701"},
@@ -96,7 +96,7 @@ func TestEvexGroundTruth(t *testing.T) {
{"VPBROADCASTD 4(SI),Z10", "VPBROADCASTD", []Operand{Ptr(SI, 4, 4), vreg(t, "Z10")}, "62727d48585601"}, {"VPBROADCASTD 4(SI),Z10", "VPBROADCASTD", []Operand{Ptr(SI, 4, 4), vreg(t, "Z10")}, "62727d48585601"},
{"VPBROADCASTQ R8,X31", "VPBROADCASTQ", []Operand{vreg(t, "R8"), vreg(t, "X31")}, "6242fd087cf8"}, {"VPBROADCASTQ R8,X31", "VPBROADCASTQ", []Operand{vreg(t, "R8"), vreg(t, "X31")}, "6242fd087cf8"},
{"VPBROADCASTQ AX,Z9", "VPBROADCASTQ", []Operand{AX, vreg(t, "Z9")}, "6272fd487cc8"}, {"VPBROADCASTQ AX,Z9", "VPBROADCASTQ", []Operand{AX, vreg(t, "Z9")}, "6272fd487cc8"},
// Register indices 16–31 exist only in EVEX encodings. // Register indices 16-31 exist only in EVEX encodings.
{"VPBROADCASTD AX,Y30", "VPBROADCASTD", []Operand{AX, vreg(t, "Y30")}, "62627d287cf0"}, {"VPBROADCASTD AX,Y30", "VPBROADCASTD", []Operand{AX, vreg(t, "Y30")}, "62627d287cf0"},
// Packed double arithmetic / unpack (EVEX forms carry W=1). // Packed double arithmetic / unpack (EVEX forms carry W=1).
{"VSUBPD Z1,Z2,Z3", "VSUBPD", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f1ed485cd9"}, {"VSUBPD Z1,Z2,Z3", "VSUBPD", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f1ed485cd9"},
@@ -107,7 +107,7 @@ func TestEvexGroundTruth(t *testing.T) {
{"VUNPCKHPD Z1,Z2,Z3", "VUNPCKHPD", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f1ed4815d9"}, {"VUNPCKHPD Z1,Z2,Z3", "VUNPCKHPD", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f1ed4815d9"},
{"VSUBPD 64(AX),Z1,Z2", "VSUBPD", []Operand{Ptr(AX, 64, 64), vreg(t, "Z1"), vreg(t, "Z2")}, "62f1f5485c5001"}, {"VSUBPD 64(AX),Z1,Z2", "VSUBPD", []Operand{Ptr(AX, 64, 64), vreg(t, "Z1"), vreg(t, "Z2")}, "62f1f5485c5001"},
{"VSUBPD Z17,Z18,Z19", "VSUBPD", []Operand{vreg(t, "Z17"), vreg(t, "Z18"), vreg(t, "Z19")}, "62a1ed405cd9"}, {"VSUBPD Z17,Z18,Z19", "VSUBPD", []Operand{vreg(t, "Z17"), vreg(t, "Z18"), vreg(t, "Z19")}, "62a1ed405cd9"},
// VMOVDDUP — duplicate the low double; disp8×N = 64 at 512 bits, and // VMOVDDUP; duplicate the low double; disp8×N = 64 at 512 bits, and
// X16/X17 force EVEX (the mod=11 rm[4] extension rides in X̄). // X16/X17 force EVEX (the mod=11 rm[4] extension rides in X̄).
{"VMOVDDUP Z1,Z2", "VMOVDDUP", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f1ff4812d1"}, {"VMOVDDUP Z1,Z2", "VMOVDDUP", []Operand{vreg(t, "Z1"), vreg(t, "Z2")}, "62f1ff4812d1"},
{"VMOVDDUP 64(AX),Z1", "VMOVDDUP", []Operand{Ptr(AX, 64, 64), vreg(t, "Z1")}, "62f1ff48124801"}, {"VMOVDDUP 64(AX),Z1", "VMOVDDUP", []Operand{Ptr(AX, 64, 64), vreg(t, "Z1")}, "62f1ff48124801"},
@@ -150,7 +150,7 @@ func TestEvexGroundTruth(t *testing.T) {
} }
} }
// TestEvexMasking checks the AVX-512 mask operand (K1–K7, placed freely among // TestEvexMasking checks the AVX-512 mask operand (K1-K7, placed freely among
// the operands) and the .Z zeroing suffix, byte for byte against the Go // the operands) and the .Z zeroing suffix, byte for byte against the Go
// assembler. // assembler.
func TestEvexMasking(t *testing.T) { func TestEvexMasking(t *testing.T) {
@@ -241,11 +241,11 @@ func TestEvexMasking(t *testing.T) {
} }
} }
// TestEvexExtendedGroundTruth covers the wider EVEX/AVX-512 set — ternary // TestEvexExtendedGroundTruth covers the wider EVEX/AVX-512 set; ternary
// logic, lane shuffles/inserts/extracts, compares with a K destination, // logic, lane shuffles/inserts/extracts, compares with a K destination,
// permutes, the wider integer families, expand/compress, broadcasts, // permutes, the wider integer families, expand/compress, broadcasts,
// rotates and word shifts, the opmask instructions, the EVEX suffixes // rotates and word shifts, the opmask instructions, the EVEX suffixes
// (rounding/SAE/broadcast) and the aligned/scalar moves — byte for byte // (rounding/SAE/broadcast) and the aligned/scalar moves; byte for byte
// against the Go assembler. // against the Go assembler.
func TestEvexExtendedGroundTruth(t *testing.T) { func TestEvexExtendedGroundTruth(t *testing.T) {
mem64 := func(base Reg) Operand { return Ptr(base, 0, 64) } mem64 := func(base Reg) Operand { return Ptr(base, 0, 64) }
@@ -275,7 +275,7 @@ func TestEvexExtendedGroundTruth(t *testing.T) {
{"VMULPD.RZ_SAE.Z", "VMULPD.RZ_SAE.Z", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "K1"), vreg(t, "Z3")}, "62f1edf959d9"}, {"VMULPD.RZ_SAE.Z", "VMULPD.RZ_SAE.Z", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "K1"), vreg(t, "Z3")}, "62f1edf959d9"},
{"VMAXPD.SAE", "VMAXPD.SAE", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f1ed585fd9"}, {"VMAXPD.SAE", "VMAXPD.SAE", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f1ed585fd9"},
{"VADDPD.BCST", "VADDPD.BCST", []Operand{mem64(AX), vreg(t, "Z1"), vreg(t, "Z2")}, "62f1f5585810"}, {"VADDPD.BCST", "VADDPD.BCST", []Operand{mem64(AX), vreg(t, "Z1"), vreg(t, "Z2")}, "62f1f5585810"},
// Packed single arithmetic (same opcodes, no mandatory prefix) — // Packed single arithmetic (same opcodes, no mandatory prefix);
// ZMM, YMM and XMM widths, rounding and broadcast. // ZMM, YMM and XMM widths, rounding and broadcast.
{"VADDPS", "VADDPS", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f16c4858d9"}, {"VADDPS", "VADDPS", []Operand{vreg(t, "Z1"), vreg(t, "Z2"), vreg(t, "Z3")}, "62f16c4858d9"},
{"VMULPS", "VMULPS", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c5ec59d9"}, {"VMULPS", "VMULPS", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c5ec59d9"},
@@ -399,8 +399,8 @@ func TestEvexExtendedGroundTruth(t *testing.T) {
} }
// TestEvexHelperGroundTruth covers the floating-point helper and conversion // TestEvexHelperGroundTruth covers the floating-point helper and conversion
// tail of the EVEX set — reciprocals, rsqrt, getexp/getmant, scalef, // tail of the EVEX set; reciprocals, rsqrt, getexp/getmant, scalef,
// rndscale, reduce, fixupimm, range, fpclass, the remaining conversions — // rndscale, reduce, fixupimm, range, fpclass, the remaining conversions;
// plus gather/scatter with VSIB addressing, byte for byte against the Go // plus gather/scatter with VSIB addressing, byte for byte against the Go
// assembler. // assembler.
func TestEvexHelperGroundTruth(t *testing.T) { func TestEvexHelperGroundTruth(t *testing.T) {
@@ -502,9 +502,9 @@ func TestEvexHelperGroundTruth(t *testing.T) {
} }
// TestEvexGprGroundTruth covers the scalar conversions between vector and // TestEvexGprGroundTruth covers the scalar conversions between vector and
// general-purpose registers — the signed and truncated VCVT{,T}S{D,S}2SI // general-purpose registers; the signed and truncated VCVT{,T}S{D,S}2SI
// forms (VEX and EVEX), the unsigned EVEX-only forms, and the GPR-to-vector // forms (VEX and EVEX), the unsigned EVEX-only forms, and the GPR-to-vector
// VCVTSI2*/VCVTUSI2* forms with the preserved vector source in vvvv — byte // VCVTSI2*/VCVTUSI2* forms with the preserved vector source in vvvv; byte
// for byte against the Go assembler, including memory sources and extended // for byte against the Go assembler, including memory sources and extended
// GPRs. // GPRs.
func TestEvexGprGroundTruth(t *testing.T) { func TestEvexGprGroundTruth(t *testing.T) {
+4 -4
View File
@@ -158,8 +158,8 @@ DATA mask<>+8(SB)/8, $0x800f0e0d0c0b0a09
t.Errorf("funcinfo bytes %x", fi) t.Errorf("funcinfo bytes %x", fi)
} }
// The pc-value tables of addq (non-package indices 0–3, so global // The pc-value tables of addq (non-package indices 0-3, so global
// indices 7–10): pcsp a flat zero over the whole function, pcinline a // indices 7-10): pcsp a flat zero over the whole function, pcinline a
// flat -1, both with the pc delta in MinLC (1) units. // flat -1, both with the pc delta in MinLC (1) units.
pcsp := data[le.Uint32(didx[4*7:]):] pcsp := data[le.Uint32(didx[4*7:]):]
if got := pcsp[:3]; !bytes.Equal(got, []byte{0x02, 19, 0x00}) { if got := pcsp[:3]; !bytes.Equal(got, []byte{0x02, 19, 0x00}) {
@@ -294,7 +294,7 @@ TEXT ·framed(SB), NOSPLIT, $8-0
} }
for i := range wantPCs { for i := range wantPCs {
if pcs[i] != wantPCs[i] || vals[i] != wantVals[i] { if pcs[i] != wantPCs[i] || vals[i] != wantVals[i] {
t.Errorf("pcsp[%d] = (%d,%d), want (%d,%d) — all: %v %v", i, pcs[i], vals[i], wantPCs[i], wantVals[i], pcs, vals) t.Errorf("pcsp[%d] = (%d,%d), want (%d,%d); all: %v %v", i, pcs[i], vals[i], wantPCs[i], wantVals[i], pcs, vals)
} }
} }
// The last two steps unwind the epilogue to zero. // The last two steps unwind the epilogue to zero.
@@ -333,7 +333,7 @@ TEXT ·useext(SB), NOSPLIT, $0-8
// TestGOObjectLinkAndRun is the end-to-end check: assemble the test // TestGOObjectLinkAndRun is the end-to-end check: assemble the test
// functions to a GOOBJ, swap it into a go build in place of the toolchain's // functions to a GOOBJ, swap it into a go build in place of the toolchain's
// assembly object, link, and run — the output must match the baseline // assembly object, link, and run; the output must match the baseline
// binary the Go assembler produced. Skipped when no Go toolchain is // binary the Go assembler produced. Skipped when no Go toolchain is
// available. // available.
func TestGOObjectLinkAndRun(t *testing.T) { func TestGOObjectLinkAndRun(t *testing.T) {
+3 -3
View File
@@ -19,8 +19,8 @@ import (
"sourcedock.dev/petrbalvin/gasm-devkit/parser" "sourcedock.dev/petrbalvin/gasm-devkit/parser"
) )
// TestAssembleGoFlacAVX2Kernel assembles the whole production AVX2 kernel — // TestAssembleGoFlacAVX2Kernel assembles the whole production AVX2 kernel;
// all functions plus the file-local mask24 constant — and checks that every // all functions plus the file-local mask24 constant; and checks that every
// static-symbol load resolves to the right bytes in the image. // static-symbol load resolves to the right bytes in the image.
func TestAssembleGoFlacAVX2Kernel(t *testing.T) { func TestAssembleGoFlacAVX2Kernel(t *testing.T) {
path := "../../go-libraries/go-flac/avx2_amd64.s" path := "../../go-libraries/go-flac/avx2_amd64.s"
@@ -81,7 +81,7 @@ func TestAssembleGoFlacAVX2Kernel(t *testing.T) {
} }
// TestAssembleGoFlacAVX512Kernel assembles the whole production AVX-512 // TestAssembleGoFlacAVX512Kernel assembles the whole production AVX-512
// kernel — all functions plus the file-global idx16 constant — and checks // kernel, all functions plus the file-global idx16 constant, and checks
// that the static-symbol load resolves to the right bytes in the image. // that the static-symbol load resolves to the right bytes in the image.
func TestAssembleGoFlacAVX512Kernel(t *testing.T) { func TestAssembleGoFlacAVX512Kernel(t *testing.T) {
path := "../../go-libraries/go-flac/avx512_amd64.s" path := "../../go-libraries/go-flac/avx512_amd64.s"
+2 -2
View File
@@ -94,9 +94,9 @@ DATA ·table<>+0(SB)/8, $0x1122334455667788
} }
// The debug_line program: LNE_set_address (the R_ADDR relocation // The debug_line program: LNE_set_address (the R_ADDR relocation
// carries the function address), then one row per line change — the // carries the function address), then one row per line change; the
// TEXT is on line 4 (a leading blank line precedes the include), the // TEXT is on line 4 (a leading blank line precedes the include), the
// instructions on lines 5–9 — an advance to the 20-byte end and an // instructions on lines 5-9; an advance to the 20-byte end and an
// end-of-sequence. // end-of-sequence.
linesOff := le.Uint32(dataIdx[4*2:]) linesOff := le.Uint32(dataIdx[4*2:])
lines := dataBlk[linesOff : linesOff+21] lines := dataBlk[linesOff : linesOff+21]
+2 -2
View File
@@ -10,8 +10,8 @@ import (
"sourcedock.dev/petrbalvin/gasm-devkit/parser" "sourcedock.dev/petrbalvin/gasm-devkit/parser"
) )
// TestAssembleFileStaticData checks the whole-image layout — code, padding // TestAssembleFileStaticData checks the whole-image layout; code, padding
// and the data section — and that the RIP-relative displacements of static // and the data section; and that the RIP-relative displacements of static
// symbol loads resolve to the right bytes. // symbol loads resolve to the right bytes.
func TestAssembleFileStaticData(t *testing.T) { func TestAssembleFileStaticData(t *testing.T) {
f, errs := parser.Parse("d_amd64.s", ` f, errs := parser.Parse("d_amd64.s", `
+1 -1
View File
@@ -280,7 +280,7 @@ done:
// TestLOONG64_pcsp checks the stack-adjustment table of a framed function: // TestLOONG64_pcsp checks the stack-adjustment table of a framed function:
// the prologue raises the SP delta by autosize (in effect from the third // the prologue raises the SP delta by autosize (in effect from the third
// instruction) and the RET's epilogue restores it to zero, with the pc deltas // instruction) and the RET's epilogue restores it to zero, with the pc deltas
// in MinLC (4) units — byte-identical to `go tool asm`. // in MinLC (4) units; byte-identical to `go tool asm`.
func TestLOONG64_pcsp(t *testing.T) { func TestLOONG64_pcsp(t *testing.T) {
cases := []struct { cases := []struct {
name string name string
+1 -1
View File
@@ -289,7 +289,7 @@ TEXT ·cmp(SB), NOSPLIT, $0
} }
func TestRISCV_forwardBranch(t *testing.T) { func TestRISCV_forwardBranch(t *testing.T) {
// Forward label reference — must not fail. // Forward label reference; must not fail.
fn := firstTextRISCV(t, `#include "textflag.h" fn := firstTextRISCV(t, `#include "textflag.h"
TEXT ·fwd(SB), NOSPLIT, $0 TEXT ·fwd(SB), NOSPLIT, $0
ADDI $1, X10, X10 ADDI $1, X10, X10
+5 -5
View File
@@ -173,7 +173,7 @@ func TestVexGroundTruth(t *testing.T) {
{"VPMULLD Y1,Y2,Y3", "VPMULLD", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c4e26d40d9", ""}, {"VPMULLD Y1,Y2,Y3", "VPMULLD", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c4e26d40d9", ""},
{"VPUNPCKLDQ Y4,Y3,Y5", "VPUNPCKLDQ", []Operand{vreg(t, "Y4"), vreg(t, "Y3"), vreg(t, "Y5")}, "c5e562ec", ""}, {"VPUNPCKLDQ Y4,Y3,Y5", "VPUNPCKLDQ", []Operand{vreg(t, "Y4"), vreg(t, "Y3"), vreg(t, "Y5")}, "c5e562ec", ""},
{"VPERMD Y1,Y2,Y3", "VPERMD", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c4e26d36d9", ""}, {"VPERMD Y1,Y2,Y3", "VPERMD", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c4e26d36d9", ""},
// Floating point (packed and scalar) and FMA — same NDS form, the pp // Floating point (packed and scalar) and FMA; same NDS form, the pp
// bits and map select the operation. // bits and map select the operation.
{"VADDPD Y9,Y8,Y8", "VADDPD", []Operand{vreg(t, "Y9"), vreg(t, "Y8"), vreg(t, "Y8")}, "c4413d58c1", ""}, {"VADDPD Y9,Y8,Y8", "VADDPD", []Operand{vreg(t, "Y9"), vreg(t, "Y8"), vreg(t, "Y8")}, "c4413d58c1", ""},
{"VADDPD X1,X2,X3", "VADDPD", []Operand{vreg(t, "X1"), vreg(t, "X2"), vreg(t, "X3")}, "c5e958d9", ""}, {"VADDPD X1,X2,X3", "VADDPD", []Operand{vreg(t, "X1"), vreg(t, "X2"), vreg(t, "X3")}, "c5e958d9", ""},
@@ -217,7 +217,7 @@ func TestVexGroundTruth(t *testing.T) {
{"VEXTRACTI128 $1,Y8,X9", "VEXTRACTI128", []Operand{Imm(1), vreg(t, "Y8"), vreg(t, "X9")}, "c4437d39c101", ""}, {"VEXTRACTI128 $1,Y8,X9", "VEXTRACTI128", []Operand{Imm(1), vreg(t, "Y8"), vreg(t, "X9")}, "c4437d39c101", ""},
{"VEXTRACTI128 $1,Y8,(DI)", "VEXTRACTI128", []Operand{Imm(1), vreg(t, "Y8"), Ptr(DI, 0, 16)}, "c4637d390701", ""}, {"VEXTRACTI128 $1,Y8,(DI)", "VEXTRACTI128", []Operand{Imm(1), vreg(t, "Y8"), Ptr(DI, 0, 16)}, "c4637d390701", ""},
{"VEXTRACTF128 $1,Y8,X9", "VEXTRACTF128", []Operand{Imm(1), vreg(t, "Y8"), vreg(t, "X9")}, "c4437d19c101", ""}, {"VEXTRACTF128 $1,Y8,X9", "VEXTRACTF128", []Operand{Imm(1), vreg(t, "Y8"), vreg(t, "X9")}, "c4437d19c101", ""},
// Moves — each direction picks its own opcode and VEX.W. // Moves; each direction picks its own opcode and VEX.W.
{"VMOVDQU (SI),Y1", "VMOVDQU", []Operand{Ptr(SI, 0, 32), vreg(t, "Y1")}, "c5fe6f0e", ""}, {"VMOVDQU (SI),Y1", "VMOVDQU", []Operand{Ptr(SI, 0, 32), vreg(t, "Y1")}, "c5fe6f0e", ""},
{"VMOVDQU Y3,(DI)", "VMOVDQU", []Operand{vreg(t, "Y3"), Ptr(DI, 0, 32)}, "c5fe7f1f", ""}, {"VMOVDQU Y3,(DI)", "VMOVDQU", []Operand{vreg(t, "Y3"), Ptr(DI, 0, 32)}, "c5fe7f1f", ""},
{"VMOVDQU X1,X2", "VMOVDQU", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5fa7fca", ""}, {"VMOVDQU X1,X2", "VMOVDQU", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5fa7fca", ""},
@@ -234,7 +234,7 @@ func TestVexGroundTruth(t *testing.T) {
{"VMOVD AX,X0", "VMOVD", []Operand{AX, vreg(t, "X0")}, "c5f96ec0", ""}, {"VMOVD AX,X0", "VMOVD", []Operand{AX, vreg(t, "X0")}, "c5f96ec0", ""},
{"VMOVSD (SI),X8", "VMOVSD", []Operand{Ptr(SI, 0, 8), vreg(t, "X8")}, "c57b1006", ""}, {"VMOVSD (SI),X8", "VMOVSD", []Operand{Ptr(SI, 0, 8), vreg(t, "X8")}, "c57b1006", ""},
{"VMOVSD X8,(SI)", "VMOVSD", []Operand{vreg(t, "X8"), Ptr(SI, 0, 8)}, "c57b1106", ""}, {"VMOVSD X8,(SI)", "VMOVSD", []Operand{vreg(t, "X8"), Ptr(SI, 0, 8)}, "c57b1106", ""},
// Packed double arithmetic and unpack — the NDS form, the opcode // Packed double arithmetic and unpack; the NDS form, the opcode
// selects the operation. // selects the operation.
{"VSUBPD Y1,Y2,Y3", "VSUBPD", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c5ed5cd9", ""}, {"VSUBPD Y1,Y2,Y3", "VSUBPD", []Operand{vreg(t, "Y1"), vreg(t, "Y2"), vreg(t, "Y3")}, "c5ed5cd9", ""},
{"VDIVPD X1,X2,X3", "VDIVPD", []Operand{vreg(t, "X1"), vreg(t, "X2"), vreg(t, "X3")}, "c5e95ed9", ""}, {"VDIVPD X1,X2,X3", "VDIVPD", []Operand{vreg(t, "X1"), vreg(t, "X2"), vreg(t, "X3")}, "c5e95ed9", ""},
@@ -255,12 +255,12 @@ func TestVexGroundTruth(t *testing.T) {
{"VMINSS X6,X7,X8", "VMINSS", []Operand{vreg(t, "X6"), vreg(t, "X7"), vreg(t, "X8")}, "c5425dc6", ""}, {"VMINSS X6,X7,X8", "VMINSS", []Operand{vreg(t, "X6"), vreg(t, "X7"), vreg(t, "X8")}, "c5425dc6", ""},
{"VMAXSS X1,X2,X3", "VMAXSS", []Operand{vreg(t, "X1"), vreg(t, "X2"), vreg(t, "X3")}, "c5ea5fd9", ""}, {"VMAXSS X1,X2,X3", "VMAXSS", []Operand{vreg(t, "X1"), vreg(t, "X2"), vreg(t, "X3")}, "c5ea5fd9", ""},
{"VADDSD 8(AX),X1,X2", "VADDSD", []Operand{Ptr(AX, 8, 8), vreg(t, "X1"), vreg(t, "X2")}, "c5f3585008", ""}, {"VADDSD 8(AX),X1,X2", "VADDSD", []Operand{Ptr(AX, 8, 8), vreg(t, "X1"), vreg(t, "X2")}, "c5f3585008", ""},
// VMOVDDUP — duplicate the low double (reg=dst, rm=src, F2 pp). // VMOVDDUP; duplicate the low double (reg=dst, rm=src, F2 pp).
{"VMOVDDUP X1,X2", "VMOVDDUP", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5fb12d1", ""}, {"VMOVDDUP X1,X2", "VMOVDDUP", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5fb12d1", ""},
{"VMOVDDUP Y1,Y2", "VMOVDDUP", []Operand{vreg(t, "Y1"), vreg(t, "Y2")}, "c5ff12d1", ""}, {"VMOVDDUP Y1,Y2", "VMOVDDUP", []Operand{vreg(t, "Y1"), vreg(t, "Y2")}, "c5ff12d1", ""},
{"VMOVDDUP 8(AX),X1", "VMOVDDUP", []Operand{Ptr(AX, 8, 8), vreg(t, "X1")}, "c5fb124808", ""}, {"VMOVDDUP 8(AX),X1", "VMOVDDUP", []Operand{Ptr(AX, 8, 8), vreg(t, "X1")}, "c5fb124808", ""},
// Conversions: DQ→PS (no prefix), PS→PD (Go emits it without the F3 // Conversions: DQ→PS (no prefix), PS→PD (Go emits it without the F3
// prefix — see the table comment), DQ→PD. // prefix; see the table comment), DQ→PD.
{"VCVTDQ2PS X1,X2", "VCVTDQ2PS", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5f85bd1", ""}, {"VCVTDQ2PS X1,X2", "VCVTDQ2PS", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5f85bd1", ""},
{"VCVTDQ2PS Y3,Y4", "VCVTDQ2PS", []Operand{vreg(t, "Y3"), vreg(t, "Y4")}, "c5fc5be3", ""}, {"VCVTDQ2PS Y3,Y4", "VCVTDQ2PS", []Operand{vreg(t, "Y3"), vreg(t, "Y4")}, "c5fc5be3", ""},
{"VCVTPS2PD X1,X2", "VCVTPS2PD", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5f85ad1", ""}, {"VCVTPS2PD X1,X2", "VCVTPS2PD", []Operand{vreg(t, "X1"), vreg(t, "X2")}, "c5f85ad1", ""},
+1 -1
View File
@@ -275,7 +275,7 @@ func TestVerifySmokeCrashIsolation(t *testing.T) {
} }
if exitErr, ok := err.(*exec.ExitError); ok { if exitErr, ok := err.(*exec.ExitError); ok {
if ws, ok := exitErr.Sys().(syscall.WaitStatus); ok && ws.Signaled() { if ws, ok := exitErr.Sys().(syscall.WaitStatus); ok && ws.Signaled() {
t.Fatalf("verify died from %v — the crash was not isolated:\n%s", ws.Signal(), out) t.Fatalf("verify died from %v; the crash was not isolated:\n%s", ws.Signal(), out)
} }
} }
if !strings.Contains(string(out), "CRASH") { if !strings.Contains(string(out), "CRASH") {
+1 -1
View File
@@ -39,7 +39,7 @@ func TestGolden(t *testing.T) {
} }
// TestDocCommentIndent checks that a doc comment preceding a TEXT directive // TestDocCommentIndent checks that a doc comment preceding a TEXT directive
// sits at column 0 even when another function (ending in RET) precedes it — // sits at column 0 even when another function (ending in RET) precedes it;
// the RET must terminate the previous body for indentation purposes. // the RET must terminate the previous body for indentation purposes.
func TestDocCommentIndent(t *testing.T) { func TestDocCommentIndent(t *testing.T) {
in := "#include \"textflag.h\"\n" + in := "#include \"textflag.h\"\n" +
+1 -1
View File
@@ -20,7 +20,7 @@ import (
// architecture's syntax (macros, addressing modes, branch aliases) against // architecture's syntax (macros, addressing modes, branch aliases) against
// production assembly. It is skipped when the toolchain source is absent. // production assembly. It is skipped when the toolchain source is absent.
// //
// The bar is zero parse errors and zero error-severity diagnostics — i.e. no // The bar is zero parse errors and zero error-severity diagnostics; i.e. no
// false "unknown instruction" / "undefined label" findings on code the real // false "unknown instruction" / "undefined label" findings on code the real
// assembler accepts. Advisory warnings are reported but not fatal, since they // assembler accepts. Advisory warnings are reported but not fatal, since they
// are heuristics that may legitimately differ across Go versions. // are heuristics that may legitimately differ across Go versions.
+7 -7
View File
@@ -48,7 +48,7 @@ func TestFixtureIsClean(t *testing.T) {
t.Fatalf("parse: %v", errs) t.Fatalf("parse: %v", errs)
} }
// The fixture mirrors the go-flac kernels, which write the Go ABI0 // The fixture mirrors the go-flac kernels, which write the Go ABI0
// scratch registers (BX, R13) without saving them — legal under Go's // scratch registers (BX, R13) without saving them; legal under Go's
// stack-based ABI, so the register-clobber audit stays silent and the // stack-based ABI, so the register-clobber audit stays silent and the
// fixture must lint entirely clean. // fixture must lint entirely clean.
diags := File(f, Config{Arch: arch.AMD64}) diags := File(f, Config{Arch: arch.AMD64})
@@ -186,8 +186,8 @@ done:
} }
} }
// TestEvexMaskingRecognised checks that masked EVEX forms — the .Z suffix and // TestEvexMaskingRecognised checks that masked EVEX forms; the .Z suffix and
// an explicit K operand — are recognised and exempt from operand-count // an explicit K operand; are recognised and exempt from operand-count
// checks. // checks.
func TestEvexMaskingRecognised(t *testing.T) { func TestEvexMaskingRecognised(t *testing.T) {
diags := lintSrc(t, ` diags := lintSrc(t, `
@@ -284,7 +284,7 @@ TEXT ·f(SB), NOSPLIT|NOFRAME|DUPOK, $0
} }
func TestStackImbalance(t *testing.T) { func TestStackImbalance(t *testing.T) {
// Function with frame size 16 but only SUB 8, SP — imbalance. // Function with frame size 16 but only SUB 8, SP; imbalance.
diags := lintSrc(t, ` diags := lintSrc(t, `
#include "textflag.h" #include "textflag.h"
TEXT ·f(SB), NOSPLIT, $16-0 TEXT ·f(SB), NOSPLIT, $16-0
@@ -297,7 +297,7 @@ TEXT ·f(SB), NOSPLIT, $16-0
} }
func TestStackBalanced(t *testing.T) { func TestStackBalanced(t *testing.T) {
// Function with frame size 16 and matching SUB/ADD — balanced. // Function with frame size 16 and matching SUB/ADD; balanced.
diags := lintSrc(t, ` diags := lintSrc(t, `
#include "textflag.h" #include "textflag.h"
TEXT ·f(SB), NOSPLIT, $16-0 TEXT ·f(SB), NOSPLIT, $16-0
@@ -311,7 +311,7 @@ TEXT ·f(SB), NOSPLIT, $16-0
} }
func TestRegisterWidthMismatch(t *testing.T) { func TestRegisterWidthMismatch(t *testing.T) {
// MOVQ with 32-bit register — mismatch. // MOVQ with 32-bit register; mismatch.
diags := lintSrc(t, ` diags := lintSrc(t, `
#include "textflag.h" #include "textflag.h"
TEXT ·f(SB), NOSPLIT, $0 TEXT ·f(SB), NOSPLIT, $0
@@ -324,7 +324,7 @@ TEXT ·f(SB), NOSPLIT, $0
} }
func TestRegisterWidthCorrect(t *testing.T) { func TestRegisterWidthCorrect(t *testing.T) {
// MOVQ with 64-bit registers — correct. // MOVQ with 64-bit registers; correct.
diags := lintSrc(t, ` diags := lintSrc(t, `
#include "textflag.h" #include "textflag.h"
TEXT ·f(SB), NOSPLIT, $0 TEXT ·f(SB), NOSPLIT, $0
+5 -5
View File
@@ -7,13 +7,13 @@ import "testing"
// TestRegisterClobber checks the register-clobber audit is calibrated to the // TestRegisterClobber checks the register-clobber audit is calibrated to the
// Go ABI (cmd/compile/abi-internal.md), not the platform ABI: Go's // Go ABI (cmd/compile/abi-internal.md), not the platform ABI: Go's
// stack-based ABI0 — which hand-written assembly uses — has no System V // stack-based ABI0, which hand-written assembly uses, has no System V
// style callee-saved registers, so argument and scratch registers may be // style callee-saved registers, so argument and scratch registers may be
// clobbered freely. Only the registers the ABI fixes across calls (the // clobbered freely. Only the registers the ABI fixes across calls (the
// frame pointer, the goroutine pointer, OS-reserved registers) are audited. // frame pointer, the goroutine pointer, OS-reserved registers) are audited.
func TestRegisterClobber(t *testing.T) { func TestRegisterClobber(t *testing.T) {
// amd64: BX, R12, R13 and R15 are argument/permanent-scratch registers in // amd64: BX, R12, R13 and R15 are argument/permanent-scratch registers in
// Go ABI0 — writing them unsaved is legal (a System V calibration would // Go ABI0; writing them unsaved is legal (a System V calibration would
// report all of these). // report all of these).
scratch := lintSrc(t, "#include \"textflag.h\"\n"+ scratch := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+ "TEXT ·f(SB), NOSPLIT, $0\n"+
@@ -27,7 +27,7 @@ func TestRegisterClobber(t *testing.T) {
} }
// amd64: R14 (the goroutine pointer) in a NOSPLIT function without calls // amd64: R14 (the goroutine pointer) in a NOSPLIT function without calls
// is the runtime's own pattern — the ABI0 transition restores it — so it // is the runtime's own pattern (the ABI0 transition restores it), so it
// is not flagged. // is not flagged.
leaf := lintSrc(t, "#include \"textflag.h\"\n"+ leaf := lintSrc(t, "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+ "TEXT ·f(SB), NOSPLIT, $0\n"+
@@ -101,7 +101,7 @@ func TestRegisterClobber(t *testing.T) {
t.Fatalf("arm64 R18 write should be flagged: %+v", armReserved) t.Fatalf("arm64 R18 write should be flagged: %+v", armReserved)
} }
// riscv64: X27 holds the goroutine; X5–X7 are scratch. // riscv64: X27 holds the goroutine; X5-X7 are scratch.
riscScratch := lintSrcArch(t, "t_riscv64.s", "#include \"textflag.h\"\n"+ riscScratch := lintSrcArch(t, "t_riscv64.s", "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+ "TEXT ·f(SB), NOSPLIT, $0\n"+
"\tMOV X5, X6\n"+ "\tMOV X5, X6\n"+
@@ -117,7 +117,7 @@ func TestRegisterClobber(t *testing.T) {
t.Fatalf("unsaved riscv64 X27 write should be flagged: %+v", riscG) t.Fatalf("unsaved riscv64 X27 write should be flagged: %+v", riscG)
} }
// loong64: R22 holds the goroutine; R5–R19 are argument/scratch. // loong64: R22 holds the goroutine; R5-R19 are argument/scratch.
loongScratch := lintSrcArch(t, "t_loong64.s", "#include \"textflag.h\"\n"+ loongScratch := lintSrcArch(t, "t_loong64.s", "#include \"textflag.h\"\n"+
"TEXT ·f(SB), NOSPLIT, $0\n"+ "TEXT ·f(SB), NOSPLIT, $0\n"+
"\tMOVV R5, R6\n"+ "\tMOVV R5, R6\n"+
+3 -3
View File
@@ -149,7 +149,7 @@ func TestOperandStructure(t *testing.T) {
} }
} }
// MOVQ swin_base+0(FP), SI — the first MOVQ in the body. // MOVQ swin_base+0(FP), SI; the first MOVQ in the body.
var mov *ast.Instr var mov *ast.Instr
for _, s := range fn.Body { for _, s := range fn.Body {
if in, ok := s.(*ast.Instr); ok && in.Mnemonic.Text == "MOVQ" { if in, ok := s.(*ast.Instr); ok && in.Mnemonic.Text == "MOVQ" {
@@ -202,7 +202,7 @@ func TestAVX512Operands(t *testing.T) {
} }
} }
// VALIGND $15, Z9, Z0, Z1 — four operands. // VALIGND $15, Z9, Z0, Z1; four operands.
val := byMnem["VALIGND"] val := byMnem["VALIGND"]
if val == nil { if val == nil {
t.Fatal("VALIGND not found") t.Fatal("VALIGND not found")
@@ -224,7 +224,7 @@ func TestAVX512Operands(t *testing.T) {
t.Errorf("VMOVDQU32 dst = %+v, want 4(SI)(AX*1)", dst) t.Errorf("VMOVDQU32 dst = %+v, want 4(SI)(AX*1)", dst)
} }
// KTESTW K1, K1 — mask registers parse as bare names. // KTESTW K1, K1; mask registers parse as bare names.
kt := byMnem["KTESTW"] kt := byMnem["KTESTW"]
if kt == nil || len(kt.Operands) != 2 { if kt == nil || len(kt.Operands) != 2 {
t.Fatalf("KTESTW = %+v, want two operands", kt) t.Fatalf("KTESTW = %+v, want two operands", kt)
+1 -1
View File
@@ -20,7 +20,7 @@ TEXT ·dirtyBP(SB), NOSPLIT, $0-16
RET RET
// func dirtyR14(a int64) int64 // func dirtyR14(a int64) int64
// Deliberately clobbers R14 (the goroutine pointer — a serious ABI violation). // Deliberately clobbers R14 (the goroutine pointer; a serious ABI violation).
TEXT ·dirtyR14(SB), NOSPLIT, $0-16 TEXT ·dirtyR14(SB), NOSPLIT, $0-16
MOVQ $0x5678, R14 MOVQ $0x5678, R14
MOVQ a+0(FP), AX MOVQ a+0(FP), AX
+2 -2
View File
@@ -9,7 +9,7 @@
// //
// The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no // The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no
// Go function declaration, so the toolchain does NOT interpose an // Go function declaration, so the toolchain does NOT interpose an
// ABIInternal wrapper — the JIT function RETs directly into the check code, // ABIInternal wrapper; the JIT function RETs directly into the check code,
// which sees the registers exactly as the function left them. // which sees the registers exactly as the function left them.
// //
// Go ABI0 on amd64 guarantees: // Go ABI0 on amd64 guarantees:
@@ -39,7 +39,7 @@ TEXT ·enterJITChecked(SB), NOSPLIT, $0-16
JMP AX JMP AX
// leaveJITCheckedRaw is the raw return trampoline. It has NO Go function // leaveJITCheckedRaw is the raw return trampoline. It has NO Go function
// declaration, so no ABIInternal wrapper is generated — the JIT function's // declaration, so no ABIInternal wrapper is generated; the JIT function's
// RET lands here directly, seeing BP and R14 exactly as the function left // RET lands here directly, seeing BP and R14 exactly as the function left
// them. It checks the sentinels, records violations in abiResult, then // them. It checks the sentinels, records violations in abiResult, then
// restores the Go stack and returns. // restores the Go stack and returns.
+2 -2
View File
@@ -9,7 +9,7 @@
// //
// The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no // The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no
// Go function declaration, so the toolchain does NOT interpose an // Go function declaration, so the toolchain does NOT interpose an
// ABIInternal wrapper — the JIT function RETs directly into the check // ABIInternal wrapper; the JIT function RETs directly into the check
// code, which sees the registers exactly as the function left them. // code, which sees the registers exactly as the function left them.
// //
// Go ABI on arm64 guarantees: // Go ABI on arm64 guarantees:
@@ -48,7 +48,7 @@ TEXT ·enterJITChecked(SB), NOSPLIT, $0-16
JMP (R0) // branch to JIT function JMP (R0) // branch to JIT function
// leaveJITCheckedRaw is the raw return trampoline. It has NO Go function // leaveJITCheckedRaw is the raw return trampoline. It has NO Go function
// declaration, so no ABIInternal wrapper is generated — the JIT function's // declaration, so no ABIInternal wrapper is generated; the JIT function's
// RET lands here directly, seeing R29 and g exactly as the function left // RET lands here directly, seeing R29 and g exactly as the function left
// them. It checks the sentinels, records violations in abiResult, then // them. It checks the sentinels, records violations in abiResult, then
// restores the Go stack and returns. // restores the Go stack and returns.
+2 -2
View File
@@ -9,7 +9,7 @@
// //
// The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no // The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no
// Go function declaration, so the toolchain does NOT interpose an // Go function declaration, so the toolchain does NOT interpose an
// ABIInternal wrapper — the JIT function RETs directly into the check // ABIInternal wrapper; the JIT function RETs directly into the check
// code, which sees the registers exactly as the function left them. // code, which sees the registers exactly as the function left them.
// //
// Go ABI on loong64 guarantees: // Go ABI on loong64 guarantees:
@@ -42,7 +42,7 @@ TEXT ·enterJITChecked(SB), NOSPLIT, $0-16
JIRL R0, R4, 0 // jump to JIT function JIRL R0, R4, 0 // jump to JIT function
// leaveJITCheckedRaw is the raw return trampoline. It has NO Go function // leaveJITCheckedRaw is the raw return trampoline. It has NO Go function
// declaration, so no ABIInternal wrapper is generated — the JIT function's // declaration, so no ABIInternal wrapper is generated; the JIT function's
// RET lands here directly, seeing g exactly as the function left it. It // RET lands here directly, seeing g exactly as the function left it. It
// checks the sentinel, records violations in abiResult, then restores the // checks the sentinel, records violations in abiResult, then restores the
// Go stack and returns. // Go stack and returns.
+2 -2
View File
@@ -9,7 +9,7 @@
// //
// The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no // The return trampoline (leaveJITCheckedRaw) is a raw TEXT symbol with no
// Go function declaration, so the toolchain does NOT interpose an // Go function declaration, so the toolchain does NOT interpose an
// ABIInternal wrapper — the JIT function RETs directly into the check // ABIInternal wrapper; the JIT function RETs directly into the check
// code, which sees the registers exactly as the function left them. // code, which sees the registers exactly as the function left them.
// //
// Go ABI on riscv64 guarantees: // Go ABI on riscv64 guarantees:
@@ -42,7 +42,7 @@ TEXT ·enterJITChecked(SB), NOSPLIT, $0-16
JALR X0, 0(X5) // jump to JIT function JALR X0, 0(X5) // jump to JIT function
// leaveJITCheckedRaw is the raw return trampoline. It has NO Go function // leaveJITCheckedRaw is the raw return trampoline. It has NO Go function
// declaration, so no ABIInternal wrapper is generated — the JIT function's // declaration, so no ABIInternal wrapper is generated; the JIT function's
// RET lands here directly, seeing g exactly as the function left it. It // RET lands here directly, seeing g exactly as the function left it. It
// checks the sentinel, records violations in abiResult, then restores the // checks the sentinel, records violations in abiResult, then restores the
// Go stack and returns. // Go stack and returns.
+2 -2
View File
@@ -105,7 +105,7 @@ func TestBlockCount(t *testing.T) {
func TestFillBuffer(t *testing.T) { func TestFillBuffer(t *testing.T) {
t.Run("zero", func(t *testing.T) { t.Run("zero", func(t *testing.T) {
// fillBuffer("zero") is a no-op — relies on make already zeroing. // fillBuffer("zero") is a no-op; relies on make already zeroing.
buf := make([]byte, 16) buf := make([]byte, 16)
fillBuffer(buf, "zero") fillBuffer(buf, "zero")
for _, b := range buf { for _, b := range buf {
@@ -159,7 +159,7 @@ func TestFuzzFuncChecked(t *testing.T) {
if !result.OK() { if !result.OK() {
t.Errorf("FuzzFuncChecked(sum): %s", result) t.Errorf("FuzzFuncChecked(sum): %s", result)
} }
// Test with non-existent function — should report failure. // Test with non-existent function; should report failure.
result = k.FuzzFuncChecked("nope", sig, 10, 0) result = k.FuzzFuncChecked("nope", sig, 10, 0)
if result.OK() { if result.OK() {
t.Error("FuzzFuncChecked(nope): expected failure") t.Error("FuzzFuncChecked(nope): expected failure")
+1 -1
View File
@@ -22,7 +22,7 @@ func mustRead(t *testing.T, path string) string {
} }
func TestGroundTruthBasic(t *testing.T) { func TestGroundTruthBasic(t *testing.T) {
// Use the simple test kernel — it assembles with go tool asm. // Use the simple test kernel; it assembles with go tool asm.
gt, err := GroundTruth("../testdata/verify/basic_amd64.s") gt, err := GroundTruth("../testdata/verify/basic_amd64.s")
if err != nil { if err != nil {
t.Fatalf("GroundTruth: %v", err) t.Fatalf("GroundTruth: %v", err)