Skip to content

Commit

Permalink
asm: complete arm64 instruction encodings for homemade assembler (#431)
Browse files Browse the repository at this point in the history
This commit implements all the arm64 instruction encodings necessary
for our JIT compiler and replaces the golang-asm assembler with our
handmade assembler on arm64 platform. Notably, this allows us to do
concurrent compilations.

This closes #233 combined with #406.

Signed-off-by: Takeshi Yoneda <takeshi@tetrate.io>
Co-authored-by: Adrian Cole <adrian@tetrate.io>
  • Loading branch information
mathetake and Adrian Cole authored Apr 12, 2022
1 parent 9040fff commit ecb35e2
Show file tree
Hide file tree
Showing 26 changed files with 5,633 additions and 671 deletions.
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ module github.com/tetratelabs/wazero
go 1.17

require (
// Test-only dependency.
github.com/stretchr/testify v1.7.0
// Once we reach some maturity, remove this dep and implement our own assembler.
// Test-only dependency.
github.com/twitchyliquid64/golang-asm v0.15.1
)

Expand Down
33 changes: 30 additions & 3 deletions internal/asm/amd64/assembler.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,32 +7,59 @@ import (
// Assembler is the interface used by amd64 JIT compiler.
type Assembler interface {
asm.AssemblerBase

// CompileJumpToMemory adds jump-type instruction whose destination is stored in the memory address specified by `baseReg+offset`,
// and returns the corresponding Node in the assembled linked list.
CompileJumpToMemory(jmpInstruction asm.Instruction, baseReg asm.Register, offset asm.ConstantValue)

// CompileRegisterToRegisterWithMode adds an instruction where source and destination
// are `from` and `to` registers and the instruction's "Mode" is specified by `Mode`.
CompileRegisterToRegisterWithMode(instruction asm.Instruction, from, to asm.Register, mode Mode)

// CompileMemoryWithIndexToRegister adds an instruction where source operand is the memory address
// specified as `srcBaseReg + srcOffsetConst + srcIndex*srcScale` and destination is the register `DstReg`.
// Note: sourceScale must be one of 1, 2, 4, 8.
CompileMemoryWithIndexToRegister(instruction asm.Instruction, srcBaseReg asm.Register, srcOffsetConst int64, srcIndex asm.Register, srcScale int16, dstReg asm.Register)
CompileMemoryWithIndexToRegister(
instruction asm.Instruction,
srcBaseReg asm.Register,
srcOffsetConst int64,
srcIndex asm.Register,
srcScale int16,
dstReg asm.Register,
)

// CompileRegisterToMemoryWithIndex adds an instruction where source operand is the register `SrcReg`,
// and the destination is the memory address specified as `dstBaseReg + dstOffsetConst + dstIndex*dstScale`
// Note: dstScale must be one of 1, 2, 4, 8.
CompileRegisterToMemoryWithIndex(instruction asm.Instruction, srcReg asm.Register, dstBaseReg asm.Register, dstOffsetConst int64, dstIndex asm.Register, dstScale int16)
CompileRegisterToMemoryWithIndex(
instruction asm.Instruction,
srcReg asm.Register,
dstBaseReg asm.Register,
dstOffsetConst int64,
dstIndex asm.Register,
dstScale int16,
)

// CompileRegisterToConst adds an instruction where source operand is the register `srcRegister`,
// and the destination is the const `value`.
CompileRegisterToConst(instruction asm.Instruction, srcRegister asm.Register, value int64) asm.Node

// CompileRegisterToNone adds an instruction where source operand is the register `register`,
// and there's no destination operand.
CompileRegisterToNone(instruction asm.Instruction, register asm.Register)

// CompileNoneToRegister adds an instruction where destination operand is the register `register`,
// and there's no source operand.
CompileNoneToRegister(instruction asm.Instruction, register asm.Register)

// CompileNoneToMemory adds an instruction where destination operand is the memory address specified
// as `baseReg+offset`. and there's no source operand.
CompileNoneToMemory(instruction asm.Instruction, baseReg asm.Register, offset int64)

// CompileConstToMemory adds an instruction where source operand is the constant `value` and
// the destination is the memory address sppecified as `dstbaseReg+dstOffset`.
// the destination is the memory address specified as `dstbaseReg+dstOffset`.
CompileConstToMemory(instruction asm.Instruction, value int64, dstbaseReg asm.Register, dstOffset int64) asm.Node

// CompileMemoryToConst adds an instruction where source operand is the memory address, and
// the destination is the constant `value`.
CompileMemoryToConst(instruction asm.Instruction, srcBaseReg asm.Register, srcOffset int64, value int64) asm.Node
Expand Down
17 changes: 9 additions & 8 deletions internal/asm/amd64/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package asm_amd64
import "github.com/tetratelabs/wazero/internal/asm"

// AMD64-specific conditional register states.
// https://www.lri.fr/~filliatr/ens/compil/x86-64.pdf
// https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
//
// See https://www.lri.fr/~filliatr/ens/compil/x86-64.pdf
// See https://www.intel.com/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf
const (
ConditionalRegisterStateE = asm.ConditionalRegisterStateUnset + 1 + iota // ZF equal to zero
ConditionalRegisterStateNE //˜ZF not equal to zero
Expand All @@ -21,10 +22,10 @@ const (
)

// AMD64-specific instructions.
// https://www.felixcloutier.com/x86/index.html
//
// Note: here we do not define all of amd64 instructions, and we only define the ones used by wazero's JIT compiler.
// Note: naming convension is exactly the same as Go assembler: https://go.dev/doc/asm
// Note: This only defines amd64 instructions used by wazero's JIT compiler.
// Note: Naming conventions intentionally match the Go assembler: https://go.dev/doc/asm
// See https://www.felixcloutier.com/x86/index.html
const (
NONE asm.Instruction = iota
ADDL
Expand Down Expand Up @@ -426,10 +427,10 @@ func InstructionName(instruction asm.Instruction) string {
}

// Arm64-specific registers.
// https://www.lri.fr/~filliatr/ens/compil/x86-64.pdf
// https://cs.brown.edu/courses/cs033/docs/guides/x64_cheatsheet.pdf
//
// Note: naming convension is exactly the same as Go assembler: https://go.dev/doc/asm
// Note: naming convention intentionally matches the Go assembler: https://go.dev/doc/asm
// See https://www.lri.fr/~filliatr/ens/compil/x86-64.pdf
// See https://cs.brown.edu/courses/cs033/docs/guides/x64_cheatsheet.pdf
const (
REG_AX asm.Register = asm.NilRegister + 1 + iota
REG_CX
Expand Down
Loading

0 comments on commit ecb35e2

Please sign in to comment.