~mpldr/go-yenc

29b5d249e0d5a0a47f0539f7bf513bc2ddac1a9d — Moritz Poldrack 1 year, 6 months ago 52b8b16
use lookuptable in assembler
M testdata/benchmarks/asm-plain.go => testdata/benchmarks/asm-plain.go +2 -2
@@ 1,6 1,6 @@
// Code generated by command: go run asm.go -out asm-plain.s -stubs asm-plain.go -pkg yenc. DO NOT EDIT.
// Code generated by command: go run asm-plain_gen.go -pkg yenc -stubs asm-plain.go -out asm-plain.s. DO NOT EDIT.

package yenc

// yenc encode using x86 assembler instructions
func Assembler(input []byte, output []byte)
func AssemblerPlain(input []byte, output []byte)

M testdata/benchmarks/asm-plain.s => testdata/benchmarks/asm-plain.s +10 -16
@@ 1,8 1,8 @@
// Code generated by command: go run asm.go -out asm-plain.s -stubs asm-plain.go -pkg yenc. DO NOT EDIT.
// Code generated by command: go run asm-plain_gen.go -pkg yenc -stubs asm-plain.go -out asm-plain.s. DO NOT EDIT.

#include "textflag.h"

DATA consts<>+0(SB)/1, $0x00
DATA consts<>+0(SB)/1, $0x01
DATA consts<>+1(SB)/1, $0x00
DATA consts<>+2(SB)/1, $0x00
DATA consts<>+3(SB)/1, $0x00


@@ 12,10 12,10 @@ DATA consts<>+6(SB)/1, $0x00
DATA consts<>+7(SB)/1, $0x00
DATA consts<>+8(SB)/1, $0x00
DATA consts<>+9(SB)/1, $0x00
DATA consts<>+10(SB)/1, $0x0a
DATA consts<>+10(SB)/1, $0x01
DATA consts<>+11(SB)/1, $0x00
DATA consts<>+12(SB)/1, $0x00
DATA consts<>+13(SB)/1, $0x0d
DATA consts<>+13(SB)/1, $0x01
DATA consts<>+14(SB)/1, $0x00
DATA consts<>+15(SB)/1, $0x00
DATA consts<>+16(SB)/1, $0x00


@@ 63,7 63,7 @@ DATA consts<>+57(SB)/1, $0x00
DATA consts<>+58(SB)/1, $0x00
DATA consts<>+59(SB)/1, $0x00
DATA consts<>+60(SB)/1, $0x00
DATA consts<>+61(SB)/1, $0x3d
DATA consts<>+61(SB)/1, $0x01
DATA consts<>+62(SB)/1, $0x00
DATA consts<>+63(SB)/1, $0x00
DATA consts<>+64(SB)/1, $0x00


@@ 260,13 260,13 @@ DATA consts<>+254(SB)/1, $0x00
DATA consts<>+255(SB)/1, $0x00
GLOBL consts<>(SB), RODATA|NOPTR, $256

// func Assembler(input []byte, output []byte)
TEXT ·Assembler(SB), NOSPLIT, $0-48
// func AssemblerPlain(input []byte, output []byte)
TEXT ·AssemblerPlain(SB), NOSPLIT, $0-48
	// load input, input length, and output
	MOVQ input_base+0(FP), AX
	MOVQ input_len+8(FP), CX
	MOVQ output_base+24(FP), DX
	LEAQ consts<>+0(SB), BX
	LEAQ consts<>+0(SB), SI

encode_loop:
	// when there are 0 byte left to encode, we're done


@@ 274,7 274,7 @@ encode_loop:
	JZ   done

	// load the next input value
	MOVB (AX), BL
	MOVBQZX (AX), BX

	// decrement number of bytes to be loaded and move the input pointer to the next byte
	DECQ CX


@@ 284,13 284,7 @@ encode_loop:
	ADDB $0x2a, BL

	// check if it's 0, 10, 13, or 61 and escape if so
	CMPB BL, $0x00
	JE   escape
	CMPB BL, $0x0a
	JE   escape
	CMPB BL, $0x0d
	JE   escape
	CMPB BL, $0x3d
	CMPB (SI)(BX*1), $0x01
	JE   escape

escape_done:

M testdata/benchmarks/asm-plain_gen.go => testdata/benchmarks/asm-plain_gen.go +7 -13
@@ 24,7 24,7 @@ func main() {
	input := Load(Param("input").Base(), GP64())
	inputLen := Load(Param("input").Len(), GP64())
	output := Load(Param("output").Base(), GP64())
	value := GP8()
	value := GP64()
	LTPtr := Mem{Base: GP64()}
	LEAQ(data, LTPtr.Base)



@@ 34,37 34,31 @@ func main() {
	JZ(LabelRef("done"))

	Comment("load the next input value")
	MOVB(Mem{Base: input}, value)
	MOVBQZX(Mem{Base: input}, value)


	Comment("decrement number of bytes to be loaded and move the input pointer to the next byte")
	DECQ(inputLen)
	INCQ(input)

	Comment("add 42")
	ADDB(U8(0x2a), value)
	ADDB(U8(0x2a), value.As8())

	Comment("check if it's 0, 10, 13, or 61 and escape if so")
	// CMPB(LTPtr.Idx(value, 1), Imm(0x00))
	CMPB(value, Imm(0x00))
	JE(LabelRef("escape"))
	CMPB(value, Imm(0x0a))
	JE(LabelRef("escape"))
	CMPB(value, Imm(0x0d))
	JE(LabelRef("escape"))
	CMPB(value, Imm(0x3d))
	CMPB(LTPtr.Idx(value, 1), U8(1))
	JE(LabelRef("escape"))
	// or fallthrough

	Label("escape_done")
	Comment("return encoded character")
	MOVB(value, Mem{Base: output})
	MOVB(value.As8(), Mem{Base: output})
	ADDQ(Imm(1), output)
	JMP(LabelRef("encode_loop"))
	// end of encode loop

	Label("escape")
	Comment("add 64")
	ADDB(U8(64), value)
	ADDB(U8(64), value.As8())
	Comment("write escape character to output")
	MOVB(Imm(0x3d), Mem{Base: output})
	ADDQ(Imm(1), output)

M testdata/benchmarks/go.mod => testdata/benchmarks/go.mod +7 -0
@@ 1,3 1,10 @@
module benchmarks

go 1.19

require (
	github.com/mmcloughlin/avo v0.5.0 // indirect
	golang.org/x/mod v0.6.0 // indirect
	golang.org/x/sys v0.1.0 // indirect
	golang.org/x/tools v0.2.0 // indirect
)

M testdata/benchmarks/yenc_test.go => testdata/benchmarks/yenc_test.go +6 -6
@@ 53,7 53,7 @@ func TestEncodingMultibyte(t *testing.T) {
		{"bootleg-simd", YEncBootlegSIMD},
		{"assembler", func(in [8]byte) []byte {
			out := make([]byte, 16)
			Assembler(in[:], out)
			AssemblerPlain(in[:], out)
			return out
		}},
	}


@@ 190,7 190,7 @@ func BenchmarkEncoding8Byte(b *testing.B) {
		{"bootleg-simd", YEncBootlegSIMD},
		{"assembler", func(in [8]byte) []byte {
			out := make([]byte, 16)
			Assembler(in[:], out)
			AssemblerPlain(in[:], out)
			return out
		}},
	}


@@ 230,7 230,7 @@ func BenchmarkEncoding8ByteEscaped(b *testing.B) {
		{"bootleg-simd", YEncBootlegSIMD},
		{"assembler", func(in [8]byte) []byte {
			out := make([]byte, 16)
			Assembler(in[:], out)
			AssemblerPlain(in[:], out)
			return out
		}},
	}


@@ 284,7 284,7 @@ func BenchmarkEncoding16Byte(b *testing.B) {
	}{
		{"assembler", func(in [16]byte) []byte {
			out := make([]byte, 32)
			Assembler(in[:], out)
			AssemblerPlain(in[:], out)
			return out
		}},
	}


@@ 337,7 337,7 @@ func BenchmarkEncoding16ByteEscaped(b *testing.B) {
	}{
		{"assembler", func(in [16]byte) []byte {
			out := make([]byte, 32)
			Assembler(in[:], out)
			AssemblerPlain(in[:], out)
			return out
		}},
	}


@@ 400,7 400,7 @@ func BenchmarkEncoding64Byte(b *testing.B) {
	}{
		{"assembler", func(in [64]byte) []byte {
			out := make([]byte, 128)
			Assembler(in[:], out)
			AssemblerPlain(in[:], out)
			return out
		}},
	}