diff --git a/examples/README.md b/examples/README.md index aeb6a362..5b9e842b 100644 --- a/examples/README.md +++ b/examples/README.md @@ -11,3 +11,11 @@ Features: * **[returns](returns):** Building return values. * **[complex](complex):** Working with `complex{64,128}` types. * **[data](data):** Defining `DATA` sections. + +"Real" examples: + +* **[fnv1a](fnv1a):** [FNV-1a](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash) hash function. +* **[dot](dot):** Vector dot product. +* **[geohash](geohash):** Integer [geohash](https://en.wikipedia.org/wiki/Geohash) encoding. +* **[sha1](sha1):** [SHA-1](https://en.wikipedia.org/wiki/SHA-1) cryptographic hash. +* **[stadtx](stadtx):** [`StadtX` hash](https://github.com/demerphq/BeagleHash) port from [dgryski/go-stadtx](https://github.com/dgryski/go-stadtx). diff --git a/examples/fnv1a/README.md b/examples/fnv1a/README.md new file mode 100644 index 00000000..80438be2 --- /dev/null +++ b/examples/fnv1a/README.md @@ -0,0 +1,39 @@ +# fnv1a + +[FNV-1a](https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function#FNV-1a_hash) in `avo`. + +[embedmd]:# (asm.go /const/ $) +```go +const ( + OffsetBasis = 0xcbf29ce484222325 + Prime = 0x100000001b3 +) + +func main() { + TEXT("Hash64", "func(data []byte) uint64") + Doc("Hash64 computes the FNV-1a hash of data.") + 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() +} +``` diff --git a/examples/geohash/README.md b/examples/geohash/README.md new file mode 100644 index 00000000..b8761020 --- /dev/null +++ b/examples/geohash/README.md @@ -0,0 +1,41 @@ +# geohash + +Integer [geohash](https://en.wikipedia.org/wiki/Geohash) encoding. + +Refer to ["Geohash in Golang Assembly"](https://mmcloughlin.com/posts/geohash-assembly) for implementation details. + +[embedmd]:# (asm.go /func main/ $) +```go +func main() { + TEXT("EncodeInt", "func(lat, lng float64) uint64") + Doc("EncodeInt computes the 64-bit integer geohash of (lat, lng).") + lat := Load(Param("lat"), Xv()) + lng := Load(Param("lng"), Xv()) + + MULSD(ConstData("reciprocal180", F64(1/180.0)), lat) + onepointfive := ConstData("onepointfive", F64(1.5)) + ADDSD(onepointfive, lat) + + MULSD(ConstData("reciprocal360", F64(1/360.0)), lng) + ADDSD(onepointfive, lng) + + lngi, lati := GP64v(), GP64v() + MOVQ(lat, lati) + SHRQ(U8(20), lati) + MOVQ(lng, lngi) + SHRQ(U8(20), lngi) + + mask := ConstData("mask", U64(0x5555555555555555)) + ghsh := GP64v() + PDEPQ(mask, lati, ghsh) + temp := GP64v() + PDEPQ(mask, lngi, temp) + SHLQ(U8(1), temp) + XORQ(temp, ghsh) + + Store(ghsh, ReturnIndex(0)) + RET() + + Generate() +} +``` diff --git a/examples/sha1/README.md b/examples/sha1/README.md new file mode 100644 index 00000000..43e47c43 --- /dev/null +++ b/examples/sha1/README.md @@ -0,0 +1,96 @@ +# sha1 + +[SHA-1](https://en.wikipedia.org/wiki/SHA-1) in `avo`. + +Compare to the [`crypto/sha1`](https://github.com/golang/go/blob/204a8f55dc2e0ac8d27a781dab0da609b98560da/src/crypto/sha1/sha1block_amd64.s#L16-L225) assembly. + +[embedmd]:# (asm.go /func main/ /^}/) +```go +func main() { + TEXT("block", "func(h *[5]uint32, m []byte)") + Doc("block SHA-1 hashes the 64-byte message m into the running state h.") + h := Mem{Base: Load(Param("h"), GP64v())} + m := Mem{Base: Load(Param("m").Base(), GP64v())} + + // Store message values on the stack. + w := AllocLocal(64) + W := func(r int) Mem { return w.Offset((r % 16) * 4) } + + // Load initial hash. + h0, h1, h2, h3, h4 := GP32v(), GP32v(), GP32v(), GP32v(), GP32v() + + MOVL(h.Offset(0), h0) + MOVL(h.Offset(4), h1) + MOVL(h.Offset(8), h2) + MOVL(h.Offset(12), h3) + MOVL(h.Offset(16), h4) + + // Initialize registers. + a, b, c, d, e := GP32v(), GP32v(), GP32v(), GP32v(), GP32v() + + MOVL(h0, a) + MOVL(h1, b) + MOVL(h2, c) + MOVL(h3, d) + MOVL(h4, e) + + // Generate round updates. + quarter := []struct { + F func(Register, Register, Register) Register + K uint32 + }{ + {choose, 0x5a827999}, + {xor, 0x6ed9eba1}, + {majority, 0x8f1bbcdc}, + {xor, 0xca62c1d6}, + } + + for r := 0; r < 80; r++ { + q := quarter[r/20] + + // Load message value. + u := GP32v() + if r < 16 { + MOVL(m.Offset(4*r), u) + BSWAPL(u) + } else { + MOVL(W(r-3), u) + XORL(W(r-8), u) + XORL(W(r-14), u) + XORL(W(r-16), u) + ROLL(U8(1), u) + } + MOVL(u, W(r)) + + // Compute the next state register. + t := GP32v() + MOVL(a, t) + ROLL(U8(5), t) + ADDL(q.F(b, c, d), t) + ADDL(e, t) + ADDL(U32(q.K), t) + ADDL(u, t) + + // Update registers. + ROLL(Imm(30), b) + a, b, c, d, e = t, a, b, c, d + } + + // Final add. + ADDL(a, h0) + ADDL(b, h1) + ADDL(c, h2) + ADDL(d, h3) + ADDL(e, h4) + + // Store results back. + MOVL(h0, h.Offset(0)) + MOVL(h1, h.Offset(4)) + MOVL(h2, h.Offset(8)) + MOVL(h3, h.Offset(12)) + MOVL(h4, h.Offset(16)) + RET() + + Generate() +} +```