Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

62 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

GoAT

test GitHub release (with filter)

Go assembly transpiler for C programming languages. It help to utilize optimization from C compiler in Go projects. For example, generate SIMD vectorized functions for Go (refer to How to Use AVX512 in Golang).

Prerequisites

The following packages are required:

  • Ubuntu for AMD64:
sudo apt update
sudo apt install clang libc6-dev-i386
  • Ubuntu for ARM64:
sudo apt update
sudo apt install clang
  • macOS:
brew install llvm binutils

# Override the default clang and objdump to use Homebrew's version
export PATH="/opt/homebrew/opt/llvm/bin:$PATH"
export PATH="/opt/homebrew/opt/binutils/bin:$PATH"
  • Windows:

Install LLVM and MinGW from the official website or use Chocolatey package manager:

choco install llvm mingw

Install

Install the latest version:

go install github.com/gorse-io/goat@latest

Or install the latest development version:

go install github.com/gorse-io/goat@main

Usage

  goat source [-o output_directory] [flags]

Flags:
  -e, --extra-option strings     extra option for clang
  -h, --help                     help for goat
  -m, --machine-option strings   machine option for clang
  -O, --optimize-level int       optimization level for clang
  -o, --output string            output directory of generated files
  -t, --target string            target architecture, using Go GOARCH names (default current GOARCH)
  -v, --verbose                  if set, increase verbosity level

Example

Suppose you have a C function that adds two arrays of floats in src/add.c:

void add(float *a, float *b, float *result, long n) {
    for (long i = 0; i < n; i++) {
        result[i] = a[i] + b[i];
    }
}

You can use GoAT to transpile this C function to Go assembly code with the following command:

goat src/add.c -o . -O3 -mavx

Warning

The output directory must be different from the source directory, otherwise the intermediate files will break the compilation.

Two files will be generated in the output directory:

  • Go function definition file add.go:
//go:build !noasm && amd64
// Code generated by GoAT. DO NOT EDIT.
// versions:
// 	clang   18.1.3 (1ubuntu1)
// 	objdump 2.42
// flags: -mavx -O0
// source: example/src/add.c

package example

import "unsafe"

//go:noescape
func add(a, b, result unsafe.Pointer, n int64)
  • Go assembly file add.s:
//go:build !noasm && amd64
// Code generated by GoAT. DO NOT EDIT.
// versions:
// 	clang   18.1.3 (1ubuntu1)
// 	objdump 2.42
// flags: -mavx -O0
// source: example/src/add.c

TEXT ·add(SB), $0-32
	MOVQ a+0(FP), DI
	MOVQ b+8(FP), SI
	MOVQ result+16(FP), DX
	MOVQ n+24(FP), CX
	BYTE $0x55                           // pushq	%rbp
	WORD $0x8948; BYTE $0xe5             // movq	%rsp, %rbp
	LONG $0xf8e48348                     // andq	$-8, %rsp
	LONG $0x30ec8348                     // subq	$48, %rsp
	LONG $0x247c8948; BYTE $0x28         // movq	%rdi, 40(%rsp)
	LONG $0x24748948; BYTE $0x20         // movq	%rsi, 32(%rsp)
	LONG $0x24548948; BYTE $0x18         // movq	%rdx, 24(%rsp)
	LONG $0x244c8948; BYTE $0x10         // movq	%rcx, 16(%rsp)
	QUAD $0x000000082444c748; BYTE $0x00 // movq	$0, 8(%rsp)

LBB0_1:
	LONG $0x24448b48; BYTE $0x08 // movq	8(%rsp), %rax
	LONG $0x24443b48; BYTE $0x10 // cmpq	16(%rsp), %rax
	JGE  LBB0_4
	LONG $0x24448b48; BYTE $0x28 // movq	40(%rsp), %rax
	LONG $0x244c8b48; BYTE $0x08 // movq	8(%rsp), %rcx
	LONG $0x0410fac5; BYTE $0x88 // vmovss	(%rax,%rcx,4), %xmm0            # xmm0 = mem[0],zero,zero,zero
	LONG $0x24448b48; BYTE $0x20 // movq	32(%rsp), %rax
	LONG $0x244c8b48; BYTE $0x08 // movq	8(%rsp), %rcx
	LONG $0x0458fac5; BYTE $0x88 // vaddss	(%rax,%rcx,4), %xmm0, %xmm0
	LONG $0x24448b48; BYTE $0x18 // movq	24(%rsp), %rax
	LONG $0x244c8b48; BYTE $0x08 // movq	8(%rsp), %rcx
	LONG $0x0411fac5; BYTE $0x88 // vmovss	%xmm0, (%rax,%rcx,4)
	LONG $0x24448b48; BYTE $0x08 // movq	8(%rsp), %rax
	LONG $0x01c08348             // addq	$1, %rax
	LONG $0x24448948; BYTE $0x08 // movq	%rax, 8(%rsp)
	JMP  LBB0_1

LBB0_4:
	WORD $0x8948; BYTE $0xec // movq	%rbp, %rsp
	BYTE $0x5d               // popq	%rbp
	RET

Finally, the add function can be used by:

func Add(a, b, c []float32) {
	if len(a) ! = len(b) || len(a) ! = len(c) {
		panic("floats: slice lengths do not match")
	}
	add(unsafe.Pointer(&a[0]), unsafe.Pointer(&b[0]), unsafe.Pointer(&c[0]), int64(len(a)))
}

Limitations

  • No call statements except for inline functions.
  • Arguments must be int64_t, long, float, double, _Bool or pointer.
  • Potentially BUGGY code generation.

Acknowledgments

About

Go assembly transpiler for C programming language support amd64, arm64, riscv64, loong64, s390x and ppc64le

Resources

Stars

120 stars

Watchers

3 watching

Forks

Releases

Packages

Used by

Contributors

Languages