MCPcopy Index your code
hub / github.com/mmcloughlin/avo

github.com/mmcloughlin/avo @v0.6.0 sqlite

repository ↗ · DeepWiki ↗ · release v0.6.0 ↗
7,905 symbols 23,560 edges 276 files 3,921 documented · 50% 1 cross-repo links
README

avo

Build Status go.dev Go Report Card

Generate x86 Assembly with Go

avo makes high-performance Go assembly easier to write, review and maintain. The avo package presents a familiar assembly-like interface that simplifies development without sacrificing performance:

  • Use Go control structures for assembly generation; avo programs are Go programs
  • Register allocation: write functions with virtual registers and avo assigns physical registers for you
  • Automatically load arguments and store return values: ensure memory offsets are correct for complex structures
  • Generation of stub files to interface with your Go package

For more about avo:

Note: APIs subject to change while avo is still in an experimental phase. You can use it to build real things but we suggest you pin a version with your package manager of choice.

Quick Start

Install avo with go get:

$ go get -u github.com/mmcloughlin/avo

avo assembly generators are pure Go programs. Here's a function that adds two uint64 values:

//go:build ignore

package main

import . "github.com/mmcloughlin/avo/build"

func main() {
    TEXT("Add", NOSPLIT, "func(x, y uint64) uint64")
    Doc("Add adds x and y.")
    x := Load(Param("x"), GP64())
    y := Load(Param("y"), GP64())
    ADDQ(x, y)
    Store(y, ReturnIndex(0))
    RET()
    Generate()
}

go run this code to see the assembly output. To integrate this into the rest of your Go package we recommend a go:generate line to produce the assembly and the corresponding Go stub file.

//go:generate go run asm.go -out add.s -stubs stub.go

After running go generate the add.s file will contain the Go assembly.

// Code generated by command: go run asm.go -out add.s -stubs stub.go. DO NOT EDIT.

#include "textflag.h"

// func Add(x uint64, y uint64) uint64
TEXT ·Add(SB), NOSPLIT, $0-24
    MOVQ x+0(FP), AX
    MOVQ y+8(FP), CX
    ADDQ AX, CX
    MOVQ CX, ret+16(FP)
    RET

The same call will produce the stub file stub.go which will enable the function to be called from your Go code.

// Code generated by command: go run asm.go -out add.s -stubs stub.go. DO NOT EDIT.

package add

// Add adds x and y.
func Add(x uint64, y uint64) uint64

See the examples/add directory for the complete working example.

Examples

See examples for the full suite of examples.

Slice Sum

Sum a slice of uint64s:

func main() {
    TEXT("Sum", NOSPLIT, "func(xs []uint64) uint64")
    Doc("Sum returns the sum of the elements in xs.")
    ptr := Load(Param("xs").Base(), GP64())
    n := Load(Param("xs").Len(), GP64())

    Comment("Initialize sum register to zero.")
    s := GP64()
    XORQ(s, s)

    Label("loop")
    Comment("Loop until zero bytes remain.")
    CMPQ(n, Imm(0))
    JE(LabelRef("done"))

    Comment("Load from pointer and add to running sum.")
    ADDQ(Mem{Base: ptr}, s)

    Comment("Advance pointer, decrement byte count.")
    ADDQ(Imm(8), ptr)
    DECQ(n)
    JMP(LabelRef("loop"))

    Label("done")
    Comment("Store sum to return value.")
    Store(s, ReturnIndex(0))
    RET()
    Generate()
}

The result from this code generator is:

// Code generated by command: go run asm.go -out sum.s -stubs stub.go. DO NOT EDIT.

#include "textflag.h"

// func Sum(xs []uint64) uint64
TEXT ·Sum(SB), NOSPLIT, $0-32
    MOVQ xs_base+0(FP), AX
    MOVQ xs_len+8(FP), CX

    // Initialize sum register to zero.
    XORQ DX, DX

loop:
    // Loop until zero bytes remain.
    CMPQ CX, $0x00
    JE   done

    // Load from pointer and add to running sum.
    ADDQ (AX), DX

    // Advance pointer, decrement byte count.
    ADDQ $0x08, AX
    DECQ CX
    JMP  loop

done:
    // Store sum to return value.
    MOVQ DX, ret+24(FP)
    RET

Full example at examples/sum.

Features

For demonstrations of avo features:

  • args: Loading function arguments.
  • returns: Building return values.
  • complex: Working with complex{64,128} types.
  • data: Defining DATA sections.
  • ext: Interacting with types from external packages.
  • pragma: Apply compiler directives to generated functions.

Real Examples

Implementations of full algorithms:

Adopters

Popular projects[^projects] using avo:

[^projects]: Projects drawn from the avo third-party test suite. Popularity estimated from Github star count collected on Jan 1, 2024.

golang / go :star: 116.7k

The Go programming language

klauspost / compress :star: 4.3k

Optimized Go Compression Packages

golang / crypto :star: 2.9k

[mirror] Go supplementary cryptography libraries

klauspost / reedsolomon :star: 1.8k

Reed-Solomon Erasure Coding in Go

cloudflare / circl :star: 1.1k

CIRCL: Cloudflare Interoperable Reusable Cryptographic Library

segmentio / asm :star: 820

Go library providing algorithms optimized to leverage the characteristics of modern CPUs

zeebo / xxh3 :star: 358

XXH3 algorithm in Go

zeebo / blake3 :star: 353

Pure Go implementation of BLAKE3 with AVX2 and SSE4.1 acceleration

lukechampine / blake3 :star: 316

A pure-Go implementation of the BLAKE3 cryptographic hash function

minio / md5-simd :star: 159

Accelerate aggregated MD5 hashing performance up to 8x for AVX512 and 4x for AVX2. Useful for server applications that need to compute many MD5 sums in parallel.

See the full list of projects using avo.

Contributing

Contributions to avo are welcome:

Credits

Inspired by the PeachPy and asmjit projects. Thanks to Damian Gryski for advice, and his extensive library of PeachPy Go projects.

License

avo is available under the BSD 3-Clause License.

Extension points exported contracts — how you extend this code

Op (Interface)
Op is an operand. [3 implementers]
operand/types.go
Printer (Interface)
Printer can produce output for an avo File. [2 implementers]
printer/printer.go
Node (Interface)
Node is a part of a Function. [2 implementers]
ir/ir.go
GP (Interface)
GP provides additional methods for general purpose registers. [2 implementers]
reg/x86.go
Signature (Interface)
Signature provides access to details about the signature of an instruction function. [2 implementers]
internal/api/signature.go
Virtual (Interface)
Virtual is a register of a given type and size, not yet allocated to a physical register. [1 implementers]
reg/types.go
Component (Interface)
Component provides access to sub-components of a Go type. [1 implementers]
gotypes/components.go
Constant (Interface)
Constant represents a constant literal.
operand/const.go

Core symbols most depended-on inside this repo

build
called by 3205
x86/optab.go
Forms
called by 3205
x86/zoptab.go
Printf
called by 209
internal/prnt/printer.go
MOVOU
called by 132
x86/zctors.go
ADDQ
called by 118
x86/zctors.go
As32
called by 102
reg/x86.go
MOVQ
called by 100
x86/zctors.go
vec
called by 96
reg/x86.go

Shape

Function 7,278
Method 455
Struct 95
TypeAlias 46
Interface 24
FuncType 7

Languages

Go100%

Modules by API surface

x86/zctors_test.go3,205 symbols
x86/zctors.go3,205 symbols
tests/signature/stub.go256 symbols
reg/types.go62 symbols
reg/x86.go52 symbols
operand/checks.go50 symbols
ir/ir.go50 symbols
buildtags/buildtags.go43 symbols
operand/zconst.go40 symbols
gotypes/components.go40 symbols
tests/thirdparty/config.go37 symbols
internal/inst/types.go36 symbols

Used by 1 indexed graphs manifest dependencies, hub-wide

Dependencies from manifests, versioned

golang.org/x/archv0.6.0 · 1×
golang.org/x/modv0.14.0 · 1×
golang.org/x/sysv0.15.0 · 1×
golang.org/x/toolsv0.16.1 · 1×

For agents

$ claude mcp add avo \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact