go / src /simd /archsimd /internal /simd_test /simulation_helpers_test.go
AbdulElahGwaith's picture
Upload folder using huggingface_hub
e36aeda verified
// 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 simd_test
import (
"math"
)
func less[T number](x, y T) bool {
return x < y
}
func lessEqual[T number](x, y T) bool {
return x <= y
}
func greater[T number](x, y T) bool {
return x > y
}
func greaterEqual[T number](x, y T) bool {
return x >= y
}
func equal[T number](x, y T) bool {
return x == y
}
func notEqual[T number](x, y T) bool {
return x != y
}
func isNaN[T float](x T) bool {
return x != x
}
func abs[T number](x T) T {
// TODO this will need a non-standard FP-equality test.
if x == 0 { // true if x is -0.
return 0 // this is not a negative zero
}
if x < 0 {
return -x
}
return x
}
func ceil[T float](x T) T {
return T(math.Ceil(float64(x)))
}
func floor[T float](x T) T {
return T(math.Floor(float64(x)))
}
func not[T integer](x T) T {
return ^x
}
func round[T float](x T) T {
return T(math.RoundToEven(float64(x)))
}
func sqrt[T float](x T) T {
return T(math.Sqrt(float64(x)))
}
func trunc[T float](x T) T {
return T(math.Trunc(float64(x)))
}
func add[T number](x, y T) T {
return x + y
}
func sub[T number](x, y T) T {
return x - y
}
func max_[T number](x, y T) T { // "max" lands in infinite recursion
return max(x, y)
}
func min_[T number](x, y T) T { // "min" lands in infinite recursion
return min(x, y)
}
// Also mulLow for integers
func mul[T number](x, y T) T {
return x * y
}
func div[T number](x, y T) T {
return x / y
}
func and[T integer](x, y T) T {
return x & y
}
func andNotI[T integer](x, y T) T {
return x & ^y // order corrected to match expectations
}
func orI[T integer](x, y T) T {
return x | y
}
func xorI[T integer](x, y T) T {
return x ^ y
}
func ima[T integer](x, y, z T) T {
return x*y + z
}
func fma[T float](x, y, z T) T {
return T(math.FMA(float64(x), float64(y), float64(z)))
}
func toUint8[T number](x T) uint8 {
return uint8(x)
}
func toUint16[T number](x T) uint16 {
return uint16(x)
}
func toUint64[T number](x T) uint64 {
return uint64(x)
}
func toUint32[T number](x T) uint32 {
return uint32(x)
}
func toInt8[T number](x T) int8 {
return int8(x)
}
func toInt16[T number](x T) int16 {
return int16(x)
}
func toInt32[T number](x T) int32 {
return int32(x)
}
func toInt64[T number](x T) int64 {
return int64(x)
}
func toFloat32[T number](x T) float32 {
return float32(x)
}
func toFloat64[T number](x T) float64 {
return float64(x)
}
// X86 specific behavior for conversion from float to int32.
// If the value cannot be represented as int32, it returns -0x80000000.
func floatToInt32_x86[T float](x T) int32 {
switch y := (any(x)).(type) {
case float32:
if y != y || y < math.MinInt32 ||
y >= math.MaxInt32 { // float32(MaxInt32) == 0x80000000, actually overflows
return -0x80000000
}
case float64:
if y != y || y < math.MinInt32 ||
y > math.MaxInt32 { // float64(MaxInt32) is exact, no overflow
return -0x80000000
}
}
return int32(x)
}
// X86 specific behavior for conversion from float to int64.
// If the value cannot be represented as int64, it returns -0x80000000_00000000.
func floatToInt64_x86[T float](x T) int64 {
switch y := (any(x)).(type) {
case float32:
if y != y || y < math.MinInt64 ||
y >= math.MaxInt64 { // float32(MaxInt64) == 0x80000000_00000000, actually overflows
return -0x80000000_00000000
}
case float64:
if y != y || y < math.MinInt64 ||
y >= math.MaxInt64 { // float64(MaxInt64) == 0x80000000_00000000, also overflows
return -0x80000000_00000000
}
}
return int64(x)
}
// X86 specific behavior for conversion from float to uint32.
// If the value cannot be represented as uint32, it returns 1<<32 - 1.
func floatToUint32_x86[T float](x T) uint32 {
switch y := (any(x)).(type) {
case float32:
if y < 0 || y > math.MaxUint32 || y != y {
return 1<<32 - 1
}
case float64:
if y < 0 || y > math.MaxUint32 || y != y {
return 1<<32 - 1
}
}
return uint32(x)
}
// X86 specific behavior for conversion from float to uint64.
// If the value cannot be represented as uint64, it returns 1<<64 - 1.
func floatToUint64_x86[T float](x T) uint64 {
switch y := (any(x)).(type) {
case float32:
if y < 0 || y > math.MaxUint64 || y != y {
return 1<<64 - 1
}
case float64:
if y < 0 || y > math.MaxUint64 || y != y {
return 1<<64 - 1
}
}
return uint64(x)
}
func ceilResidueForPrecision[T float](i int) func(T) T {
f := 1.0
for i > 0 {
f *= 2
i--
}
return func(x T) T {
y := float64(x)
if math.IsInf(float64(x*T(f)), 0) {
return 0
}
// TODO sort out the rounding issues when T === float32
return T(y - math.Ceil(y*f)/f)
}
}
// Slice versions of all these elementwise operations
func addSlice[T number](x, y []T) []T {
return map2[T](add)(x, y)
}
func subSlice[T number](x, y []T) []T {
return map2[T](sub)(x, y)
}
func maxSlice[T number](x, y []T) []T {
return map2[T](max_)(x, y)
}
func minSlice[T number](x, y []T) []T {
return map2[T](min_)(x, y)
}
// mulLow for integers
func mulSlice[T number](x, y []T) []T {
return map2[T](mul)(x, y)
}
func divSlice[T number](x, y []T) []T {
return map2[T](div)(x, y)
}
func andSlice[T integer](x, y []T) []T {
return map2[T](and)(x, y)
}
func andNotSlice[T integer](x, y []T) []T {
return map2[T](andNotI)(x, y)
}
func orSlice[T integer](x, y []T) []T {
return map2[T](orI)(x, y)
}
func xorSlice[T integer](x, y []T) []T {
return map2[T](xorI)(x, y)
}
func lessSlice[T number](x, y []T) []int64 {
return mapCompare[T](less)(x, y)
}
func lessEqualSlice[T number](x, y []T) []int64 {
return mapCompare[T](lessEqual)(x, y)
}
func greaterSlice[T number](x, y []T) []int64 {
return mapCompare[T](greater)(x, y)
}
func greaterEqualSlice[T number](x, y []T) []int64 {
return mapCompare[T](greaterEqual)(x, y)
}
func equalSlice[T number](x, y []T) []int64 {
return mapCompare[T](equal)(x, y)
}
func notEqualSlice[T number](x, y []T) []int64 {
return mapCompare[T](notEqual)(x, y)
}
func isNaNSlice[T float](x []T) []int64 {
return map1[T](func(x T) int64 {
if isNaN(x) {
return -1
}
return 0
})(x)
}
func ceilSlice[T float](x []T) []T {
return map1[T](ceil)(x)
}
func floorSlice[T float](x []T) []T {
return map1[T](floor)(x)
}
func notSlice[T integer](x []T) []T {
return map1[T](not)(x)
}
func roundSlice[T float](x []T) []T {
return map1[T](round)(x)
}
func sqrtSlice[T float](x []T) []T {
return map1[T](sqrt)(x)
}
func truncSlice[T float](x []T) []T {
return map1[T](trunc)(x)
}
func imaSlice[T integer](x, y, z []T) []T {
return map3[T](ima)(x, y, z)
}
func fmaSlice[T float](x, y, z []T) []T {
return map3[T](fma)(x, y, z)
}
func satToInt8[T integer](x T) int8 {
var m int8 = -128
var M int8 = 127
if T(M) < T(m) { // expecting T being a larger type
panic("bad input type")
}
if x < T(m) {
return m
}
if x > T(M) {
return M
}
return int8(x)
}
func satToUint8[T integer](x T) uint8 {
var M uint8 = 255
if T(M) < 0 { // expecting T being a larger type
panic("bad input type")
}
if x < 0 {
return 0
}
if x > T(M) {
return M
}
return uint8(x)
}
func satToInt16[T integer](x T) int16 {
var m int16 = -32768
var M int16 = 32767
if T(M) < T(m) { // expecting T being a larger type
panic("bad input type")
}
if x < T(m) {
return m
}
if x > T(M) {
return M
}
return int16(x)
}
func satToUint16[T integer](x T) uint16 {
var M uint16 = 65535
if T(M) < 0 { // expecting T being a larger type
panic("bad input type")
}
if x < 0 {
return 0
}
if x > T(M) {
return M
}
return uint16(x)
}
func satToInt32[T integer](x T) int32 {
var m int32 = -1 << 31
var M int32 = 1<<31 - 1
if T(M) < T(m) { // expecting T being a larger type
panic("bad input type")
}
if x < T(m) {
return m
}
if x > T(M) {
return M
}
return int32(x)
}
func satToUint32[T integer](x T) uint32 {
var M uint32 = 1<<32 - 1
if T(M) < 0 { // expecting T being a larger type
panic("bad input type")
}
if x < 0 {
return 0
}
if x > T(M) {
return M
}
return uint32(x)
}