Files
gasm-sdk/verify/riscv_groundtruth_test.go
2026-09-26 11:08:43 +02:00

86 lines
2.5 KiB
Go

// Copyright (c) 2026 Petr Balvín <opensource@petrbalvin.org> (https://petrbalvin.org)
// SPDX-License-Identifier: BSD-3-Clause
package verify
import (
"bytes"
"os"
"testing"
"sourcedock.dev/petrbalvin/gasm-sdk/asm"
"sourcedock.dev/petrbalvin/gasm-sdk/parser"
)
// TestGroundTruthRISCV assembles the riscv64 test kernels with gasm and
// compares them byte-for-byte against `go tool asm` (GOARCH=riscv64). The
// relocation fields of static-symbol references are masked before the
// comparison, since the toolchain leaves them zero for the linker.
func TestGroundTruthRISCV(t *testing.T) {
for _, path := range []string{
"../testdata/verify/basic_riscv64.s",
"../testdata/verify/rvc_riscv64.s",
"../testdata/verify/loadstore_riscv64.s",
"../testdata/verify/largeimm_riscv64.s",
"../testdata/verify/movimm_riscv64.s",
"../testdata/verify/branch_riscv64.s",
"../testdata/verify/call_riscv64.s",
"../testdata/verify/bigframe_riscv64.s",
"../testdata/verify/guard_riscv64.s",
"../testdata/verify/indirect_riscv64.s",
"../testdata/verify/misc_riscv64.s",
"../testdata/verify/rvcstore_riscv64.s",
"../testdata/verify/atomics_riscv64.s",
"../testdata/verify/vector_riscv64.s",
"../testdata/verify/bitmanip_riscv64.s",
"../testdata/verify/pcalign_riscv64.s",
"../testdata/verify/branch_far_riscv64.s",
"../testdata/verify/wideimm_riscv64.s",
"../testdata/verify/bookkeep_riscv64.s",
"trampoline_riscv64.s",
} {
t.Run(path, func(t *testing.T) {
testGroundTruthRISCVFile(t, path)
})
}
}
func testGroundTruthRISCVFile(t *testing.T, path string) {
src, err := os.ReadFile(path)
if err != nil {
t.Fatalf("read: %v", err)
}
f, errs := parser.Parse(path, string(src))
if len(errs) > 0 {
t.Fatalf("parse: %v", errs)
}
img, err := asm.AssembleFileRISCV(f)
if err != nil {
t.Fatalf("AssembleFileRISCV: %v", err)
}
gt, err := GroundTruthRISCV(path)
if err != nil {
t.Fatalf("GroundTruthRISCV: %v", err)
}
matched := 0
for _, fn := range img.Funcs {
gasmCode := maskRelocs(append([]byte(nil), img.Code[fn.Offset:fn.Offset+fn.Size]...), fn.Relocs)
goCode, ok := gt[fn.Name]
if !ok {
t.Errorf("%s: not in ground truth (%d functions)", fn.Name, len(gt))
continue
}
goCode = maskRelocs(goCode, fn.Relocs)
if !bytes.Equal(gasmCode, goCode) {
t.Errorf("%s: MISMATCH gasm=%d go=%d bytes\n%s", fn.Name, len(gasmCode), len(goCode), diffHex(gasmCode, goCode))
continue
}
matched++
t.Logf("%s: MATCH (%d bytes)", fn.Name, fn.Size)
}
if matched == 0 {
t.Fatal("no functions matched")
}
}