From 219f10d7f51b1391a8f46a42f2445f5370a39e5a Mon Sep 17 00:00:00 2001 From: Sun Yimin Date: Thu, 17 Oct 2024 08:11:41 +0800 Subject: [PATCH] refactoring, reduce duplicated code --- base64_amd64.go | 54 --------- base64_amd64.s | 12 +- base64_ppc64x.go => base64_asm.go | 10 +- base64_amd64_test.go => base64_asm_test.go | 6 +- base64_ppc64x_test.go | 121 --------------------- 5 files changed, 19 insertions(+), 184 deletions(-) delete mode 100644 base64_amd64.go rename base64_ppc64x.go => base64_asm.go (88%) rename base64_amd64_test.go => base64_asm_test.go (94%) delete mode 100644 base64_ppc64x_test.go diff --git a/base64_amd64.go b/base64_amd64.go deleted file mode 100644 index e4d1cec..0000000 --- a/base64_amd64.go +++ /dev/null @@ -1,54 +0,0 @@ -//go:build amd64 && !purego - -package base64 - -import "golang.org/x/sys/cpu" - -var useAVX2 = cpu.X86.HasAVX2 -var useAVX = cpu.X86.HasAVX - -//go:noescape -func encodeSIMD(dst, src []byte, lut *[16]byte) int - -//go:noescape -func decodeStdSIMD(dst, src []byte) int - -//go:noescape -func decodeUrlSIMD(dst, src []byte) int - -func encode(enc *Encoding, dst, src []byte) { - if len(src) >= 16 && enc.lut != nil { - encoded := encodeSIMD(dst, src, enc.lut) - if encoded > 0 { - src = src[(encoded/4)*3:] - dst = dst[encoded:] - } - } - encodeGeneric(enc, dst, src) -} - -func decode(enc *Encoding, dst, src []byte) (int, error) { - srcLen := len(src) - if srcLen >= 24 { - remain := srcLen - if enc.lut == &encodeStdLut { - remain = decodeStdSIMD(dst, src) - } else if enc.lut == &encodeURLLut { - remain = decodeUrlSIMD(dst, src) - } - - if remain < srcLen { - // decoded by SIMD - remain = srcLen - remain // remain is decoded length now - src = src[remain:] - dstStart := (remain / 4) * 3 - dst = dst[dstStart:] - n, err := decodeGeneric(enc, dst, src) - if cerr, ok := err.(CorruptInputError); ok { - return n + dstStart, CorruptInputError(int(cerr) + remain) - } - return n + dstStart, err - } - } - return decodeGeneric(enc, dst, src) -} diff --git a/base64_amd64.s b/base64_amd64.s index 71840b8..46744be 100644 --- a/base64_amd64.s +++ b/base64_amd64.s @@ -171,8 +171,8 @@ GLOBL dec_reshuffle_mask<>(SB), (NOPTR+RODATA), $16 VPSHUFB tmp1, lut, tmp1; \ // get offsets and add offsets to input value. VPADDB tmp1, in_out, in_out -//func encodeSIMD(dst, src []byte, lut *[16]byte) int -TEXT ·encodeSIMD(SB),NOSPLIT,$0 +//func encodeAsm(dst, src []byte, lut *[16]byte) int +TEXT ·encodeAsm(SB),NOSPLIT,$0 MOVQ dst_base+0(FP), AX MOVQ src_base+24(FP), BX MOVQ src_len+32(FP), CX @@ -387,8 +387,8 @@ avx2_done: VPMADDWD mask1, in_out, in_out; \ // swap and merge 12-bit words into a 24-bit word VPSHUFB mask2, in_out, in_out -//func decodeStdSIMD(dst, src []byte) int -TEXT ·decodeStdSIMD(SB),NOSPLIT,$0 +//func decodeStdAsm(dst, src []byte) int +TEXT ·decodeStdAsm(SB),NOSPLIT,$0 MOVQ dst_base+0(FP), AX MOVQ src_base+24(FP), BX MOVQ src_len+32(FP), CX @@ -535,8 +535,8 @@ avx2_done: VZEROUPPER RET -//func decodeUrlSIMD(dst, src []byte) int -TEXT ·decodeUrlSIMD(SB),NOSPLIT,$0 +//func decodeUrlAsmdst, src []byte) int +TEXT ·decodeUrlAsm(SB),NOSPLIT,$0 MOVQ dst_base+0(FP), AX MOVQ src_base+24(FP), BX MOVQ src_len+32(FP), CX diff --git a/base64_ppc64x.go b/base64_asm.go similarity index 88% rename from base64_ppc64x.go rename to base64_asm.go index 0da6ca5..4a53a66 100644 --- a/base64_ppc64x.go +++ b/base64_asm.go @@ -2,10 +2,15 @@ // Use of this source code is governed by a BSD 3-Clause-style // license that can be found in the LICENSE file. -//go:build (ppc64 || ppc64le) && !purego +//go:build (amd64 || ppc64 || ppc64le) && !purego package base64 +import "golang.org/x/sys/cpu" + +var useAVX2 = cpu.X86.HasAVX2 +var useAVX = cpu.X86.HasAVX + //go:noescape func encodeAsm(dst, src []byte, lut *[16]byte) int @@ -35,8 +40,9 @@ func decode(enc *Encoding, dst, src []byte) (int, error) { } else if enc.lut == &encodeURLLut { remain = decodeUrlAsm(dst, src) } + if remain < srcLen { - // decoded by ASM + // decoded by SIMD remain = srcLen - remain // remain is decoded length now src = src[remain:] dstStart := (remain / 4) * 3 diff --git a/base64_amd64_test.go b/base64_asm_test.go similarity index 94% rename from base64_amd64_test.go rename to base64_asm_test.go index 26b460c..00a0278 100644 --- a/base64_amd64_test.go +++ b/base64_asm_test.go @@ -1,4 +1,8 @@ -//go:build amd64 && !purego +// Copyright 2024 Sun Yimin. All rights reserved. +// Use of this source code is governed by a BSD 3-Clause-style +// license that can be found in the LICENSE file. + +//go:build (amd64 || ppc64 || ppc64le) && !purego package base64 diff --git a/base64_ppc64x_test.go b/base64_ppc64x_test.go deleted file mode 100644 index 4fd0de6..0000000 --- a/base64_ppc64x_test.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2024 Sun Yimin. All rights reserved. -// Use of this source code is governed by a BSD 3-Clause-style -// license that can be found in the LICENSE file. - -//go:build (ppc64 || ppc64le) && !purego - -package base64 - -import ( - "bytes" - "testing" -) - -func TestStdEncodeAsm(t *testing.T) { - pairs := []testpair{ - {"abcdefghijkl0000", "YWJjZGVmZ2hpamts"}, - {"\x2b\xf7\xcc\x27\x01\xfe\x43\x97\xb4\x9e\xbe\xed\x5a\xcc\x70\x90", "K/fMJwH+Q5e0nr7t"}, - {"abcdefghijklabcdefghijkl0000", "YWJjZGVmZ2hpamtsYWJjZGVmZ2hpamts"}, - {"abcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijkl", "YWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamts"}, - {"abcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijkl", "YWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamts"}, - {"abcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijklabcdefghijkl", "YWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamts"}, - } - for _, p := range pairs { - src := []byte(p.decoded) - expected := []byte(p.encoded) - dst := make([]byte, len(expected)) - - ret := encodeAsm(dst, src, &encodeStdLut) - if ret != len(expected) { - t.Errorf("should return %v, got %v", len(expected), ret) - } - if !bytes.Equal(dst, expected) { - t.Errorf("got %x, expected %x", dst, expected) - } - - } -} - -func TestStdDecodeSIMD(t *testing.T) { - pairs := []testpair{ - {"abcdefghijkl", "YWJjZGVmZ2hpamtsYWJjZGVmZ2hpamts"}, - {"\x2b\xf7\xcc\x27\x01\xfe\x43\x97\xb4\x9e\xbe\xed", "K/fMJwH+Q5e0nr7tK/fMJwH+Q5e0nr7t"}, - {"abcdefghijklabcdefghijklabcdefghijkl", "YWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamtsYWJjZGVmZ2hpamts"}, - } - for _, p := range pairs { - expected := []byte(p.decoded) - src := []byte(p.encoded) - dst := make([]byte, len(expected)) - - ret := decodeStdAsm(dst, src) - if ret == len(src) { - t.Errorf("should return decode") - } - if !bytes.Equal(dst, expected) { - t.Errorf("got %x, expected %x", dst, expected) - } - } -} - -func TestURLEncodeSIMD(t *testing.T) { - pairs := []testpair{ - {"!?$*&()'-=@~0000", "IT8kKiYoKSctPUB-"}, - {"\x2b\xf7\xcc\x27\x01\xfe\x43\x97\xb4\x9e\xbe\xed\x5a\xcc\x70\x90", "K_fMJwH-Q5e0nr7t"}, - {"!?$*&()'-=@~!?$*&()'-=@~0000", "IT8kKiYoKSctPUB-IT8kKiYoKSctPUB-"}, - } - for _, p := range pairs { - src := []byte(p.decoded) - expected := []byte(p.encoded) - dst := make([]byte, len(expected)) - - ret := encodeAsm(dst, src, &encodeURLLut) - if ret != len(expected) { - t.Errorf("should return %v", len(expected)) - } - if !bytes.Equal(dst, expected) { - t.Errorf("got %v", string(dst)) - } - - } -} - -func TestUrlDecodeSIMD(t *testing.T) { - pairs := []testpair{ - {"!?$*&()'-=@~", "IT8kKiYoKSctPUB-IT8kKiYoKSctPUB-"}, - {"\x2b\xf7\xcc\x27\x01\xfe\x43\x97\xb4\x9e\xbe\xed", "K_fMJwH-Q5e0nr7tK_fMJwH-Q5e0nr7t"}, - {"!?$*&()'-=@~!?$*&()'-=@~!?$*&()'-=@~", "IT8kKiYoKSctPUB-IT8kKiYoKSctPUB-IT8kKiYoKSctPUB-IT8kKiYoKSctPUB-"}, - } - for _, p := range pairs { - expected := []byte(p.decoded) - src := []byte(p.encoded) - dst := make([]byte, len(expected)) - - ret := decodeUrlAsm(dst, src) - if ret == len(src) { - t.Errorf("should return decode") - } - if !bytes.Equal(dst, expected) { - t.Errorf("got %x, expected %x", dst, expected) - } - } -} - - -func BenchmarkEncode(b *testing.B) { - data := make([]byte, 8192) - dst := make([]byte, StdEncoding.EncodedLen(8192)) - b.SetBytes(int64(len(data))) - for i := 0; i < b.N; i++ { - StdEncoding.Encode(dst, data) - } -} - -func BenchmarkDecode(b *testing.B) { - data := []byte(StdEncoding.EncodeToString(make([]byte, 8192))) - dbuf := make([]byte, StdEncoding.DecodedLen(len(data))) - b.SetBytes(int64(len(data))) - b.ResetTimer() - for i := 0; i < b.N; i++ { - StdEncoding.Decode(dbuf, data) - } -}