add fnv1a example
This commit is contained in:
41
examples/fnv1a/asm.go
Normal file
41
examples/fnv1a/asm.go
Normal 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
21
examples/fnv1a/fnv1a.s
Normal 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
|
||||||
20
examples/fnv1a/fnv_test.go
Normal file
20
examples/fnv1a/fnv_test.go
Normal 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
3
examples/fnv1a/stub.go
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
package fnv1a
|
||||||
|
|
||||||
|
func Hash64(data []byte) uint64
|
||||||
@@ -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.
|
||||||
|
|||||||
@@ -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()®.Restricted) == 0 {
|
||||||
rs = append(rs, r)
|
rs = append(rs, r)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
21
reg/types.go
21
reg/types.go
@@ -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
|
||||||
|
|||||||
@@ -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")
|
||||||
|
|||||||
Reference in New Issue
Block a user