fix(go.sum): update ResolveSpec dependency to v1.0.87
This commit is contained in:
+21
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2021 Segment
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
package ascii
|
||||
|
||||
import _ "github.com/segmentio/asm/cpu"
|
||||
|
||||
// https://graphics.stanford.edu/~seander/bithacks.html#HasLessInWord
|
||||
const (
|
||||
hasLessConstL64 = (^uint64(0)) / 255
|
||||
hasLessConstR64 = hasLessConstL64 * 128
|
||||
|
||||
hasLessConstL32 = (^uint32(0)) / 255
|
||||
hasLessConstR32 = hasLessConstL32 * 128
|
||||
|
||||
hasMoreConstL64 = (^uint64(0)) / 255
|
||||
hasMoreConstR64 = hasMoreConstL64 * 128
|
||||
|
||||
hasMoreConstL32 = (^uint32(0)) / 255
|
||||
hasMoreConstR32 = hasMoreConstL32 * 128
|
||||
)
|
||||
|
||||
func hasLess64(x, n uint64) bool {
|
||||
return ((x - (hasLessConstL64 * n)) & ^x & hasLessConstR64) != 0
|
||||
}
|
||||
|
||||
func hasLess32(x, n uint32) bool {
|
||||
return ((x - (hasLessConstL32 * n)) & ^x & hasLessConstR32) != 0
|
||||
}
|
||||
|
||||
func hasMore64(x, n uint64) bool {
|
||||
return (((x + (hasMoreConstL64 * (127 - n))) | x) & hasMoreConstR64) != 0
|
||||
}
|
||||
|
||||
func hasMore32(x, n uint32) bool {
|
||||
return (((x + (hasMoreConstL32 * (127 - n))) | x) & hasMoreConstR32) != 0
|
||||
}
|
||||
|
||||
var lowerCase = [256]byte{
|
||||
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
|
||||
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
|
||||
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
|
||||
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
|
||||
0x40, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
|
||||
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
|
||||
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
|
||||
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
|
||||
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
|
||||
0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
|
||||
0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
|
||||
0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
|
||||
0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
|
||||
0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
|
||||
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff,
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
package ascii
|
||||
|
||||
import (
|
||||
"github.com/segmentio/asm/internal/unsafebytes"
|
||||
)
|
||||
|
||||
// EqualFold is a version of bytes.EqualFold designed to work on ASCII input
|
||||
// instead of UTF-8.
|
||||
//
|
||||
// When the program has guarantees that the input is composed of ASCII
|
||||
// characters only, it allows for greater optimizations.
|
||||
func EqualFold(a, b []byte) bool {
|
||||
return EqualFoldString(unsafebytes.String(a), unsafebytes.String(b))
|
||||
}
|
||||
|
||||
func HasPrefixFold(s, prefix []byte) bool {
|
||||
return len(s) >= len(prefix) && EqualFold(s[:len(prefix)], prefix)
|
||||
}
|
||||
|
||||
func HasSuffixFold(s, suffix []byte) bool {
|
||||
return len(s) >= len(suffix) && EqualFold(s[len(s)-len(suffix):], suffix)
|
||||
}
|
||||
|
||||
func HasPrefixFoldString(s, prefix string) bool {
|
||||
return len(s) >= len(prefix) && EqualFoldString(s[:len(prefix)], prefix)
|
||||
}
|
||||
|
||||
func HasSuffixFoldString(s, suffix string) bool {
|
||||
return len(s) >= len(suffix) && EqualFoldString(s[len(s)-len(suffix):], suffix)
|
||||
}
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// Code generated by command: go run equal_fold_asm.go -pkg ascii -out ../ascii/equal_fold_amd64.s -stubs ../ascii/equal_fold_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
package ascii
|
||||
|
||||
// EqualFoldString is a version of strings.EqualFold designed to work on ASCII
|
||||
// input instead of UTF-8.
|
||||
//
|
||||
// When the program has guarantees that the input is composed of ASCII
|
||||
// characters only, it allows for greater optimizations.
|
||||
func EqualFoldString(a string, b string) bool
|
||||
+304
@@ -0,0 +1,304 @@
|
||||
// Code generated by command: go run equal_fold_asm.go -pkg ascii -out ../ascii/equal_fold_amd64.s -stubs ../ascii/equal_fold_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func EqualFoldString(a string, b string) bool
|
||||
// Requires: AVX, AVX2, SSE4.1
|
||||
TEXT ·EqualFoldString(SB), NOSPLIT, $0-33
|
||||
MOVQ a_base+0(FP), CX
|
||||
MOVQ a_len+8(FP), DX
|
||||
MOVQ b_base+16(FP), BX
|
||||
CMPQ DX, b_len+24(FP)
|
||||
JNE done
|
||||
XORQ AX, AX
|
||||
CMPQ DX, $0x10
|
||||
JB init_x86
|
||||
BTL $0x08, github·com∕segmentio∕asm∕cpu·X86+0(SB)
|
||||
JCS init_avx
|
||||
|
||||
init_x86:
|
||||
LEAQ github·com∕segmentio∕asm∕ascii·lowerCase+0(SB), R9
|
||||
XORL SI, SI
|
||||
|
||||
cmp8:
|
||||
CMPQ DX, $0x08
|
||||
JB cmp7
|
||||
MOVBLZX (CX)(AX*1), DI
|
||||
MOVBLZX (BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
MOVBLZX 1(CX)(AX*1), DI
|
||||
MOVBLZX 1(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
MOVBLZX 2(CX)(AX*1), DI
|
||||
MOVBLZX 2(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
MOVBLZX 3(CX)(AX*1), DI
|
||||
MOVBLZX 3(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
MOVBLZX 4(CX)(AX*1), DI
|
||||
MOVBLZX 4(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
MOVBLZX 5(CX)(AX*1), DI
|
||||
MOVBLZX 5(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
MOVBLZX 6(CX)(AX*1), DI
|
||||
MOVBLZX 6(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
MOVBLZX 7(CX)(AX*1), DI
|
||||
MOVBLZX 7(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
JNE done
|
||||
ADDQ $0x08, AX
|
||||
SUBQ $0x08, DX
|
||||
JMP cmp8
|
||||
|
||||
cmp7:
|
||||
CMPQ DX, $0x07
|
||||
JB cmp6
|
||||
MOVBLZX 6(CX)(AX*1), DI
|
||||
MOVBLZX 6(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
|
||||
cmp6:
|
||||
CMPQ DX, $0x06
|
||||
JB cmp5
|
||||
MOVBLZX 5(CX)(AX*1), DI
|
||||
MOVBLZX 5(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
|
||||
cmp5:
|
||||
CMPQ DX, $0x05
|
||||
JB cmp4
|
||||
MOVBLZX 4(CX)(AX*1), DI
|
||||
MOVBLZX 4(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
|
||||
cmp4:
|
||||
CMPQ DX, $0x04
|
||||
JB cmp3
|
||||
MOVBLZX 3(CX)(AX*1), DI
|
||||
MOVBLZX 3(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
|
||||
cmp3:
|
||||
CMPQ DX, $0x03
|
||||
JB cmp2
|
||||
MOVBLZX 2(CX)(AX*1), DI
|
||||
MOVBLZX 2(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
|
||||
cmp2:
|
||||
CMPQ DX, $0x02
|
||||
JB cmp1
|
||||
MOVBLZX 1(CX)(AX*1), DI
|
||||
MOVBLZX 1(BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
|
||||
cmp1:
|
||||
CMPQ DX, $0x01
|
||||
JB success
|
||||
MOVBLZX (CX)(AX*1), DI
|
||||
MOVBLZX (BX)(AX*1), R8
|
||||
MOVB (R9)(DI*1), DI
|
||||
XORB (R9)(R8*1), DI
|
||||
ORB DI, SI
|
||||
|
||||
done:
|
||||
SETEQ ret+32(FP)
|
||||
RET
|
||||
|
||||
success:
|
||||
MOVB $0x01, ret+32(FP)
|
||||
RET
|
||||
|
||||
init_avx:
|
||||
MOVB $0x20, SI
|
||||
PINSRB $0x00, SI, X12
|
||||
VPBROADCASTB X12, Y12
|
||||
MOVB $0x1f, SI
|
||||
PINSRB $0x00, SI, X13
|
||||
VPBROADCASTB X13, Y13
|
||||
MOVB $0x9a, SI
|
||||
PINSRB $0x00, SI, X14
|
||||
VPBROADCASTB X14, Y14
|
||||
MOVB $0x01, SI
|
||||
PINSRB $0x00, SI, X15
|
||||
VPBROADCASTB X15, Y15
|
||||
|
||||
cmp128:
|
||||
CMPQ DX, $0x80
|
||||
JB cmp64
|
||||
VMOVDQU (CX)(AX*1), Y0
|
||||
VMOVDQU 32(CX)(AX*1), Y1
|
||||
VMOVDQU 64(CX)(AX*1), Y2
|
||||
VMOVDQU 96(CX)(AX*1), Y3
|
||||
VMOVDQU (BX)(AX*1), Y4
|
||||
VMOVDQU 32(BX)(AX*1), Y5
|
||||
VMOVDQU 64(BX)(AX*1), Y6
|
||||
VMOVDQU 96(BX)(AX*1), Y7
|
||||
VXORPD Y0, Y4, Y4
|
||||
VPCMPEQB Y12, Y4, Y8
|
||||
VORPD Y12, Y0, Y0
|
||||
VPADDB Y13, Y0, Y0
|
||||
VPCMPGTB Y0, Y14, Y0
|
||||
VPAND Y8, Y0, Y0
|
||||
VPAND Y15, Y0, Y0
|
||||
VPSLLW $0x05, Y0, Y0
|
||||
VPCMPEQB Y4, Y0, Y0
|
||||
VXORPD Y1, Y5, Y5
|
||||
VPCMPEQB Y12, Y5, Y9
|
||||
VORPD Y12, Y1, Y1
|
||||
VPADDB Y13, Y1, Y1
|
||||
VPCMPGTB Y1, Y14, Y1
|
||||
VPAND Y9, Y1, Y1
|
||||
VPAND Y15, Y1, Y1
|
||||
VPSLLW $0x05, Y1, Y1
|
||||
VPCMPEQB Y5, Y1, Y1
|
||||
VXORPD Y2, Y6, Y6
|
||||
VPCMPEQB Y12, Y6, Y10
|
||||
VORPD Y12, Y2, Y2
|
||||
VPADDB Y13, Y2, Y2
|
||||
VPCMPGTB Y2, Y14, Y2
|
||||
VPAND Y10, Y2, Y2
|
||||
VPAND Y15, Y2, Y2
|
||||
VPSLLW $0x05, Y2, Y2
|
||||
VPCMPEQB Y6, Y2, Y2
|
||||
VXORPD Y3, Y7, Y7
|
||||
VPCMPEQB Y12, Y7, Y11
|
||||
VORPD Y12, Y3, Y3
|
||||
VPADDB Y13, Y3, Y3
|
||||
VPCMPGTB Y3, Y14, Y3
|
||||
VPAND Y11, Y3, Y3
|
||||
VPAND Y15, Y3, Y3
|
||||
VPSLLW $0x05, Y3, Y3
|
||||
VPCMPEQB Y7, Y3, Y3
|
||||
VPAND Y1, Y0, Y0
|
||||
VPAND Y3, Y2, Y2
|
||||
VPAND Y2, Y0, Y0
|
||||
ADDQ $0x80, AX
|
||||
SUBQ $0x80, DX
|
||||
VPMOVMSKB Y0, SI
|
||||
XORL $0xffffffff, SI
|
||||
JNE done
|
||||
JMP cmp128
|
||||
|
||||
cmp64:
|
||||
CMPQ DX, $0x40
|
||||
JB cmp32
|
||||
VMOVDQU (CX)(AX*1), Y0
|
||||
VMOVDQU 32(CX)(AX*1), Y1
|
||||
VMOVDQU (BX)(AX*1), Y2
|
||||
VMOVDQU 32(BX)(AX*1), Y3
|
||||
VXORPD Y0, Y2, Y2
|
||||
VPCMPEQB Y12, Y2, Y4
|
||||
VORPD Y12, Y0, Y0
|
||||
VPADDB Y13, Y0, Y0
|
||||
VPCMPGTB Y0, Y14, Y0
|
||||
VPAND Y4, Y0, Y0
|
||||
VPAND Y15, Y0, Y0
|
||||
VPSLLW $0x05, Y0, Y0
|
||||
VPCMPEQB Y2, Y0, Y0
|
||||
VXORPD Y1, Y3, Y3
|
||||
VPCMPEQB Y12, Y3, Y5
|
||||
VORPD Y12, Y1, Y1
|
||||
VPADDB Y13, Y1, Y1
|
||||
VPCMPGTB Y1, Y14, Y1
|
||||
VPAND Y5, Y1, Y1
|
||||
VPAND Y15, Y1, Y1
|
||||
VPSLLW $0x05, Y1, Y1
|
||||
VPCMPEQB Y3, Y1, Y1
|
||||
VPAND Y1, Y0, Y0
|
||||
ADDQ $0x40, AX
|
||||
SUBQ $0x40, DX
|
||||
VPMOVMSKB Y0, SI
|
||||
XORL $0xffffffff, SI
|
||||
JNE done
|
||||
|
||||
cmp32:
|
||||
CMPQ DX, $0x20
|
||||
JB cmp16
|
||||
VMOVDQU (CX)(AX*1), Y0
|
||||
VMOVDQU (BX)(AX*1), Y1
|
||||
VXORPD Y0, Y1, Y1
|
||||
VPCMPEQB Y12, Y1, Y2
|
||||
VORPD Y12, Y0, Y0
|
||||
VPADDB Y13, Y0, Y0
|
||||
VPCMPGTB Y0, Y14, Y0
|
||||
VPAND Y2, Y0, Y0
|
||||
VPAND Y15, Y0, Y0
|
||||
VPSLLW $0x05, Y0, Y0
|
||||
VPCMPEQB Y1, Y0, Y0
|
||||
ADDQ $0x20, AX
|
||||
SUBQ $0x20, DX
|
||||
VPMOVMSKB Y0, SI
|
||||
XORL $0xffffffff, SI
|
||||
JNE done
|
||||
|
||||
cmp16:
|
||||
CMPQ DX, $0x10
|
||||
JLE cmp_tail
|
||||
VMOVDQU (CX)(AX*1), X0
|
||||
VMOVDQU (BX)(AX*1), X1
|
||||
VXORPD X0, X1, X1
|
||||
VPCMPEQB X12, X1, X2
|
||||
VORPD X12, X0, X0
|
||||
VPADDB X13, X0, X0
|
||||
VPCMPGTB X0, X14, X0
|
||||
VPAND X2, X0, X0
|
||||
VPAND X15, X0, X0
|
||||
VPSLLW $0x05, X0, X0
|
||||
VPCMPEQB X1, X0, X0
|
||||
ADDQ $0x10, AX
|
||||
SUBQ $0x10, DX
|
||||
VPMOVMSKB X0, SI
|
||||
XORL $0x0000ffff, SI
|
||||
JNE done
|
||||
|
||||
cmp_tail:
|
||||
SUBQ $0x10, DX
|
||||
ADDQ DX, AX
|
||||
VMOVDQU (CX)(AX*1), X0
|
||||
VMOVDQU (BX)(AX*1), X1
|
||||
VXORPD X0, X1, X1
|
||||
VPCMPEQB X12, X1, X2
|
||||
VORPD X12, X0, X0
|
||||
VPADDB X13, X0, X0
|
||||
VPCMPGTB X0, X14, X0
|
||||
VPAND X2, X0, X0
|
||||
VPAND X15, X0, X0
|
||||
VPSLLW $0x05, X0, X0
|
||||
VPCMPEQB X1, X0, X0
|
||||
VPMOVMSKB X0, AX
|
||||
XORL $0x0000ffff, AX
|
||||
JMP done
|
||||
+60
@@ -0,0 +1,60 @@
|
||||
//go:build purego || !amd64
|
||||
// +build purego !amd64
|
||||
|
||||
package ascii
|
||||
|
||||
// EqualFoldString is a version of strings.EqualFold designed to work on ASCII
|
||||
// input instead of UTF-8.
|
||||
//
|
||||
// When the program has guarantees that the input is composed of ASCII
|
||||
// characters only, it allows for greater optimizations.
|
||||
func EqualFoldString(a, b string) bool {
|
||||
if len(a) != len(b) {
|
||||
return false
|
||||
}
|
||||
|
||||
var cmp byte
|
||||
|
||||
for len(a) >= 8 {
|
||||
cmp |= lowerCase[a[0]] ^ lowerCase[b[0]]
|
||||
cmp |= lowerCase[a[1]] ^ lowerCase[b[1]]
|
||||
cmp |= lowerCase[a[2]] ^ lowerCase[b[2]]
|
||||
cmp |= lowerCase[a[3]] ^ lowerCase[b[3]]
|
||||
cmp |= lowerCase[a[4]] ^ lowerCase[b[4]]
|
||||
cmp |= lowerCase[a[5]] ^ lowerCase[b[5]]
|
||||
cmp |= lowerCase[a[6]] ^ lowerCase[b[6]]
|
||||
cmp |= lowerCase[a[7]] ^ lowerCase[b[7]]
|
||||
|
||||
if cmp != 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
a = a[8:]
|
||||
b = b[8:]
|
||||
}
|
||||
|
||||
switch len(a) {
|
||||
case 7:
|
||||
cmp |= lowerCase[a[6]] ^ lowerCase[b[6]]
|
||||
fallthrough
|
||||
case 6:
|
||||
cmp |= lowerCase[a[5]] ^ lowerCase[b[5]]
|
||||
fallthrough
|
||||
case 5:
|
||||
cmp |= lowerCase[a[4]] ^ lowerCase[b[4]]
|
||||
fallthrough
|
||||
case 4:
|
||||
cmp |= lowerCase[a[3]] ^ lowerCase[b[3]]
|
||||
fallthrough
|
||||
case 3:
|
||||
cmp |= lowerCase[a[2]] ^ lowerCase[b[2]]
|
||||
fallthrough
|
||||
case 2:
|
||||
cmp |= lowerCase[a[1]] ^ lowerCase[b[1]]
|
||||
fallthrough
|
||||
case 1:
|
||||
cmp |= lowerCase[a[0]] ^ lowerCase[b[0]]
|
||||
}
|
||||
|
||||
return cmp == 0
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package ascii
|
||||
|
||||
import "github.com/segmentio/asm/internal/unsafebytes"
|
||||
|
||||
// Valid returns true if b contains only ASCII characters.
|
||||
func Valid(b []byte) bool {
|
||||
return ValidString(unsafebytes.String(b))
|
||||
}
|
||||
|
||||
// ValidBytes returns true if b is an ASCII character.
|
||||
func ValidByte(b byte) bool {
|
||||
return b <= 0x7f
|
||||
}
|
||||
|
||||
// ValidBytes returns true if b is an ASCII character.
|
||||
func ValidRune(r rune) bool {
|
||||
return r <= 0x7f
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Code generated by command: go run valid_asm.go -pkg ascii -out ../ascii/valid_amd64.s -stubs ../ascii/valid_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
package ascii
|
||||
|
||||
// ValidString returns true if s contains only ASCII characters.
|
||||
func ValidString(s string) bool
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
// Code generated by command: go run valid_asm.go -pkg ascii -out ../ascii/valid_amd64.s -stubs ../ascii/valid_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func ValidString(s string) bool
|
||||
// Requires: AVX, AVX2, SSE4.1
|
||||
TEXT ·ValidString(SB), NOSPLIT, $0-17
|
||||
MOVQ s_base+0(FP), AX
|
||||
MOVQ s_len+8(FP), CX
|
||||
MOVQ $0x8080808080808080, DX
|
||||
CMPQ CX, $0x10
|
||||
JB cmp8
|
||||
BTL $0x08, github·com∕segmentio∕asm∕cpu·X86+0(SB)
|
||||
JCS init_avx
|
||||
|
||||
cmp8:
|
||||
CMPQ CX, $0x08
|
||||
JB cmp4
|
||||
TESTQ DX, (AX)
|
||||
JNZ invalid
|
||||
ADDQ $0x08, AX
|
||||
SUBQ $0x08, CX
|
||||
JMP cmp8
|
||||
|
||||
cmp4:
|
||||
CMPQ CX, $0x04
|
||||
JB cmp3
|
||||
TESTL $0x80808080, (AX)
|
||||
JNZ invalid
|
||||
ADDQ $0x04, AX
|
||||
SUBQ $0x04, CX
|
||||
|
||||
cmp3:
|
||||
CMPQ CX, $0x03
|
||||
JB cmp2
|
||||
MOVWLZX (AX), CX
|
||||
MOVBLZX 2(AX), AX
|
||||
SHLL $0x10, AX
|
||||
ORL CX, AX
|
||||
TESTL $0x80808080, AX
|
||||
JMP done
|
||||
|
||||
cmp2:
|
||||
CMPQ CX, $0x02
|
||||
JB cmp1
|
||||
TESTW $0x8080, (AX)
|
||||
JMP done
|
||||
|
||||
cmp1:
|
||||
CMPQ CX, $0x00
|
||||
JE done
|
||||
TESTB $0x80, (AX)
|
||||
|
||||
done:
|
||||
SETEQ ret+16(FP)
|
||||
RET
|
||||
|
||||
invalid:
|
||||
MOVB $0x00, ret+16(FP)
|
||||
RET
|
||||
|
||||
init_avx:
|
||||
PINSRQ $0x00, DX, X4
|
||||
VPBROADCASTQ X4, Y4
|
||||
|
||||
cmp256:
|
||||
CMPQ CX, $0x00000100
|
||||
JB cmp128
|
||||
VMOVDQU (AX), Y0
|
||||
VPOR 32(AX), Y0, Y0
|
||||
VMOVDQU 64(AX), Y1
|
||||
VPOR 96(AX), Y1, Y1
|
||||
VMOVDQU 128(AX), Y2
|
||||
VPOR 160(AX), Y2, Y2
|
||||
VMOVDQU 192(AX), Y3
|
||||
VPOR 224(AX), Y3, Y3
|
||||
VPOR Y1, Y0, Y0
|
||||
VPOR Y3, Y2, Y2
|
||||
VPOR Y2, Y0, Y0
|
||||
VPTEST Y0, Y4
|
||||
JNZ invalid
|
||||
ADDQ $0x00000100, AX
|
||||
SUBQ $0x00000100, CX
|
||||
JMP cmp256
|
||||
|
||||
cmp128:
|
||||
CMPQ CX, $0x80
|
||||
JB cmp64
|
||||
VMOVDQU (AX), Y0
|
||||
VPOR 32(AX), Y0, Y0
|
||||
VMOVDQU 64(AX), Y1
|
||||
VPOR 96(AX), Y1, Y1
|
||||
VPOR Y1, Y0, Y0
|
||||
VPTEST Y0, Y4
|
||||
JNZ invalid
|
||||
ADDQ $0x80, AX
|
||||
SUBQ $0x80, CX
|
||||
|
||||
cmp64:
|
||||
CMPQ CX, $0x40
|
||||
JB cmp32
|
||||
VMOVDQU (AX), Y0
|
||||
VPOR 32(AX), Y0, Y0
|
||||
VPTEST Y0, Y4
|
||||
JNZ invalid
|
||||
ADDQ $0x40, AX
|
||||
SUBQ $0x40, CX
|
||||
|
||||
cmp32:
|
||||
CMPQ CX, $0x20
|
||||
JB cmp16
|
||||
VPTEST (AX), Y4
|
||||
JNZ invalid
|
||||
ADDQ $0x20, AX
|
||||
SUBQ $0x20, CX
|
||||
|
||||
cmp16:
|
||||
CMPQ CX, $0x10
|
||||
JLE cmp_tail
|
||||
VPTEST (AX), X4
|
||||
JNZ invalid
|
||||
ADDQ $0x10, AX
|
||||
SUBQ $0x10, CX
|
||||
|
||||
cmp_tail:
|
||||
SUBQ $0x10, CX
|
||||
ADDQ CX, AX
|
||||
VPTEST (AX), X4
|
||||
JMP done
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
//go:build purego || !amd64
|
||||
// +build purego !amd64
|
||||
|
||||
package ascii
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
// ValidString returns true if s contains only ASCII characters.
|
||||
func ValidString(s string) bool {
|
||||
p := *(*unsafe.Pointer)(unsafe.Pointer(&s))
|
||||
i := uintptr(0)
|
||||
n := uintptr(len(s))
|
||||
|
||||
for i+8 <= n {
|
||||
if (*(*uint64)(unsafe.Pointer(uintptr(p) + i)) & 0x8080808080808080) != 0 {
|
||||
return false
|
||||
}
|
||||
i += 8
|
||||
}
|
||||
|
||||
if i+4 <= n {
|
||||
if (*(*uint32)(unsafe.Pointer(uintptr(p) + i)) & 0x80808080) != 0 {
|
||||
return false
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
|
||||
if i == n {
|
||||
return true
|
||||
}
|
||||
|
||||
p = unsafe.Pointer(uintptr(p) + i)
|
||||
|
||||
var x uint32
|
||||
switch n - i {
|
||||
case 3:
|
||||
x = uint32(*(*uint16)(p)) | uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + 2)))<<16
|
||||
case 2:
|
||||
x = uint32(*(*uint16)(p))
|
||||
case 1:
|
||||
x = uint32(*(*uint8)(p))
|
||||
default:
|
||||
return true
|
||||
}
|
||||
return (x & 0x80808080) == 0
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
package ascii
|
||||
|
||||
import "github.com/segmentio/asm/internal/unsafebytes"
|
||||
|
||||
// ValidPrint returns true if b contains only printable ASCII characters.
|
||||
func ValidPrint(b []byte) bool {
|
||||
return ValidPrintString(unsafebytes.String(b))
|
||||
}
|
||||
|
||||
// ValidPrintBytes returns true if b is an ASCII character.
|
||||
func ValidPrintByte(b byte) bool {
|
||||
return 0x20 <= b && b <= 0x7e
|
||||
}
|
||||
|
||||
// ValidPrintBytes returns true if b is an ASCII character.
|
||||
func ValidPrintRune(r rune) bool {
|
||||
return 0x20 <= r && r <= 0x7e
|
||||
}
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
// Code generated by command: go run valid_print_asm.go -pkg ascii -out ../ascii/valid_print_amd64.s -stubs ../ascii/valid_print_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
package ascii
|
||||
|
||||
// ValidPrintString returns true if s contains only printable ASCII characters.
|
||||
func ValidPrintString(s string) bool
|
||||
+185
@@ -0,0 +1,185 @@
|
||||
// Code generated by command: go run valid_print_asm.go -pkg ascii -out ../ascii/valid_print_amd64.s -stubs ../ascii/valid_print_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func ValidPrintString(s string) bool
|
||||
// Requires: AVX, AVX2, SSE4.1
|
||||
TEXT ·ValidPrintString(SB), NOSPLIT, $0-17
|
||||
MOVQ s_base+0(FP), AX
|
||||
MOVQ s_len+8(FP), CX
|
||||
CMPQ CX, $0x10
|
||||
JB init_x86
|
||||
BTL $0x08, github·com∕segmentio∕asm∕cpu·X86+0(SB)
|
||||
JCS init_avx
|
||||
|
||||
init_x86:
|
||||
CMPQ CX, $0x08
|
||||
JB cmp4
|
||||
MOVQ $0xdfdfdfdfdfdfdfe0, DX
|
||||
MOVQ $0x0101010101010101, BX
|
||||
MOVQ $0x8080808080808080, SI
|
||||
|
||||
cmp8:
|
||||
MOVQ (AX), DI
|
||||
MOVQ DI, R8
|
||||
LEAQ (DI)(DX*1), R9
|
||||
NOTQ R8
|
||||
ANDQ R8, R9
|
||||
LEAQ (DI)(BX*1), R8
|
||||
ORQ R8, DI
|
||||
ORQ R9, DI
|
||||
ADDQ $0x08, AX
|
||||
SUBQ $0x08, CX
|
||||
TESTQ SI, DI
|
||||
JNE done
|
||||
CMPQ CX, $0x08
|
||||
JB cmp4
|
||||
JMP cmp8
|
||||
|
||||
cmp4:
|
||||
CMPQ CX, $0x04
|
||||
JB cmp3
|
||||
MOVL (AX), DX
|
||||
MOVL DX, BX
|
||||
LEAL 3755991008(DX), SI
|
||||
NOTL BX
|
||||
ANDL BX, SI
|
||||
LEAL 16843009(DX), BX
|
||||
ORL BX, DX
|
||||
ORL SI, DX
|
||||
ADDQ $0x04, AX
|
||||
SUBQ $0x04, CX
|
||||
TESTL $0x80808080, DX
|
||||
JNE done
|
||||
|
||||
cmp3:
|
||||
CMPQ CX, $0x03
|
||||
JB cmp2
|
||||
MOVWLZX (AX), DX
|
||||
MOVBLZX 2(AX), AX
|
||||
SHLL $0x10, AX
|
||||
ORL DX, AX
|
||||
ORL $0x20000000, AX
|
||||
JMP final
|
||||
|
||||
cmp2:
|
||||
CMPQ CX, $0x02
|
||||
JB cmp1
|
||||
MOVWLZX (AX), AX
|
||||
ORL $0x20200000, AX
|
||||
JMP final
|
||||
|
||||
cmp1:
|
||||
CMPQ CX, $0x00
|
||||
JE done
|
||||
MOVBLZX (AX), AX
|
||||
ORL $0x20202000, AX
|
||||
|
||||
final:
|
||||
MOVL AX, CX
|
||||
LEAL 3755991008(AX), DX
|
||||
NOTL CX
|
||||
ANDL CX, DX
|
||||
LEAL 16843009(AX), CX
|
||||
ORL CX, AX
|
||||
ORL DX, AX
|
||||
TESTL $0x80808080, AX
|
||||
|
||||
done:
|
||||
SETEQ ret+16(FP)
|
||||
RET
|
||||
|
||||
init_avx:
|
||||
MOVB $0x1f, DL
|
||||
PINSRB $0x00, DX, X8
|
||||
VPBROADCASTB X8, Y8
|
||||
MOVB $0x7e, DL
|
||||
PINSRB $0x00, DX, X9
|
||||
VPBROADCASTB X9, Y9
|
||||
|
||||
cmp128:
|
||||
CMPQ CX, $0x80
|
||||
JB cmp64
|
||||
VMOVDQU (AX), Y0
|
||||
VMOVDQU 32(AX), Y1
|
||||
VMOVDQU 64(AX), Y2
|
||||
VMOVDQU 96(AX), Y3
|
||||
VPCMPGTB Y8, Y0, Y4
|
||||
VPCMPGTB Y9, Y0, Y0
|
||||
VPANDN Y4, Y0, Y0
|
||||
VPCMPGTB Y8, Y1, Y5
|
||||
VPCMPGTB Y9, Y1, Y1
|
||||
VPANDN Y5, Y1, Y1
|
||||
VPCMPGTB Y8, Y2, Y6
|
||||
VPCMPGTB Y9, Y2, Y2
|
||||
VPANDN Y6, Y2, Y2
|
||||
VPCMPGTB Y8, Y3, Y7
|
||||
VPCMPGTB Y9, Y3, Y3
|
||||
VPANDN Y7, Y3, Y3
|
||||
VPAND Y1, Y0, Y0
|
||||
VPAND Y3, Y2, Y2
|
||||
VPAND Y2, Y0, Y0
|
||||
ADDQ $0x80, AX
|
||||
SUBQ $0x80, CX
|
||||
VPMOVMSKB Y0, DX
|
||||
XORL $0xffffffff, DX
|
||||
JNE done
|
||||
JMP cmp128
|
||||
|
||||
cmp64:
|
||||
CMPQ CX, $0x40
|
||||
JB cmp32
|
||||
VMOVDQU (AX), Y0
|
||||
VMOVDQU 32(AX), Y1
|
||||
VPCMPGTB Y8, Y0, Y2
|
||||
VPCMPGTB Y9, Y0, Y0
|
||||
VPANDN Y2, Y0, Y0
|
||||
VPCMPGTB Y8, Y1, Y3
|
||||
VPCMPGTB Y9, Y1, Y1
|
||||
VPANDN Y3, Y1, Y1
|
||||
VPAND Y1, Y0, Y0
|
||||
ADDQ $0x40, AX
|
||||
SUBQ $0x40, CX
|
||||
VPMOVMSKB Y0, DX
|
||||
XORL $0xffffffff, DX
|
||||
JNE done
|
||||
|
||||
cmp32:
|
||||
CMPQ CX, $0x20
|
||||
JB cmp16
|
||||
VMOVDQU (AX), Y0
|
||||
VPCMPGTB Y8, Y0, Y1
|
||||
VPCMPGTB Y9, Y0, Y0
|
||||
VPANDN Y1, Y0, Y0
|
||||
ADDQ $0x20, AX
|
||||
SUBQ $0x20, CX
|
||||
VPMOVMSKB Y0, DX
|
||||
XORL $0xffffffff, DX
|
||||
JNE done
|
||||
|
||||
cmp16:
|
||||
CMPQ CX, $0x10
|
||||
JLE cmp_tail
|
||||
VMOVDQU (AX), X0
|
||||
VPCMPGTB X8, X0, X1
|
||||
VPCMPGTB X9, X0, X0
|
||||
VPANDN X1, X0, X0
|
||||
ADDQ $0x10, AX
|
||||
SUBQ $0x10, CX
|
||||
VPMOVMSKB X0, DX
|
||||
XORL $0x0000ffff, DX
|
||||
JNE done
|
||||
|
||||
cmp_tail:
|
||||
SUBQ $0x10, CX
|
||||
ADDQ CX, AX
|
||||
VMOVDQU (AX), X0
|
||||
VPCMPGTB X8, X0, X1
|
||||
VPCMPGTB X9, X0, X0
|
||||
VPANDN X1, X0, X0
|
||||
VPMOVMSKB X0, DX
|
||||
XORL $0x0000ffff, DX
|
||||
JMP done
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
//go:build purego || !amd64
|
||||
// +build purego !amd64
|
||||
|
||||
package ascii
|
||||
|
||||
import "unsafe"
|
||||
|
||||
// ValidString returns true if s contains only printable ASCII characters.
|
||||
func ValidPrintString(s string) bool {
|
||||
p := *(*unsafe.Pointer)(unsafe.Pointer(&s))
|
||||
i := uintptr(0)
|
||||
n := uintptr(len(s))
|
||||
|
||||
for i+8 <= n {
|
||||
if hasLess64(*(*uint64)(unsafe.Pointer(uintptr(p) + i)), 0x20) || hasMore64(*(*uint64)(unsafe.Pointer(uintptr(p) + i)), 0x7e) {
|
||||
return false
|
||||
}
|
||||
i += 8
|
||||
}
|
||||
|
||||
if i+4 <= n {
|
||||
if hasLess32(*(*uint32)(unsafe.Pointer(uintptr(p) + i)), 0x20) || hasMore32(*(*uint32)(unsafe.Pointer(uintptr(p) + i)), 0x7e) {
|
||||
return false
|
||||
}
|
||||
i += 4
|
||||
}
|
||||
|
||||
if i == n {
|
||||
return true
|
||||
}
|
||||
|
||||
p = unsafe.Pointer(uintptr(p) + i)
|
||||
|
||||
var x uint32
|
||||
switch n - i {
|
||||
case 3:
|
||||
x = 0x20000000 | uint32(*(*uint16)(p)) | uint32(*(*uint8)(unsafe.Pointer(uintptr(p) + 2)))<<16
|
||||
case 2:
|
||||
x = 0x20200000 | uint32(*(*uint16)(p))
|
||||
case 1:
|
||||
x = 0x20202000 | uint32(*(*uint8)(p))
|
||||
default:
|
||||
return true
|
||||
}
|
||||
return !(hasLess32(x, 0x20) || hasMore32(x, 0x7e))
|
||||
}
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
package base64
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
)
|
||||
|
||||
const (
|
||||
StdPadding rune = base64.StdPadding
|
||||
NoPadding rune = base64.NoPadding
|
||||
|
||||
encodeStd = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
encodeURL = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
encodeIMAP = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"
|
||||
|
||||
letterRange = int8('Z' - 'A' + 1)
|
||||
)
|
||||
|
||||
// StdEncoding is the standard base64 encoding, as defined in RFC 4648.
|
||||
var StdEncoding = NewEncoding(encodeStd)
|
||||
|
||||
// URLEncoding is the alternate base64 encoding defined in RFC 4648.
|
||||
// It is typically used in URLs and file names.
|
||||
var URLEncoding = NewEncoding(encodeURL)
|
||||
|
||||
// RawStdEncoding is the standard unpadded base64 encoding defined in RFC 4648 section 3.2.
|
||||
// This is the same as StdEncoding but omits padding characters.
|
||||
var RawStdEncoding = StdEncoding.WithPadding(NoPadding)
|
||||
|
||||
// RawURLEncoding is the unpadded alternate base64 encoding defined in RFC 4648.
|
||||
// This is the same as URLEncoding but omits padding characters.
|
||||
var RawURLEncoding = URLEncoding.WithPadding(NoPadding)
|
||||
|
||||
// NewEncoding returns a new padded Encoding defined by the given alphabet,
|
||||
// which must be a 64-byte string that does not contain the padding character
|
||||
// or CR / LF ('\r', '\n'). Unlike the standard library, the encoding alphabet
|
||||
// cannot be abitrary, and it must follow one of the know standard encoding
|
||||
// variants.
|
||||
//
|
||||
// Required alphabet values:
|
||||
// * [0,26): characters 'A'..'Z'
|
||||
// * [26,52): characters 'a'..'z'
|
||||
// * [52,62): characters '0'..'9'
|
||||
// Flexible alphabet value options:
|
||||
// * RFC 4648, RFC 1421, RFC 2045, RFC 2152, RFC 4880: '+' and '/'
|
||||
// * RFC 4648 URI: '-' and '_'
|
||||
// * RFC 3501: '+' and ','
|
||||
//
|
||||
// The resulting Encoding uses the default padding character ('='), which may
|
||||
// be changed or disabled via WithPadding. The padding characters is urestricted,
|
||||
// but it must be a character outside of the encoder alphabet.
|
||||
func NewEncoding(encoder string) *Encoding {
|
||||
if len(encoder) != 64 {
|
||||
panic("encoding alphabet is not 64-bytes long")
|
||||
}
|
||||
|
||||
if _, ok := allowedEncoding[encoder]; !ok {
|
||||
panic("non-standard encoding alphabets are not supported")
|
||||
}
|
||||
|
||||
return newEncoding(encoder)
|
||||
}
|
||||
|
||||
var allowedEncoding = map[string]struct{}{
|
||||
encodeStd: {},
|
||||
encodeURL: {},
|
||||
encodeIMAP: {},
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
//go:build amd64 && !purego
|
||||
// +build amd64,!purego
|
||||
|
||||
package base64
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
|
||||
"github.com/segmentio/asm/cpu"
|
||||
"github.com/segmentio/asm/cpu/x86"
|
||||
"github.com/segmentio/asm/internal/unsafebytes"
|
||||
)
|
||||
|
||||
// An Encoding is a radix 64 encoding/decoding scheme, defined by a
|
||||
// 64-character alphabet.
|
||||
type Encoding struct {
|
||||
enc func(dst []byte, src []byte, lut *int8) (int, int)
|
||||
enclut [32]int8
|
||||
|
||||
dec func(dst []byte, src []byte, lut *int8) (int, int)
|
||||
declut [48]int8
|
||||
|
||||
base *base64.Encoding
|
||||
}
|
||||
|
||||
const (
|
||||
minEncodeLen = 28
|
||||
minDecodeLen = 45
|
||||
)
|
||||
|
||||
func newEncoding(encoder string) *Encoding {
|
||||
e := &Encoding{base: base64.NewEncoding(encoder)}
|
||||
if cpu.X86.Has(x86.AVX2) {
|
||||
e.enableEncodeAVX2(encoder)
|
||||
e.enableDecodeAVX2(encoder)
|
||||
}
|
||||
return e
|
||||
}
|
||||
|
||||
func (e *Encoding) enableEncodeAVX2(encoder string) {
|
||||
// Translate values 0..63 to the Base64 alphabet. There are five sets:
|
||||
//
|
||||
// From To Add Index Example
|
||||
// [0..25] [65..90] +65 0 ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
// [26..51] [97..122] +71 1 abcdefghijklmnopqrstuvwxyz
|
||||
// [52..61] [48..57] -4 [2..11] 0123456789
|
||||
// [62] [43] -19 12 +
|
||||
// [63] [47] -16 13 /
|
||||
tab := [32]int8{int8(encoder[0]), int8(encoder[letterRange]) - letterRange}
|
||||
for i, ch := range encoder[2*letterRange:] {
|
||||
tab[2+i] = int8(ch) - 2*letterRange - int8(i)
|
||||
}
|
||||
|
||||
e.enc = encodeAVX2
|
||||
e.enclut = tab
|
||||
}
|
||||
|
||||
func (e *Encoding) enableDecodeAVX2(encoder string) {
|
||||
c62, c63 := int8(encoder[62]), int8(encoder[63])
|
||||
url := c63 == '_'
|
||||
if url {
|
||||
c63 = '/'
|
||||
}
|
||||
|
||||
// Translate values from the Base64 alphabet using five sets. Values outside
|
||||
// of these ranges are considered invalid:
|
||||
//
|
||||
// From To Add Index Example
|
||||
// [47] [63] +16 1 /
|
||||
// [43] [62] +19 2 +
|
||||
// [48..57] [52..61] +4 3 0123456789
|
||||
// [65..90] [0..25] -65 4,5 ABCDEFGHIJKLMNOPQRSTUVWXYZ
|
||||
// [97..122] [26..51] -71 6,7 abcdefghijklmnopqrstuvwxyz
|
||||
tab := [48]int8{
|
||||
0, 63 - c63, 62 - c62, 4, -65, -65, -71, -71,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x15, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11,
|
||||
0x11, 0x11, 0x13, 0x1B, 0x1B, 0x1B, 0x1B, 0x1B,
|
||||
}
|
||||
tab[(c62&15)+16] = 0x1A
|
||||
tab[(c63&15)+16] = 0x1A
|
||||
|
||||
if url {
|
||||
e.dec = decodeAVX2URI
|
||||
} else {
|
||||
e.dec = decodeAVX2
|
||||
}
|
||||
e.declut = tab
|
||||
}
|
||||
|
||||
// WithPadding creates a duplicate Encoding updated with a specified padding
|
||||
// character, or NoPadding to disable padding. The padding character must not
|
||||
// be contained in the encoding alphabet, must not be '\r' or '\n', and must
|
||||
// be no greater than '\xFF'.
|
||||
func (enc Encoding) WithPadding(padding rune) *Encoding {
|
||||
enc.base = enc.base.WithPadding(padding)
|
||||
return &enc
|
||||
}
|
||||
|
||||
// Strict creates a duplicate encoding updated with strict decoding enabled.
|
||||
// This requires that trailing padding bits are zero.
|
||||
func (enc Encoding) Strict() *Encoding {
|
||||
enc.base = enc.base.Strict()
|
||||
return &enc
|
||||
}
|
||||
|
||||
// Encode encodes src using the defined encoding alphabet.
|
||||
// This will write EncodedLen(len(src)) bytes to dst.
|
||||
func (enc *Encoding) Encode(dst, src []byte) {
|
||||
if len(src) >= minEncodeLen && enc.enc != nil {
|
||||
d, s := enc.enc(dst, src, &enc.enclut[0])
|
||||
dst = dst[d:]
|
||||
src = src[s:]
|
||||
}
|
||||
enc.base.Encode(dst, src)
|
||||
}
|
||||
|
||||
// Encode encodes src using the encoding enc, writing
|
||||
// EncodedLen(len(src)) bytes to dst.
|
||||
func (enc *Encoding) EncodeToString(src []byte) string {
|
||||
buf := make([]byte, enc.base.EncodedLen(len(src)))
|
||||
enc.Encode(buf, src)
|
||||
return string(buf)
|
||||
}
|
||||
|
||||
// EncodedLen calculates the base64-encoded byte length for a message
|
||||
// of length n.
|
||||
func (enc *Encoding) EncodedLen(n int) int {
|
||||
return enc.base.EncodedLen(n)
|
||||
}
|
||||
|
||||
// Decode decodes src using the defined encoding alphabet.
|
||||
// This will write DecodedLen(len(src)) bytes to dst and return the number of
|
||||
// bytes written.
|
||||
func (enc *Encoding) Decode(dst, src []byte) (n int, err error) {
|
||||
var d, s int
|
||||
if len(src) >= minDecodeLen && enc.dec != nil {
|
||||
d, s = enc.dec(dst, src, &enc.declut[0])
|
||||
dst = dst[d:]
|
||||
src = src[s:]
|
||||
}
|
||||
n, err = enc.base.Decode(dst, src)
|
||||
n += d
|
||||
return
|
||||
}
|
||||
|
||||
// DecodeString decodes the base64 encoded string s, returns the decoded
|
||||
// value as bytes.
|
||||
func (enc *Encoding) DecodeString(s string) ([]byte, error) {
|
||||
src := unsafebytes.BytesOf(s)
|
||||
dst := make([]byte, enc.base.DecodedLen(len(s)))
|
||||
n, err := enc.Decode(dst, src)
|
||||
return dst[:n], err
|
||||
}
|
||||
|
||||
// DecodedLen calculates the decoded byte length for a base64-encoded message
|
||||
// of length n.
|
||||
func (enc *Encoding) DecodedLen(n int) int {
|
||||
return enc.base.DecodedLen(n)
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
//go:build purego || !amd64
|
||||
// +build purego !amd64
|
||||
|
||||
package base64
|
||||
|
||||
import "encoding/base64"
|
||||
|
||||
// An Encoding is a radix 64 encoding/decoding scheme, defined by a
|
||||
// 64-character alphabet.
|
||||
type Encoding = base64.Encoding
|
||||
|
||||
func newEncoding(encoder string) *Encoding {
|
||||
return base64.NewEncoding(encoder)
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
package base64
|
||||
|
||||
func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
|
||||
|
||||
func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int)
|
||||
+144
@@ -0,0 +1,144 @@
|
||||
// Code generated by command: go run decode_asm.go -pkg base64 -out ../base64/decode_amd64.s -stubs ../base64/decode_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
DATA b64_dec_lut_hi<>+0(SB)/8, $0x0804080402011010
|
||||
DATA b64_dec_lut_hi<>+8(SB)/8, $0x1010101010101010
|
||||
DATA b64_dec_lut_hi<>+16(SB)/8, $0x0804080402011010
|
||||
DATA b64_dec_lut_hi<>+24(SB)/8, $0x1010101010101010
|
||||
GLOBL b64_dec_lut_hi<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA b64_dec_madd1<>+0(SB)/8, $0x0140014001400140
|
||||
DATA b64_dec_madd1<>+8(SB)/8, $0x0140014001400140
|
||||
DATA b64_dec_madd1<>+16(SB)/8, $0x0140014001400140
|
||||
DATA b64_dec_madd1<>+24(SB)/8, $0x0140014001400140
|
||||
GLOBL b64_dec_madd1<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA b64_dec_madd2<>+0(SB)/8, $0x0001100000011000
|
||||
DATA b64_dec_madd2<>+8(SB)/8, $0x0001100000011000
|
||||
DATA b64_dec_madd2<>+16(SB)/8, $0x0001100000011000
|
||||
DATA b64_dec_madd2<>+24(SB)/8, $0x0001100000011000
|
||||
GLOBL b64_dec_madd2<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA b64_dec_shuf_lo<>+0(SB)/8, $0x0000000000000000
|
||||
DATA b64_dec_shuf_lo<>+8(SB)/8, $0x0600010200000000
|
||||
GLOBL b64_dec_shuf_lo<>(SB), RODATA|NOPTR, $16
|
||||
|
||||
DATA b64_dec_shuf<>+0(SB)/8, $0x090a040506000102
|
||||
DATA b64_dec_shuf<>+8(SB)/8, $0x000000000c0d0e08
|
||||
DATA b64_dec_shuf<>+16(SB)/8, $0x0c0d0e08090a0405
|
||||
DATA b64_dec_shuf<>+24(SB)/8, $0x0000000000000000
|
||||
GLOBL b64_dec_shuf<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
// func decodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
|
||||
// Requires: AVX, AVX2, SSE4.1
|
||||
TEXT ·decodeAVX2(SB), NOSPLIT, $0-72
|
||||
MOVQ dst_base+0(FP), AX
|
||||
MOVQ src_base+24(FP), DX
|
||||
MOVQ lut+48(FP), SI
|
||||
MOVQ src_len+32(FP), DI
|
||||
MOVB $0x2f, CL
|
||||
PINSRB $0x00, CX, X8
|
||||
VPBROADCASTB X8, Y8
|
||||
XORQ CX, CX
|
||||
XORQ BX, BX
|
||||
VPXOR Y7, Y7, Y7
|
||||
VPERMQ $0x44, (SI), Y6
|
||||
VPERMQ $0x44, 16(SI), Y4
|
||||
VMOVDQA b64_dec_lut_hi<>+0(SB), Y5
|
||||
|
||||
loop:
|
||||
VMOVDQU (DX)(BX*1), Y0
|
||||
VPSRLD $0x04, Y0, Y2
|
||||
VPAND Y8, Y0, Y3
|
||||
VPSHUFB Y3, Y4, Y3
|
||||
VPAND Y8, Y2, Y2
|
||||
VPSHUFB Y2, Y5, Y9
|
||||
VPTEST Y9, Y3
|
||||
JNE done
|
||||
VPCMPEQB Y8, Y0, Y3
|
||||
VPADDB Y3, Y2, Y2
|
||||
VPSHUFB Y2, Y6, Y2
|
||||
VPADDB Y0, Y2, Y0
|
||||
VPMADDUBSW b64_dec_madd1<>+0(SB), Y0, Y0
|
||||
VPMADDWD b64_dec_madd2<>+0(SB), Y0, Y0
|
||||
VEXTRACTI128 $0x01, Y0, X1
|
||||
VPSHUFB b64_dec_shuf_lo<>+0(SB), X1, X1
|
||||
VPSHUFB b64_dec_shuf<>+0(SB), Y0, Y0
|
||||
VPBLENDD $0x08, Y1, Y0, Y1
|
||||
VPBLENDD $0xc0, Y7, Y1, Y1
|
||||
VMOVDQU Y1, (AX)(CX*1)
|
||||
ADDQ $0x18, CX
|
||||
ADDQ $0x20, BX
|
||||
SUBQ $0x20, DI
|
||||
CMPQ DI, $0x2d
|
||||
JB done
|
||||
JMP loop
|
||||
|
||||
done:
|
||||
MOVQ CX, ret+56(FP)
|
||||
MOVQ BX, ret1+64(FP)
|
||||
VZEROUPPER
|
||||
RET
|
||||
|
||||
// func decodeAVX2URI(dst []byte, src []byte, lut *int8) (int, int)
|
||||
// Requires: AVX, AVX2, SSE4.1
|
||||
TEXT ·decodeAVX2URI(SB), NOSPLIT, $0-72
|
||||
MOVB $0x2f, AL
|
||||
PINSRB $0x00, AX, X0
|
||||
VPBROADCASTB X0, Y0
|
||||
MOVB $0x5f, AL
|
||||
PINSRB $0x00, AX, X1
|
||||
VPBROADCASTB X1, Y1
|
||||
MOVQ dst_base+0(FP), AX
|
||||
MOVQ src_base+24(FP), DX
|
||||
MOVQ lut+48(FP), SI
|
||||
MOVQ src_len+32(FP), DI
|
||||
MOVB $0x2f, CL
|
||||
PINSRB $0x00, CX, X10
|
||||
VPBROADCASTB X10, Y10
|
||||
XORQ CX, CX
|
||||
XORQ BX, BX
|
||||
VPXOR Y9, Y9, Y9
|
||||
VPERMQ $0x44, (SI), Y8
|
||||
VPERMQ $0x44, 16(SI), Y6
|
||||
VMOVDQA b64_dec_lut_hi<>+0(SB), Y7
|
||||
|
||||
loop:
|
||||
VMOVDQU (DX)(BX*1), Y2
|
||||
VPCMPEQB Y2, Y1, Y4
|
||||
VPBLENDVB Y4, Y0, Y2, Y2
|
||||
VPSRLD $0x04, Y2, Y4
|
||||
VPAND Y10, Y2, Y5
|
||||
VPSHUFB Y5, Y6, Y5
|
||||
VPAND Y10, Y4, Y4
|
||||
VPSHUFB Y4, Y7, Y11
|
||||
VPTEST Y11, Y5
|
||||
JNE done
|
||||
VPCMPEQB Y10, Y2, Y5
|
||||
VPADDB Y5, Y4, Y4
|
||||
VPSHUFB Y4, Y8, Y4
|
||||
VPADDB Y2, Y4, Y2
|
||||
VPMADDUBSW b64_dec_madd1<>+0(SB), Y2, Y2
|
||||
VPMADDWD b64_dec_madd2<>+0(SB), Y2, Y2
|
||||
VEXTRACTI128 $0x01, Y2, X3
|
||||
VPSHUFB b64_dec_shuf_lo<>+0(SB), X3, X3
|
||||
VPSHUFB b64_dec_shuf<>+0(SB), Y2, Y2
|
||||
VPBLENDD $0x08, Y3, Y2, Y3
|
||||
VPBLENDD $0xc0, Y9, Y3, Y3
|
||||
VMOVDQU Y3, (AX)(CX*1)
|
||||
ADDQ $0x18, CX
|
||||
ADDQ $0x20, BX
|
||||
SUBQ $0x20, DI
|
||||
CMPQ DI, $0x2d
|
||||
JB done
|
||||
JMP loop
|
||||
|
||||
done:
|
||||
MOVQ CX, ret+56(FP)
|
||||
MOVQ BX, ret1+64(FP)
|
||||
VZEROUPPER
|
||||
RET
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
package base64
|
||||
|
||||
func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
|
||||
+88
@@ -0,0 +1,88 @@
|
||||
// Code generated by command: go run encode_asm.go -pkg base64 -out ../base64/encode_amd64.s -stubs ../base64/encode_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func encodeAVX2(dst []byte, src []byte, lut *int8) (int, int)
|
||||
// Requires: AVX, AVX2, SSE4.1
|
||||
TEXT ·encodeAVX2(SB), NOSPLIT, $0-72
|
||||
MOVQ dst_base+0(FP), AX
|
||||
MOVQ src_base+24(FP), DX
|
||||
MOVQ lut+48(FP), SI
|
||||
MOVQ src_len+32(FP), DI
|
||||
MOVB $0x33, CL
|
||||
PINSRB $0x00, CX, X4
|
||||
VPBROADCASTB X4, Y4
|
||||
MOVB $0x19, CL
|
||||
PINSRB $0x00, CX, X5
|
||||
VPBROADCASTB X5, Y5
|
||||
XORQ CX, CX
|
||||
XORQ BX, BX
|
||||
|
||||
// Load the 16-byte LUT into both lanes of the register
|
||||
VPERMQ $0x44, (SI), Y3
|
||||
|
||||
// Load the first block using a mask to avoid potential fault
|
||||
VMOVDQU b64_enc_load<>+0(SB), Y0
|
||||
VPMASKMOVD -4(DX)(BX*1), Y0, Y0
|
||||
|
||||
loop:
|
||||
VPSHUFB b64_enc_shuf<>+0(SB), Y0, Y0
|
||||
VPAND b64_enc_mask1<>+0(SB), Y0, Y1
|
||||
VPSLLW $0x08, Y1, Y2
|
||||
VPSLLW $0x04, Y1, Y1
|
||||
VPBLENDW $0xaa, Y2, Y1, Y2
|
||||
VPAND b64_enc_mask2<>+0(SB), Y0, Y1
|
||||
VPMULHUW b64_enc_mult<>+0(SB), Y1, Y0
|
||||
VPOR Y0, Y2, Y0
|
||||
VPSUBUSB Y4, Y0, Y1
|
||||
VPCMPGTB Y5, Y0, Y2
|
||||
VPSUBB Y2, Y1, Y1
|
||||
VPSHUFB Y1, Y3, Y1
|
||||
VPADDB Y0, Y1, Y0
|
||||
VMOVDQU Y0, (AX)(CX*1)
|
||||
ADDQ $0x20, CX
|
||||
ADDQ $0x18, BX
|
||||
SUBQ $0x18, DI
|
||||
CMPQ DI, $0x20
|
||||
JB done
|
||||
VMOVDQU -4(DX)(BX*1), Y0
|
||||
JMP loop
|
||||
|
||||
done:
|
||||
MOVQ CX, ret+56(FP)
|
||||
MOVQ BX, ret1+64(FP)
|
||||
VZEROUPPER
|
||||
RET
|
||||
|
||||
DATA b64_enc_load<>+0(SB)/8, $0x8000000000000000
|
||||
DATA b64_enc_load<>+8(SB)/8, $0x8000000080000000
|
||||
DATA b64_enc_load<>+16(SB)/8, $0x8000000080000000
|
||||
DATA b64_enc_load<>+24(SB)/8, $0x8000000080000000
|
||||
GLOBL b64_enc_load<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA b64_enc_shuf<>+0(SB)/8, $0x0809070805060405
|
||||
DATA b64_enc_shuf<>+8(SB)/8, $0x0e0f0d0e0b0c0a0b
|
||||
DATA b64_enc_shuf<>+16(SB)/8, $0x0405030401020001
|
||||
DATA b64_enc_shuf<>+24(SB)/8, $0x0a0b090a07080607
|
||||
GLOBL b64_enc_shuf<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA b64_enc_mask1<>+0(SB)/8, $0x003f03f0003f03f0
|
||||
DATA b64_enc_mask1<>+8(SB)/8, $0x003f03f0003f03f0
|
||||
DATA b64_enc_mask1<>+16(SB)/8, $0x003f03f0003f03f0
|
||||
DATA b64_enc_mask1<>+24(SB)/8, $0x003f03f0003f03f0
|
||||
GLOBL b64_enc_mask1<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA b64_enc_mask2<>+0(SB)/8, $0x0fc0fc000fc0fc00
|
||||
DATA b64_enc_mask2<>+8(SB)/8, $0x0fc0fc000fc0fc00
|
||||
DATA b64_enc_mask2<>+16(SB)/8, $0x0fc0fc000fc0fc00
|
||||
DATA b64_enc_mask2<>+24(SB)/8, $0x0fc0fc000fc0fc00
|
||||
GLOBL b64_enc_mask2<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA b64_enc_mult<>+0(SB)/8, $0x0400004004000040
|
||||
DATA b64_enc_mult<>+8(SB)/8, $0x0400004004000040
|
||||
DATA b64_enc_mult<>+16(SB)/8, $0x0400004004000040
|
||||
DATA b64_enc_mult<>+24(SB)/8, $0x0400004004000040
|
||||
GLOBL b64_enc_mult<>(SB), RODATA|NOPTR, $32
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
package arm
|
||||
|
||||
import (
|
||||
"github.com/segmentio/asm/cpu/cpuid"
|
||||
. "golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
type CPU cpuid.CPU
|
||||
|
||||
func (cpu CPU) Has(feature Feature) bool {
|
||||
return cpuid.CPU(cpu).Has(cpuid.Feature(feature))
|
||||
}
|
||||
|
||||
func (cpu *CPU) set(feature Feature, enable bool) {
|
||||
(*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable)
|
||||
}
|
||||
|
||||
type Feature cpuid.Feature
|
||||
|
||||
const (
|
||||
SWP Feature = 1 << iota // SWP instruction support
|
||||
HALF // Half-word load and store support
|
||||
THUMB // ARM Thumb instruction set
|
||||
BIT26 // Address space limited to 26-bits
|
||||
FASTMUL // 32-bit operand, 64-bit result multiplication support
|
||||
FPA // Floating point arithmetic support
|
||||
VFP // Vector floating point support
|
||||
EDSP // DSP Extensions support
|
||||
JAVA // Java instruction set
|
||||
IWMMXT // Intel Wireless MMX technology support
|
||||
CRUNCH // MaverickCrunch context switching and handling
|
||||
THUMBEE // Thumb EE instruction set
|
||||
NEON // NEON instruction set
|
||||
VFPv3 // Vector floating point version 3 support
|
||||
VFPv3D16 // Vector floating point version 3 D8-D15
|
||||
TLS // Thread local storage support
|
||||
VFPv4 // Vector floating point version 4 support
|
||||
IDIVA // Integer divide instruction support in ARM mode
|
||||
IDIVT // Integer divide instruction support in Thumb mode
|
||||
VFPD32 // Vector floating point version 3 D15-D31
|
||||
LPAE // Large Physical Address Extensions
|
||||
EVTSTRM // Event stream support
|
||||
AES // AES hardware implementation
|
||||
PMULL // Polynomial multiplication instruction set
|
||||
SHA1 // SHA1 hardware implementation
|
||||
SHA2 // SHA2 hardware implementation
|
||||
CRC32 // CRC32 hardware implementation
|
||||
)
|
||||
|
||||
func ABI() CPU {
|
||||
cpu := CPU(0)
|
||||
cpu.set(SWP, ARM.HasSWP)
|
||||
cpu.set(HALF, ARM.HasHALF)
|
||||
cpu.set(THUMB, ARM.HasTHUMB)
|
||||
cpu.set(BIT26, ARM.Has26BIT)
|
||||
cpu.set(FASTMUL, ARM.HasFASTMUL)
|
||||
cpu.set(FPA, ARM.HasFPA)
|
||||
cpu.set(VFP, ARM.HasVFP)
|
||||
cpu.set(EDSP, ARM.HasEDSP)
|
||||
cpu.set(JAVA, ARM.HasJAVA)
|
||||
cpu.set(IWMMXT, ARM.HasIWMMXT)
|
||||
cpu.set(CRUNCH, ARM.HasCRUNCH)
|
||||
cpu.set(THUMBEE, ARM.HasTHUMBEE)
|
||||
cpu.set(NEON, ARM.HasNEON)
|
||||
cpu.set(VFPv3, ARM.HasVFPv3)
|
||||
cpu.set(VFPv3D16, ARM.HasVFPv3D16)
|
||||
cpu.set(TLS, ARM.HasTLS)
|
||||
cpu.set(VFPv4, ARM.HasVFPv4)
|
||||
cpu.set(IDIVA, ARM.HasIDIVA)
|
||||
cpu.set(IDIVT, ARM.HasIDIVT)
|
||||
cpu.set(VFPD32, ARM.HasVFPD32)
|
||||
cpu.set(LPAE, ARM.HasLPAE)
|
||||
cpu.set(EVTSTRM, ARM.HasEVTSTRM)
|
||||
cpu.set(AES, ARM.HasAES)
|
||||
cpu.set(PMULL, ARM.HasPMULL)
|
||||
cpu.set(SHA1, ARM.HasSHA1)
|
||||
cpu.set(SHA2, ARM.HasSHA2)
|
||||
cpu.set(CRC32, ARM.HasCRC32)
|
||||
return cpu
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
package arm64
|
||||
|
||||
import (
|
||||
"github.com/segmentio/asm/cpu/cpuid"
|
||||
. "golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
type CPU cpuid.CPU
|
||||
|
||||
func (cpu CPU) Has(feature Feature) bool {
|
||||
return cpuid.CPU(cpu).Has(cpuid.Feature(feature))
|
||||
}
|
||||
|
||||
func (cpu *CPU) set(feature Feature, enable bool) {
|
||||
(*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable)
|
||||
}
|
||||
|
||||
type Feature cpuid.Feature
|
||||
|
||||
const (
|
||||
FP Feature = 1 << iota // Floating-point instruction set (always available)
|
||||
ASIMD // Advanced SIMD (always available)
|
||||
EVTSTRM // Event stream support
|
||||
AES // AES hardware implementation
|
||||
PMULL // Polynomial multiplication instruction set
|
||||
SHA1 // SHA1 hardware implementation
|
||||
SHA2 // SHA2 hardware implementation
|
||||
CRC32 // CRC32 hardware implementation
|
||||
ATOMICS // Atomic memory operation instruction set
|
||||
FPHP // Half precision floating-point instruction set
|
||||
ASIMDHP // Advanced SIMD half precision instruction set
|
||||
CPUID // CPUID identification scheme registers
|
||||
ASIMDRDM // Rounding double multiply add/subtract instruction set
|
||||
JSCVT // Javascript conversion from floating-point to integer
|
||||
FCMA // Floating-point multiplication and addition of complex numbers
|
||||
LRCPC // Release Consistent processor consistent support
|
||||
DCPOP // Persistent memory support
|
||||
SHA3 // SHA3 hardware implementation
|
||||
SM3 // SM3 hardware implementation
|
||||
SM4 // SM4 hardware implementation
|
||||
ASIMDDP // Advanced SIMD double precision instruction set
|
||||
SHA512 // SHA512 hardware implementation
|
||||
SVE // Scalable Vector Extensions
|
||||
ASIMDFHM // Advanced SIMD multiplication FP16 to FP32
|
||||
)
|
||||
|
||||
func ABI() CPU {
|
||||
cpu := CPU(0)
|
||||
cpu.set(FP, ARM64.HasFP)
|
||||
cpu.set(ASIMD, ARM64.HasASIMD)
|
||||
cpu.set(EVTSTRM, ARM64.HasEVTSTRM)
|
||||
cpu.set(AES, ARM64.HasAES)
|
||||
cpu.set(PMULL, ARM64.HasPMULL)
|
||||
cpu.set(SHA1, ARM64.HasSHA1)
|
||||
cpu.set(SHA2, ARM64.HasSHA2)
|
||||
cpu.set(CRC32, ARM64.HasCRC32)
|
||||
cpu.set(ATOMICS, ARM64.HasATOMICS)
|
||||
cpu.set(FPHP, ARM64.HasFPHP)
|
||||
cpu.set(ASIMDHP, ARM64.HasASIMDHP)
|
||||
cpu.set(CPUID, ARM64.HasCPUID)
|
||||
cpu.set(ASIMDRDM, ARM64.HasASIMDRDM)
|
||||
cpu.set(JSCVT, ARM64.HasJSCVT)
|
||||
cpu.set(FCMA, ARM64.HasFCMA)
|
||||
cpu.set(LRCPC, ARM64.HasLRCPC)
|
||||
cpu.set(DCPOP, ARM64.HasDCPOP)
|
||||
cpu.set(SHA3, ARM64.HasSHA3)
|
||||
cpu.set(SM3, ARM64.HasSM3)
|
||||
cpu.set(SM4, ARM64.HasSM4)
|
||||
cpu.set(ASIMDDP, ARM64.HasASIMDDP)
|
||||
cpu.set(SHA512, ARM64.HasSHA512)
|
||||
cpu.set(SVE, ARM64.HasSVE)
|
||||
cpu.set(ASIMDFHM, ARM64.HasASIMDFHM)
|
||||
return cpu
|
||||
}
|
||||
+22
@@ -0,0 +1,22 @@
|
||||
// Pakage cpu provides APIs to detect CPU features available at runtime.
|
||||
package cpu
|
||||
|
||||
import (
|
||||
"github.com/segmentio/asm/cpu/arm"
|
||||
"github.com/segmentio/asm/cpu/arm64"
|
||||
"github.com/segmentio/asm/cpu/x86"
|
||||
)
|
||||
|
||||
var (
|
||||
// X86 is the bitset representing the set of the x86 instruction sets are
|
||||
// supported by the CPU.
|
||||
X86 = x86.ABI()
|
||||
|
||||
// ARM is the bitset representing which parts of the arm instruction sets
|
||||
// are supported by the CPU.
|
||||
ARM = arm.ABI()
|
||||
|
||||
// ARM64 is the bitset representing which parts of the arm64 instruction
|
||||
// sets are supported by the CPU.
|
||||
ARM64 = arm64.ABI()
|
||||
)
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
// Package cpuid provides generic types used to represent CPU features supported
|
||||
// by the architecture.
|
||||
package cpuid
|
||||
|
||||
// CPU is a bitset of feature flags representing the capabilities of various CPU
|
||||
// architeectures that this package provides optimized assembly routines for.
|
||||
//
|
||||
// The intent is to provide a stable ABI between the Go code that generate the
|
||||
// assembly, and the program that uses the library functions.
|
||||
type CPU uint64
|
||||
|
||||
// Feature represents a single CPU feature.
|
||||
type Feature uint64
|
||||
|
||||
const (
|
||||
// None is a Feature value that has no CPU features enabled.
|
||||
None Feature = 0
|
||||
// All is a Feature value that has all CPU features enabled.
|
||||
All Feature = 0xFFFFFFFFFFFFFFFF
|
||||
)
|
||||
|
||||
func (cpu CPU) Has(feature Feature) bool {
|
||||
return (Feature(cpu) & feature) == feature
|
||||
}
|
||||
|
||||
func (cpu *CPU) Set(feature Feature, enabled bool) {
|
||||
if enabled {
|
||||
*cpu |= CPU(feature)
|
||||
} else {
|
||||
*cpu &= ^CPU(feature)
|
||||
}
|
||||
}
|
||||
+76
@@ -0,0 +1,76 @@
|
||||
package x86
|
||||
|
||||
import (
|
||||
"github.com/segmentio/asm/cpu/cpuid"
|
||||
. "golang.org/x/sys/cpu"
|
||||
)
|
||||
|
||||
type CPU cpuid.CPU
|
||||
|
||||
func (cpu CPU) Has(feature Feature) bool {
|
||||
return cpuid.CPU(cpu).Has(cpuid.Feature(feature))
|
||||
}
|
||||
|
||||
func (cpu *CPU) set(feature Feature, enable bool) {
|
||||
(*cpuid.CPU)(cpu).Set(cpuid.Feature(feature), enable)
|
||||
}
|
||||
|
||||
type Feature cpuid.Feature
|
||||
|
||||
const (
|
||||
SSE Feature = 1 << iota // SSE functions
|
||||
SSE2 // P4 SSE functions
|
||||
SSE3 // Prescott SSE3 functions
|
||||
SSE41 // Penryn SSE4.1 functions
|
||||
SSE42 // Nehalem SSE4.2 functions
|
||||
SSE4A // AMD Barcelona microarchitecture SSE4a instructions
|
||||
SSSE3 // Conroe SSSE3 functions
|
||||
AVX // AVX functions
|
||||
AVX2 // AVX2 functions
|
||||
AVX512BF16 // AVX-512 BFLOAT16 Instructions
|
||||
AVX512BITALG // AVX-512 Bit Algorithms
|
||||
AVX512BW // AVX-512 Byte and Word Instructions
|
||||
AVX512CD // AVX-512 Conflict Detection Instructions
|
||||
AVX512DQ // AVX-512 Doubleword and Quadword Instructions
|
||||
AVX512ER // AVX-512 Exponential and Reciprocal Instructions
|
||||
AVX512F // AVX-512 Foundation
|
||||
AVX512IFMA // AVX-512 Integer Fused Multiply-Add Instructions
|
||||
AVX512PF // AVX-512 Prefetch Instructions
|
||||
AVX512VBMI // AVX-512 Vector Bit Manipulation Instructions
|
||||
AVX512VBMI2 // AVX-512 Vector Bit Manipulation Instructions, Version 2
|
||||
AVX512VL // AVX-512 Vector Length Extensions
|
||||
AVX512VNNI // AVX-512 Vector Neural Network Instructions
|
||||
AVX512VP2INTERSECT // AVX-512 Intersect for D/Q
|
||||
AVX512VPOPCNTDQ // AVX-512 Vector Population Count Doubleword and Quadword
|
||||
CMOV // Conditional move
|
||||
)
|
||||
|
||||
func ABI() CPU {
|
||||
cpu := CPU(0)
|
||||
cpu.set(SSE, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have SEE?
|
||||
cpu.set(SSE2, X86.HasSSE2)
|
||||
cpu.set(SSE3, X86.HasSSE3)
|
||||
cpu.set(SSE41, X86.HasSSE41)
|
||||
cpu.set(SSE42, X86.HasSSE42)
|
||||
cpu.set(SSE4A, false) // TODO: add upstream support in golang.org/x/sys/cpu?
|
||||
cpu.set(SSSE3, X86.HasSSSE3)
|
||||
cpu.set(AVX, X86.HasAVX)
|
||||
cpu.set(AVX2, X86.HasAVX2)
|
||||
cpu.set(AVX512BF16, X86.HasAVX512BF16)
|
||||
cpu.set(AVX512BITALG, X86.HasAVX512BITALG)
|
||||
cpu.set(AVX512BW, X86.HasAVX512BW)
|
||||
cpu.set(AVX512CD, X86.HasAVX512CD)
|
||||
cpu.set(AVX512DQ, X86.HasAVX512DQ)
|
||||
cpu.set(AVX512ER, X86.HasAVX512ER)
|
||||
cpu.set(AVX512F, X86.HasAVX512F)
|
||||
cpu.set(AVX512IFMA, X86.HasAVX512IFMA)
|
||||
cpu.set(AVX512PF, X86.HasAVX512PF)
|
||||
cpu.set(AVX512VBMI, X86.HasAVX512VBMI)
|
||||
cpu.set(AVX512VBMI2, X86.HasAVX512VBMI2)
|
||||
cpu.set(AVX512VL, X86.HasAVX512VL)
|
||||
cpu.set(AVX512VNNI, X86.HasAVX512VNNI)
|
||||
cpu.set(AVX512VP2INTERSECT, false) // TODO: add upstream support in golang.org/x/sys/cpu?
|
||||
cpu.set(AVX512VPOPCNTDQ, X86.HasAVX512VPOPCNTDQ)
|
||||
cpu.set(CMOV, true) // TODO: golang.org/x/sys/cpu assumes all CPUs have CMOV?
|
||||
return cpu
|
||||
}
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
package unsafebytes
|
||||
|
||||
import "unsafe"
|
||||
|
||||
func Pointer(b []byte) *byte {
|
||||
return *(**byte)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
func String(b []byte) string {
|
||||
return *(*string)(unsafe.Pointer(&b))
|
||||
}
|
||||
|
||||
func BytesOf(s string) []byte {
|
||||
return *(*[]byte)(unsafe.Pointer(&sliceHeader{str: s, cap: len(s)}))
|
||||
}
|
||||
|
||||
type sliceHeader struct {
|
||||
str string
|
||||
cap int
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
package keyset
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/segmentio/asm/cpu"
|
||||
"github.com/segmentio/asm/cpu/arm64"
|
||||
"github.com/segmentio/asm/cpu/x86"
|
||||
)
|
||||
|
||||
// New prepares a set of keys for use with Lookup.
|
||||
//
|
||||
// An optimized routine is used if the processor supports AVX instructions and
|
||||
// the maximum length of any of the keys is less than or equal to 16. If New
|
||||
// returns nil, this indicates that an optimized routine is not available, and
|
||||
// the caller should use a fallback.
|
||||
func New(keys [][]byte) []byte {
|
||||
maxWidth, hasNullByte := checkKeys(keys)
|
||||
if hasNullByte || maxWidth > 16 || !(cpu.X86.Has(x86.AVX) || cpu.ARM64.Has(arm64.ASIMD)) {
|
||||
return nil
|
||||
}
|
||||
|
||||
set := make([]byte, len(keys)*16)
|
||||
for i, k := range keys {
|
||||
copy(set[i*16:], k)
|
||||
}
|
||||
return set
|
||||
}
|
||||
|
||||
func checkKeys(keys [][]byte) (maxWidth int, hasNullByte bool) {
|
||||
for _, k := range keys {
|
||||
if len(k) > maxWidth {
|
||||
maxWidth = len(k)
|
||||
}
|
||||
if bytes.IndexByte(k, 0) >= 0 {
|
||||
hasNullByte = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
// Code generated by command: go run keyset_asm.go -pkg keyset -out ../keyset/keyset_amd64.s -stubs ../keyset/keyset_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
package keyset
|
||||
|
||||
// Lookup searches for a key in a set of keys, returning its index if
|
||||
// found. If the key cannot be found, the number of keys is returned.
|
||||
func Lookup(keyset []byte, key []byte) int
|
||||
+108
@@ -0,0 +1,108 @@
|
||||
// Code generated by command: go run keyset_asm.go -pkg keyset -out ../keyset/keyset_amd64.s -stubs ../keyset/keyset_amd64.go. DO NOT EDIT.
|
||||
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func Lookup(keyset []byte, key []byte) int
|
||||
// Requires: AVX
|
||||
TEXT ·Lookup(SB), NOSPLIT, $0-56
|
||||
MOVQ keyset_base+0(FP), AX
|
||||
MOVQ keyset_len+8(FP), CX
|
||||
SHRQ $0x04, CX
|
||||
MOVQ key_base+24(FP), DX
|
||||
MOVQ key_len+32(FP), BX
|
||||
MOVQ key_cap+40(FP), SI
|
||||
CMPQ BX, $0x10
|
||||
JA not_found
|
||||
CMPQ SI, $0x10
|
||||
JB safe_load
|
||||
|
||||
load:
|
||||
VMOVUPS (DX), X0
|
||||
|
||||
prepare:
|
||||
VPXOR X2, X2, X2
|
||||
VPCMPEQB X1, X1, X1
|
||||
LEAQ blend_masks<>+16(SB), DX
|
||||
SUBQ BX, DX
|
||||
VMOVUPS (DX), X3
|
||||
VPBLENDVB X3, X0, X2, X0
|
||||
XORQ DX, DX
|
||||
MOVQ CX, BX
|
||||
SHRQ $0x02, BX
|
||||
SHLQ $0x02, BX
|
||||
|
||||
bigloop:
|
||||
CMPQ DX, BX
|
||||
JE loop
|
||||
VPCMPEQB (AX), X0, X8
|
||||
VPTEST X1, X8
|
||||
JCS done
|
||||
VPCMPEQB 16(AX), X0, X9
|
||||
VPTEST X1, X9
|
||||
JCS found1
|
||||
VPCMPEQB 32(AX), X0, X10
|
||||
VPTEST X1, X10
|
||||
JCS found2
|
||||
VPCMPEQB 48(AX), X0, X11
|
||||
VPTEST X1, X11
|
||||
JCS found3
|
||||
ADDQ $0x04, DX
|
||||
ADDQ $0x40, AX
|
||||
JMP bigloop
|
||||
|
||||
loop:
|
||||
CMPQ DX, CX
|
||||
JE done
|
||||
VPCMPEQB (AX), X0, X2
|
||||
VPTEST X1, X2
|
||||
JCS done
|
||||
INCQ DX
|
||||
ADDQ $0x10, AX
|
||||
JMP loop
|
||||
JMP done
|
||||
|
||||
found3:
|
||||
INCQ DX
|
||||
|
||||
found2:
|
||||
INCQ DX
|
||||
|
||||
found1:
|
||||
INCQ DX
|
||||
|
||||
done:
|
||||
MOVQ DX, ret+48(FP)
|
||||
RET
|
||||
|
||||
not_found:
|
||||
MOVQ CX, ret+48(FP)
|
||||
RET
|
||||
|
||||
safe_load:
|
||||
MOVQ DX, SI
|
||||
ANDQ $0x00000fff, SI
|
||||
CMPQ SI, $0x00000ff0
|
||||
JBE load
|
||||
MOVQ $0xfffffffffffffff0, SI
|
||||
ADDQ BX, SI
|
||||
VMOVUPS (DX)(SI*1), X0
|
||||
LEAQ shuffle_masks<>+16(SB), DX
|
||||
SUBQ BX, DX
|
||||
VMOVUPS (DX), X1
|
||||
VPSHUFB X1, X0, X0
|
||||
JMP prepare
|
||||
|
||||
DATA blend_masks<>+0(SB)/8, $0xffffffffffffffff
|
||||
DATA blend_masks<>+8(SB)/8, $0xffffffffffffffff
|
||||
DATA blend_masks<>+16(SB)/8, $0x0000000000000000
|
||||
DATA blend_masks<>+24(SB)/8, $0x0000000000000000
|
||||
GLOBL blend_masks<>(SB), RODATA|NOPTR, $32
|
||||
|
||||
DATA shuffle_masks<>+0(SB)/8, $0x0706050403020100
|
||||
DATA shuffle_masks<>+8(SB)/8, $0x0f0e0d0c0b0a0908
|
||||
DATA shuffle_masks<>+16(SB)/8, $0x0706050403020100
|
||||
DATA shuffle_masks<>+24(SB)/8, $0x0f0e0d0c0b0a0908
|
||||
GLOBL shuffle_masks<>(SB), RODATA|NOPTR, $32
|
||||
+8
@@ -0,0 +1,8 @@
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
package keyset
|
||||
|
||||
// Lookup searches for a key in a set of keys, returning its index if
|
||||
// found. If the key cannot be found, the number of keys is returned.
|
||||
func Lookup(keyset []byte, key []byte) int
|
||||
+143
@@ -0,0 +1,143 @@
|
||||
//go:build !purego
|
||||
// +build !purego
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
// func Lookup(keyset []byte, key []byte) int
|
||||
TEXT ·Lookup(SB), NOSPLIT, $0-56
|
||||
MOVD keyset+0(FP), R0
|
||||
MOVD keyset_len+8(FP), R1
|
||||
MOVD key+24(FP), R2
|
||||
MOVD key_len+32(FP), R3
|
||||
MOVD key_cap+40(FP), R4
|
||||
|
||||
// None of the keys in the set are greater than 16 bytes, so if the input
|
||||
// key is we can jump straight to not found.
|
||||
CMP $16, R3
|
||||
BHI notfound
|
||||
|
||||
// We'll be moving the keyset pointer (R0) forward as we compare keys, so
|
||||
// make a copy of the starting point (R6). Also add the byte length (R1) to
|
||||
// obtain a pointer to the end of the keyset (R5).
|
||||
MOVD R0, R6
|
||||
ADD R0, R1, R5
|
||||
|
||||
// Prepare a 64-bit mask of all ones.
|
||||
MOVD $-1, R7
|
||||
|
||||
// Prepare a vector of all zeroes.
|
||||
VMOV ZR, V1.B16
|
||||
|
||||
// Check that it's safe to load 16 bytes of input. If cap(input)<16, jump
|
||||
// to a check that determines whether a tail load is necessary (to avoid a
|
||||
// page fault).
|
||||
CMP $16, R4
|
||||
BLO safeload
|
||||
|
||||
load:
|
||||
// Load the input key (V0) and pad with zero bytes (V1). To blend the two
|
||||
// vectors, we load a mask for the particular key length and then use TBL
|
||||
// to select bytes from either V0 or V1.
|
||||
VLD1 (R2), [V0.B16]
|
||||
MOVD $blend_masks<>(SB), R10
|
||||
ADD R3<<4, R10, R10
|
||||
VLD1 (R10), [V2.B16]
|
||||
VTBL V2.B16, [V0.B16, V1.B16], V3.B16
|
||||
|
||||
loop:
|
||||
// Loop through each 16 byte key in the keyset.
|
||||
CMP R0, R5
|
||||
BEQ notfound
|
||||
|
||||
// Load and compare the next key.
|
||||
VLD1.P 16(R0), [V4.B16]
|
||||
VCMEQ V3.B16, V4.B16, V5.B16
|
||||
VMOV V5.D[0], R8
|
||||
VMOV V5.D[1], R9
|
||||
AND R8, R9, R9
|
||||
|
||||
// If the masks match, we found the key.
|
||||
CMP R9, R7
|
||||
BEQ found
|
||||
JMP loop
|
||||
|
||||
found:
|
||||
// If the key was found, take the position in the keyset and convert it
|
||||
// to an index. The keyset pointer (R0) will be 1 key past the match, so
|
||||
// subtract the starting pointer (R6), divide by 16 to convert from byte
|
||||
// length to an index, and then subtract one.
|
||||
SUB R6, R0, R0
|
||||
ADD R0>>4, ZR, R0
|
||||
SUB $1, R0, R0
|
||||
MOVD R0, ret+48(FP)
|
||||
RET
|
||||
|
||||
notfound:
|
||||
// Return the number of keys in the keyset, which is the byte length (R1)
|
||||
// divided by 16.
|
||||
ADD R1>>4, ZR, R1
|
||||
MOVD R1, ret+48(FP)
|
||||
RET
|
||||
|
||||
safeload:
|
||||
// Check if the input crosses a page boundary. If not, jump back.
|
||||
AND $4095, R2, R12
|
||||
CMP $4080, R12
|
||||
BLS load
|
||||
|
||||
// If it does cross a page boundary, we must assume that loading 16 bytes
|
||||
// will cause a fault. Instead, we load the 16 bytes up to and including the
|
||||
// key and then shuffle the key forward in the register. We can shuffle and
|
||||
// pad with zeroes at the same time to avoid having to also blend (as load
|
||||
// does).
|
||||
MOVD $16, R12
|
||||
SUB R3, R12, R12
|
||||
SUB R12, R2, R2
|
||||
VLD1 (R2), [V0.B16]
|
||||
MOVD $shuffle_masks<>(SB), R10
|
||||
ADD R12, R10, R10
|
||||
VLD1 (R10), [V2.B16]
|
||||
VTBL V2.B16, [V0.B16, V1.B16], V3.B16
|
||||
JMP loop
|
||||
|
||||
DATA blend_masks<>+0(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+8(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+16(SB)/8, $0x1010101010101000
|
||||
DATA blend_masks<>+24(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+32(SB)/8, $0x1010101010100100
|
||||
DATA blend_masks<>+40(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+48(SB)/8, $0x1010101010020100
|
||||
DATA blend_masks<>+56(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+64(SB)/8, $0x1010101003020100
|
||||
DATA blend_masks<>+72(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+80(SB)/8, $0x1010100403020100
|
||||
DATA blend_masks<>+88(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+96(SB)/8, $0x1010050403020100
|
||||
DATA blend_masks<>+104(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+112(SB)/8, $0x1006050403020100
|
||||
DATA blend_masks<>+120(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+128(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+136(SB)/8, $0x1010101010101010
|
||||
DATA blend_masks<>+144(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+152(SB)/8, $0x1010101010101008
|
||||
DATA blend_masks<>+160(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+168(SB)/8, $0x1010101010100908
|
||||
DATA blend_masks<>+176(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+184(SB)/8, $0x10101010100A0908
|
||||
DATA blend_masks<>+192(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+200(SB)/8, $0x101010100B0A0908
|
||||
DATA blend_masks<>+208(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+216(SB)/8, $0x1010100C0B0A0908
|
||||
DATA blend_masks<>+224(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+232(SB)/8, $0x10100D0C0B0A0908
|
||||
DATA blend_masks<>+240(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+248(SB)/8, $0x100E0D0C0B0A0908
|
||||
DATA blend_masks<>+256(SB)/8, $0x0706050403020100
|
||||
DATA blend_masks<>+264(SB)/8, $0x0F0E0D0C0B0A0908
|
||||
GLOBL blend_masks<>(SB), RODATA|NOPTR, $272
|
||||
|
||||
DATA shuffle_masks<>+0(SB)/8, $0x0706050403020100
|
||||
DATA shuffle_masks<>+8(SB)/8, $0x0F0E0D0C0B0A0908
|
||||
DATA shuffle_masks<>+16(SB)/8, $0x1010101010101010
|
||||
DATA shuffle_masks<>+24(SB)/8, $0x1010101010101010
|
||||
GLOBL shuffle_masks<>(SB), RODATA|NOPTR, $32
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
//go:build purego || !(amd64 || arm64)
|
||||
// +build purego !amd64,!arm64
|
||||
|
||||
package keyset
|
||||
|
||||
func Lookup(keyset []byte, key []byte) int {
|
||||
if len(key) > 16 {
|
||||
return len(keyset) / 16
|
||||
}
|
||||
var padded [16]byte
|
||||
copy(padded[:], key)
|
||||
|
||||
for i := 0; i < len(keyset); i += 16 {
|
||||
if string(padded[:]) == string(keyset[i:i+16]) {
|
||||
return i / 16
|
||||
}
|
||||
}
|
||||
return len(keyset) / 16
|
||||
}
|
||||
Reference in New Issue
Block a user