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.
|
||||
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.
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
@@ -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()®.Restricted) == 0 {
|
||||
rs = append(rs, r)
|
||||
}
|
||||
}
|
||||
|
||||
21
reg/types.go
21
reg/types.go
@@ -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)
|
||||
}
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -128,6 +145,7 @@ type register struct {
|
||||
id PID
|
||||
kind Kind
|
||||
name string
|
||||
info Info
|
||||
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) 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
|
||||
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
@@ -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")
|
||||
|
||||
Reference in New Issue
Block a user