Implement Go interceptor chain (#4)

## Summary

Implements the Go SDK for MCP interceptors — validation and mutation
middleware for any MCP server.

The framework treats interceptors as first-class MCP primitives: they
are registered on an MCP server, discoverable via `interceptors/list`,
and invocable via `interceptor/invoke` — the same JSON-RPC pattern as
tools, prompts, and resources. A chain engine orchestrates execution
across one or more interceptor servers, and an optional go-sdk
middleware integration applies interceptors automatically on every
matching request/response.

## Architecture

**Three-layer design:**

1. **`interceptors`** — Protocol-agnostic core. Defines interceptor
types (validators, mutators), metadata, invocation, wire types, and
results. Zero MCP dependencies.

2. **`interceptors/mcpserver`** — MCP server integration. Wraps
`mcp.Server` to register `interceptors/list` and `interceptor/invoke` as
custom JSON-RPC methods and advertise interceptor capabilities during
`initialize`.

3. **`interceptors/chain`** — Chain engine. Orchestrates execution
across N interceptor servers with trust-boundary-aware ordering,
priority-based mutation sequencing, parallel validation, audit-mode
isolation, and fail-open/fail-closed semantics.

4. **`interceptors/integrations/gomiddleware`** — Optional go-sdk
middleware. Installs on `mcp.Server` via `AddReceivingMiddleware()` to
automatically run the interceptor chain on every matching
request/response.

**Key design decisions:**

- **Trust-boundary ordering** — request phase: validate → mutate;
response phase: mutate → validate. Validation always guards the boundary
crossing.
- **Wire-level invocation** — the chain calls `interceptor/invoke` over
the MCP transport (even in-process via `LocalChain()`), so local and
remote interceptor servers use the same interface.
- **Audit-mode isolation** — audit-mode mutators compute transformations
without applying them. Only audit mutators pay the serialization cost.
- **Concurrency** — validators run in parallel; mutators run
sequentially in priority order.

### Package Structure

| Package | File | Responsibility |
|---------|------|----------------|
| `interceptors` | `interceptor.go` | Enums, Metadata, Interceptor
interface, Validator/Mutator structs, handler types, Invocation |
| `interceptors` | `wire.go` | Wire types: ListParams/Result,
InvokeParams/Result, InterceptorInfo, event/method constants |
| `interceptors` | `priority.go` | Priority with phase-aware resolution
and JSON marshaling |
| `interceptors` | `doc.go` | Package documentation with examples |
| `interceptors/chain` | `chain.go` | Chain engine: discovery,
filtering, sorting, execution orchestration |
| `interceptors/chain` | `result.go` | ExecutionResult, AbortInfo |
| `interceptors/chain` | `doc.go` | Sub-package documentation |
| `interceptors/mcpserver` | `server.go` | MCP server wrapper,
interceptor registry, capability advertisement, `LocalChain()` |
| `interceptors/mcpserver` | `rpc.go` | `interceptors/list` and
`interceptor/invoke` JSON-RPC handlers |
| `interceptors/mcpserver` | `doc.go` | Sub-package documentation |
| `integrations/gomiddleware` | `middleware.go` | go-sdk `Middleware`
that runs the chain on every request/response |
| `integrations/gomiddleware` | `errors.go` | Abort-to-JSONRPC error
conversion |
| `integrations/gomiddleware` | `doc.go` | Sub-package documentation |

### Documentation

- `doc/DESIGN.md` — architecture, execution model, integration with
go-sdk
- `doc/CONFORMANCE.md` — SEP conformance status
- `doc/PERFORMANCE.md` — per-request cost model

### Examples

- `examples/validator` — blocks dangerous tool calls, demonstrates
`WithContextProvider`
- `examples/mutator` — tags tool responses with audit trail

## Vendor: go-sdk v1.4.0 with custom method support

Vendors `go-sdk` with minimal extensions for custom JSON-RPC methods:

- `Server.AddCustomMethod` — registers a handler that bypasses the typed
pipeline
- `ClientSession.CallCustom` — sends raw JSON-RPC calls for custom
methods

These changes are generic (not interceptor-specific) and enable any MCP
extension to define its own JSON-RPC methods.

## TODO

- More integration tests
- Unit tests
- Support wildcards for event interception (separate PR)

---------

Signed-off-by: Kurt Degiorgio <kdegiorgio@bloomberg.net>
This commit is contained in:
Kurt Degiorgio 2026-04-29 15:29:25 +01:00 • committed by GitHub
commit c9900f02ab
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
33 changed files with 62908 additions and 19 deletions

21
go/sdk/vendor/github.com/segmentio/asm/LICENSE generated vendored Normal file
View file

@ -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
go/sdk/vendor/github.com/segmentio/asm/ascii/ascii.go generated vendored Normal file
View file

@ -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,
}

View file

@ -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)
}

View file

@ -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

View file

@ -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

View file

@ -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
go/sdk/vendor/github.com/segmentio/asm/ascii/valid.go generated vendored Normal file
View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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
}

View file

@ -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
}

View file

@ -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

View file

@ -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

View file

@ -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))
}

View file

@ -0,0 +1,68 @@
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: {},
}

View file

@ -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)
}

View file

@ -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)
}

View file

@ -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)

View file

@ -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

View file

@ -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)

Some files were not shown because too many files have changed in this diff Show more