Skip to content

Commit

Permalink
add fnv1a example
Browse files Browse the repository at this point in the history
  • Loading branch information
mmcloughlin committed Dec 13, 2018
1 parent b89d211 commit 93b5337
Show file tree
Hide file tree
Showing 8 changed files with 124 additions and 14 deletions.
41 changes: 41 additions & 0 deletions examples/fnv1a/asm.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// +build ignore

package main

import (
. "github.com/mmcloughlin/avo/build"
"github.com/mmcloughlin/avo/operand"
"github.com/mmcloughlin/avo/reg"
)

const (
OffsetBasis = 0xcbf29ce484222325
Prime = 0x100000001b3
)

func main() {
TEXT("Hash64", "func(data []byte) uint64")
ptr := Load(Param("data").Base(), GP64v())
n := Load(Param("data").Len(), GP64v())

h := reg.RAX
MOVQ(operand.Imm(OffsetBasis), h)
p := GP64v()
MOVQ(operand.Imm(Prime), p)

LABEL("loop")
CMPQ(n, operand.Imm(0))
JE(operand.LabelRef("done"))
b := GP64v()
MOVBQZX(operand.Mem{Base: ptr}, b)
XORQ(b, h)
MULQ(p)
INCQ(ptr)
DECQ(n)

JMP(operand.LabelRef("loop"))
LABEL("done")
Store(h, ReturnIndex(0))
RET()
Generate()
}
21 changes: 21 additions & 0 deletions examples/fnv1a/fnv1a.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@

#include "textflag.h"

// func Hash64(data []byte) uint64
TEXT ·Hash64(SB),0,$0-32
MOVQ data_base(FP), CX
MOVQ data_len+8(FP), BX
MOVQ $0xcbf29ce484222325, AX
MOVQ $0x100000001b3, BP
loop:
CMPQ BX, $0x0
JE done
MOVBQZX (CX), DX
XORQ DX, AX
MULQ BP
INCQ CX
DECQ BX
JMP loop
done:
MOVQ AX, ret+24(FP)
RET
20 changes: 20 additions & 0 deletions examples/fnv1a/fnv_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package fnv1a

import (
"hash/fnv"
"testing"
"testing/quick"
)

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

func TestHash64(t *testing.T) {
expect := func(data []byte) uint64 {
h := fnv.New64a()
h.Write(data)
return h.Sum64()
}
if err := quick.CheckEqual(Hash64, expect, nil); err != nil {
t.Fatal(err)
}
}
3 changes: 3 additions & 0 deletions examples/fnv1a/stub.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
package fnv1a

func Hash64(data []byte) uint64
16 changes: 11 additions & 5 deletions operand/checks.go
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ func IsR64(op Op) bool {

// IsPseudo returns true if op is a pseudo register.
func IsPseudo(op Op) bool {
return IsRegisterKindSize(op, reg.Internal, 0)
return IsRegisterKind(op, reg.Internal)
}

// IsGP returns true if op is a general-purpose register of size n bytes.
Expand Down Expand Up @@ -140,6 +140,12 @@ func IsRegisterKindSize(op Op, k reg.Kind, n uint) bool {
return ok && r.Kind() == k && r.Bytes() == n
}

// IsRegisterKind returns true if op is a register of the given kind.
func IsRegisterKind(op Op, k reg.Kind) bool {
r, ok := op.(reg.Register)
return ok && r.Kind() == k
}

// IsM returns true if op is a 16-, 32- or 64-bit memory operand.
func IsM(op Op) bool {
// TODO(mbm): confirm "m" check is defined correctly
Expand Down Expand Up @@ -176,12 +182,12 @@ func IsM64(op Op) bool {
func IsMSize(op Op, n uint) bool {
// TODO(mbm): should memory operands have a size attribute as well?
m, ok := op.(Mem)
return ok && IsMRegSize(m.Base, n) && (m.Index == nil || IsMRegSize(m.Index, n))
return ok && IsMReg(m.Base) && (m.Index == nil || IsMReg(m.Index))
}

// IsMRegSize returns true if op is a register that can be used in a memory operand of size n bytes.
func IsMRegSize(op Op, n uint) bool {
return IsPseudo(op) || IsGP(op, n)
// IsMReg returns true if op is a register that can be used in a memory operand.
func IsMReg(op Op) bool {
return IsPseudo(op) || IsRegisterKind(op, reg.GP)
}

// IsM128 returns true if op is a 128-bit memory operand.
Expand Down
8 changes: 4 additions & 4 deletions pass/alloc.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func (a *Allocator) Add(r reg.Register) {
if _, found := a.possible[v]; found {
return
}
a.possible[v] = a.registersofsize(v.Bytes())
a.possible[v] = a.possibleregisters(v.Bytes())
}

func (a *Allocator) Allocate() (reg.Allocation, error) {
Expand Down Expand Up @@ -146,11 +146,11 @@ func (a *Allocator) remaining() int {
return len(a.possible)
}

// registersofsize returns all registers of the given size.
func (a *Allocator) registersofsize(n uint) []reg.Physical {
// possibleregisters returns all allocate-able registers of the given size.
func (a *Allocator) possibleregisters(n uint) []reg.Physical {
var rs []reg.Physical
for _, r := range a.registers {
if r.Bytes() == n {
if r.Bytes() == n && (r.Info()&reg.Restricted) == 0 {
rs = append(rs, r)
}
}
Expand Down
21 changes: 20 additions & 1 deletion reg/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,17 +26,26 @@ type Family struct {
registers []Physical
}

func (f *Family) define(s Spec, id PID, name string) Physical {
func (f *Family) add(s Spec, id PID, name string, info Info) Physical {
r := register{
id: id,
kind: f.Kind,
name: name,
info: info,
Spec: s,
}
f.registers = append(f.registers, r)
return r
}

func (f *Family) define(s Spec, id PID, name string) Physical {
return f.add(s, id, name, None)
}

func (f *Family) restricted(s Spec, id PID, name string) Physical {
return f.add(s, id, name, Restricted)
}

func (f *Family) Virtual(id VID, s Size) Virtual {
return NewVirtual(id, f.Kind, s)
}
Expand Down Expand Up @@ -110,9 +119,17 @@ func (v virtual) Asm() string {

func (v virtual) register() {}

type Info uint8

const (
None Info = 0
Restricted Info = 1 << iota
)

type Physical interface {
PhysicalID() PID
Mask() uint16
Info() Info
Register
}

Expand All @@ -128,13 +145,15 @@ type register struct {
id PID
kind Kind
name string
info Info
Spec
}

func (r register) PhysicalID() PID { return r.id }
func (r register) ID() ID { return (ID(r.Mask()) << 16) | ID(r.id) }
func (r register) Kind() Kind { return r.kind }
func (r register) Asm() string { return r.name }
func (r register) Info() Info { return r.info }
func (r register) register() {}

type Spec uint16
Expand Down
8 changes: 4 additions & 4 deletions reg/x86.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ var (
BH = GeneralPurpose.define(S8H, 3, "BH")

// 8-bit
SPB = GeneralPurpose.define(S8, 4, "SP")
SPB = GeneralPurpose.restricted(S8, 4, "SP")
BPB = GeneralPurpose.define(S8, 5, "BP")
SIB = GeneralPurpose.define(S8, 6, "SI")
DIB = GeneralPurpose.define(S8, 7, "DI")
Expand All @@ -72,7 +72,7 @@ var (
CX = GeneralPurpose.define(S16, 1, "CX")
DX = GeneralPurpose.define(S16, 2, "DX")
BX = GeneralPurpose.define(S16, 3, "BX")
SP = GeneralPurpose.define(S16, 4, "SP")
SP = GeneralPurpose.restricted(S16, 4, "SP")
BP = GeneralPurpose.define(S16, 5, "BP")
SI = GeneralPurpose.define(S16, 6, "SI")
DI = GeneralPurpose.define(S16, 7, "DI")
Expand All @@ -90,7 +90,7 @@ var (
ECX = GeneralPurpose.define(S32, 1, "CX")
EDX = GeneralPurpose.define(S32, 2, "DX")
EBX = GeneralPurpose.define(S32, 3, "BX")
ESP = GeneralPurpose.define(S32, 4, "SP")
ESP = GeneralPurpose.restricted(S32, 4, "SP")
EBP = GeneralPurpose.define(S32, 5, "BP")
ESI = GeneralPurpose.define(S32, 6, "SI")
EDI = GeneralPurpose.define(S32, 7, "DI")
Expand All @@ -108,7 +108,7 @@ var (
RCX = GeneralPurpose.define(S64, 1, "CX")
RDX = GeneralPurpose.define(S64, 2, "DX")
RBX = GeneralPurpose.define(S64, 3, "BX")
RSP = GeneralPurpose.define(S64, 4, "SP")
RSP = GeneralPurpose.restricted(S64, 4, "SP")
RBP = GeneralPurpose.define(S64, 5, "BP")
RSI = GeneralPurpose.define(S64, 6, "SI")
RDI = GeneralPurpose.define(S64, 7, "DI")
Expand Down

0 comments on commit 93b5337

Please sign in to comment.