mirror of
https://github.com/containerd/containerd.git
synced 2026-11-06 05:17:02 +00:00
build(deps): bump github.com/klauspost/compress from 1.19.1 to 1.19.2
Bumps [github.com/klauspost/compress](https://github.com/klauspost/compress) from 1.19.1 to 1.19.2. - [Release notes](https://github.com/klauspost/compress/releases) - [Commits](https://github.com/klauspost/compress/compare/v1.19.1...v1.19.2) --- updated-dependencies: - dependency-name: github.com/klauspost/compress dependency-version: 1.19.2 dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
1 parent
e1bbb3df6a
commit
da7420a420
14 files changed
+1525
-505
No files matched your search
@@ -44,7 +44,7 @@ require (
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.1.0
|
||||
github.com/intel/goresctrl v0.13.0
|
||||
github.com/klauspost/compress v1.19.1
|
||||
github.com/klauspost/compress v1.19.2
|
||||
github.com/mdlayher/vsock v1.3.0
|
||||
github.com/moby/locker v1.0.1
|
||||
github.com/moby/sys/mountinfo v0.7.2
|
||||
|
||||
@@ -205,8 +205,8 @@ github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/u
|
||||
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
|
||||
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
|
||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||
github.com/klauspost/compress v1.19.1 h1:VsB4HPswih7mmZ8WleSFQ75c/Ui1M4trX5oAsJnhSlk=
|
||||
github.com/klauspost/compress v1.19.1/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/klauspost/compress v1.19.2 h1:hMRETovs/pu/dVWN7zIT1PGG8t509MwT6bO7XSi26R8=
|
||||
github.com/klauspost/compress v1.19.2/go.mod h1:cwPg85FWrGar70rWktvGQj8/hthj3wpl0PGDogxkrSQ=
|
||||
github.com/knqyf263/go-plugin v0.9.0 h1:CQs2+lOPIlkZVtcb835ZYDEoyyWJWLbSTWeCs0EwTwI=
|
||||
github.com/knqyf263/go-plugin v0.9.0/go.mod h1:2z5lCO1/pez6qGo8CvCxSlBFSEat4MEp1DrnA+f7w8Q=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
|
||||
+15
-188
@@ -1,222 +1,49 @@
|
||||
//go:build amd64 && !appengine && !noasm && gc
|
||||
|
||||
// This file contains the specialisation of Decoder.Decompress4X
|
||||
// and Decoder.Decompress1X that use an asm implementation of thir main loops.
|
||||
// amd64 stubs and dispatch for the asm loops used by decompress_asm.go.
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
"github.com/klauspost/compress/internal/cpuinfo"
|
||||
)
|
||||
|
||||
// decompress4x_main_loop_x86 is an x86 assembler implementation
|
||||
// decompress4x_main_loop_amd64 is an x86 assembler implementation
|
||||
// of Decompress4X when tablelog > 8.
|
||||
//
|
||||
//go:noescape
|
||||
func decompress4x_main_loop_amd64(ctx *decompress4xContext)
|
||||
|
||||
// decompress4x_8b_loop_x86 is an x86 assembler implementation
|
||||
// decompress4x_8b_main_loop_amd64 is an x86 assembler implementation
|
||||
// of Decompress4X when tablelog <= 8 which decodes 4 entries
|
||||
// per loop.
|
||||
//
|
||||
//go:noescape
|
||||
func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
|
||||
|
||||
// fallback8BitSize is the size where using Go version is faster.
|
||||
const fallback8BitSize = 800
|
||||
|
||||
type decompress4xContext struct {
|
||||
pbr *[4]bitReaderShifted
|
||||
peekBits uint8
|
||||
out *byte
|
||||
dstEvery int
|
||||
tbl *dEntrySingle
|
||||
decoded int
|
||||
limit *byte
|
||||
}
|
||||
|
||||
// Decompress4X will decompress a 4X encoded stream.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
// The *capacity* of the dst slice must match the destination size of
|
||||
// the uncompressed data exactly.
|
||||
func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
|
||||
if len(d.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
if len(src) < 6+(4*1) {
|
||||
return nil, errors.New("input too small")
|
||||
}
|
||||
|
||||
use8BitTables := d.actualTableLog <= 8
|
||||
if cap(dst) < fallback8BitSize && use8BitTables {
|
||||
return d.decompress4X8bit(dst, src)
|
||||
}
|
||||
|
||||
var br [4]bitReaderShifted
|
||||
// Decode "jump table"
|
||||
start := 6
|
||||
for i := range 3 {
|
||||
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
|
||||
if start+length >= len(src) {
|
||||
return nil, errors.New("truncated input (or invalid offset)")
|
||||
}
|
||||
err := br[i].init(src[start : start+length])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
start += length
|
||||
}
|
||||
err := br[3].init(src[start:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// destination, offset to match first output
|
||||
dstSize := cap(dst)
|
||||
dst = dst[:dstSize]
|
||||
out := dst
|
||||
dstEvery := (dstSize + 3) / 4
|
||||
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
single := d.dt.single[:tlSize]
|
||||
|
||||
var decoded int
|
||||
|
||||
if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) {
|
||||
ctx := decompress4xContext{
|
||||
pbr: &br,
|
||||
peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
|
||||
out: &out[0],
|
||||
dstEvery: dstEvery,
|
||||
tbl: &single[0],
|
||||
limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last.
|
||||
}
|
||||
if use8BitTables {
|
||||
decompress4x_8b_main_loop_amd64(&ctx)
|
||||
} else {
|
||||
decompress4x_main_loop_amd64(&ctx)
|
||||
}
|
||||
|
||||
decoded = ctx.decoded
|
||||
out = out[decoded/4:]
|
||||
}
|
||||
|
||||
// Decode remaining.
|
||||
remainBytes := dstEvery - (decoded / 4)
|
||||
for i := range br {
|
||||
offset := dstEvery * i
|
||||
endsAt := min(offset+remainBytes, len(out))
|
||||
br := &br[i]
|
||||
bitsLeft := br.remaining()
|
||||
for bitsLeft > 0 {
|
||||
br.fill()
|
||||
if offset >= endsAt {
|
||||
return nil, errors.New("corruption detected: stream overrun 4")
|
||||
}
|
||||
|
||||
// Read value and increment offset.
|
||||
val := br.peekBitsFast(d.actualTableLog)
|
||||
v := single[val&tlMask].entry
|
||||
nBits := uint8(v)
|
||||
br.advance(nBits)
|
||||
bitsLeft -= uint(nBits)
|
||||
out[offset] = uint8(v >> 8)
|
||||
offset++
|
||||
}
|
||||
if offset != endsAt {
|
||||
return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
|
||||
}
|
||||
decoded += offset - dstEvery*i
|
||||
err = br.close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if dstSize != decoded {
|
||||
return nil, errors.New("corruption detected: short output block")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
// decompress4x_main_loop_x86 is an x86 assembler implementation
|
||||
// decompress1x_main_loop_amd64 is an x86 assembler implementation
|
||||
// of Decompress1X when tablelog > 8.
|
||||
//
|
||||
//go:noescape
|
||||
func decompress1x_main_loop_amd64(ctx *decompress1xContext)
|
||||
|
||||
// decompress4x_main_loop_x86 is an x86 with BMI2 assembler implementation
|
||||
// decompress1x_main_loop_bmi2 is an x86 with BMI2 assembler implementation
|
||||
// of Decompress1X when tablelog > 8.
|
||||
//
|
||||
//go:noescape
|
||||
func decompress1x_main_loop_bmi2(ctx *decompress1xContext)
|
||||
|
||||
type decompress1xContext struct {
|
||||
pbr *bitReaderShifted
|
||||
peekBits uint8
|
||||
out *byte
|
||||
outCap int
|
||||
tbl *dEntrySingle
|
||||
decoded int
|
||||
func decompress4x_main_loop_asm(ctx *decompress4xContext) {
|
||||
decompress4x_main_loop_amd64(ctx)
|
||||
}
|
||||
|
||||
// Error reported by asm implementations
|
||||
const error_max_decoded_size_exeeded = -1
|
||||
func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) {
|
||||
decompress4x_8b_main_loop_amd64(ctx)
|
||||
}
|
||||
|
||||
// Decompress1X will decompress a 1X encoded stream.
|
||||
// The cap of the output buffer will be the maximum decompressed size.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
|
||||
if len(d.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
func decompress1x_main_loop_asm(ctx *decompress1xContext) {
|
||||
if cpuinfo.HasBMI2() {
|
||||
decompress1x_main_loop_bmi2(ctx)
|
||||
} else {
|
||||
decompress1x_main_loop_amd64(ctx)
|
||||
}
|
||||
var br bitReaderShifted
|
||||
err := br.init(src)
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
maxDecodedSize := cap(dst)
|
||||
dst = dst[:maxDecodedSize]
|
||||
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
|
||||
if maxDecodedSize >= 4 {
|
||||
ctx := decompress1xContext{
|
||||
pbr: &br,
|
||||
out: &dst[0],
|
||||
outCap: maxDecodedSize,
|
||||
peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
|
||||
tbl: &d.dt.single[0],
|
||||
}
|
||||
|
||||
if cpuinfo.HasBMI2() {
|
||||
decompress1x_main_loop_bmi2(&ctx)
|
||||
} else {
|
||||
decompress1x_main_loop_amd64(&ctx)
|
||||
}
|
||||
if ctx.decoded == error_max_decoded_size_exeeded {
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
|
||||
dst = dst[:ctx.decoded]
|
||||
}
|
||||
|
||||
// br < 8, so uint8 is fine
|
||||
bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
|
||||
for bitsLeft > 0 {
|
||||
br.fill()
|
||||
if len(dst) >= maxDecodedSize {
|
||||
br.close()
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
nBits := uint8(v.entry)
|
||||
br.advance(nBits)
|
||||
bitsLeft -= nBits
|
||||
dst = append(dst, uint8(v.entry>>8))
|
||||
}
|
||||
return dst, br.close()
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
// Code generated by command: go run gen.go -out ../decompress_amd64.s -pkg=huff0. DO NOT EDIT.
|
||||
// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT.
|
||||
|
||||
//go:build amd64 && !appengine && !noasm && gc
|
||||
//go:build !appengine && !noasm && gc
|
||||
|
||||
// func decompress4x_main_loop_amd64(ctx *decompress4xContext)
|
||||
TEXT ·decompress4x_main_loop_amd64(SB), $0-8
|
||||
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
//go:build arm64 && !appengine && !noasm && gc
|
||||
|
||||
// arm64 stubs and dispatch for the asm loops used by decompress_asm.go.
|
||||
// The asm (decompress_arm64.s) is generated by the avo arm64 lowering
|
||||
// printer from the same source as the amd64 asm; see _generate/gen.go.
|
||||
package huff0
|
||||
|
||||
// decompress4x_main_loop_arm64 is an arm64 assembler implementation
|
||||
// of Decompress4X when tablelog > 8.
|
||||
//
|
||||
//go:noescape
|
||||
func decompress4x_main_loop_arm64(ctx *decompress4xContext)
|
||||
|
||||
// decompress4x_8b_main_loop_arm64 is an arm64 assembler implementation
|
||||
// of Decompress4X when tablelog <= 8 which decodes 4 entries
|
||||
// per loop.
|
||||
//
|
||||
//go:noescape
|
||||
func decompress4x_8b_main_loop_arm64(ctx *decompress4xContext)
|
||||
|
||||
// decompress1x_main_loop_arm64 is an arm64 assembler implementation
|
||||
// of Decompress1X when tablelog > 8.
|
||||
//
|
||||
//go:noescape
|
||||
func decompress1x_main_loop_arm64(ctx *decompress1xContext)
|
||||
|
||||
func decompress4x_main_loop_asm(ctx *decompress4xContext) {
|
||||
decompress4x_main_loop_arm64(ctx)
|
||||
}
|
||||
|
||||
func decompress4x_8b_main_loop_asm(ctx *decompress4xContext) {
|
||||
decompress4x_8b_main_loop_arm64(ctx)
|
||||
}
|
||||
|
||||
func decompress1x_main_loop_asm(ctx *decompress1xContext) {
|
||||
decompress1x_main_loop_arm64(ctx)
|
||||
}
|
||||
+851
@@ -0,0 +1,851 @@
|
||||
// Code generated by command: go run gen.go -out ../decompress.s -arch amd64,arm64 -pkg=huff0. DO NOT EDIT.
|
||||
// EXPERIMENTAL arm64 output lowered from an amd64 avo program.
|
||||
|
||||
//go:build arm64 && !appengine && !noasm && gc
|
||||
|
||||
// func decompress4x_main_loop_amd64(ctx *decompress4xContext)
|
||||
TEXT ·decompress4x_main_loop_arm64(SB), $0-8
|
||||
// Preload values
|
||||
MOVD ctx+0(FP), R0
|
||||
MOVBU 8(R0), R6
|
||||
MOVD 16(R0), R3
|
||||
MOVD 48(R0), R5
|
||||
MOVD 24(R0), R7
|
||||
MOVD 32(R0), R8
|
||||
MOVD (R0), R9
|
||||
|
||||
// Main loop
|
||||
main_loop:
|
||||
MOVD $0, R2
|
||||
CMP R5, R3
|
||||
CSET GE, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
// br0.fillFast32()
|
||||
MOVD 32(R9), R10
|
||||
MOVBU 40(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill0
|
||||
MOVD 24(R9), R0
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R0, R0
|
||||
MOVD (R9), R12
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R12, R0, R15
|
||||
MOVWU (R15), R12
|
||||
MOVD R11, R1
|
||||
LSL R1, R12, R12
|
||||
MOVD R0, 24(R9)
|
||||
ORR R12, R10, R10
|
||||
|
||||
// exhausted += (br0.off < 4)
|
||||
CMP $0x04, R0
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill0:
|
||||
// val0 := br0.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br0.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br0.peekTopBits(peekBits)
|
||||
MOVD R6, R1
|
||||
MOVD R10, R12
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val1&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br0.advance(uint8(v1.entry))
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// these two writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
MOVH R0, (R3)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 32(R9)
|
||||
MOVB R11, 40(R9)
|
||||
|
||||
// br1.fillFast32()
|
||||
MOVD 80(R9), R10
|
||||
MOVBU 88(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill1
|
||||
MOVD 72(R9), R0
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R0, R0
|
||||
MOVD 48(R9), R12
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R12, R0, R15
|
||||
MOVWU (R15), R12
|
||||
MOVD R11, R1
|
||||
LSL R1, R12, R12
|
||||
MOVD R0, 72(R9)
|
||||
ORR R12, R10, R10
|
||||
|
||||
// exhausted += (br1.off < 4)
|
||||
CMP $0x04, R0
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill1:
|
||||
// val0 := br1.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br1.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br1.peekTopBits(peekBits)
|
||||
MOVD R6, R1
|
||||
MOVD R10, R12
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val1&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br1.advance(uint8(v1.entry))
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// these two writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
ADD R7, R3, R15
|
||||
MOVH R0, (R15)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 80(R9)
|
||||
MOVB R11, 88(R9)
|
||||
|
||||
// br2.fillFast32()
|
||||
MOVD 128(R9), R10
|
||||
MOVBU 136(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill2
|
||||
MOVD 120(R9), R0
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R0, R0
|
||||
MOVD 96(R9), R12
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R12, R0, R15
|
||||
MOVWU (R15), R12
|
||||
MOVD R11, R1
|
||||
LSL R1, R12, R12
|
||||
MOVD R0, 120(R9)
|
||||
ORR R12, R10, R10
|
||||
|
||||
// exhausted += (br2.off < 4)
|
||||
CMP $0x04, R0
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill2:
|
||||
// val0 := br2.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br2.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br2.peekTopBits(peekBits)
|
||||
MOVD R6, R1
|
||||
MOVD R10, R12
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val1&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br2.advance(uint8(v1.entry))
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// these two writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
ADD R7<<1, R3, R15
|
||||
MOVH R0, (R15)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 128(R9)
|
||||
MOVB R11, 136(R9)
|
||||
|
||||
// br3.fillFast32()
|
||||
MOVD 176(R9), R10
|
||||
MOVBU 184(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill3
|
||||
MOVD 168(R9), R0
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R0, R0
|
||||
MOVD 144(R9), R12
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R12, R0, R15
|
||||
MOVWU (R15), R12
|
||||
MOVD R11, R1
|
||||
LSL R1, R12, R12
|
||||
MOVD R0, 168(R9)
|
||||
ORR R12, R10, R10
|
||||
|
||||
// exhausted += (br3.off < 4)
|
||||
CMP $0x04, R0
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill3:
|
||||
// val0 := br3.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br3.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br3.peekTopBits(peekBits)
|
||||
MOVD R6, R1
|
||||
MOVD R10, R12
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val1&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br3.advance(uint8(v1.entry))
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// these two writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
ADD R7<<1, R7, R1
|
||||
ADD R1, R3, R15
|
||||
MOVH R0, (R15)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 176(R9)
|
||||
MOVB R11, 184(R9)
|
||||
ADD $0x02, R3, R3
|
||||
AND $0xff, R2, R15
|
||||
AND $0xff, R2, R16
|
||||
TST R16, R15
|
||||
BEQ main_loop
|
||||
MOVD ctx+0(FP), R0
|
||||
MOVD 16(R0), R16
|
||||
SUB R16, R3, R3
|
||||
LSL $0x02, R3, R3
|
||||
MOVD R3, 40(R0)
|
||||
RET
|
||||
|
||||
// func decompress4x_8b_main_loop_amd64(ctx *decompress4xContext)
|
||||
TEXT ·decompress4x_8b_main_loop_arm64(SB), $0-8
|
||||
// Preload values
|
||||
MOVD ctx+0(FP), R1
|
||||
MOVBU 8(R1), R6
|
||||
MOVD 16(R1), R3
|
||||
MOVD 48(R1), R5
|
||||
MOVD 24(R1), R7
|
||||
MOVD 32(R1), R8
|
||||
MOVD (R1), R9
|
||||
|
||||
// Main loop
|
||||
main_loop:
|
||||
MOVD $0, R2
|
||||
CMP R5, R3
|
||||
CSET GE, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
// br0.fillFast32()
|
||||
MOVD 32(R9), R10
|
||||
MOVBU 40(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill0
|
||||
MOVD 24(R9), R12
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R12, R12
|
||||
MOVD (R9), R13
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R13, R12, R15
|
||||
MOVWU (R15), R13
|
||||
MOVD R11, R1
|
||||
LSL R1, R13, R13
|
||||
MOVD R12, 24(R9)
|
||||
ORR R13, R10, R10
|
||||
|
||||
// exhausted += (br0.off < 4)
|
||||
CMP $0x04, R12
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill0:
|
||||
// val0 := br0.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br0.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br0.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br0.advance(uint8(v1.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// val2 := br0.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v2 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br0.advance(uint8(v2.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val3 := br0.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v3 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br0.advance(uint8(v3.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// these four writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
|
||||
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
|
||||
MOVW R0, (R3)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 32(R9)
|
||||
MOVB R11, 40(R9)
|
||||
|
||||
// br1.fillFast32()
|
||||
MOVD 80(R9), R10
|
||||
MOVBU 88(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill1
|
||||
MOVD 72(R9), R12
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R12, R12
|
||||
MOVD 48(R9), R13
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R13, R12, R15
|
||||
MOVWU (R15), R13
|
||||
MOVD R11, R1
|
||||
LSL R1, R13, R13
|
||||
MOVD R12, 72(R9)
|
||||
ORR R13, R10, R10
|
||||
|
||||
// exhausted += (br1.off < 4)
|
||||
CMP $0x04, R12
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill1:
|
||||
// val0 := br1.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br1.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br1.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br1.advance(uint8(v1.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// val2 := br1.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v2 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br1.advance(uint8(v2.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val3 := br1.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v3 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br1.advance(uint8(v3.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// these four writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
|
||||
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
|
||||
ADD R7, R3, R15
|
||||
MOVW R0, (R15)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 80(R9)
|
||||
MOVB R11, 88(R9)
|
||||
|
||||
// br2.fillFast32()
|
||||
MOVD 128(R9), R10
|
||||
MOVBU 136(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill2
|
||||
MOVD 120(R9), R12
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R12, R12
|
||||
MOVD 96(R9), R13
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R13, R12, R15
|
||||
MOVWU (R15), R13
|
||||
MOVD R11, R1
|
||||
LSL R1, R13, R13
|
||||
MOVD R12, 120(R9)
|
||||
ORR R13, R10, R10
|
||||
|
||||
// exhausted += (br2.off < 4)
|
||||
CMP $0x04, R12
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill2:
|
||||
// val0 := br2.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br2.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br2.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br2.advance(uint8(v1.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// val2 := br2.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v2 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br2.advance(uint8(v2.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val3 := br2.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v3 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br2.advance(uint8(v3.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// these four writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
|
||||
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
|
||||
ADD R7<<1, R3, R15
|
||||
MOVW R0, (R15)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 128(R9)
|
||||
MOVB R11, 136(R9)
|
||||
|
||||
// br3.fillFast32()
|
||||
MOVD 176(R9), R10
|
||||
MOVBU 184(R9), R11
|
||||
CMP $0x20, R11
|
||||
BLS skip_fill3
|
||||
MOVD 168(R9), R12
|
||||
SUB $0x20, R11, R11
|
||||
SUB $0x04, R12, R12
|
||||
MOVD 144(R9), R13
|
||||
|
||||
// b.value |= uint64(low) << (b.bitsRead & 63)
|
||||
ADD R13, R12, R15
|
||||
MOVWU (R15), R13
|
||||
MOVD R11, R1
|
||||
LSL R1, R13, R13
|
||||
MOVD R12, 168(R9)
|
||||
ORR R13, R10, R10
|
||||
|
||||
// exhausted += (br3.off < 4)
|
||||
CMP $0x04, R12
|
||||
CSINC HS, R2, R2, R16
|
||||
BFI $0, R16, $8, R2
|
||||
|
||||
skip_fill3:
|
||||
// val0 := br3.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v0 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br3.advance(uint8(v0.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val1 := br3.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v1 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br3.advance(uint8(v1.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// val2 := br3.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v2 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br3.advance(uint8(v2.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
|
||||
// val3 := br3.peekTopBits(peekBits)
|
||||
MOVD R10, R12
|
||||
MOVD R6, R1
|
||||
LSR R1, R12, R12
|
||||
|
||||
// v3 := table[val0&mask]
|
||||
ADD R12<<1, R8, R15
|
||||
MOVHU (R15), R1
|
||||
|
||||
// br3.advance(uint8(v3.entry)
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
LSL R1, R10, R10
|
||||
ADD R1, R11, R15
|
||||
BFI $0, R15, $8, R11
|
||||
REVW R0, R0
|
||||
|
||||
// these four writes get coalesced
|
||||
// out[id * dstEvery + 0] = uint8(v0.entry >> 8)
|
||||
// out[id * dstEvery + 1] = uint8(v1.entry >> 8)
|
||||
// out[id * dstEvery + 3] = uint8(v2.entry >> 8)
|
||||
// out[id * dstEvery + 4] = uint8(v3.entry >> 8)
|
||||
ADD R7<<1, R7, R1
|
||||
ADD R1, R3, R15
|
||||
MOVW R0, (R15)
|
||||
|
||||
// update the bitreader structure
|
||||
MOVD R10, 176(R9)
|
||||
MOVB R11, 184(R9)
|
||||
ADD $0x04, R3, R3
|
||||
AND $0xff, R2, R15
|
||||
AND $0xff, R2, R16
|
||||
TST R16, R15
|
||||
BEQ main_loop
|
||||
MOVD ctx+0(FP), R0
|
||||
MOVD 16(R0), R16
|
||||
SUB R16, R3, R3
|
||||
LSL $0x02, R3, R3
|
||||
MOVD R3, 40(R0)
|
||||
RET
|
||||
|
||||
// func decompress1x_main_loop_amd64(ctx *decompress1xContext)
|
||||
TEXT ·decompress1x_main_loop_arm64(SB), $0-8
|
||||
MOVD ctx+0(FP), R1
|
||||
MOVD 16(R1), R2
|
||||
MOVD 24(R1), R3
|
||||
CMP $0x04, R3
|
||||
BLO error_max_decoded_size_exceeded
|
||||
ADD R3, R2, R3
|
||||
MOVD (R1), R5
|
||||
MOVD (R5), R7
|
||||
MOVD 24(R5), R8
|
||||
MOVD 32(R5), R9
|
||||
MOVBU 40(R5), R10
|
||||
MOVD 32(R1), R5
|
||||
MOVBU 8(R1), R6
|
||||
JMP loop_condition
|
||||
|
||||
main_loop:
|
||||
// Check if we have room for 4 bytes in the output buffer
|
||||
ADD $4, R2, R1
|
||||
CMP R3, R1
|
||||
BGE error_max_decoded_size_exceeded
|
||||
|
||||
// Decode 4 values
|
||||
CMP $0x20, R10
|
||||
BLT bitReader_fillFast_1_end
|
||||
SUB $0x20, R10, R10
|
||||
SUB $0x04, R8, R8
|
||||
ADD R8, R7, R15
|
||||
MOVWU (R15), R11
|
||||
MOVD R10, R1
|
||||
LSL R1, R11, R11
|
||||
ORR R11, R9, R9
|
||||
|
||||
bitReader_fillFast_1_end:
|
||||
MOVD R6, R1
|
||||
MOVD R9, R11
|
||||
LSR R1, R11, R11
|
||||
ADD R11<<1, R5, R15
|
||||
MOVHU (R15), R1
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
MOVBU R1, R1
|
||||
ADD R1, R10, R10
|
||||
LSL R1, R9, R9
|
||||
MOVD R6, R1
|
||||
MOVD R9, R11
|
||||
LSR R1, R11, R11
|
||||
ADD R11<<1, R5, R15
|
||||
MOVHU (R15), R1
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
MOVBU R1, R1
|
||||
ADD R1, R10, R10
|
||||
LSL R1, R9, R9
|
||||
REVW R0, R0
|
||||
CMP $0x20, R10
|
||||
BLT bitReader_fillFast_2_end
|
||||
SUB $0x20, R10, R10
|
||||
SUB $0x04, R8, R8
|
||||
ADD R8, R7, R15
|
||||
MOVWU (R15), R11
|
||||
MOVD R10, R1
|
||||
LSL R1, R11, R11
|
||||
ORR R11, R9, R9
|
||||
|
||||
bitReader_fillFast_2_end:
|
||||
MOVD R6, R1
|
||||
MOVD R9, R11
|
||||
LSR R1, R11, R11
|
||||
ADD R11<<1, R5, R15
|
||||
MOVHU (R15), R1
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $8, R16, $8, R0
|
||||
MOVBU R1, R1
|
||||
ADD R1, R10, R10
|
||||
LSL R1, R9, R9
|
||||
MOVD R6, R1
|
||||
MOVD R9, R11
|
||||
LSR R1, R11, R11
|
||||
ADD R11<<1, R5, R15
|
||||
MOVHU (R15), R1
|
||||
UBFX $8, R1, $8, R16
|
||||
BFI $0, R16, $8, R0
|
||||
MOVBU R1, R1
|
||||
ADD R1, R10, R10
|
||||
LSL R1, R9, R9
|
||||
REVW R0, R0
|
||||
|
||||
// Store the decoded values
|
||||
MOVW R0, (R2)
|
||||
ADD $0x04, R2, R2
|
||||
|
||||
loop_condition:
|
||||
CMP $0x08, R8
|
||||
BGE main_loop
|
||||
|
||||
// Update ctx structure
|
||||
MOVD ctx+0(FP), R0
|
||||
MOVD 16(R0), R16
|
||||
SUB R16, R2, R2
|
||||
MOVD R2, 40(R0)
|
||||
MOVD (R0), R0
|
||||
MOVD R8, 24(R0)
|
||||
MOVD R9, 32(R0)
|
||||
MOVB R10, 40(R0)
|
||||
RET
|
||||
|
||||
// Report error
|
||||
error_max_decoded_size_exceeded:
|
||||
MOVD ctx+0(FP), R0
|
||||
MOVD $-1, R1
|
||||
MOVD R1, 40(R0)
|
||||
RET
|
||||
|
||||
// skipped decompress1x_main_loop_bmi2 (generic twin preferred on arm64)
|
||||
+193
@@ -0,0 +1,193 @@
|
||||
//go:build (amd64 || arm64) && !appengine && !noasm && gc
|
||||
|
||||
// This file contains the specialisation of Decoder.Decompress4X
|
||||
// and Decoder.Decompress1X that use an asm implementation of their main loops.
|
||||
// The asm function stubs and any per-arch dispatch live in decompress_amd64.go
|
||||
// and decompress_arm64.go.
|
||||
package huff0
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
// fallback8BitSize is the size where using Go version is faster.
|
||||
const fallback8BitSize = 800
|
||||
|
||||
type decompress4xContext struct {
|
||||
pbr *[4]bitReaderShifted
|
||||
peekBits uint8
|
||||
out *byte
|
||||
dstEvery int
|
||||
tbl *dEntrySingle
|
||||
decoded int
|
||||
limit *byte
|
||||
}
|
||||
|
||||
// Decompress4X will decompress a 4X encoded stream.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
// The *capacity* of the dst slice must match the destination size of
|
||||
// the uncompressed data exactly.
|
||||
func (d *Decoder) Decompress4X(dst, src []byte) ([]byte, error) {
|
||||
if len(d.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
if len(src) < 6+(4*1) {
|
||||
return nil, errors.New("input too small")
|
||||
}
|
||||
|
||||
use8BitTables := d.actualTableLog <= 8
|
||||
if cap(dst) < fallback8BitSize && use8BitTables {
|
||||
return d.decompress4X8bit(dst, src)
|
||||
}
|
||||
|
||||
var br [4]bitReaderShifted
|
||||
// Decode "jump table"
|
||||
start := 6
|
||||
for i := range 3 {
|
||||
length := int(src[i*2]) | (int(src[i*2+1]) << 8)
|
||||
if start+length >= len(src) {
|
||||
return nil, errors.New("truncated input (or invalid offset)")
|
||||
}
|
||||
err := br[i].init(src[start : start+length])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
start += length
|
||||
}
|
||||
err := br[3].init(src[start:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// destination, offset to match first output
|
||||
dstSize := cap(dst)
|
||||
dst = dst[:dstSize]
|
||||
out := dst
|
||||
dstEvery := (dstSize + 3) / 4
|
||||
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
single := d.dt.single[:tlSize]
|
||||
|
||||
var decoded int
|
||||
|
||||
if len(out) > 4*4 && !(br[0].off < 4 || br[1].off < 4 || br[2].off < 4 || br[3].off < 4) {
|
||||
ctx := decompress4xContext{
|
||||
pbr: &br,
|
||||
peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
|
||||
out: &out[0],
|
||||
dstEvery: dstEvery,
|
||||
tbl: &single[0],
|
||||
limit: &out[dstEvery-4], // Always stop decoding when first buffer gets here to avoid writing OOB on last.
|
||||
}
|
||||
if use8BitTables {
|
||||
decompress4x_8b_main_loop_asm(&ctx)
|
||||
} else {
|
||||
decompress4x_main_loop_asm(&ctx)
|
||||
}
|
||||
|
||||
decoded = ctx.decoded
|
||||
out = out[decoded/4:]
|
||||
}
|
||||
|
||||
// Decode remaining.
|
||||
remainBytes := dstEvery - (decoded / 4)
|
||||
for i := range br {
|
||||
offset := dstEvery * i
|
||||
endsAt := min(offset+remainBytes, len(out))
|
||||
br := &br[i]
|
||||
bitsLeft := br.remaining()
|
||||
for bitsLeft > 0 {
|
||||
br.fill()
|
||||
if offset >= endsAt {
|
||||
return nil, errors.New("corruption detected: stream overrun 4")
|
||||
}
|
||||
|
||||
// Read value and increment offset.
|
||||
val := br.peekBitsFast(d.actualTableLog)
|
||||
v := single[val&tlMask].entry
|
||||
nBits := uint8(v)
|
||||
br.advance(nBits)
|
||||
bitsLeft -= uint(nBits)
|
||||
out[offset] = uint8(v >> 8)
|
||||
offset++
|
||||
}
|
||||
if offset != endsAt {
|
||||
return nil, fmt.Errorf("corruption detected: short output block %d, end %d != %d", i, offset, endsAt)
|
||||
}
|
||||
decoded += offset - dstEvery*i
|
||||
err = br.close()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
if dstSize != decoded {
|
||||
return nil, errors.New("corruption detected: short output block")
|
||||
}
|
||||
return dst, nil
|
||||
}
|
||||
|
||||
type decompress1xContext struct {
|
||||
pbr *bitReaderShifted
|
||||
peekBits uint8
|
||||
out *byte
|
||||
outCap int
|
||||
tbl *dEntrySingle
|
||||
decoded int
|
||||
}
|
||||
|
||||
// Error reported by asm implementations
|
||||
const error_max_decoded_size_exeeded = -1
|
||||
|
||||
// Decompress1X will decompress a 1X encoded stream.
|
||||
// The cap of the output buffer will be the maximum decompressed size.
|
||||
// The length of the supplied input must match the end of a block exactly.
|
||||
func (d *Decoder) Decompress1X(dst, src []byte) ([]byte, error) {
|
||||
if len(d.dt.single) == 0 {
|
||||
return nil, errors.New("no table loaded")
|
||||
}
|
||||
var br bitReaderShifted
|
||||
err := br.init(src)
|
||||
if err != nil {
|
||||
return dst, err
|
||||
}
|
||||
maxDecodedSize := cap(dst)
|
||||
dst = dst[:maxDecodedSize]
|
||||
|
||||
const tlSize = 1 << tableLogMax
|
||||
const tlMask = tlSize - 1
|
||||
|
||||
if maxDecodedSize >= 4 {
|
||||
ctx := decompress1xContext{
|
||||
pbr: &br,
|
||||
out: &dst[0],
|
||||
outCap: maxDecodedSize,
|
||||
peekBits: uint8((64 - d.actualTableLog) & 63), // see: bitReaderShifted.peekBitsFast()
|
||||
tbl: &d.dt.single[0],
|
||||
}
|
||||
|
||||
decompress1x_main_loop_asm(&ctx)
|
||||
if ctx.decoded == error_max_decoded_size_exeeded {
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
|
||||
dst = dst[:ctx.decoded]
|
||||
}
|
||||
|
||||
// br < 8, so uint8 is fine
|
||||
bitsLeft := uint8(br.off)*8 + 64 - br.bitsRead
|
||||
for bitsLeft > 0 {
|
||||
br.fill()
|
||||
if len(dst) >= maxDecodedSize {
|
||||
br.close()
|
||||
return nil, ErrMaxDecodedSizeExceeded
|
||||
}
|
||||
v := d.dt.single[br.peekBitsFast(d.actualTableLog)&tlMask]
|
||||
nBits := uint8(v.entry)
|
||||
br.advance(nBits)
|
||||
bitsLeft -= nBits
|
||||
dst = append(dst, uint8(v.entry>>8))
|
||||
}
|
||||
return dst, br.close()
|
||||
}
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
//go:build !amd64 || appengine || !gc || noasm
|
||||
//go:build (!amd64 && !arm64) || appengine || !gc || noasm
|
||||
|
||||
// This file contains a generic implementation of Decoder.Decompress4X.
|
||||
package huff0
|
||||
|
||||
+3
-6
@@ -400,8 +400,9 @@ func (b *blockDec) decodeLiterals(in []byte, hist *history) (remain []byte, err
|
||||
}
|
||||
}
|
||||
var err error
|
||||
// Use our out buffer.
|
||||
huff.MaxDecodedSize = litRegenSize
|
||||
// Decoder.Decompress* uses cap(dst) for the size limit. Do not write
|
||||
// MaxDecodedSize on hist.huffTree: with a trained dictionary that
|
||||
// pointer aliases the shared dict.litEnc and concurrent DecodeAll races.
|
||||
if fourStreams {
|
||||
literals, err = huff.Decoder().Decompress4X(b.literalBuf[:0:litRegenSize], literals)
|
||||
} else {
|
||||
@@ -673,10 +674,6 @@ func (b *blockDec) executeSequences(hist *history) error {
|
||||
hbytes := hist.b
|
||||
if len(hbytes) > hist.windowSize {
|
||||
hbytes = hbytes[len(hbytes)-hist.windowSize:]
|
||||
// We do not need history anymore.
|
||||
if hist.dict != nil {
|
||||
hist.dict.content = nil
|
||||
}
|
||||
}
|
||||
hist.decoders.windowSize = hist.windowSize
|
||||
hist.decoders.out = b.dst[:0]
|
||||
|
||||
+64
-21
@@ -296,40 +296,81 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
if offset > 3 {
|
||||
newOffsets[offset-3]++
|
||||
} else {
|
||||
newOffsets[uint32(o.Offsets[offset-1])]++
|
||||
// Repeat codes reference the training Offsets. Skip unset
|
||||
// (zero) entries so they are not ranked as real offsets.
|
||||
prev := o.Offsets[offset-1]
|
||||
if prev > 0 {
|
||||
newOffsets[uint32(prev)]++
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Find most used offsets.
|
||||
var sortedOffsets []uint32
|
||||
for k := range newOffsets {
|
||||
if k == 0 {
|
||||
continue
|
||||
}
|
||||
sortedOffsets = append(sortedOffsets, k)
|
||||
}
|
||||
sort.Slice(sortedOffsets, func(i, j int) bool {
|
||||
a, b := sortedOffsets[i], sortedOffsets[j]
|
||||
if a == b {
|
||||
ca, cb := newOffsets[a], newOffsets[b]
|
||||
if ca == cb {
|
||||
// Prefer the longer offset
|
||||
return sortedOffsets[i] > sortedOffsets[j]
|
||||
return a > b
|
||||
}
|
||||
return newOffsets[sortedOffsets[i]] > newOffsets[sortedOffsets[j]]
|
||||
return ca > cb
|
||||
})
|
||||
if len(sortedOffsets) > 3 {
|
||||
if debug {
|
||||
print("Offsets:")
|
||||
for i, v := range sortedOffsets {
|
||||
if i > 20 {
|
||||
break
|
||||
}
|
||||
printf("[%d: %d],", v, newOffsets[v])
|
||||
if debug {
|
||||
print("Offsets:")
|
||||
for i, v := range sortedOffsets {
|
||||
if i > 20 {
|
||||
break
|
||||
}
|
||||
println("")
|
||||
printf("[%d: %d],", v, newOffsets[v])
|
||||
}
|
||||
|
||||
sortedOffsets = sortedOffsets[:3]
|
||||
println("")
|
||||
}
|
||||
for i, v := range sortedOffsets {
|
||||
o.Offsets[i] = int(v)
|
||||
// Dictionary recent-offsets must be three positive values within the
|
||||
// history. Ranked matches may be fewer (or empty when only unset
|
||||
// repeat codes were seen), so fill remaining slots with defaults.
|
||||
used := make(map[int]bool, 3)
|
||||
var finalOffsets [3]int
|
||||
nOff := 0
|
||||
for _, v := range sortedOffsets {
|
||||
iv := int(v)
|
||||
if iv <= 0 || iv > len(hist) || used[iv] {
|
||||
continue
|
||||
}
|
||||
finalOffsets[nOff] = iv
|
||||
used[iv] = true
|
||||
nOff++
|
||||
if nOff == 3 {
|
||||
break
|
||||
}
|
||||
}
|
||||
for _, def := range []int{1, 4, 8} {
|
||||
if nOff == 3 {
|
||||
break
|
||||
}
|
||||
if def <= len(hist) && !used[def] {
|
||||
finalOffsets[nOff] = def
|
||||
used[def] = true
|
||||
nOff++
|
||||
}
|
||||
}
|
||||
for def := 1; nOff < 3 && def <= len(hist); def++ {
|
||||
if !used[def] {
|
||||
finalOffsets[nOff] = def
|
||||
used[def] = true
|
||||
nOff++
|
||||
}
|
||||
}
|
||||
if nOff < 3 {
|
||||
return nil, fmt.Errorf("could not determine 3 valid dictionary offsets (history size %d)", len(hist))
|
||||
}
|
||||
o.Offsets = finalOffsets
|
||||
if debug {
|
||||
println("New repeat offsets", o.Offsets)
|
||||
}
|
||||
@@ -337,6 +378,9 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
if nUsed == 0 || seqs == 0 {
|
||||
return nil, fmt.Errorf("%d blocks, %d sequences found", nUsed, seqs)
|
||||
}
|
||||
if litTotal == 0 {
|
||||
return nil, errors.New("0 literals found")
|
||||
}
|
||||
if debug {
|
||||
println("Sequences:", seqs, "Blocks:", nUsed, "Literals:", litTotal)
|
||||
}
|
||||
@@ -517,11 +561,10 @@ func BuildDict(o BuildDictOptions) ([]byte, error) {
|
||||
out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[1])))
|
||||
out.Write(binary.LittleEndian.AppendUint32(nil, uint32(o.Offsets[2])))
|
||||
out.Write(hist)
|
||||
if _, err := loadDict(out.Bytes()); err != nil {
|
||||
return nil, fmt.Errorf("built dictionary failed validation: %w", err)
|
||||
}
|
||||
if debug {
|
||||
_, err := loadDict(out.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
i, err := InspectDictionary(out.Bytes())
|
||||
if err != nil {
|
||||
panic(err)
|
||||
|
||||
+2
-2
@@ -2081,7 +2081,7 @@ sequenceDecs_decodeSync_amd64_match_len_ofs_ok:
|
||||
MOVQ 16(SP), R13
|
||||
|
||||
// Check if we have enough space in s.out
|
||||
LEAQ (AX)(R13*1), R14
|
||||
LEAQ 16(AX)(R13*1), R14
|
||||
ADDQ R10, R14
|
||||
CMPQ R14, 32(SP)
|
||||
JA error_not_enough_space
|
||||
@@ -2601,7 +2601,7 @@ sequenceDecs_decodeSync_bmi2_match_len_ofs_ok:
|
||||
MOVQ 16(SP), R13
|
||||
|
||||
// Check if we have enough space in s.out
|
||||
LEAQ (CX)(R13*1), R14
|
||||
LEAQ 16(CX)(R13*1), R14
|
||||
ADDQ R9, R14
|
||||
CMPQ R14, 32(SP)
|
||||
JA error_not_enough_space
|
||||
|
||||
+323
-278
File diff suppressed because it is too large.
Load diff
+30
-3
@@ -77,6 +77,35 @@ const errorNotEnoughSpace = 5
|
||||
// error reported when bits are overread.
|
||||
const errorOverread = 6
|
||||
|
||||
// useSafeDecodeSync reports whether decodeSyncSimple must use the bounds-exact
|
||||
// ("safe") copy variants for the current buffer geometry.
|
||||
//
|
||||
// When the output and literal buffers have compressedBlockOverAlloc (16)
|
||||
// bytes of slack past their logical use, the assembly may use extended
|
||||
// memory copies that read and write in 16-byte blocks, overrunning the end
|
||||
// of a literal run or match by up to 15 bytes. Otherwise it must use the
|
||||
// bounds-exact ("safe") copies. This mirrors the analogous, always-dynamic
|
||||
// selection in executeSimple below.
|
||||
//
|
||||
// The unsafe copies were disabled in #644 (2022) as a mitigation for a
|
||||
// crash, but that crash's root cause — an unguarded bitReader overread that
|
||||
// produced out-of-range match offsets/lengths — was fixed three days later
|
||||
// in #645, which also added the fuzz corpus that has guarded this path since.
|
||||
// See #1168. An asan-instrumented fuzz job (see .github/workflows/go.yml)
|
||||
// covers the extended-copy path, which -race and plain fuzzing cannot.
|
||||
func (s *sequenceDecs) useSafeDecodeSync() bool {
|
||||
if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc {
|
||||
return true
|
||||
}
|
||||
if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) {
|
||||
return true
|
||||
}
|
||||
if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// decode sequences from the stream with the provided history but without a dictionary.
|
||||
func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
||||
if len(s.dict) > 0 {
|
||||
@@ -86,9 +115,7 @@ func (s *sequenceDecs) decodeSyncSimple(hist []byte) (bool, error) {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
// FIXME: Using unsafe memory copies leads to rare, random crashes
|
||||
// with fuzz testing. It is therefore disabled for now.
|
||||
const useSafe = true
|
||||
useSafe := s.useSafeDecodeSync()
|
||||
|
||||
br := s.br
|
||||
|
||||
|
||||
Vendored
+1
-1
@@ -415,7 +415,7 @@ github.com/intel/goresctrl/pkg/utils
|
||||
# github.com/json-iterator/go v1.1.12
|
||||
## explicit; go 1.12
|
||||
github.com/json-iterator/go
|
||||
# github.com/klauspost/compress v1.19.1
|
||||
# github.com/klauspost/compress v1.19.2
|
||||
## explicit; go 1.24
|
||||
github.com/klauspost/compress
|
||||
github.com/klauspost/compress/flate
|
||||
|
||||
Reference in new issue
Block a user