Extends avo to support most AVX-512 instruction sets.
The instruction type is extended to support suffixes. The K family of opmask
registers is added to the register package, and the operand package is updated
to support the new operand types. Move instruction deduction in `Load` and
`Store` is extended to support KMOV* and VMOV* forms.
Internal code generation packages were overhauled. Instruction database loading
required various messy changes to account for the additional complexities of the
AVX-512 instruction sets. The internal/api package was added to introduce a
separation between instruction forms in the database, and the functions avo
provides to create them. This was required since with instruction suffixes there
is no longer a one-to-one mapping between instruction constructors and opcodes.
AVX-512 bloated generated source code size substantially, initially increasing
compilation and CI test times to an unacceptable level. Two changes were made to
address this:
1. Instruction constructors in the `x86` package moved to an optab-based
approach. This compiles substantially faster than the verbose code
generation we had before.
2. The most verbose code-generated tests are moved under build tags and
limited to a stress test mode. Stress test builds are run on
schedule but not in regular CI.
An example of AVX-512 accelerated 16-lane MD5 is provided to demonstrate and
test the new functionality.
Updates #20 #163 #229
Co-authored-by: Vaughn Iverson <vsivsi@yahoo.com>
7.5 KiB
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;
avoprograms are Go programs - Register allocation: write functions with virtual registers and
avoassigns 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:
- Introductory talk "Better
x86Assembly Generation with Go" at dotGo 2019 (slides) - Longer tutorial at Gophercon 2019 showing a highly-optimized dot product (slides)
- Watch Filippo Valsorda live code the rewrite of
filippo.io/edwards25519assembly withavo - Discuss
avoand general Go assembly topics in the #assembly channel of Gophers Slack
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
// +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
DATAsections. - ext: Interacting with types from external packages.
- pragma: Apply compiler directives to generated functions.
Real Examples
Implementations of full algorithms:
- sha1: SHA-1 cryptographic hash.
- fnv1a: FNV-1a hash function.
- dot: Vector dot product.
- md5x16: AVX-512 accelerated MD5.
- geohash: Integer geohash encoding.
- stadtx:
StadtXhash port from dgryski/go-stadtx.
Contributing
Contributions to avo are welcome:
- Feedback from using
avoin a real project is incredibly valuable. Consider porting an existing project toavo. - Submit bug reports to the issues page.
- Pull requests accepted. Take a look at outstanding issues for ideas (especially the "good first issue" label).
- Join us in the #assembly channel of Gophers Slack.
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.