add fnv1a example

This commit is contained in:
Michael McLoughlin
2018-12-13 00:18:44 -08:00
parent b89d211ff4
commit 93b53377ac
8 changed files with 124 additions and 14 deletions

41
examples/fnv1a/asm.go Normal file
View File

@@ -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
examples/fnv1a/fnv1a.s Normal file
View File

@@ -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

View File

@@ -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
examples/fnv1a/stub.go Normal file
View File

@@ -0,0 +1,3 @@
package fnv1a
func Hash64(data []byte) uint64

View File

@@ -111,7 +111,7 @@ func IsR64(op Op) bool {
// IsPseudo returns true if op is a pseudo register. // IsPseudo returns true if op is a pseudo register.
func IsPseudo(op Op) bool { 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. // IsGP returns true if op is a general-purpose register of size n bytes.
@@ -140,6 +140,12 @@ func IsRegisterKindSize(op Op, k reg.Kind, n uint) bool {
return ok && r.Kind() == k && r.Bytes() == n 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. // IsM returns true if op is a 16-, 32- or 64-bit memory operand.
func IsM(op Op) bool { func IsM(op Op) bool {
// TODO(mbm): confirm "m" check is defined correctly // TODO(mbm): confirm "m" check is defined correctly
@@ -176,12 +182,12 @@ func IsM64(op Op) bool {
func IsMSize(op Op, n uint) bool { func IsMSize(op Op, n uint) bool {
// TODO(mbm): should memory operands have a size attribute as well? // TODO(mbm): should memory operands have a size attribute as well?
m, ok := op.(Mem) 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. // IsMReg returns true if op is a register that can be used in a memory operand.
func IsMRegSize(op Op, n uint) bool { func IsMReg(op Op) bool {
return IsPseudo(op) || IsGP(op, n) return IsPseudo(op) || IsRegisterKind(op, reg.GP)
} }
// IsM128 returns true if op is a 128-bit memory operand. // IsM128 returns true if op is a 128-bit memory operand.

View File

@@ -60,7 +60,7 @@ func (a *Allocator) Add(r reg.Register) {
if _, found := a.possible[v]; found { if _, found := a.possible[v]; found {
return return
} }
a.possible[v] = a.registersofsize(v.Bytes()) a.possible[v] = a.possibleregisters(v.Bytes())
} }
func (a *Allocator) Allocate() (reg.Allocation, error) { func (a *Allocator) Allocate() (reg.Allocation, error) {
@@ -146,11 +146,11 @@ func (a *Allocator) remaining() int {
return len(a.possible) return len(a.possible)
} }
// registersofsize returns all registers of the given size. // possibleregisters returns all allocate-able registers of the given size.
func (a *Allocator) registersofsize(n uint) []reg.Physical { func (a *Allocator) possibleregisters(n uint) []reg.Physical {
var rs []reg.Physical var rs []reg.Physical
for _, r := range a.registers { for _, r := range a.registers {
if r.Bytes() == n { if r.Bytes() == n && (r.Info()&reg.Restricted) == 0 {
rs = append(rs, r) rs = append(rs, r)
} }
} }

View File

@@ -26,17 +26,26 @@ type Family struct {
registers []Physical 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{ r := register{
id: id, id: id,
kind: f.Kind, kind: f.Kind,
name: name, name: name,
info: info,
Spec: s, Spec: s,
} }
f.registers = append(f.registers, r) f.registers = append(f.registers, r)
return 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 { func (f *Family) Virtual(id VID, s Size) Virtual {
return NewVirtual(id, f.Kind, s) return NewVirtual(id, f.Kind, s)
} }
@@ -110,9 +119,17 @@ func (v virtual) Asm() string {
func (v virtual) register() {} func (v virtual) register() {}
type Info uint8
const (
None Info = 0
Restricted Info = 1 << iota
)
type Physical interface { type Physical interface {
PhysicalID() PID PhysicalID() PID
Mask() uint16 Mask() uint16
Info() Info
Register Register
} }
@@ -128,6 +145,7 @@ type register struct {
id PID id PID
kind Kind kind Kind
name string name string
info Info
Spec Spec
} }
@@ -135,6 +153,7 @@ func (r register) PhysicalID() PID { return r.id }
func (r register) ID() ID { return (ID(r.Mask()) << 16) | ID(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) Kind() Kind { return r.kind }
func (r register) Asm() string { return r.name } func (r register) Asm() string { return r.name }
func (r register) Info() Info { return r.info }
func (r register) register() {} func (r register) register() {}
type Spec uint16 type Spec uint16

View File

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