// Copyright (c) 2026 Petr Balvín (https://petrbalvin.org) // SPDX-License-Identifier: BSD-3-Clause package asm import ( "testing" "sourcedock.dev/petrbalvin/gasm-devkit/parser" ) // TestRISCVFrameSpadjAndLines checks that a framed function records its // stack-adjustment boundaries and source-line table, the inputs the GOOBJ // emitter turns into the pcsp/pcfile/pcline tables. func TestRISCVFrameSpadjAndLines(t *testing.T) { f, errs := parser.Parse("frame_riscv64.s", `#include "textflag.h" TEXT ·framed(SB), NOSPLIT, $16-16 MOV a+0(FP), X10 MOV b+8(FP), X11 ADD X11, X10, X10 MOV X10, ret+16(FP) RET `) if len(errs) > 0 { t.Fatalf("parse: %v", errs) } img, err := AssembleFileRISCV(f) if err != nil { t.Fatalf("AssembleFileRISCV: %v", err) } fn := img.Funcs[0] if fn.Size != 24 { t.Fatalf("size = %d, want 24", fn.Size) } // autosize = 16 + 8 = 24; the prologue boundary is just past its C.ADDI // (SD 4 + C.ADDI 2 = 6), and the RET restores SP just past its C.ADDI // (RET starts at 16; C.LDSP 2 + C.ADDI 2 = 20). wantSpadj := []SpadjStep{{PC: 6, Value: 24}, {PC: 20, Value: 0}} if len(fn.Spadj) != len(wantSpadj) { t.Fatalf("spadj = %v, want %v", fn.Spadj, wantSpadj) } for i := range wantSpadj { if fn.Spadj[i] != wantSpadj[i] { t.Errorf("spadj[%d] = %v, want %v", i, fn.Spadj[i], wantSpadj[i]) } } // One line entry per instruction, in emission order. wantLines := []LineEntry{ {Offset: 8, Line: 4}, {Offset: 10, Line: 5}, {Offset: 12, Line: 6}, {Offset: 14, Line: 7}, {Offset: 16, Line: 8}, } if len(fn.Lines) != len(wantLines) { t.Fatalf("lines = %v, want %v", fn.Lines, wantLines) } for i := range wantLines { if fn.Lines[i] != wantLines[i] { t.Errorf("lines[%d] = %v, want %v", i, fn.Lines[i], wantLines[i]) } } } // TestRISCVRegAliases checks the Go ABI register aliases that the toolchain // defines: LR is the link register (X1) and TMP is the assembler scratch // register (X31/T6). func TestRISCVRegAliases(t *testing.T) { for name, want := range map[string]int{ "X1": 1, "RA": 1, "LR": 1, "X31": 31, "T6": 31, "TMP": 31, "X2": 2, "SP": 2, } { if got := riscvRegNum(name); got != want { t.Errorf("riscvRegNum(%q) = %d, want %d", name, got, want) } } }