diff --git a/common/hexutil/asmhex/LICENSE b/common/hexutil/asmhex/LICENSE new file mode 100644 index 0000000000..1163cdf254 --- /dev/null +++ b/common/hexutil/asmhex/LICENSE @@ -0,0 +1,82 @@ +Copyright (c) 2016, Tom Thorogood. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of the Tom Thorogood nor the + names of its contributors may be used to endorse or promote products + derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---- Portions of the source code are also covered by the following license: ---- + +Copyright (c) 2012 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +---- Portions of the source code are also covered by the following license: ---- + +Copyright (c) 2005-2016, Wojciech Muła +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED +TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/common/hexutil/asmhex/asmhex.go b/common/hexutil/asmhex/asmhex.go new file mode 100644 index 0000000000..13b1c56435 --- /dev/null +++ b/common/hexutil/asmhex/asmhex.go @@ -0,0 +1,13 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. +// +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package asmhex is an efficient hexadecimal implementation for Golang. +package asmhex + +var alphabet = []byte("0123456789abcdef") diff --git a/common/hexutil/asmhex/asmhex_amd64.go b/common/hexutil/asmhex/asmhex_amd64.go new file mode 100644 index 0000000000..87b20c2c97 --- /dev/null +++ b/common/hexutil/asmhex/asmhex_amd64.go @@ -0,0 +1,80 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. + +//go:build amd64 && !gccgo && !appengine + +package asmhex + +import ( + "encoding/hex" + + "golang.org/x/sys/cpu" +) + +func Encode(dst, src []byte) int { + if len(dst) < len(src)*2 { + panic("dst buffer is too small") + } + if len(src) == 0 { + return 0 + } + switch { + case cpu.X86.HasAVX: + encodeAVX(&dst[0], &src[0], uint64(len(src)), &alphabet[0]) + case cpu.X86.HasSSE41: + encodeSSE(&dst[0], &src[0], uint64(len(src)), &alphabet[0]) + default: + return hex.Encode(dst, src) + } + return len(src) * 2 +} + +func Decode(dst, src []byte) (int, error) { + if len(src)%2 != 0 { + return 0, hex.ErrLength + } + if len(dst) < len(src)/2 { + panic("dst buffer is too small") + } + if len(src) == 0 { + return 0, nil + } + var ( + n uint64 + ok bool + ) + switch { + case cpu.X86.HasAVX: + n, ok = decodeAVX(&dst[0], &src[0], uint64(len(src))) + case cpu.X86.HasSSE41: + n, ok = decodeSSE(&dst[0], &src[0], uint64(len(src))) + default: + return hex.Decode(dst, src) + } + if !ok { + return 0, hex.InvalidByteError(src[n]) + } + return len(src) / 2, nil +} + +// This function is implemented in asmhex_encode_amd64.s +// +//go:noescape +func encodeAVX(dst *byte, src *byte, len uint64, alpha *byte) + +// This function is implemented in asmhex_encode_amd64.s +// +//go:noescape +func encodeSSE(dst *byte, src *byte, len uint64, alpha *byte) + +// This function is implemented in asmhex_decode_amd64.s +// +//go:noescape +func decodeAVX(dst *byte, src *byte, len uint64) (n uint64, ok bool) + +// This function is implemented in asmhex_decode_amd64.s +// +//go:noescape +func decodeSSE(dst *byte, src *byte, len uint64) (n uint64, ok bool) diff --git a/common/hexutil/asmhex/asmhex_decode_amd64.s b/common/hexutil/asmhex/asmhex_decode_amd64.s new file mode 100644 index 0000000000..25d9cefb15 --- /dev/null +++ b/common/hexutil/asmhex/asmhex_decode_amd64.s @@ -0,0 +1,303 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. +// +// Copyright 2005-2016, Wojciech Muła. All rights reserved. +// Use of this source code is governed by a +// Simplified BSD License license that can be found in +// the LICENSE file. +// +// This file is auto-generated - do not modify + +// +build amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA decodeBase<>+0x00(SB)/8, $0x3030303030303030 +DATA decodeBase<>+0x08(SB)/8, $0x3030303030303030 +DATA decodeBase<>+0x10(SB)/8, $0x2727272727272727 +DATA decodeBase<>+0x18(SB)/8, $0x2727272727272727 +GLOBL decodeBase<>(SB),RODATA,$32 + +DATA decodeToLower<>+0x00(SB)/8, $0x2020202020202020 +DATA decodeToLower<>+0x08(SB)/8, $0x2020202020202020 +GLOBL decodeToLower<>(SB),RODATA,$16 + +DATA decodeHigh<>+0x00(SB)/8, $0x0e0c0a0806040200 +DATA decodeHigh<>+0x08(SB)/8, $0xffffffffffffffff +GLOBL decodeHigh<>(SB),RODATA,$16 + +DATA decodeLow<>+0x00(SB)/8, $0x0f0d0b0907050301 +DATA decodeLow<>+0x08(SB)/8, $0xffffffffffffffff +GLOBL decodeLow<>(SB),RODATA,$16 + +DATA decodeValid<>+0x00(SB)/8, $0xb0b0b0b0b0b0b0b0 +DATA decodeValid<>+0x08(SB)/8, $0xb0b0b0b0b0b0b0b0 +DATA decodeValid<>+0x10(SB)/8, $0xb9b9b9b9b9b9b9b9 +DATA decodeValid<>+0x18(SB)/8, $0xb9b9b9b9b9b9b9b9 +DATA decodeValid<>+0x20(SB)/8, $0xe1e1e1e1e1e1e1e1 +DATA decodeValid<>+0x28(SB)/8, $0xe1e1e1e1e1e1e1e1 +DATA decodeValid<>+0x30(SB)/8, $0xe6e6e6e6e6e6e6e6 +DATA decodeValid<>+0x38(SB)/8, $0xe6e6e6e6e6e6e6e6 +GLOBL decodeValid<>(SB),RODATA,$64 + +DATA decodeToSigned<>+0x00(SB)/8, $0x8080808080808080 +DATA decodeToSigned<>+0x08(SB)/8, $0x8080808080808080 +GLOBL decodeToSigned<>(SB),RODATA,$16 + +TEXT ·decodeAVX(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ SI, R15 + MOVOU decodeValid<>(SB), X14 + MOVOU decodeValid<>+0x20(SB), X15 + MOVW $65535, DX + CMPQ BX, $16 + JB tail +bigloop: + MOVOU (SI), X0 + VPXOR decodeToSigned<>(SB), X0, X1 + POR decodeToLower<>(SB), X0 + VPXOR decodeToSigned<>(SB), X0, X2 + VPCMPGTB X1, X14, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + VPCMPGTB X2, X15, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + VPSHUFB decodeLow<>(SB), X0, X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + MOVQ X0, (DI) + SUBQ $16, BX + JZ ret + ADDQ $16, SI + ADDQ $8, DI + CMPQ BX, $16 + JAE bigloop +tail: + MOVQ $16, CX + SUBQ BX, CX + SHRW CX, DX + CMPQ BX, $4 + JB tail_in_2 + JE tail_in_4 + CMPQ BX, $8 + JB tail_in_6 + JE tail_in_8 + CMPQ BX, $12 + JB tail_in_10 + JE tail_in_12 +tail_in_14: + PINSRW $6, 12(SI), X0 +tail_in_12: + PINSRW $5, 10(SI), X0 +tail_in_10: + PINSRW $4, 8(SI), X0 +tail_in_8: + PINSRQ $0, (SI), X0 + JMP tail_conv +tail_in_6: + PINSRW $2, 4(SI), X0 +tail_in_4: + PINSRW $1, 2(SI), X0 +tail_in_2: + PINSRW $0, (SI), X0 +tail_conv: + VPXOR decodeToSigned<>(SB), X0, X1 + POR decodeToLower<>(SB), X0 + VPXOR decodeToSigned<>(SB), X0, X2 + VPCMPGTB X1, X14, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + VPCMPGTB X2, X15, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + VPSHUFB decodeLow<>(SB), X0, X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + CMPQ BX, $4 + JB tail_out_2 + JE tail_out_4 + CMPQ BX, $8 + JB tail_out_6 + JE tail_out_8 + CMPQ BX, $12 + JB tail_out_10 + JE tail_out_12 +tail_out_14: + PEXTRB $6, X0, 6(DI) +tail_out_12: + PEXTRB $5, X0, 5(DI) +tail_out_10: + PEXTRB $4, X0, 4(DI) +tail_out_8: + MOVL X0, (DI) + JMP ret +tail_out_6: + PEXTRB $2, X0, 2(DI) +tail_out_4: + PEXTRB $1, X0, 1(DI) +tail_out_2: + PEXTRB $0, X0, (DI) +ret: + MOVB $1, ok+32(FP) + RET +invalid: + BSFW AX, AX + SUBQ R15, SI + ADDQ SI, AX + MOVQ AX, n+24(FP) + MOVB $0, ok+32(FP) + RET + +TEXT ·decodeSSE(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ SI, R15 + MOVOU decodeValid<>(SB), X14 + MOVOU decodeValid<>+0x20(SB), X15 + MOVW $65535, DX + CMPQ BX, $16 + JB tail +bigloop: + MOVOU (SI), X0 + MOVOU X0, X1 + PXOR decodeToSigned<>(SB), X1 + POR decodeToLower<>(SB), X0 + MOVOU X0, X2 + PXOR decodeToSigned<>(SB), X2 + MOVOU X14, X3 + PCMPGTB X1, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + MOVOU X15, X4 + PCMPGTB X2, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + MOVOU X0, X3 + PSHUFB decodeLow<>(SB), X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + MOVQ X0, (DI) + SUBQ $16, BX + JZ ret + ADDQ $16, SI + ADDQ $8, DI + CMPQ BX, $16 + JAE bigloop +tail: + MOVQ $16, CX + SUBQ BX, CX + SHRW CX, DX + CMPQ BX, $4 + JB tail_in_2 + JE tail_in_4 + CMPQ BX, $8 + JB tail_in_6 + JE tail_in_8 + CMPQ BX, $12 + JB tail_in_10 + JE tail_in_12 +tail_in_14: + PINSRW $6, 12(SI), X0 +tail_in_12: + PINSRW $5, 10(SI), X0 +tail_in_10: + PINSRW $4, 8(SI), X0 +tail_in_8: + PINSRQ $0, (SI), X0 + JMP tail_conv +tail_in_6: + PINSRW $2, 4(SI), X0 +tail_in_4: + PINSRW $1, 2(SI), X0 +tail_in_2: + PINSRW $0, (SI), X0 +tail_conv: + MOVOU X0, X1 + PXOR decodeToSigned<>(SB), X1 + POR decodeToLower<>(SB), X0 + MOVOU X0, X2 + PXOR decodeToSigned<>(SB), X2 + MOVOU X14, X3 + PCMPGTB X1, X3 + PCMPGTB decodeValid<>+0x10(SB), X1 + MOVOU X15, X4 + PCMPGTB X2, X4 + PCMPGTB decodeValid<>+0x30(SB), X2 + PAND X4, X1 + POR X2, X3 + POR X1, X3 + PMOVMSKB X3, AX + TESTW AX, DX + JNZ invalid + PSUBB decodeBase<>(SB), X0 + PANDN decodeBase<>+0x10(SB), X4 + PSUBB X4, X0 + MOVOU X0, X3 + PSHUFB decodeLow<>(SB), X3 + PSHUFB decodeHigh<>(SB), X0 + PSLLW $4, X0 + POR X3, X0 + CMPQ BX, $4 + JB tail_out_2 + JE tail_out_4 + CMPQ BX, $8 + JB tail_out_6 + JE tail_out_8 + CMPQ BX, $12 + JB tail_out_10 + JE tail_out_12 +tail_out_14: + PEXTRB $6, X0, 6(DI) +tail_out_12: + PEXTRB $5, X0, 5(DI) +tail_out_10: + PEXTRB $4, X0, 4(DI) +tail_out_8: + MOVL X0, (DI) + JMP ret +tail_out_6: + PEXTRB $2, X0, 2(DI) +tail_out_4: + PEXTRB $1, X0, 1(DI) +tail_out_2: + PEXTRB $0, X0, (DI) +ret: + MOVB $1, ok+32(FP) + RET +invalid: + BSFW AX, AX + SUBQ R15, SI + ADDQ SI, AX + MOVQ AX, n+24(FP) + MOVB $0, ok+32(FP) + RET diff --git a/common/hexutil/asmhex/asmhex_encode_amd64.s b/common/hexutil/asmhex/asmhex_encode_amd64.s new file mode 100644 index 0000000000..96e6e4caac --- /dev/null +++ b/common/hexutil/asmhex/asmhex_encode_amd64.s @@ -0,0 +1,227 @@ +// Copyright 2016 Tom Thorogood. All rights reserved. +// Use of this source code is governed by a +// Modified BSD License license that can be found in +// the LICENSE file. +// +// Copyright 2005-2016, Wojciech Muła. All rights reserved. +// Use of this source code is governed by a +// Simplified BSD License license that can be found in +// the LICENSE file. +// +// This file is auto-generated - do not modify + +// +build amd64,!gccgo,!appengine + +#include "textflag.h" + +DATA encodeMask<>+0x00(SB)/8, $0x0f0f0f0f0f0f0f0f +DATA encodeMask<>+0x08(SB)/8, $0x0f0f0f0f0f0f0f0f +GLOBL encodeMask<>(SB),RODATA,$16 + +TEXT ·encodeAVX(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ alpha+24(FP), DX + MOVOU (DX), X15 + CMPQ BX, $16 + JB tail +bigloop: + MOVOU -16(SI)(BX*1), X0 + VPAND encodeMask<>(SB), X0, X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + VPUNPCKHBW X1, X0, X3 + PUNPCKLBW X1, X0 + VPSHUFB X0, X15, X1 + VPSHUFB X3, X15, X2 + MOVOU X2, -16(DI)(BX*2) + MOVOU X1, -32(DI)(BX*2) + SUBQ $16, BX + JZ ret + CMPQ BX, $16 + JAE bigloop +tail: + CMPQ BX, $2 + JB tail_in_1 + JE tail_in_2 + CMPQ BX, $4 + JB tail_in_3 + JE tail_in_4 + CMPQ BX, $6 + JB tail_in_5 + JE tail_in_6 + CMPQ BX, $8 + JB tail_in_7 +tail_in_8: + MOVQ (SI), X0 + JMP tail_conv +tail_in_7: + PINSRB $6, 6(SI), X0 +tail_in_6: + PINSRB $5, 5(SI), X0 +tail_in_5: + PINSRB $4, 4(SI), X0 +tail_in_4: + PINSRD $0, (SI), X0 + JMP tail_conv +tail_in_3: + PINSRB $2, 2(SI), X0 +tail_in_2: + PINSRB $1, 1(SI), X0 +tail_in_1: + PINSRB $0, (SI), X0 +tail_conv: + VPAND encodeMask<>(SB), X0, X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + PUNPCKLBW X1, X0 + VPSHUFB X0, X15, X1 + CMPQ BX, $2 + JB tail_out_1 + JE tail_out_2 + CMPQ BX, $4 + JB tail_out_3 + JE tail_out_4 + CMPQ BX, $6 + JB tail_out_5 + JE tail_out_6 + CMPQ BX, $8 + JB tail_out_7 +tail_out_8: + MOVOU X1, (DI) + SUBQ $8, BX + JZ ret + ADDQ $8, SI + ADDQ $16, DI + JMP tail +tail_out_7: + PEXTRB $13, X1, 13(DI) + PEXTRB $12, X1, 12(DI) +tail_out_6: + PEXTRB $11, X1, 11(DI) + PEXTRB $10, X1, 10(DI) +tail_out_5: + PEXTRB $9, X1, 9(DI) + PEXTRB $8, X1, 8(DI) +tail_out_4: + MOVQ X1, (DI) + RET +tail_out_3: + PEXTRB $5, X1, 5(DI) + PEXTRB $4, X1, 4(DI) +tail_out_2: + PEXTRB $3, X1, 3(DI) + PEXTRB $2, X1, 2(DI) +tail_out_1: + PEXTRB $1, X1, 1(DI) + PEXTRB $0, X1, (DI) +ret: + RET + +TEXT ·encodeSSE(SB),NOSPLIT,$0 + MOVQ dst+0(FP), DI + MOVQ src+8(FP), SI + MOVQ len+16(FP), BX + MOVQ alpha+24(FP), DX + MOVOU (DX), X15 + CMPQ BX, $16 + JB tail +bigloop: + MOVOU -16(SI)(BX*1), X0 + MOVOU X0, X1 + PAND encodeMask<>(SB), X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + MOVOU X0, X3 + PUNPCKHBW X1, X3 + PUNPCKLBW X1, X0 + MOVOU X15, X1 + PSHUFB X0, X1 + MOVOU X15, X2 + PSHUFB X3, X2 + MOVOU X2, -16(DI)(BX*2) + MOVOU X1, -32(DI)(BX*2) + SUBQ $16, BX + JZ ret + CMPQ BX, $16 + JAE bigloop +tail: + CMPQ BX, $2 + JB tail_in_1 + JE tail_in_2 + CMPQ BX, $4 + JB tail_in_3 + JE tail_in_4 + CMPQ BX, $6 + JB tail_in_5 + JE tail_in_6 + CMPQ BX, $8 + JB tail_in_7 +tail_in_8: + MOVQ (SI), X0 + JMP tail_conv +tail_in_7: + PINSRB $6, 6(SI), X0 +tail_in_6: + PINSRB $5, 5(SI), X0 +tail_in_5: + PINSRB $4, 4(SI), X0 +tail_in_4: + PINSRD $0, (SI), X0 + JMP tail_conv +tail_in_3: + PINSRB $2, 2(SI), X0 +tail_in_2: + PINSRB $1, 1(SI), X0 +tail_in_1: + PINSRB $0, (SI), X0 +tail_conv: + MOVOU X0, X1 + PAND encodeMask<>(SB), X1 + PSRLW $4, X0 + PAND encodeMask<>(SB), X0 + PUNPCKLBW X1, X0 + MOVOU X15, X1 + PSHUFB X0, X1 + CMPQ BX, $2 + JB tail_out_1 + JE tail_out_2 + CMPQ BX, $4 + JB tail_out_3 + JE tail_out_4 + CMPQ BX, $6 + JB tail_out_5 + JE tail_out_6 + CMPQ BX, $8 + JB tail_out_7 +tail_out_8: + MOVOU X1, (DI) + SUBQ $8, BX + JZ ret + ADDQ $8, SI + ADDQ $16, DI + JMP tail +tail_out_7: + PEXTRB $13, X1, 13(DI) + PEXTRB $12, X1, 12(DI) +tail_out_6: + PEXTRB $11, X1, 11(DI) + PEXTRB $10, X1, 10(DI) +tail_out_5: + PEXTRB $9, X1, 9(DI) + PEXTRB $8, X1, 8(DI) +tail_out_4: + MOVQ X1, (DI) + RET +tail_out_3: + PEXTRB $5, X1, 5(DI) + PEXTRB $4, X1, 4(DI) +tail_out_2: + PEXTRB $3, X1, 3(DI) + PEXTRB $2, X1, 2(DI) +tail_out_1: + PEXTRB $1, X1, 1(DI) + PEXTRB $0, X1, (DI) +ret: + RET diff --git a/common/hexutil/asmhex/asmhex_other.go b/common/hexutil/asmhex/asmhex_other.go new file mode 100644 index 0000000000..3b10e50aa8 --- /dev/null +++ b/common/hexutil/asmhex/asmhex_other.go @@ -0,0 +1,17 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +//go:build !amd64 || gccgo || appengine + +package asmhex + +import "encoding/hex" + +func Encode(dst, src []byte) int { + return hex.Encode(dst, src) +} + +func Decode(dst, src []byte) (int, error) { + return hex.Decode(dst, src) +} diff --git a/common/hexutil/asmhex/asmhex_test.go b/common/hexutil/asmhex/asmhex_test.go new file mode 100644 index 0000000000..e3ca69f546 --- /dev/null +++ b/common/hexutil/asmhex/asmhex_test.go @@ -0,0 +1,54 @@ +// Copyright 2024 The go-ethereum Authors +// This file is part of the go-ethereum library. +// +// The go-ethereum library is free software: you can redistribute it and/or modify +// it under the terms of the GNU Lesser General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// The go-ethereum library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Lesser General Public License for more details. +// +// You should have received a copy of the GNU Lesser General Public License +// along with the go-ethereum library. If not, see . + +package asmhex + +import ( + "bytes" + "encoding/hex" + "fmt" + "testing" +) + +func BenchmarkAsmHexDecode(b *testing.B) { + for _, size := range []int{64, 256, 1024, 4096, 16384, 65536} { + src := bytes.Repeat([]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'B', 'c', 'D', 'e', 'f'}, size/8) + sink := make([]byte, size) + + b.Run(fmt.Sprintf("%v", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + if _, err := Decode(sink, src); err != nil { + b.Fatal(err) + } + } + }) + } +} + +func BenchmarkStdlibDecode(b *testing.B) { + for _, size := range []int{64, 256, 1024, 4096, 16384, 65536} { + src := bytes.Repeat([]byte{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'B', 'c', 'D', 'e', 'f'}, size/8) + sink := make([]byte, size) + + b.Run(fmt.Sprintf("%v", size), func(b *testing.B) { + for i := 0; i < b.N; i++ { + if _, err := hex.Decode(sink, src); err != nil { + b.Fatal(err) + } + } + }) + } +} diff --git a/common/hexutil/hexutil.go b/common/hexutil/hexutil.go index d3201850a8..3ddb008b57 100644 --- a/common/hexutil/hexutil.go +++ b/common/hexutil/hexutil.go @@ -35,6 +35,8 @@ import ( "fmt" "math/big" "strconv" + + "github.com/ethereum/go-ethereum/common/hexutil/asmhex" ) const uintBits = 32 << (uint64(^uint(0)) >> 63) @@ -58,17 +60,22 @@ func (err decError) Error() string { return err.msg } // Decode decodes a hex string with 0x prefix. func Decode(input string) ([]byte, error) { + // Sanity check the input if len(input) == 0 { return nil, ErrEmptyString } if !has0xPrefix(input) { return nil, ErrMissingPrefix } - b, err := hex.DecodeString(input[2:]) + // Preallocate the output and decode the string + src := ([]byte)(input)[2:] + dst := make([]byte, len(src)>>1) + + _, err := asmhex.Decode(dst, src) if err != nil { err = mapError(err) } - return b, err + return dst, err } // MustDecode decodes a hex string with 0x prefix. It panics for invalid input. @@ -84,7 +91,7 @@ func MustDecode(input string) []byte { func Encode(b []byte) string { enc := make([]byte, len(b)*2+2) copy(enc, "0x") - hex.Encode(enc[2:], b) + asmhex.Encode(enc[2:], b) return string(enc) } diff --git a/common/hexutil/json.go b/common/hexutil/json.go index e0ac98f52d..2e0fadf65f 100644 --- a/common/hexutil/json.go +++ b/common/hexutil/json.go @@ -17,13 +17,13 @@ package hexutil import ( - "encoding/hex" "encoding/json" "fmt" "math/big" "reflect" "strconv" + "github.com/ethereum/go-ethereum/common/hexutil/asmhex" "github.com/holiman/uint256" ) @@ -43,7 +43,7 @@ type Bytes []byte func (b Bytes) MarshalText() ([]byte, error) { result := make([]byte, len(b)*2+2) copy(result, `0x`) - hex.Encode(result[2:], b) + asmhex.Encode(result[2:], b) return result, nil } @@ -62,7 +62,7 @@ func (b *Bytes) UnmarshalText(input []byte) error { return err } dec := make([]byte, len(raw)/2) - if _, err = hex.Decode(dec, raw); err != nil { + if _, err = asmhex.Decode(dec, raw); err != nil { err = mapError(err) } else { *b = dec @@ -121,7 +121,7 @@ func UnmarshalFixedText(typname string, input, out []byte) error { return ErrSyntax } } - hex.Decode(out, raw) + asmhex.Decode(out, raw) return nil } @@ -142,7 +142,7 @@ func UnmarshalFixedUnprefixedText(typname string, input, out []byte) error { return ErrSyntax } } - hex.Decode(out, raw) + asmhex.Decode(out, raw) return nil }