//go:build amd64 && !appengine && !noasm && gc
// +build amd64,!appengine,!noasm,gc

package zstd

import (
	
	

	
)

type decodeSyncAsmContext struct {
	llTable     []decSymbol
	mlTable     []decSymbol
	ofTable     []decSymbol
	llState     uint64
	mlState     uint64
	ofState     uint64
	iteration   int
	litRemain   int
	out         []byte
	outPosition int
	literals    []byte
	litPosition int
	history     []byte
	windowSize  int
	ll          int // set on error (not for all errors, please refer to _generate/gen.go)
	ml          int // set on error (not for all errors, please refer to _generate/gen.go)
	mo          int // set on error (not for all errors, please refer to _generate/gen.go)
}

// sequenceDecs_decodeSync_amd64 implements the main loop of sequenceDecs.decodeSync in x86 asm.
//
// Please refer to seqdec_generic.go for the reference implementation.
//
//go:noescape
func sequenceDecs_decodeSync_amd64( *sequenceDecs,  *bitReader,  *decodeSyncAsmContext) int

// sequenceDecs_decodeSync_bmi2 implements the main loop of sequenceDecs.decodeSync in x86 asm with BMI2 extensions.
//
//go:noescape
func sequenceDecs_decodeSync_bmi2( *sequenceDecs,  *bitReader,  *decodeSyncAsmContext) int

// sequenceDecs_decodeSync_safe_amd64 does the same as above, but does not write more than output buffer.
//
//go:noescape
func sequenceDecs_decodeSync_safe_amd64( *sequenceDecs,  *bitReader,  *decodeSyncAsmContext) int

// sequenceDecs_decodeSync_safe_bmi2 does the same as above, but does not write more than output buffer.
//
//go:noescape
func sequenceDecs_decodeSync_safe_bmi2( *sequenceDecs,  *bitReader,  *decodeSyncAsmContext) int

// decode sequences from the stream with the provided history but without a dictionary.
func ( *sequenceDecs) ( []byte) (bool, error) {
	if len(.dict) > 0 {
		return false, nil
	}
	if .maxSyncLen == 0 && cap(.out)-len(.out) < maxCompressedBlockSize {
		return false, nil
	}

	// FIXME: Using unsafe memory copies leads to rare, random crashes
	// with fuzz testing. It is therefore disabled for now.
	const  = true
	/*
		useSafe := false
		if s.maxSyncLen == 0 && cap(s.out)-len(s.out) < maxCompressedBlockSizeAlloc {
			useSafe = true
		}
		if s.maxSyncLen > 0 && cap(s.out)-len(s.out)-compressedBlockOverAlloc < int(s.maxSyncLen) {
			useSafe = true
		}
		if cap(s.literals) < len(s.literals)+compressedBlockOverAlloc {
			useSafe = true
		}
	*/

	 := .br

	 := min(.windowSize, maxCompressedBlockSize)

	 := decodeSyncAsmContext{
		llTable:     .litLengths.fse.dt[:maxTablesize],
		mlTable:     .matchLengths.fse.dt[:maxTablesize],
		ofTable:     .offsets.fse.dt[:maxTablesize],
		llState:     uint64(.litLengths.state.state),
		mlState:     uint64(.matchLengths.state.state),
		ofState:     uint64(.offsets.state.state),
		iteration:   .nSeqs - 1,
		litRemain:   len(.literals),
		out:         .out,
		outPosition: len(.out),
		literals:    .literals,
		windowSize:  .windowSize,
		history:     ,
	}

	.seqSize = 0
	 := len(.out)

	var  int
	if cpuinfo.HasBMI2() {
		if  {
			 = sequenceDecs_decodeSync_safe_bmi2(, , &)
		} else {
			 = sequenceDecs_decodeSync_bmi2(, , &)
		}
	} else {
		if  {
			 = sequenceDecs_decodeSync_safe_amd64(, , &)
		} else {
			 = sequenceDecs_decodeSync_amd64(, , &)
		}
	}
	switch  {
	case noError:
		break

	case errorMatchLenOfsMismatch:
		return true, fmt.Errorf("zero matchoff and matchlen (%d) > 0", .ml)

	case errorMatchLenTooBig:
		return true, fmt.Errorf("match len (%d) bigger than max allowed length", .ml)

	case errorMatchOffTooBig:
		return true, fmt.Errorf("match offset (%d) bigger than current history (%d)",
			.mo, .outPosition+len()-)

	case errorNotEnoughLiterals:
		return true, fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available",
			.ll, .litRemain+.ll)

	case errorOverread:
		return true, io.ErrUnexpectedEOF

	case errorNotEnoughSpace:
		 := .outPosition + .ll + .ml
		if debugDecoder {
			println("msl:", .maxSyncLen, "cap", cap(.out), "bef:", , "sz:", -, "mbs:", , "outsz:", cap(.out)-)
		}
		return true, fmt.Errorf("output bigger than max block size (%d)", )

	default:
		return true, fmt.Errorf("sequenceDecs_decode returned erroneous code %d", )
	}

	.seqSize += .litRemain
	if .seqSize >  {
		return true, fmt.Errorf("output bigger than max block size (%d)", )
	}
	 := .close()
	if  != nil {
		printf("Closing sequences: %v, %+v\n", , *)
		return true, 
	}

	.literals = .literals[.litPosition:]
	 := .outPosition
	.out = .out[:]

	// Add final literals
	.out = append(.out, .literals...)
	if debugDecoder {
		 += len(.literals)
		if  != len(.out) {
			panic(fmt.Errorf("length mismatch, want %d, got %d", len(.out), ))
		}
	}

	return true, nil
}

// --------------------------------------------------------------------------------

type decodeAsmContext struct {
	llTable   []decSymbol
	mlTable   []decSymbol
	ofTable   []decSymbol
	llState   uint64
	mlState   uint64
	ofState   uint64
	iteration int
	seqs      []seqVals
	litRemain int
}

const noError = 0

// error reported when mo == 0 && ml > 0
const errorMatchLenOfsMismatch = 1

// error reported when ml > maxMatchLen
const errorMatchLenTooBig = 2

// error reported when mo > available history or mo > s.windowSize
const errorMatchOffTooBig = 3

// error reported when the sum of literal lengths exeeceds the literal buffer size
const errorNotEnoughLiterals = 4

// error reported when capacity of `out` is too small
const errorNotEnoughSpace = 5

// error reported when bits are overread.
const errorOverread = 6

// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
//
// Please refer to seqdec_generic.go for the reference implementation.
//
//go:noescape
func sequenceDecs_decode_amd64( *sequenceDecs,  *bitReader,  *decodeAsmContext) int

// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm.
//
// Please refer to seqdec_generic.go for the reference implementation.
//
//go:noescape
func sequenceDecs_decode_56_amd64( *sequenceDecs,  *bitReader,  *decodeAsmContext) int

// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
//
//go:noescape
func sequenceDecs_decode_bmi2( *sequenceDecs,  *bitReader,  *decodeAsmContext) int

// sequenceDecs_decode implements the main loop of sequenceDecs in x86 asm with BMI2 extensions.
//
//go:noescape
func sequenceDecs_decode_56_bmi2( *sequenceDecs,  *bitReader,  *decodeAsmContext) int

// decode sequences from the stream without the provided history.
func ( *sequenceDecs) ( []seqVals) error {
	 := .br

	 := min(.windowSize, maxCompressedBlockSize)

	 := decodeAsmContext{
		llTable:   .litLengths.fse.dt[:maxTablesize],
		mlTable:   .matchLengths.fse.dt[:maxTablesize],
		ofTable:   .offsets.fse.dt[:maxTablesize],
		llState:   uint64(.litLengths.state.state),
		mlState:   uint64(.matchLengths.state.state),
		ofState:   uint64(.offsets.state.state),
		seqs:      ,
		iteration: len() - 1,
		litRemain: len(.literals),
	}

	if debugDecoder {
		println("decode: decoding", len(), "sequences", .remain(), "bits remain on stream")
	}

	.seqSize = 0
	 := .maxBits+.offsets.fse.actualTableLog+.matchLengths.fse.actualTableLog+.litLengths.fse.actualTableLog <= 56
	var  int
	if cpuinfo.HasBMI2() {
		if  {
			 = sequenceDecs_decode_56_bmi2(, , &)
		} else {
			 = sequenceDecs_decode_bmi2(, , &)
		}
	} else {
		if  {
			 = sequenceDecs_decode_56_amd64(, , &)
		} else {
			 = sequenceDecs_decode_amd64(, , &)
		}
	}
	if  != 0 {
		 := len() - .iteration - 1
		switch  {
		case errorMatchLenOfsMismatch:
			 := .seqs[].ml
			return fmt.Errorf("zero matchoff and matchlen (%d) > 0", )

		case errorMatchLenTooBig:
			 := .seqs[].ml
			return fmt.Errorf("match len (%d) bigger than max allowed length", )

		case errorNotEnoughLiterals:
			 := .seqs[].ll
			return fmt.Errorf("unexpected literal count, want %d bytes, but only %d is available", , .litRemain+)
		case errorOverread:
			return io.ErrUnexpectedEOF
		}

		return fmt.Errorf("sequenceDecs_decode_amd64 returned erroneous code %d", )
	}

	if .litRemain < 0 {
		return fmt.Errorf("literal count is too big: total available %d, total requested %d",
			len(.literals), len(.literals)-.litRemain)
	}

	.seqSize += .litRemain
	if .seqSize >  {
		return fmt.Errorf("output bigger than max block size (%d)", )
	}
	if debugDecoder {
		println("decode: ", .remain(), "bits remain on stream. code:", )
	}
	 := .close()
	if  != nil {
		printf("Closing sequences: %v, %+v\n", , *)
	}
	return 
}

// --------------------------------------------------------------------------------

type executeAsmContext struct {
	seqs        []seqVals
	seqIndex    int
	out         []byte
	history     []byte
	literals    []byte
	outPosition int
	litPosition int
	windowSize  int
}

// sequenceDecs_executeSimple_amd64 implements the main loop of sequenceDecs.executeSimple in x86 asm.
//
// Returns false if a match offset is too big.
//
// Please refer to seqdec_generic.go for the reference implementation.
//
//go:noescape
func sequenceDecs_executeSimple_amd64( *executeAsmContext) bool

// Same as above, but with safe memcopies
//
//go:noescape
func sequenceDecs_executeSimple_safe_amd64( *executeAsmContext) bool

// executeSimple handles cases when dictionary is not used.
func ( *sequenceDecs) ( []seqVals,  []byte) error {
	// Ensure we have enough output size...
	if len(.out)+.seqSize+compressedBlockOverAlloc > cap(.out) {
		 := .seqSize + len(.out) + compressedBlockOverAlloc
		.out = append(.out, make([]byte, )...)
		.out = .out[:len(.out)-]
	}

	if debugDecoder {
		printf("Execute %d seqs with literals: %d into %d bytes\n", len(), len(.literals), .seqSize)
	}

	var  = len(.out)
	 := .out[:+.seqSize]

	 := executeAsmContext{
		seqs:        ,
		seqIndex:    0,
		out:         ,
		history:     ,
		outPosition: ,
		litPosition: 0,
		literals:    .literals,
		windowSize:  .windowSize,
	}
	var  bool
	if cap(.literals) < len(.literals)+compressedBlockOverAlloc {
		 = sequenceDecs_executeSimple_safe_amd64(&)
	} else {
		 = sequenceDecs_executeSimple_amd64(&)
	}
	if ! {
		return fmt.Errorf("match offset (%d) bigger than current history (%d)",
			[.seqIndex].mo, .outPosition+len())
	}
	.literals = .literals[.litPosition:]
	 = .outPosition

	// Add final literals
	copy([:], .literals)
	if debugDecoder {
		 += len(.literals)
		if  != len() {
			panic(fmt.Errorf("length mismatch, want %d, got %d, ss: %d", len(), , .seqSize))
		}
	}
	.out = 

	return nil
}