// Copyright 2025 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

//go:build goexperiment.simd && amd64

package archsimd

// Implementation of all the {Int,Uint}{8,16} load and store slice part
// functions and methods for 256-bit vectors.

/* These two masks are used by generated code */

var vecMask64 = [16]int64{
	-1, -1, -1, -1,
	-1, -1, -1, -1,
	0, 0, 0, 0,
	0, 0, 0, 0,
}

var vecMask32 = [32]int32{
	-1, -1, -1, -1,
	-1, -1, -1, -1,
	-1, -1, -1, -1,
	-1, -1, -1, -1,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
	0, 0, 0, 0,
}

/* 256-bit int vector loads and stores made from 128-bit parts */

// LoadInt8x32Part loads a Int8x32 from the slice s.
// If s has fewer than 32 elements, the remaining elements of the vector are filled with zeroes.
// If s has 32 or more elements, the function is equivalent to LoadInt8x32Slice.
func LoadInt8x32Part(s []int8) (Int8x32, int) {
	l := len(s)
	if l >= 32 {
		return LoadInt8x32(s), 32
	}
	var x Int8x32
	if l == 0 {
		return x, 0
	}
	if l > 16 {
		v, _ := LoadInt8x16Part(s[16:])
		return x.SetLo(LoadInt8x16(s)).SetHi(v), l
	} else {
		v, _ := LoadInt8x16Part(s)
		return x.SetLo(v), l
	}
}

// LoadInt16x16Part loads a Int16x16 from the slice s.
// If s has fewer than 16 elements, the remaining elements of the vector are filled with zeroes.
// If s has 16 or more elements, the function is equivalent to LoadInt16x16Slice.
func LoadInt16x16Part(s []int16) (Int16x16, int) {
	l := len(s)
	if l >= 16 {
		return LoadInt16x16(s), 16
	}
	var x Int16x16
	if l == 0 {
		return x, 0
	}
	if l > 8 {
		v, _ := LoadInt16x8Part(s[8:])
		return x.SetLo(LoadInt16x8(s)).SetHi(v), l
	} else {
		v, _ := LoadInt16x8Part(s)
		return x.SetLo(v), l
	}
}

// StorePart stores the elements of x into the slice s.
// It stores as many elements as will fit in s.
// If s has 32 or more elements, the method is equivalent to x.StoreSlice.
func (x Int8x32) StorePart(s []int8) int {
	l := len(s)
	if l >= 32 {
		x.Store(s)
		return 32
	}
	if l == 0 {
		return 0
	}
	if l > 16 {
		x.GetLo().Store(s)
		x.GetHi().StorePart(s[16:])
	} else { // fits in one
		x.GetLo().StorePart(s)
	}
	return l
}

// StorePart stores the elements of x into the slice s.
// It stores as many elements as will fit in s.
// If s has 16 or more elements, the method is equivalent to x.StoreSlice.
func (x Int16x16) StorePart(s []int16) int {
	l := len(s)
	if l >= 16 {
		x.Store(s)
		return 16
	}
	if l == 0 {
		return 0
	}
	if l > 8 {
		x.GetLo().Store(s)
		x.GetHi().StorePart(s[8:])
	} else { // fits in one
		x.GetLo().StorePart(s)
	}
	return l
}
