asmgen — Overview¶
go-asmgen generates Go-compatible Plan 9 assembly for every 64-bit Go
target — amd64, arm64, riscv64, loong64, ppc64le, and s390x. It splits the
problem into three layers:
abi— the architecture-independent ABI0 frame layout (offsets, alignment, word size). All six targets share it.amd64/arm64/riscv64/loong64/ppc64le/s390x— thin per-architecture builders: a move/register table over the shared layout, plus aRawescape hatch for everything else.emit— writes well-formed Plan 9.slines (theTEXTblock, instruction lines, the file header with//go:buildand#include "textflag.h"). It knows nothing about any specific ISA.
The key idea: emit text, don't encode bytes¶
avo contains a full amd64 instruction encoder. That is powerful, but porting it
to a new ISA means re-implementing encoding for that ISA. go-asmgen sidesteps
this: it produces the same Plan 9 assembly text a human would hand-write, and
cmd/asm does the encoding — the very same assembler the Go toolchain
already uses. Adding an architecture therefore costs only a move table over the
shared ABI0 model, not an encoder.
What you write¶
You describe a function's signature, then drive a small builder:
sig := arm64.Layout(
[]string{"a", "b"}, []arm64.Type{arm64.Int64, arm64.Int64}, // args
[]string{"ret"}, []arm64.Type{arm64.Int64}, // result
)
b := arm64.NewFunc("add", sig, 0) // frameSize 0, NOSPLIT by default
b.LoadArg("a", "R0").
LoadArg("b", "R1").
Raw("ADD R1, R0, R2").
StoreRet("R2", "ret").
Ret()
What it emits¶
// Code generated by go-asmgen. DO NOT EDIT.
//go:build arm64
#include "textflag.h"
TEXT ·add(SB), NOSPLIT, $0-24
MOVD a+0(FP), R0
MOVD b+8(FP), R1
ADD R1, R0, R2
MOVD R2, ret+16(FP)
RET
go vet's asmdecl pass then cross-checks every name+offset(FP) against the Go
declaration, and the function can be called like any other.
See the Quick start for the full, runnable example.