From 07e72ed98c8d71021d7397f5941c9536fccf0320 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Jun 2024 17:47:02 -0700 Subject: [PATCH 01/39] Update Vector to implement ISimdVector --- .../src/System/Numerics/Vector.cs | 74 +++++- .../src/System/Numerics/Vector_1.cs | 238 +++++++++++++++++- 2 files changed, 304 insertions(+), 8 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 0e8e2b6bf2bf67..a14d46ebad892d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -13,7 +13,7 @@ namespace System.Numerics [Intrinsic] public static unsafe partial class Vector { - internal static readonly nuint Alignment = (sizeof(Vector) == sizeof(Vector128)) ? (uint)(Vector128.Alignment) : (uint)(Vector256.Alignment); + internal static int Alignment => sizeof(Vector); /// Gets a value that indicates whether vector operations are subject to hardware acceleration through JIT intrinsic support. /// if vector operations are subject to hardware acceleration; otherwise, . @@ -207,6 +207,40 @@ public static Vector As(this Vector vector) [Intrinsic] public static Vector BitwiseOr(Vector left, Vector right) => left | right; + /// Computes the ceiling of each element in a vector. + /// The vector that will have its ceiling computed. + /// A vector whose elements are the ceiling of the elements in . + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector Ceiling(Vector vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.Ceiling(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + /// Computes the ceiling of each element in a vector. /// The vector that will have its ceiling computed. /// A vector whose elements are the ceiling of the elements in . @@ -662,6 +696,40 @@ public static bool EqualsAny(Vector left, Vector right) return false; } + /// Computes the floor of each element in a vector. + /// The vector that will have its floor computed. + /// A vector whose elements are the floor of the elements in . + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector Floor(Vector vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.Floor(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + /// Computes the floor of each element in a vector. /// The vector that will have its floor computed. /// A vector whose elements are the floor of the elements in . @@ -1141,7 +1209,7 @@ public static Vector LoadAligned(T* source) { ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType(); - if (((nuint)(source) % Alignment) != 0) + if (((nuint)(source) % (uint)(Alignment)) != 0) { ThrowHelper.ThrowAccessViolationException(); } @@ -1706,7 +1774,7 @@ public static void StoreAligned(this Vector source, T* destination) { ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType(); - if (((nuint)destination % Alignment) != 0) + if (((nuint)destination % (uint)(Alignment)) != 0) { ThrowHelper.ThrowAccessViolationException(); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index 79a66dca0a6f5e..061bd9c94780f7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -28,7 +28,7 @@ namespace System.Numerics [Intrinsic] [DebuggerDisplay("{DisplayString,nq}")] [DebuggerTypeProxy(typeof(VectorDebugView<>))] - public readonly struct Vector : IEquatable>, IFormattable + public readonly unsafe struct Vector : ISimdVector, T>, IFormattable { // These fields exist to ensure the alignment is 8, rather than 1. internal readonly ulong _00; @@ -107,7 +107,7 @@ public Vector(ReadOnlySpan values) /// A new with its elements set to the first sizeof() elements from . /// The length of is less than sizeof(). [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe Vector(ReadOnlySpan values) + public Vector(ReadOnlySpan values) { // We explicitly don't check for `null` because historically this has thrown `NullReferenceException` for perf reasons ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType(); @@ -139,7 +139,7 @@ public static Vector AllBitsSet #pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type ('T') /// Gets the number of that are in a . /// The type of the current instance () is not supported. - public static unsafe int Count + public static int Count { [Intrinsic] get @@ -655,7 +655,7 @@ public void CopyTo(T[] destination, int startIndex) /// The span to which the current instance is copied. /// The length of is less than sizeof(). [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe void CopyTo(Span destination) + public void CopyTo(Span destination) { ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType(); @@ -776,7 +776,7 @@ public string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] strin /// The span to which the current instance is copied. /// true if the current instance was successfully copied to ; otherwise, false if the length of is less than sizeof(). [MethodImpl(MethodImplOptions.AggressiveInlining)] - public unsafe bool TryCopyTo(Span destination) + public bool TryCopyTo(Span destination) { ThrowHelper.ThrowForUnsupportedNumericsVectorBaseType(); @@ -803,5 +803,233 @@ public bool TryCopyTo(Span destination) Unsafe.WriteUnaligned(ref Unsafe.As(ref MemoryMarshal.GetReference(destination)), this); return true; } + + // + // ISimdVector + // + + /// + static int ISimdVector, T>.Alignment => Vector.Alignment; + + /// + static bool ISimdVector, T>.IsHardwareAccelerated => Vector.IsHardwareAccelerated; + + /// + static Vector ISimdVector, T>.Abs(Vector vector) => Vector.Abs(vector); + + /// + static Vector ISimdVector, T>.Add(Vector left, Vector right) => left + right; + + /// + static Vector ISimdVector, T>.AndNot(Vector left, Vector right) => Vector.AndNot(left, right); + + /// + static Vector ISimdVector, T>.BitwiseAnd(Vector left, Vector right) => left & right; + + /// + static Vector ISimdVector, T>.BitwiseOr(Vector left, Vector right) => left | right; + + /// + static Vector ISimdVector, T>.Ceiling(Vector vector) => Vector.Ceiling(vector); + + /// + static Vector ISimdVector, T>.ConditionalSelect(Vector condition, Vector left, Vector right) => Vector.ConditionalSelect(condition, left, right); + + /// + static void ISimdVector, T>.CopyTo(Vector vector, T[] destination) => vector.CopyTo(destination); + + /// + static void ISimdVector, T>.CopyTo(Vector vector, T[] destination, int startIndex) => vector.CopyTo(destination, startIndex); + + /// + static void ISimdVector, T>.CopyTo(Vector vector, Span destination) => vector.CopyTo(destination); + + /// + static Vector ISimdVector, T>.Create(T value) => Vector.Create(value); + + /// + static Vector ISimdVector, T>.Create(T[] values) => new Vector(values); + + /// + static Vector ISimdVector, T>.Create(T[] values, int index) => new Vector(values, index); + + /// + static Vector ISimdVector, T>.Create(ReadOnlySpan values) => Vector.Create(values); + + /// + static Vector ISimdVector, T>.CreateScalar(T value) => Vector.CreateScalar(value); + + /// + static Vector ISimdVector, T>.CreateScalarUnsafe(T value) => Vector.CreateScalarUnsafe(value); + + /// + static Vector ISimdVector, T>.Divide(Vector left, Vector right) => left / right; + + /// + static Vector ISimdVector, T>.Divide(Vector left, T right) => left / right; + + /// + static T ISimdVector, T>.Dot(Vector left, Vector right) => Vector.Dot(left, right); + + /// + static Vector ISimdVector, T>.Equals(Vector left, Vector right) => Vector.Equals(left, right); + + /// + static bool ISimdVector, T>.EqualsAll(Vector left, Vector right) => left == right; + + /// + static bool ISimdVector, T>.EqualsAny(Vector left, Vector right) => Vector.EqualsAny(left, right); + + /// + static Vector ISimdVector, T>.Floor(Vector vector) => Vector.Floor(vector); + + /// + static T ISimdVector, T>.GetElement(Vector vector, int index) => vector.GetElement(index); + + /// + static Vector ISimdVector, T>.GreaterThan(Vector left, Vector right) => Vector.GreaterThan(left, right); + + /// + static bool ISimdVector, T>.GreaterThanAll(Vector left, Vector right) => Vector.GreaterThanAll(left, right); + + /// + static bool ISimdVector, T>.GreaterThanAny(Vector left, Vector right) => Vector.GreaterThanAny(left, right); + + /// + static Vector ISimdVector, T>.GreaterThanOrEqual(Vector left, Vector right) => Vector.GreaterThanOrEqual(left, right); + + /// + static bool ISimdVector, T>.GreaterThanOrEqualAll(Vector left, Vector right) => Vector.GreaterThanOrEqualAll(left, right); + + /// + static bool ISimdVector, T>.GreaterThanOrEqualAny(Vector left, Vector right) => Vector.GreaterThanOrEqualAny(left, right); + + /// + static Vector ISimdVector, T>.LessThan(Vector left, Vector right) => Vector.LessThan(left, right); + + /// + static bool ISimdVector, T>.LessThanAll(Vector left, Vector right) => Vector.LessThanAll(left, right); + + /// + static bool ISimdVector, T>.LessThanAny(Vector left, Vector right) => Vector.LessThanAny(left, right); + + /// + static Vector ISimdVector, T>.LessThanOrEqual(Vector left, Vector right) => Vector.LessThanOrEqual(left, right); + + /// + static bool ISimdVector, T>.LessThanOrEqualAll(Vector left, Vector right) => Vector.LessThanOrEqualAll(left, right); + + /// + static bool ISimdVector, T>.LessThanOrEqualAny(Vector left, Vector right) => Vector.LessThanOrEqualAny(left, right); + +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type ('T') + /// + static Vector ISimdVector, T>.Load(T* source) => Vector.Load(source); + + /// + static Vector ISimdVector, T>.LoadAligned(T* source) => Vector.LoadAligned(source); + + /// + static Vector ISimdVector, T>.LoadAlignedNonTemporal(T* source) => Vector.LoadAlignedNonTemporal(source); +#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type ('T') + + /// + static Vector ISimdVector, T>.LoadUnsafe(ref readonly T source) => Vector.LoadUnsafe(in source); + + /// + static Vector ISimdVector, T>.LoadUnsafe(ref readonly T source, nuint elementOffset) => Vector.LoadUnsafe(in source, elementOffset); + + /// + static Vector ISimdVector, T>.Max(Vector left, Vector right) => Vector.Max(left, right); + + /// + static Vector ISimdVector, T>.Min(Vector left, Vector right) => Vector.Min(left, right); + + /// + static Vector ISimdVector, T>.Multiply(Vector left, Vector right) => left * right; + + /// + static Vector ISimdVector, T>.Multiply(Vector left, T right) => left * right; + + /// + static Vector ISimdVector, T>.Negate(Vector vector) => -vector; + + /// + static Vector ISimdVector, T>.OnesComplement(Vector vector) => ~vector; + + /// + static Vector ISimdVector, T>.ShiftLeft(Vector vector, int shiftCount) => vector << shiftCount; + + /// + static Vector ISimdVector, T>.ShiftRightArithmetic(Vector vector, int shiftCount) => vector >> shiftCount; + + /// + static Vector ISimdVector, T>.ShiftRightLogical(Vector vector, int shiftCount) => vector >>> shiftCount; + + /// + static Vector ISimdVector, T>.Sqrt(Vector vector) => Vector.SquareRoot(vector); + +#pragma warning disable CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type ('T') + /// + static void ISimdVector, T>.Store(Vector source, T* destination) => source.Store(destination); + + /// + static void ISimdVector, T>.StoreAligned(Vector source, T* destination) => source.StoreAligned(destination); + + /// + static void ISimdVector, T>.StoreAlignedNonTemporal(Vector source, T* destination) => source.StoreAlignedNonTemporal(destination); +#pragma warning restore CS8500 // This takes the address of, gets the size of, or declares a pointer to a managed type ('T') + + /// + static void ISimdVector, T>.StoreUnsafe(Vector vector, ref T destination) => vector.StoreUnsafe(ref destination); + + /// + static void ISimdVector, T>.StoreUnsafe(Vector vector, ref T destination, nuint elementOffset) => vector.StoreUnsafe(ref destination, elementOffset); + + /// + static Vector ISimdVector, T>.Subtract(Vector left, Vector right) => left - right; + + /// + static T ISimdVector, T>.Sum(Vector vector) => Vector.Sum(vector); + + /// + static T ISimdVector, T>.ToScalar(Vector vector) => vector.ToScalar(); + + /// + static bool ISimdVector, T>.TryCopyTo(Vector vector, Span destination) => vector.TryCopyTo(destination); + + /// + static Vector ISimdVector, T>.WithElement(Vector vector, int index, T value) => vector.WithElement(index, value); + + /// + static Vector ISimdVector, T>.Xor(Vector left, Vector right) => left ^ right; + + // + // New Surface Area + // + + static bool ISimdVector, T>.AnyWhereAllBitsSet(Vector vector) => Vector.EqualsAny(vector, AllBitsSet); + + static bool ISimdVector, T>.Any(Vector vector, T value) => Vector.EqualsAny(vector, Vector.Create(value)); + + static int ISimdVector, T>.IndexOfLastMatch(Vector vector) + { + if (sizeof(Vector) == 64) + { + ulong mask = vector.AsVector512().ExtractMostSignificantBits(); + return 63 - BitOperations.LeadingZeroCount(mask); // 63 = 64 (bits in Int64) - 1 (indexing from zero) + } + else if (sizeof(Vector) == 32) + { + uint mask = vector.AsVector256().ExtractMostSignificantBits(); + return 31 - BitOperations.LeadingZeroCount(mask); // 31 = 32 (bits in Int32) - 1 (indexing from zero) + } + else + { + Debug.Assert(sizeof(Vector) == 16); + uint mask = vector.AsVector128().ExtractMostSignificantBits(); + return 31 - BitOperations.LeadingZeroCount(mask); // 31 = 32 (bits in Int32) - 1 (indexing from zero) + } + } } } From 383cc66c317d869585e359c8db2f0eb74cf63260 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Jun 2024 16:09:09 -0700 Subject: [PATCH 02/39] Expose various constants for Vector2/3/4 --- src/coreclr/jit/compiler.h | 25 ++ src/coreclr/jit/gentree.cpp | 247 +++++++++++++++++- src/coreclr/jit/hwintrinsicarm64.cpp | 55 ++++ src/coreclr/jit/hwintrinsiclistarm64.h | 10 + src/coreclr/jit/hwintrinsiclistxarch.h | 15 ++ src/coreclr/jit/hwintrinsicxarch.cpp | 66 +++++ .../ref/System.Numerics.Vectors.cs | 24 ++ .../src/System/Numerics/Vector2.cs | 66 ++++- .../src/System/Numerics/Vector3.cs | 66 ++++- .../src/System/Numerics/Vector4.cs | 77 +++++- src/mono/mono/mini/simd-intrinsics.c | 57 ++++ src/mono/mono/mini/simd-methods.h | 5 + 12 files changed, 685 insertions(+), 28 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 62fecaf3c3d2e9..21db592533614f 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3289,6 +3289,31 @@ class Compiler CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdIsNaNNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize); + + GenTree* gtNewSimdIsNegativeNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize); + + GenTree* gtNewSimdIsPositiveNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize); + + GenTree* gtNewSimdIsPositiveInfinityNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize); + + GenTree* gtNewSimdIsZeroNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize); + GenTree* gtNewSimdLoadNode( var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index f8757b26f356e3..759391984ec1ce 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -20856,13 +20856,11 @@ GenTree* Compiler::gtNewSimdAbsNode(var_types type, GenTree* op1, CorInfoType si GenTree* op1Dup1 = fgMakeMultiUse(&op1); GenTree* op1Dup2 = fgMakeMultiUse(&op1Dup1); - // op1 = op1 < Zero - tmp = gtNewZeroConNode(type); - op1 = gtNewSimdCmpOpNode(GT_LT, type, op1, tmp, simdBaseJitType, simdSize); + // op1 = IsNegative(op1) + op1 = gtNewSimdIsPositiveInfinityNode(type, op1, simdBaseJitType, simdSize); - // tmp = Zero - op1Dup1 - tmp = gtNewZeroConNode(type); - tmp = gtNewSimdBinOpNode(GT_SUB, type, tmp, op1Dup1, simdBaseJitType, simdSize); + // tmp = -op1Dup1 + tmp = gtNewSimdUnOpNode(GT_NEG, type, op1Dup1, simdBaseJitType, simdSize); // result = ConditionalSelect(op1, tmp, op1Dup2) return gtNewSimdCndSelNode(type, op1, tmp, op1Dup2, simdBaseJitType, simdSize); @@ -22222,9 +22220,8 @@ GenTree* Compiler::gtNewSimdCvtNode(var_types type, // mask1 contains the output either 0xFFFFFFFF or 0. // FixupVal zeros out any NaN values in the input by ANDing input with mask1. GenTree* op1Clone1 = fgMakeMultiUse(&op1); - GenTree* op1Clone2 = fgMakeMultiUse(&op1); - GenTree* mask1 = gtNewSimdCmpOpNode(GT_EQ, type, op1, op1Clone1, simdSourceBaseJitType, simdSize); - fixupVal = gtNewSimdBinOpNode(GT_AND, type, op1Clone2, mask1, simdSourceBaseJitType, simdSize); + GenTree* mask1 = gtNewSimdIsNaNNode(type, op1, simdSourceBaseJitType, simdSize); + fixupVal = gtNewSimdBinOpNode(GT_AND_NOT, type, op1Clone1, mask1, simdSourceBaseJitType, simdSize); } if (varTypeIsSigned(simdTargetBaseType)) @@ -23138,6 +23135,39 @@ GenTree* Compiler::gtNewSimdCmpOpNode( } break; } + + case GT_NE: + { + if (!varTypeIsFloating(simdBaseType) && (simdSize != 64)) + { + GenTree* result = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); + return gtNewSimdUnOpNode(GT_NEG, type, result, simdBaseJitType, simdSize); + } + + if (simdSize == 64) + { + assert(canUseEvexEncodingDebugOnly()); + intrinsic = NI_EVEX_CompareNotEqualMask; + needsConvertMaskToVector = true; + } + else if (simdSize == 32) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); + intrinsic = NI_AVX_CompareNotEqual; + } + else if (simdBaseType == TYP_FLOAT) + { + assert((simdSize == 8) || (simdSize == 12) || (simdSize == 16)); + intrinsic = NI_SSE_CompareNotEqual; + } + else + { + assert(simdSize == 16); + assert(simdBaseType == TYP_DOUBLE); + intrinsic = NI_SSE2_CompareNotEqual; + } + break; + } #elif defined(TARGET_ARM64) case GT_EQ: { @@ -23206,6 +23236,12 @@ GenTree* Compiler::gtNewSimdCmpOpNode( } break; } + + case GT_NE: + { + GenTree* result = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); + return gtNewSimdUnOpNode(GT_NEG, type, result, simdBaseJitType, simdSize); + } #else #error Unsupported platform #endif // !TARGET_XARCH && !TARGET_ARM64 @@ -24523,6 +24559,199 @@ GenTree* Compiler::gtNewSimdGetUpperNode(var_types type, GenTree* op1, CorInfoTy return gtNewSimdHWIntrinsicNode(type, op1, intrinsicId, simdBaseJitType, simdSize); } +//---------------------------------------------------------------------------------------------- +// Compiler::gtNewSimdIsNaNNode: Creates a new simd IsNaN node +// +// Arguments: +// type - The return type of SIMD node being created +// op1 - The vector to check for NaNs +// simdBaseJitType - The base JIT type of SIMD type of the intrinsic +// simdSize - The size of the SIMD type of the intrinsic +// +// Returns: +// The created IsNaN node +// +GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); + + if (varTypeIsFloating(simdBaseType)) + { + GenTree* op1Dup = fgMakeMultiUse(&op1); + return gtNewSimdCmpOpNode(GT_NE, type, op1, op1Dup, simdBaseJitType, simdSize); + } + return gtNewZeroConNode(type); +} + +//---------------------------------------------------------------------------------------------- +// Compiler::gtNewSimdIsNegativeNode: Creates a new simd IsNegative node +// +// Arguments: +// type - The return type of SIMD node being created +// op1 - The vector to check for Negatives +// simdBaseJitType - The base JIT type of SIMD type of the intrinsic +// simdSize - The size of the SIMD type of the intrinsic +// +// Returns: +// The created IsNegative node +// +GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + if (simdBaseJitType == CORINFO_TYPE_FLOAT) + { + simdBaseJitType = CORINFO_TYPE_INT; + } + else if (simdBaseJitType == CORINFO_TYPE_DOUBLE) + { + simdBaseJitType = CORINFO_TYPE_LONG; + } + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsIntegral(simdBaseType)); + + if (varTypeIsUnsigned(simdBaseType)) + { + return gtNewZeroConNode(type); + } + return gtNewSimdCmpOpNode(GT_LT, type, op1, gtNewZeroConNode(type), simdBaseJitType, simdSize); +} + +//---------------------------------------------------------------------------------------------- +// Compiler::gtNewSimdIsPositiveNode: Creates a new simd IsPositive node +// +// Arguments: +// type - The return type of SIMD node being created +// op1 - The vector to check for Positives +// simdBaseJitType - The base JIT type of SIMD type of the intrinsic +// simdSize - The size of the SIMD type of the intrinsic +// +// Returns: +// The created IsPositive node +// +GenTree* Compiler::gtNewSimdIsPositiveNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + if (simdBaseJitType == CORINFO_TYPE_FLOAT) + { + simdBaseJitType = CORINFO_TYPE_INT; + } + else if (simdBaseJitType == CORINFO_TYPE_DOUBLE) + { + simdBaseJitType = CORINFO_TYPE_LONG; + } + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsIntegral(simdBaseType)); + + if (varTypeIsUnsigned(simdBaseType)) + { + return gtNewAllBitsSetConNode(type); + } + return gtNewSimdCmpOpNode(GT_GE, type, op1, gtNewZeroConNode(type), simdBaseJitType, simdSize); +} + +//---------------------------------------------------------------------------------------------- +// Compiler::gtNewSimdIsPositiveInfinityNode: Creates a new simd IsPositiveInfinity node +// +// Arguments: +// type - The return type of SIMD node being created +// op1 - The vector to check for PositiveInfinities +// simdBaseJitType - The base JIT type of SIMD type of the intrinsic +// simdSize - The size of the SIMD type of the intrinsic +// +// Returns: +// The created IsPositiveInfinity node +// +GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); + + if (varTypeIsFloating(simdBaseType)) + { + double infinity = FloatingPointUtils::convertUInt64ToDouble(0x7FF0000000000000); + GenTree* cnsNode = gtNewDconNode(infinity, simdBaseType); + cnsNode = gtNewSimdCreateBroadcastNode(type, cnsNode, simdBaseJitType, simdSize); + return gtNewSimdCmpOpNode(GT_EQ, type, op1, cnsNode, simdBaseJitType, simdSize); + } + return gtNewZeroConNode(type); +} + +//---------------------------------------------------------------------------------------------- +// Compiler::gtNewSimdIsPositiveInfinityNode: Creates a new simd IsZero node +// +// Arguments: +// type - The return type of SIMD node being created +// op1 - The vector to check for Zeroes +// simdBaseJitType - The base JIT type of SIMD type of the intrinsic +// simdSize - The size of the SIMD type of the intrinsic +// +// Returns: +// The created IsZero node +// +GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, + GenTree* op1, + CorInfoType simdBaseJitType, + unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); + + return gtNewSimdCmpOpNode(GT_EQ, type, op1, gtNewZeroConNode(type), simdBaseJitType, simdSize); +} + //---------------------------------------------------------------------------------------------- // Compiler::gtNewSimdLoadNode: Creates a new simd Load node // diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index f2e283a9520e9b..fae9ebcba44f6f 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1523,6 +1523,61 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector64_IsNaN: + case NI_Vector128_IsNaN: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsNaNNode(retType, op1, simdBaseJitType, simdSize); + break; + } + + case NI_Vector64_IsNegative: + case NI_Vector128_IsNegative: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsNegativeNode(retType, op1, simdBaseJitType, simdSize); + break; + } + + case NI_Vector64_IsPositive: + case NI_Vector128_IsPositive: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsPositiveNode(retType, op1, simdBaseJitType, simdSize); + break; + } + + case NI_Vector64_IsPositiveInfinity: + case NI_Vector128_IsPositiveInfinity: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsPositiveInfinityNode(retType, op1, simdBaseJitType, simdSize); + break; + } + + case NI_Vector64_IsZero: + case NI_Vector128_IsZero: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsZeroNode(retType, op1, simdBaseJitType, simdSize); + break; + } + case NI_Vector64_LessThan: case NI_Vector128_LessThan: { diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index c59ced02357c81..c778087accc4a9 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -63,6 +63,11 @@ HARDWARE_INTRINSIC(Vector64, GreaterThanAny, HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqual, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqualAll, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, GreaterThanOrEqualAny, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector64, IsNaN, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, IsNegative, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, IsPositive, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, IsPositiveInfinity, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, IsZero, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, LessThan, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, LessThanAll, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, LessThanAny, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) @@ -166,6 +171,11 @@ HARDWARE_INTRINSIC(Vector128, GreaterThanAny, HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqual, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAll, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAny, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, IsNaN, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsNegative, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsPositive, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsPositiveInfinity, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsZero, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, LessThan, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, LessThanAll, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, LessThanAny, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 2eb67fe41dfe43..96a9d2febd30a7 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -83,6 +83,11 @@ HARDWARE_INTRINSIC(Vector128, GreaterThanAny, HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqual, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAll, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, GreaterThanOrEqualAny, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector128, IsNaN, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsNegative, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsPositive, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsPositiveInfinity, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, IsZero, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, LessThan, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, LessThanAll, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, LessThanAny, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) @@ -182,6 +187,11 @@ HARDWARE_INTRINSIC(Vector256, GreaterThanAny, HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqual, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqualAny, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, GreaterThanOrEqualAll, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector256, IsNaN, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, IsNegative, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, IsPositive, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, IsPositiveInfinity, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, IsZero, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, LessThan, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, LessThanAll, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, LessThanAny, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) @@ -282,6 +292,11 @@ HARDWARE_INTRINSIC(Vector512, GreaterThanAny, HARDWARE_INTRINSIC(Vector512, GreaterThanOrEqual, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, GreaterThanOrEqualAll, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, GreaterThanOrEqualAny, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector512, IsNaN, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, IsNegative, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, IsPositive, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, IsPositiveInfinity, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, IsZero, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, LessThan, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, LessThanAll, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, LessThanAny, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index f25e61c1e16ae7..99f0409464f94b 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2476,6 +2476,72 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_IsNaN: + case NI_Vector256_IsNaN: + case NI_Vector512_IsNaN: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsNaNNode(retType, op1, simdBaseJitType, simdSize); + break; + } + + case NI_Vector128_IsNegative: + case NI_Vector256_IsNegative: + case NI_Vector512_IsNegative: + { + assert(sig->numArgs == 1); + + if ((simdSize != 32) || compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + var_types simdType = getSIMDTypeForSize(simdSize); + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsNegativeNode(retType, op1, simdBaseJitType, simdSize); + } + break; + } + + case NI_Vector128_IsPositive: + case NI_Vector256_IsPositive: + case NI_Vector512_IsPositive: + { + assert(sig->numArgs == 1); + + if ((simdSize != 32) || compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + var_types simdType = getSIMDTypeForSize(simdSize); + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsPositiveNode(retType, op1, simdBaseJitType, simdSize); + } + break; + } + + case NI_Vector128_IsPositiveInfinity: + case NI_Vector256_IsPositiveInfinity: + case NI_Vector512_IsPositiveInfinity: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsPositiveInfinityNode(retType, op1, simdBaseJitType, simdSize); + break; + } + + case NI_Vector128_IsZero: + case NI_Vector256_IsZero: + case NI_Vector512_IsZero: + { + assert(sig->numArgs == 1); + var_types simdType = getSIMDTypeForSize(simdSize); + + op1 = impSIMDPopStack(); + retNode = gtNewSimdIsZeroNode(retType, op1, simdBaseJitType, simdSize); + break; + } + case NI_Vector128_LessThan: case NI_Vector256_LessThan: case NI_Vector512_LessThan: diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 13b94b02fd2cf2..bf8d96994fa621 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -430,7 +430,15 @@ public partial struct Vector2 : System.IEquatable, Syst public Vector2(float value) { throw null; } public Vector2(float x, float y) { throw null; } public Vector2(System.ReadOnlySpan values) { throw null; } + public static System.Numerics.Vector2 E { get { throw null; } } + public static System.Numerics.Vector2 Epsilon { get { throw null; } } + public static System.Numerics.Vector2 NaN { get { throw null; } } + public static System.Numerics.Vector2 NegativeInfinity { get { throw null; } } + public static System.Numerics.Vector2 NegativeZero { get { throw null; } } public static System.Numerics.Vector2 One { get { throw null; } } + public static System.Numerics.Vector2 Pi { get { throw null; } } + public static System.Numerics.Vector2 PositiveInfinity { get { throw null; } } + public static System.Numerics.Vector2 Tau { get { throw null; } } public static System.Numerics.Vector2 UnitX { get { throw null; } } public static System.Numerics.Vector2 UnitY { get { throw null; } } public float this[int index] { readonly get { throw null; } set { throw null; } } @@ -496,7 +504,15 @@ public partial struct Vector3 : System.IEquatable, Syst public Vector3(float value) { throw null; } public Vector3(float x, float y, float z) { throw null; } public Vector3(System.ReadOnlySpan values) { throw null; } + public static System.Numerics.Vector3 E { get { throw null; } } + public static System.Numerics.Vector3 Epsilon { get { throw null; } } + public static System.Numerics.Vector3 NaN { get { throw null; } } + public static System.Numerics.Vector3 NegativeInfinity { get { throw null; } } + public static System.Numerics.Vector3 NegativeZero { get { throw null; } } public static System.Numerics.Vector3 One { get { throw null; } } + public static System.Numerics.Vector3 Pi { get { throw null; } } + public static System.Numerics.Vector3 PositiveInfinity { get { throw null; } } + public static System.Numerics.Vector3 Tau { get { throw null; } } public static System.Numerics.Vector3 UnitX { get { throw null; } } public static System.Numerics.Vector3 UnitY { get { throw null; } } public static System.Numerics.Vector3 UnitZ { get { throw null; } } @@ -565,7 +581,15 @@ public partial struct Vector4 : System.IEquatable, Syst public Vector4(float value) { throw null; } public Vector4(float x, float y, float z, float w) { throw null; } public Vector4(System.ReadOnlySpan values) { throw null; } + public static System.Numerics.Vector4 E { get { throw null; } } + public static System.Numerics.Vector4 Epsilon { get { throw null; } } + public static System.Numerics.Vector4 NaN { get { throw null; } } + public static System.Numerics.Vector4 NegativeInfinity { get { throw null; } } + public static System.Numerics.Vector4 NegativeZero { get { throw null; } } public static System.Numerics.Vector4 One { get { throw null; } } + public static System.Numerics.Vector4 Pi { get { throw null; } } + public static System.Numerics.Vector4 PositiveInfinity { get { throw null; } } + public static System.Numerics.Vector4 Tau { get { throw null; } } public static System.Numerics.Vector4 UnitW { get { throw null; } } public static System.Numerics.Vector4 UnitX { get { throw null; } } public static System.Numerics.Vector4 UnitY { get { throw null; } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index cd4a2c5c0358e7..00a24a65dbe30a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -50,22 +50,69 @@ public Vector2(ReadOnlySpan values) this = Create(values); } - /// Returns a vector whose 2 elements are equal to zero. - /// A vector whose two elements are equal to zero (that is, it returns the vector (0,0). - public static Vector2 Zero + /// + public static Vector2 E { [Intrinsic] - get => default; + get => Create(float.E); + } + + /// + public static Vector2 Epsilon + { + [Intrinsic] + get => Create(float.Epsilon); + } + + /// + public static Vector2 NaN + { + [Intrinsic] + get => Create(float.NaN); + } + + /// + public static Vector2 NegativeInfinity + { + [Intrinsic] + get => Create(float.NegativeInfinity); + } + + /// + public static Vector2 NegativeZero + { + [Intrinsic] + get => Create(float.NegativeZero); } - /// Gets a vector whose 2 elements are equal to one. - /// A vector whose two elements are equal to one (that is, it returns the vector (1,1). + /// public static Vector2 One { [Intrinsic] get => Create(1.0f); } + /// + public static Vector2 Pi + { + [Intrinsic] + get => Create(float.Pi); + } + + /// + public static Vector2 PositiveInfinity + { + [Intrinsic] + get => Create(float.PositiveInfinity); + } + + /// + public static Vector2 Tau + { + [Intrinsic] + get => Create(float.Tau); + } + /// Gets the vector (1,0). /// The vector (1,0). public static Vector2 UnitX @@ -82,6 +129,13 @@ public static Vector2 UnitY get => Create(0.0f, 1.0f); } + /// + public static Vector2 Zero + { + [Intrinsic] + get => default; + } + /// Gets or sets the element at the specified index. /// The index of the element to get or set. /// The the element at . diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index ec97d4a4f5d525..1b1863112b13dd 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -63,22 +63,69 @@ public Vector3(ReadOnlySpan values) this = Create(values); } - /// Gets a vector whose 3 elements are equal to zero. - /// A vector whose three elements are equal to zero (that is, it returns the vector (0,0,0). - public static Vector3 Zero + /// + public static Vector3 E { [Intrinsic] - get => default; + get => Create(float.E); + } + + /// + public static Vector3 Epsilon + { + [Intrinsic] + get => Create(float.Epsilon); + } + + /// + public static Vector3 NaN + { + [Intrinsic] + get => Create(float.NaN); + } + + /// + public static Vector3 NegativeInfinity + { + [Intrinsic] + get => Create(float.NegativeInfinity); + } + + /// + public static Vector3 NegativeZero + { + [Intrinsic] + get => Create(float.NegativeZero); } - /// Gets a vector whose 3 elements are equal to one. - /// A vector whose three elements are equal to one (that is, it returns the vector (1,1,1). + /// public static Vector3 One { [Intrinsic] get => Create(1.0f); } + /// + public static Vector3 Pi + { + [Intrinsic] + get => Create(float.Pi); + } + + /// + public static Vector3 PositiveInfinity + { + [Intrinsic] + get => Create(float.PositiveInfinity); + } + + /// + public static Vector3 Tau + { + [Intrinsic] + get => Create(float.Tau); + } + /// Gets the vector (1,0,0). /// The vector (1,0,0). public static Vector3 UnitX @@ -103,6 +150,13 @@ public static Vector3 UnitZ get => Create(0.0f, 0.0f, 1.0f); } + /// + public static Vector3 Zero + { + [Intrinsic] + get => default; + } + /// Gets or sets the element at the specified index. /// The index of the element to get or set. /// The the element at . diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 2cbc385316ea40..2d00769d4e8599 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -76,23 +76,78 @@ public Vector4(ReadOnlySpan values) this = Create(values); } - /// Gets a vector whose 4 elements are equal to zero. - /// A vector whose four elements are equal to zero (that is, it returns the vector (0,0,0,0). - public static Vector4 Zero + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.E)). + public static Vector4 E { [Intrinsic] - get => default; + get => Create(float.E); + } + + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.Epsilon)). + public static Vector4 Epsilon + { + [Intrinsic] + get => Create(float.Epsilon); + } + + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.NaN)). + public static Vector4 NaN + { + [Intrinsic] + get => Create(float.NaN); + } + + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.NegativeInfinity)). + public static Vector4 NegativeInfinity + { + [Intrinsic] + get => Create(float.NegativeInfinity); + } + + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.NegativeZero)). + public static Vector4 NegativeZero + { + [Intrinsic] + get => Create(float.NegativeZero); } - /// Gets a vector whose 4 elements are equal to one. - /// Returns . - /// A vector whose four elements are equal to one (that is, it returns the vector (1,1,1,1). + /// Gets a vector whose elements are equal to one. + /// A vector whose elements are equal to one (that is, it returns the vector Create(1)). public static Vector4 One { [Intrinsic] get => Create(1); } + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.Pi)). + public static Vector4 Pi + { + [Intrinsic] + get => Create(float.Pi); + } + + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.PositiveInfinity)). + public static Vector4 PositiveInfinity + { + [Intrinsic] + get => Create(float.PositiveInfinity); + } + + /// Gets a vector whose elements are equal to . + /// A vector whose elements are equal to (that is, it returns the vector Create(float.Tau)). + public static Vector4 Tau + { + [Intrinsic] + get => Create(float.Tau); + } + /// Gets the vector (1,0,0,0). /// The vector (1,0,0,0). public static Vector4 UnitX @@ -125,6 +180,14 @@ public static Vector4 UnitW get => Create(0.0f, 0.0f, 0.0f, 1.0f); } + /// Gets a vector whose elements are equal to zero. + /// A vector whose elements are equal to zero (that is, it returns the vector Create(0)). + public static Vector4 Zero + { + [Intrinsic] + get => default; + } + /// Gets or sets the element at the specified index. /// The index of the element to get or set. /// The the element at . diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 2344c04c37ae73..00c8669e672a2e 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1219,6 +1219,11 @@ static guint16 sri_vector_methods [] = { SN_GreaterThanOrEqual, SN_GreaterThanOrEqualAll, SN_GreaterThanOrEqualAny, + SN_IsNaN, + SN_IsNegative, + SN_IsPositive, + SN_IsPositiveInfinity, + SN_IsZero, SN_LessThan, SN_LessThanAll, SN_LessThanAny, @@ -2119,6 +2124,58 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return ret; } } + case SN_IsNaN: { + if (!is_element_type_primitive (fsig->params [0])) + return NULL; + if (!type_enum_is_float(arg0_type)) + return emit_xzero (cfg, klass); + args [0] = emit_xcompare (cfg, klass, arg0_type, args [0], args [0]); + return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, SN_op_OnesComplement); + } + case SN_IsNegative: { + if (!is_element_type_primitive (fsig->params [0])) + return NULL; + if (type_enum_is_unsigned(arg0_type)) + return emit_xzero (cfg, klass); + return emit_xcompare_for_intrinsic (cfg, klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, klass)); + } + case SN_IsPositive: { + if (!is_element_type_primitive (fsig->params [0])) + return NULL; + if (type_enum_is_unsigned(arg0_type)) + return emit_xones (cfg, klass); + return emit_xcompare_for_intrinsic (cfg, klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, klass)); + } + case SN_IsPositiveInfinity: { + if (!is_element_type_primitive (fsig->params [0])) + return NULL; + if (etype == MONO_TYPE_R4) { + guint32 value[4]; + + value [0] = 0x7F800000; + value [1] = 0x7F800000; + value [2] = 0x7F800000; + value [3] = 0x7F800000; + + MonoInst* arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); + return emit_xcompare (cfg, klass, arg0_type, args [0], arg1); + } + if (etype == MONO_TYPE_R8) { + guint64 value[2]; + + value [0] = 0x7FF0000000000000; + value [1] = 0x7FF0000000000000; + + MonoInst* arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); + return emit_xcompare (cfg, klass, arg0_type, args [0], arg1); + } + return emit_xzero (cfg, klass); + } + case SN_IsZero: { + if (!is_element_type_primitive (fsig->params [0])) + return NULL; + return emit_xcompare (cfg, klass, arg0_type, args [0], emit_xzero (cfg, klass)); + } case SN_Narrow: { if (!is_element_type_primitive (fsig->params [0])) return NULL; diff --git a/src/mono/mono/mini/simd-methods.h b/src/mono/mono/mini/simd-methods.h index 6c0c47d26288c7..82fe74ebf415c2 100644 --- a/src/mono/mono/mini/simd-methods.h +++ b/src/mono/mono/mini/simd-methods.h @@ -11,6 +11,11 @@ METHOD(GreaterThanAny) METHOD(GreaterThanOrEqual) METHOD(GreaterThanOrEqualAll) METHOD(GreaterThanOrEqualAny) +METHOD(IsNaN) +METHOD(IsNegative) +METHOD(IsPositive) +METHOD(IsPositiveInfinity) +METHOD(IsZero) METHOD(LessThan) METHOD(LessThanAll) METHOD(LessThanAny) From 845978cb5e360406e4d8d77ef5a4413d5be08c43 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Jun 2024 15:57:41 -0700 Subject: [PATCH 03/39] Expose Exp, Log, and Log2 on the other vector types --- .../ref/System.Numerics.Vectors.cs | 15 ++ .../src/System/Numerics/Vector.cs | 170 +++++++++++++++++- .../src/System/Numerics/Vector2.cs | 12 ++ .../src/System/Numerics/Vector3.cs | 12 ++ .../src/System/Numerics/Vector4.cs | 12 ++ .../System/Runtime/Intrinsics/VectorMath.cs | 27 ++- 6 files changed, 243 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index bf8d96994fa621..cdaba49c0c8a6f 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -272,6 +272,8 @@ public static partial class Vector public static bool EqualsAll(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static bool EqualsAny(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Equals(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Exp(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Exp(System.Numerics.Vector vector) { throw null; } public static System.Numerics.Vector Floor(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector Floor(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector FusedMultiplyAdd(System.Numerics.Vector left, System.Numerics.Vector right, System.Numerics.Vector addend) { throw null; } @@ -316,6 +318,10 @@ public static partial class Vector public static System.Numerics.Vector LoadUnsafe(ref readonly T source) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector LoadUnsafe(ref readonly T source, nuint elementOffset) { throw null; } + public static System.Numerics.Vector Log(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Log(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Log2(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Log2(System.Numerics.Vector vector) { throw null; } public static System.Numerics.Vector Max(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Min(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -460,11 +466,14 @@ public readonly void CopyTo(System.Span destination) { } public static float Dot(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public readonly bool Equals(System.Numerics.Vector2 other) { throw null; } public override readonly bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public static System.Numerics.Vector2 Exp(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 FusedMultiplyAdd(System.Numerics.Vector2 left, System.Numerics.Vector2 right, System.Numerics.Vector2 addend) { throw null; } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } public static System.Numerics.Vector2 Lerp(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2, float amount) { throw null; } + public static System.Numerics.Vector2 Log(System.Numerics.Vector2 vector) { throw null; } + public static System.Numerics.Vector2 Log2(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 Max(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public static System.Numerics.Vector2 Min(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public static System.Numerics.Vector2 Multiply(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } @@ -537,11 +546,14 @@ public readonly void CopyTo(System.Span destination) { } public static float Dot(System.Numerics.Vector3 vector1, System.Numerics.Vector3 vector2) { throw null; } public readonly bool Equals(System.Numerics.Vector3 other) { throw null; } public override readonly bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public static System.Numerics.Vector3 Exp(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 FusedMultiplyAdd(System.Numerics.Vector3 left, System.Numerics.Vector3 right, System.Numerics.Vector3 addend) { throw null; } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } public static System.Numerics.Vector3 Lerp(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2, float amount) { throw null; } + public static System.Numerics.Vector3 Log(System.Numerics.Vector3 vector) { throw null; } + public static System.Numerics.Vector3 Log2(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 Max(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } public static System.Numerics.Vector3 Min(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } public static System.Numerics.Vector3 Multiply(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } @@ -615,11 +627,14 @@ public readonly void CopyTo(System.Span destination) { } public static float Dot(System.Numerics.Vector4 vector1, System.Numerics.Vector4 vector2) { throw null; } public readonly bool Equals(System.Numerics.Vector4 other) { throw null; } public override readonly bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) { throw null; } + public static System.Numerics.Vector4 Exp(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 FusedMultiplyAdd(System.Numerics.Vector4 left, System.Numerics.Vector4 right, System.Numerics.Vector4 addend) { throw null; } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } public static System.Numerics.Vector4 Lerp(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2, float amount) { throw null; } + public static System.Numerics.Vector4 Log(System.Numerics.Vector4 vector) { throw null; } + public static System.Numerics.Vector4 Log2(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 Max(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } public static System.Numerics.Vector4 Min(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } public static System.Numerics.Vector4 Multiply(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index a14d46ebad892d..bf5295bf1ed7e5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -561,7 +561,7 @@ public static Vector Create(ReadOnlySpan values) /// A new instance with the first element initialized to and the remaining elements initialized to zero. /// The type of () is not supported. [Intrinsic] - internal static unsafe Vector CreateScalar(T value) + internal static Vector CreateScalar(T value) { Vector result = Vector.Zero; result.SetElementUnsafe(0, value); @@ -696,6 +696,48 @@ public static bool EqualsAny(Vector left, Vector right) return false; } + internal static Vector Exp(Vector vector) + where T : IExponentialFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.Exp(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Exp(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.ExpDouble, Vector, Vector>(vector); + } + else + { + return Exp(vector); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Exp(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.ExpSingle, Vector, Vector, Vector>(vector); + } + else + { + return Exp(vector); + } + } + /// Computes the floor of each element in a vector. /// The vector that will have its floor computed. /// A vector whose elements are the floor of the elements in . @@ -1258,6 +1300,90 @@ public static Vector LoadUnsafe(ref readonly T source, nuint elementOffset return Unsafe.ReadUnaligned>(in address); } + internal static Vector Log(Vector vector) + where T : ILogarithmicFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.Log(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Log(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.LogDouble, Vector, Vector>(vector); + } + else + { + return Log(vector); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Log(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.LogSingle, Vector, Vector>(vector); + } + else + { + return Log(vector); + } + } + + internal static Vector Log2(Vector vector) + where T : ILogarithmicFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.Log2(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Log2(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.Log2Double, Vector, Vector>(vector); + } + else + { + return Log2(vector); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Log2(Vector vector) + { + if (IsHardwareAccelerated) + { + return VectorMath.Log2Single, Vector, Vector>(vector); + } + else + { + return Log2(vector); + } + } + /// Computes the maximum of two vectors on a per-element basis. /// The vector to compare with . /// The vector to compare with . @@ -1860,6 +1986,48 @@ public static T ToScalar(this Vector vector) return vector.GetElementUnsafe(0); } + /// Widens a into two . + /// The vector whose elements are to be widened. + /// A pair of vectors that contain the widened lower and upper halves of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static (Vector Lower, Vector Upper) Widen(Vector source) => (WidenLower(source), WidenUpper(source)); + + /// Widens a into two . + /// The vector whose elements are to be widened. + /// A pair of vectors that contain the widened lower and upper halves of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static (Vector Lower, Vector Upper) Widen(Vector source) => (WidenLower(source), WidenUpper(source)); + + /// Widens a into two . + /// The vector whose elements are to be widened. + /// A pair of vectors that contain the widened lower and upper halves of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static (Vector Lower, Vector Upper) Widen(Vector source) => (WidenLower(source), WidenUpper(source)); + + /// Widens a into two . + /// The vector whose elements are to be widened. + /// A pair of vectors that contain the widened lower and upper halves of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static (Vector Lower, Vector Upper) Widen(Vector source) => (WidenLower(source), WidenUpper(source)); + + /// Widens a into two . + /// The vector whose elements are to be widened. + /// A pair of vectors that contain the widened lower and upper halves of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static (Vector Lower, Vector Upper) Widen(Vector source) => (WidenLower(source), WidenUpper(source)); + + /// Widens a into two . + /// The vector whose elements are to be widened. + /// A pair of vectors that contain the widened lower and upper halves of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static (Vector Lower, Vector Upper) Widen(Vector source) => (WidenLower(source), WidenUpper(source)); + + /// Widens a into two . + /// The vector whose elements are to be widened. + /// A pair of vectors that contain the widened lower and upper halves of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static (Vector Lower, Vector Upper) Widen(Vector source) => (WidenLower(source), WidenUpper(source)); + /// Widens a into two . /// The vector whose elements are to be widened. /// A vector that will contain the widened result of the lower half of . diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index 00a24a65dbe30a..18b1375f0c4f89 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -351,6 +351,10 @@ public static Vector2 Create(ReadOnlySpan values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector2 value1, Vector2 value2) => Vector128.Dot(value1.AsVector128(), value2.AsVector128()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Exp(Vector2 vector) => Vector128.Exp(vector.AsVector128Unsafe()).AsVector2(); + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -368,6 +372,14 @@ public static Vector2 Create(ReadOnlySpan values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) => MultiplyAddEstimate(value1, Create(1.0f - amount), value2 * amount); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Log(Vector2 vector) => Vector128.Log(vector.AsVector128Unsafe()).AsVector2(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Log2(Vector2 vector) => Vector128.Log2(vector.AsVector128Unsafe()).AsVector2(); + /// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index 1b1863112b13dd..f1c96451265065 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -408,6 +408,10 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector3 vector1, Vector3 vector2) => Vector128.Dot(vector1.AsVector128(), vector2.AsVector128()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Exp(Vector3 vector) => Vector128.Exp(vector.AsVector128Unsafe()).AsVector3(); + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -422,6 +426,14 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) => MultiplyAddEstimate(value1, Create(1.0f - amount), value2 * amount); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Log(Vector3 vector) => Vector128.Log(vector.AsVector128Unsafe()).AsVector3(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Log2(Vector3 vector) => Vector128.Log2(vector.AsVector128Unsafe()).AsVector3(); + /// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 2d00769d4e8599..c809ab0762c1da 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -413,6 +413,10 @@ public static Vector4 Create(Vector3 vector, float w) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float Dot(Vector4 vector1, Vector4 vector2) => Vector128.Dot(vector1.AsVector128(), vector2.AsVector128()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Exp(Vector4 vector) => Vector128.Exp(vector.AsVector128()).AsVector4(); + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -430,6 +434,14 @@ public static Vector4 Create(Vector3 vector, float w) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Lerp(Vector4 value1, Vector4 value2, float amount) => MultiplyAddEstimate(value1, Create(1.0f - amount), value2 * amount); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Log(Vector4 vector) => Vector128.Log(vector.AsVector128()).AsVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Log2(Vector4 vector) => Vector128.Log2(vector.AsVector128()).AsVector4(); + /// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index 5b37fbfb3f85d4..f4a9f087c8597c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Diagnostics; +using System.Numerics; using System.Runtime.CompilerServices; namespace System.Runtime.Intrinsics @@ -812,7 +813,11 @@ private static TVectorDouble ConvertToDouble(TVecto { Unsafe.SkipInit(out TVectorDouble result); - if (typeof(TVectorInt64) == typeof(Vector64)) + if (typeof(TVectorInt64) == typeof(Vector)) + { + result = (TVectorDouble)(object)Vector.ConvertToDouble((Vector)(object)vector); + } + else if (typeof(TVectorInt64) == typeof(Vector64)) { result = (TVectorDouble)(object)Vector64.ConvertToDouble((Vector64)(object)vector); } @@ -843,7 +848,11 @@ private static TVectorSingle ConvertToSingle(TVecto { Unsafe.SkipInit(out TVectorSingle result); - if (typeof(TVectorInt32) == typeof(Vector64)) + if (typeof(TVectorInt32) == typeof(Vector)) + { + result = (TVectorSingle)(object)Vector.ConvertToSingle((Vector)(object)vector); + } + else if (typeof(TVectorInt32) == typeof(Vector64)) { result = (TVectorSingle)(object)Vector64.ConvertToSingle((Vector64)(object)vector); } @@ -874,7 +883,12 @@ private static TVectorSingle Narrow(TVectorDouble { Unsafe.SkipInit(out TVectorSingle result); - if (typeof(TVectorDouble) == typeof(Vector64)) + if (typeof(TVectorDouble) == typeof(Vector)) + { + Debug.Assert(typeof(TVectorSingle) == typeof(Vector)); + result = (TVectorSingle)(object)Vector.Narrow((Vector)(object)lower, (Vector)(object)upper); + } + else if (typeof(TVectorDouble) == typeof(Vector64)) { Debug.Assert(typeof(TVectorSingle) == typeof(Vector64)); result = (TVectorSingle)(object)Vector64.Narrow((Vector64)(object)lower, (Vector64)(object)upper); @@ -909,7 +923,12 @@ private static (TVectorDouble Lower, TVectorDouble Upper) Widen)) + if (typeof(TVectorSingle) == typeof(Vector)) + { + Debug.Assert(typeof(TVectorDouble) == typeof(Vector)); + result = ((TVectorDouble, TVectorDouble))(object)Vector.Widen((Vector)(object)vector); + } + else if (typeof(TVectorSingle) == typeof(Vector64)) { Debug.Assert(typeof(TVectorDouble) == typeof(Vector64)); result = ((TVectorDouble, TVectorDouble))(object)Vector64.Widen((Vector64)(object)vector); From 10ed01f7d834f462aea3ace8b8e82e8b29928356 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Jun 2024 16:41:10 -0700 Subject: [PATCH 04/39] Expose CopySign on the vector types --- .../ref/System.Numerics.Vectors.cs | 4 + .../src/System/Numerics/Vector.cs | 31 ++++++ .../src/System/Numerics/Vector2.cs | 5 + .../src/System/Numerics/Vector3.cs | 5 + .../src/System/Numerics/Vector4.cs | 5 + .../src/System/Numerics/Vector_1.cs | 3 + .../Runtime/Intrinsics/ISimdVector_2.cs | 8 +- .../src/System/Runtime/Intrinsics/Scalar.cs | 40 ++++++++ .../System/Runtime/Intrinsics/Vector128.cs | 26 +++++ .../System/Runtime/Intrinsics/Vector128_1.cs | 3 + .../System/Runtime/Intrinsics/Vector256.cs | 26 +++++ .../System/Runtime/Intrinsics/Vector256_1.cs | 3 + .../System/Runtime/Intrinsics/Vector512.cs | 26 +++++ .../System/Runtime/Intrinsics/Vector512_1.cs | 3 + .../src/System/Runtime/Intrinsics/Vector64.cs | 31 ++++++ .../System/Runtime/Intrinsics/Vector64_1.cs | 3 + .../System/Runtime/Intrinsics/VectorMath.cs | 95 +++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 4 + 18 files changed, 320 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index cdaba49c0c8a6f..14bb237a36bbbd 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -259,6 +259,7 @@ public static partial class Vector public static System.Numerics.Vector ConvertToUInt64(System.Numerics.Vector value) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Numerics.Vector ConvertToUInt64Native(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector CopySign(System.Numerics.Vector value, System.Numerics.Vector sign) { throw null; } public static System.Numerics.Vector Create(T value) { throw null; } public static System.Numerics.Vector Create(System.ReadOnlySpan values) { throw null; } public static System.Numerics.Vector CreateSequence(T start, T step) { throw null; } @@ -452,6 +453,7 @@ public partial struct Vector2 : System.IEquatable, Syst public static System.Numerics.Vector2 Abs(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 Add(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } public static System.Numerics.Vector2 Clamp(System.Numerics.Vector2 value1, System.Numerics.Vector2 min, System.Numerics.Vector2 max) { throw null; } + public static System.Numerics.Vector2 CopySign(System.Numerics.Vector2 value, System.Numerics.Vector2 sign) { throw null; } public static System.Numerics.Vector2 Create(float value) { throw null; } public static System.Numerics.Vector2 Create(float x, float y) { throw null; } public static System.Numerics.Vector2 Create(System.ReadOnlySpan values) { throw null; } @@ -530,6 +532,7 @@ public partial struct Vector3 : System.IEquatable, Syst public static System.Numerics.Vector3 Abs(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 Add(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } public static System.Numerics.Vector3 Clamp(System.Numerics.Vector3 value1, System.Numerics.Vector3 min, System.Numerics.Vector3 max) { throw null; } + public static System.Numerics.Vector3 CopySign(System.Numerics.Vector3 value, System.Numerics.Vector3 sign) { throw null; } public static System.Numerics.Vector3 Create(float value) { throw null; } public static System.Numerics.Vector3 Create(System.Numerics.Vector2 vector, float z) { throw null; } public static System.Numerics.Vector3 Create(float x, float y, float z) { throw null; } @@ -611,6 +614,7 @@ public partial struct Vector4 : System.IEquatable, Syst public static System.Numerics.Vector4 Abs(System.Numerics.Vector4 value) { throw null; } public static System.Numerics.Vector4 Add(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public static System.Numerics.Vector4 Clamp(System.Numerics.Vector4 value1, System.Numerics.Vector4 min, System.Numerics.Vector4 max) { throw null; } + public static System.Numerics.Vector4 CopySign(System.Numerics.Vector4 value, System.Numerics.Vector4 sign) { throw null; } public static System.Numerics.Vector4 Create(float value) { throw null; } public static System.Numerics.Vector4 Create(System.Numerics.Vector2 vector, float z, float w) { throw null; } public static System.Numerics.Vector4 Create(System.Numerics.Vector3 vector, float w) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index bf5295bf1ed7e5..4a02d4f28f841a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -521,6 +521,37 @@ public static Vector ConvertToUInt64Native(Vector value) return result; } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector CopySign(Vector value, Vector sign) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return value; + } + else if (IsHardwareAccelerated) + { + return VectorMath.CopySign, T>(value, sign); + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T element = Scalar.CopySign(value.GetElementUnsafe(index), sign.GetElementUnsafe(index)); + result.SetElementUnsafe(index, element); + } + + return result; + } + } + /// Creates a new instance with all elements initialized to the specified value. /// The type of the elements in the vector. /// The value that all elements will be initialized to. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index 18b1375f0c4f89..7bf1fd2df0f6bc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -277,6 +277,11 @@ public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) return Min(Max(value1, min), max); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 CopySign(Vector2 value, Vector2 sign) => Vector128.CopySign(value.AsVector128Unsafe(), sign.AsVector128Unsafe()).AsVector2(); + /// Creates a new object whose two elements have the same value. /// The value to assign to all two elements. /// A new whose two elements have the same value. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index f1c96451265065..97add35ee902e4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -298,6 +298,11 @@ public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) return Min(Max(value1, min), max); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 CopySign(Vector3 value, Vector3 sign) => Vector128.CopySign(value.AsVector128Unsafe(), sign.AsVector128Unsafe()).AsVector3(); + /// Creates a new object whose three elements have the same value. /// The value to assign to all three elements. /// A new whose three elements have the same value. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index c809ab0762c1da..405d24e9f68cf0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -317,6 +317,11 @@ public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max) return Min(Max(value1, min), max); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 CopySign(Vector4 value, Vector4 sign) => Vector128.CopySign(value.AsVector128(), sign.AsVector128()).AsVector4(); + /// Creates a new object whose four elements have the same value. /// The value to assign to all four elements. /// A new whose four elements have the same value. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index 061bd9c94780f7..7b92f20c53f0b6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -835,6 +835,9 @@ public bool TryCopyTo(Span destination) /// static Vector ISimdVector, T>.ConditionalSelect(Vector condition, Vector left, Vector right) => Vector.ConditionalSelect(condition, left, right); + /// + static Vector ISimdVector, T>.CopySign(Vector value, Vector sign) => Vector.CopySign(value, sign); + /// static void ISimdVector, T>.CopyTo(Vector vector, T[] destination) => vector.CopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs index a88b5f0dec6a1e..ca606a4c396ad5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs @@ -124,7 +124,13 @@ internal unsafe interface ISimdVector /// The vector that is selected when the corresponding bit in is zero. /// A vector whose bits come from or based on the value of . /// The type of the elements in the vector () is not supported. - static virtual TSelf ConditionalSelect(TSelf condition, TSelf left, TSelf right) => (left & condition) | (right & ~condition); + static virtual TSelf ConditionalSelect(TSelf condition, TSelf left, TSelf right) => (left & condition) | And(right & ~condition); + + /// Copies the per-element sign of a vector to the per-element sign of another vector. + /// The vector whose magnitude is used in the result. + /// The vector whose sign is used in the result. + /// A vector with the magnitude of and the sign of . + static abstract TSelf CopySign(TSelf value, TSelf sign); /// Copies a vector to a given array. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs index 1bccb11859d014..c5cb087094fd6d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs @@ -334,6 +334,46 @@ public static T Convert(int value) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T CopySign(T value, T sign) + { + // byte, ushort, uint, and ulong should have already been handled + // avoid Math.Abs for integers since it throws for MinValue + if (typeof(T) == typeof(double)) + { + return (T)(object)double.CopySign((double)(object)value, (double)(object)sign); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)short.CopySign((short)(object)value, (short)(object)sign); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)int.CopySign((int)(object)value, (int)(object)sign); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)long.CopySign((long)(object)value, (long)(object)sign); + } + else if (typeof(T) == typeof(nint)) + { + return (T)(object)nint.CopySign((nint)(object)value, (nint)(object)sign); + } + else if (typeof(T) == typeof(sbyte)) + { + return (T)(object)sbyte.CopySign((sbyte)(object)value, (sbyte)(object)sign); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.CopySign((float)(object)value, (float)(object)sign); + } + else + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); + return default!; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Divide(T left, T right) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index c92fa6a706b734..fca79d9e8c2b08 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -718,6 +718,32 @@ public static unsafe Vector128 ConvertToUInt64Native(Vector128 ve ); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 CopySign(Vector128 value, Vector128 sign) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return value; + } + else if (IsHardwareAccelerated) + { + return VectorMath.CopySign, T>(value, sign); + } + else + { + return Create( + Vector64.CopySign(value._lower, sign._lower), + Vector64.CopySign(value._upper, sign._upper) + ); + } + } + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index 50d5290d44a3d2..5ca6ba4200b91b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -482,6 +482,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector128 ISimdVector, T>.ConditionalSelect(Vector128 condition, Vector128 left, Vector128 right) => Vector128.ConditionalSelect(condition, left, right); + /// + static Vector128 ISimdVector, T>.CopySign(Vector128 value, Vector128 sign) => Vector128.CopySign(value, sign); + /// static void ISimdVector, T>.CopyTo(Vector128 vector, T[] destination) => vector.CopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 73d021ffc44475..7aeb2d4a89ffd5 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -557,6 +557,32 @@ public static Vector256 ConvertToUInt64Native(Vector256 vector) ); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 CopySign(Vector256 value, Vector256 sign) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return value; + } + else if (IsHardwareAccelerated) + { + return VectorMath.CopySign, T>(value, sign); + } + else + { + return Create( + Vector128.CopySign(value._lower, sign._lower), + Vector128.CopySign(value._upper, sign._upper) + ); + } + } + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index c4120a2c2febe5..9b66fb21e2fd38 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -471,6 +471,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector256 ISimdVector, T>.ConditionalSelect(Vector256 condition, Vector256 left, Vector256 right) => Vector256.ConditionalSelect(condition, left, right); + /// + static Vector256 ISimdVector, T>.CopySign(Vector256 value, Vector256 sign) => Vector256.CopySign(value, sign); + /// static void ISimdVector, T>.CopyTo(Vector256 vector, T[] destination) => vector.CopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index 7a80c3c393783e..b7ca8703d666e8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -486,6 +486,32 @@ public static Vector512 ConvertToUInt64Native(Vector512 vector) ); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 CopySign(Vector512 value, Vector512 sign) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return value; + } + else if (IsHardwareAccelerated) + { + return VectorMath.CopySign, T>(value, sign); + } + else + { + return Create( + Vector256.CopySign(value._lower, sign._lower), + Vector256.CopySign(value._upper, sign._upper) + ); + } + } + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs index 86a8acd8236605..0d3f622d852537 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs @@ -471,6 +471,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector512 ISimdVector, T>.ConditionalSelect(Vector512 condition, Vector512 left, Vector512 right) => Vector512.ConditionalSelect(condition, left, right); + /// + static Vector512 ISimdVector, T>.CopySign(Vector512 value, Vector512 sign) => Vector512.CopySign(value, sign); + /// static void ISimdVector, T>.CopyTo(Vector512 vector, T[] destination) => vector.CopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index f9b90a2f877ce9..ef42f6fd030ab8 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -496,6 +496,37 @@ public static unsafe Vector64 ConvertToUInt64Native(Vector64 vect return result; } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 CopySign(Vector64 value, Vector64 sign) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return value; + } + else if (IsHardwareAccelerated) + { + return VectorMath.CopySign, T>(value, sign); + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T element = Scalar.CopySign(value.GetElementUnsafe(index), sign.GetElementUnsafe(index)); + result.SetElementUnsafe(index, element); + } + + return result; + } + } + /// Copies a to a given array. /// The type of the elements in the vector. /// The vector to be copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index cca51261cf659b..984a8d2b06129d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -539,6 +539,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector64 ISimdVector, T>.ConditionalSelect(Vector64 condition, Vector64 left, Vector64 right) => Vector64.ConditionalSelect(condition, left, right); + /// + static Vector64 ISimdVector, T>.CopySign(Vector64 value, Vector64 sign) => Vector64.CopySign(value, sign); + /// static void ISimdVector, T>.CopyTo(Vector64 vector, T[] destination) => vector.CopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index f4a9f087c8597c..de3fe40fef3a3a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -9,6 +9,33 @@ namespace System.Runtime.Intrinsics { internal static class VectorMath { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector CopySign(TVector value, TVector sign) + where TVector : unmanaged, ISimdVector + { + Debug.Assert((typeof(T) != typeof(byte)) + && (typeof(T) != typeof(ushort)) + && (typeof(T) != typeof(uint)) + && (typeof(T) != typeof(ulong)) + && (typeof(T) != typeof(nuint))); + + if (typeof(T) == typeof(float)) + { + return TVector.ConditionalSelect(Create(-0.0f), sign, value); + } + else if (typeof(T) == typeof(double)) + { + return TVector.ConditionalSelect(Create(-0.0), sign, value); + } + else + { + // All values are two's complement and so `value ^ sign` will produce a positive + // number if the signs match and a negative number if the signs differ. When the + // signs differ we want to negate the value and otherwise take the value as is. + return TVector.ConditionalSelect(TVector.LessThan(value ^ sign, TVector.Zero), -value, value); + } + } + public static TVectorDouble ExpDouble(TVectorDouble x) where TVectorDouble : unmanaged, ISimdVector where TVectorUInt64 : unmanaged, ISimdVector @@ -876,6 +903,74 @@ private static TVectorSingle ConvertToSingle(TVecto return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVector Create(double value) + where TVector : unmanaged, ISimdVector + { + Unsafe.SkipInit(out TVector result); + + if (typeof(TVector) == typeof(Vector)) + { + result = (TVector)(object)Vector.Create(value); + } + else if (typeof(TVector) == typeof(Vector64)) + { + result = (TVector)(object)Vector64.Create(value); + } + else if (typeof(TVector) == typeof(Vector128)) + { + result = (TVector)(object)Vector128.Create(value); + } + else if (typeof(TVector) == typeof(Vector256)) + { + result = (TVector)(object)Vector256.Create(value); + } + else if (typeof(TVector) == typeof(Vector512)) + { + result = (TVector)(object)Vector512.Create(value); + } + else + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TVector Create(float value) + where TVector : unmanaged, ISimdVector + { + Unsafe.SkipInit(out TVector result); + + if (typeof(TVector) == typeof(Vector)) + { + result = (TVector)(object)Vector.Create(value); + } + else if (typeof(TVector) == typeof(Vector64)) + { + result = (TVector)(object)Vector64.Create(value); + } + else if (typeof(TVector) == typeof(Vector128)) + { + result = (TVector)(object)Vector128.Create(value); + } + else if (typeof(TVector) == typeof(Vector256)) + { + result = (TVector)(object)Vector256.Create(value); + } + else if (typeof(TVector) == typeof(Vector512)) + { + result = (TVector)(object)Vector512.Create(value); + } + else + { + ThrowHelper.ThrowNotSupportedException(); + } + + return result; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static TVectorSingle Narrow(TVectorDouble lower, TVectorDouble upper) where TVectorDouble : unmanaged, ISimdVector diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 2629c669e4608a..b1aa005ff71c9e 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -65,6 +65,7 @@ public static partial class Vector128 public static System.Runtime.Intrinsics.Vector128 ConvertToUInt64(System.Runtime.Intrinsics.Vector128 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector128 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 CopySign(System.Runtime.Intrinsics.Vector128 value, System.Runtime.Intrinsics.Vector128 sign) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, T[] destination, int startIndex) { } @@ -411,6 +412,7 @@ public static partial class Vector256 public static System.Runtime.Intrinsics.Vector256 ConvertToUInt64(System.Runtime.Intrinsics.Vector256 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector256 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 CopySign(System.Runtime.Intrinsics.Vector256 value, System.Runtime.Intrinsics.Vector256 sign) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, T[] destination, int startIndex) { } @@ -758,6 +760,7 @@ public static partial class Vector512 public static System.Runtime.Intrinsics.Vector512 ConvertToUInt64(System.Runtime.Intrinsics.Vector512 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector512 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 CopySign(System.Runtime.Intrinsics.Vector512 value, System.Runtime.Intrinsics.Vector512 sign) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, T[] destination, int startIndex) { } @@ -1102,6 +1105,7 @@ public static partial class Vector64 public static System.Runtime.Intrinsics.Vector64 ConvertToUInt64(System.Runtime.Intrinsics.Vector64 vector) { throw null; } [System.CLSCompliantAttribute(false)] public static System.Runtime.Intrinsics.Vector64 ConvertToUInt64Native(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 CopySign(System.Runtime.Intrinsics.Vector64 value, System.Runtime.Intrinsics.Vector64 sign) { throw null; } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, System.Span destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, T[] destination) { } public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, T[] destination, int startIndex) { } From a4507671547f3930caa342b7b9ea012c2071b9cc Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Jun 2024 17:28:10 -0700 Subject: [PATCH 05/39] Expose DegreesToRadians and RadiansToDegrees on the vector types --- .../ref/System.Numerics.Vectors.cs | 10 ++ .../src/System/Numerics/Vector.cs | 86 +++++++++++++++++ .../src/System/Numerics/Vector2.cs | 10 ++ .../src/System/Numerics/Vector3.cs | 10 ++ .../src/System/Numerics/Vector4.cs | 10 ++ .../System/Runtime/Intrinsics/Vector128.cs | 84 ++++++++++++++-- .../System/Runtime/Intrinsics/Vector256.cs | 72 ++++++++++++++ .../System/Runtime/Intrinsics/Vector512.cs | 72 ++++++++++++++ .../src/System/Runtime/Intrinsics/Vector64.cs | 96 +++++++++++++++++++ .../System/Runtime/Intrinsics/VectorMath.cs | 22 +++++ .../ref/System.Runtime.Intrinsics.cs | 16 ++++ 11 files changed, 482 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 14bb237a36bbbd..440da83d2fe6b2 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -263,6 +263,8 @@ public static partial class Vector public static System.Numerics.Vector Create(T value) { throw null; } public static System.Numerics.Vector Create(System.ReadOnlySpan values) { throw null; } public static System.Numerics.Vector CreateSequence(T start, T step) { throw null; } + public static System.Numerics.Vector DegreesToRadians(System.Numerics.Vector degrees) { throw null; } + public static System.Numerics.Vector DegreesToRadians(System.Numerics.Vector degrees) { throw null; } public static System.Numerics.Vector Divide(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Divide(System.Numerics.Vector left, T right) { throw null; } public static T Dot(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -343,6 +345,8 @@ public static partial class Vector public static System.Numerics.Vector Narrow(System.Numerics.Vector low, System.Numerics.Vector high) { throw null; } public static System.Numerics.Vector Negate(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector OnesComplement(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector RadiansToDegrees(System.Numerics.Vector radians) { throw null; } + public static System.Numerics.Vector RadiansToDegrees(System.Numerics.Vector radians) { throw null; } public static System.Numerics.Vector ShiftLeft(System.Numerics.Vector value, int shiftCount) { throw null; } public static System.Numerics.Vector ShiftLeft(System.Numerics.Vector value, int shiftCount) { throw null; } public static System.Numerics.Vector ShiftLeft(System.Numerics.Vector value, int shiftCount) { throw null; } @@ -461,6 +465,7 @@ public readonly void CopyTo(float[] array) { } public readonly void CopyTo(float[] array, int index) { } public readonly void CopyTo(System.Span destination) { } public readonly bool TryCopyTo(System.Span destination) { throw null; } + public static System.Numerics.Vector2 DegreesToRadians(System.Numerics.Vector2 degrees) { throw null; } public static float Distance(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public static float DistanceSquared(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public static System.Numerics.Vector2 Divide(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } @@ -494,6 +499,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector2 operator *(float left, System.Numerics.Vector2 right) { throw null; } public static System.Numerics.Vector2 operator -(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } public static System.Numerics.Vector2 operator -(System.Numerics.Vector2 value) { throw null; } + public static System.Numerics.Vector2 RadiansToDegrees(System.Numerics.Vector2 radians) { throw null; } public static System.Numerics.Vector2 Reflect(System.Numerics.Vector2 vector, System.Numerics.Vector2 normal) { throw null; } public static System.Numerics.Vector2 SquareRoot(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 Subtract(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } @@ -542,6 +548,7 @@ public readonly void CopyTo(float[] array, int index) { } public readonly void CopyTo(System.Span destination) { } public readonly bool TryCopyTo(System.Span destination) { throw null; } public static System.Numerics.Vector3 Cross(System.Numerics.Vector3 vector1, System.Numerics.Vector3 vector2) { throw null; } + public static System.Numerics.Vector3 DegreesToRadians(System.Numerics.Vector3 degrees) { throw null; } public static float Distance(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } public static float DistanceSquared(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } public static System.Numerics.Vector3 Divide(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } @@ -575,6 +582,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector3 operator *(float left, System.Numerics.Vector3 right) { throw null; } public static System.Numerics.Vector3 operator -(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } public static System.Numerics.Vector3 operator -(System.Numerics.Vector3 value) { throw null; } + public static System.Numerics.Vector3 RadiansToDegrees(System.Numerics.Vector3 radians) { throw null; } public static System.Numerics.Vector3 Reflect(System.Numerics.Vector3 vector, System.Numerics.Vector3 normal) { throw null; } public static System.Numerics.Vector3 SquareRoot(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 Subtract(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } @@ -624,6 +632,7 @@ public readonly void CopyTo(float[] array) { } public readonly void CopyTo(float[] array, int index) { } public readonly void CopyTo(System.Span destination) { } public readonly bool TryCopyTo(System.Span destination) { throw null; } + public static System.Numerics.Vector4 DegreesToRadians(System.Numerics.Vector4 degrees) { throw null; } public static float Distance(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } public static float DistanceSquared(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } public static System.Numerics.Vector4 Divide(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } @@ -657,6 +666,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector4 operator *(float left, System.Numerics.Vector4 right) { throw null; } public static System.Numerics.Vector4 operator -(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public static System.Numerics.Vector4 operator -(System.Numerics.Vector4 value) { throw null; } + public static System.Numerics.Vector4 RadiansToDegrees(System.Numerics.Vector4 radians) { throw null; } public static System.Numerics.Vector4 SquareRoot(System.Numerics.Vector4 value) { throw null; } public static System.Numerics.Vector4 Subtract(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public override readonly string ToString() { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 4a02d4f28f841a..c65c26ef445ec2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -627,6 +627,50 @@ internal static Vector CreateScalarUnsafe(T value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector CreateSequence(T start, T step) => (Vector.Indices * step) + Create(start); + internal static Vector DegreesToRadians(Vector degrees) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.DegreesToRadians(degrees.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector DegreesToRadians(Vector degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, double>(degrees); + } + else + { + return DegreesToRadians(degrees); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector DegreesToRadians(Vector degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, float>(degrees); + } + else + { + return DegreesToRadians(degrees); + } + } + /// Divides two vectors to compute their quotient. /// The vector that will be divided by . /// The vector that will divide . @@ -1704,6 +1748,48 @@ public static Vector Narrow(Vector low, Vector high) [Intrinsic] public static Vector OnesComplement(Vector value) => ~value; + internal static Vector RadiansToDegrees(Vector radians) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.RadiansToDegrees(radians.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [Intrinsic] + public static Vector RadiansToDegrees(Vector radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, double>(radians); + } + else + { + return RadiansToDegrees(radians); + } + } + + /// + [Intrinsic] + public static Vector RadiansToDegrees(Vector radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, float>(radians); + } + else + { + return RadiansToDegrees(radians); + } + } + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index 7bf1fd2df0f6bc..2e19c93c746544 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -320,6 +320,11 @@ public static Vector2 Create(ReadOnlySpan values) [Intrinsic] internal static Vector2 CreateScalarUnsafe(float x) => Vector128.CreateScalarUnsafe(x).AsVector2(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 DegreesToRadians(Vector2 degrees) => Vector128.DegreesToRadians(degrees.AsVector128Unsafe()).AsVector2(); + /// Computes the Euclidean distance between the two given points. /// The first point. /// The second point. @@ -439,6 +444,11 @@ public static Vector2 Create(ReadOnlySpan values) [Intrinsic] public static Vector2 Normalize(Vector2 value) => value / value.Length(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 RadiansToDegrees(Vector2 radians) => Vector128.RadiansToDegrees(radians.AsVector128Unsafe()).AsVector2(); + /// Returns the reflection of a vector off a surface that has the specified normal. /// The source vector. /// The normal of the surface being reflected off. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index 97add35ee902e4..d9695ed0f88fce 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -377,6 +377,11 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) ).AsVector3(); } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 DegreesToRadians(Vector3 degrees) => Vector128.DegreesToRadians(degrees.AsVector128Unsafe()).AsVector3(); + /// Computes the Euclidean distance between the two given points. /// The first point. /// The second point. @@ -493,6 +498,11 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) [Intrinsic] public static Vector3 Normalize(Vector3 value) => value / value.Length(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 RadiansToDegrees(Vector3 radians) => Vector128.RadiansToDegrees(radians.AsVector128Unsafe()).AsVector3(); + /// Returns the reflection of a vector off a surface that has the specified normal. /// The source vector. /// The normal of the surface being reflected off. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 405d24e9f68cf0..870511616c434b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -382,6 +382,11 @@ public static Vector4 Create(Vector3 vector, float w) [Intrinsic] internal static Vector4 CreateScalarUnsafe(float x) => Vector128.CreateScalarUnsafe(x).AsVector4(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 DegreesToRadians(Vector4 degrees) => Vector128.DegreesToRadians(degrees.AsVector128()).AsVector4(); + /// Computes the Euclidean distance between the two given points. /// The first point. /// The second point. @@ -501,6 +506,11 @@ public static Vector4 Create(Vector3 vector, float w) [Intrinsic] public static Vector4 Normalize(Vector4 vector) => vector / vector.Length(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 RadiansToDegrees(Vector4 radians) => Vector128.RadiansToDegrees(radians.AsVector128()).AsVector4(); + /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index fca79d9e8c2b08..49929407eb1284 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -989,7 +989,7 @@ public static Vector128 Create(ReadOnlySpan values) public static unsafe Vector128 Create(byte e0, byte e1, byte e2, byte e3, byte e4, byte e5, byte e6, byte e7, byte e8, byte e9, byte e10, byte e11, byte e12, byte e13, byte e14, byte e15) { return Create( - Vector64.Create(e0, e1, e2, e3, e4, e5, e6, e7), + Vector64.Create(e0, e1, e2, e3, e4, e5, e6, e7), Vector64.Create(e8, e9, e10, e11, e12, e13, e14, e15) ); } @@ -1087,7 +1087,7 @@ public static unsafe Vector128 Create(long e0, long e1) public static unsafe Vector128 Create(sbyte e0, sbyte e1, sbyte e2, sbyte e3, sbyte e4, sbyte e5, sbyte e6, sbyte e7, sbyte e8, sbyte e9, sbyte e10, sbyte e11, sbyte e12, sbyte e13, sbyte e14, sbyte e15) { return Create( - Vector64.Create(e0, e1, e2, e3, e4, e5, e6, e7), + Vector64.Create(e0, e1, e2, e3, e4, e5, e6, e7), Vector64.Create(e8, e9, e10, e11, e12, e13, e14, e15) ); } @@ -1467,6 +1467,42 @@ public static Vector128 CreateScalarUnsafe(T value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 CreateSequence(T start, T step) => (Vector128.Indices * step) + Create(start); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 DegreesToRadians(Vector128 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, double>(degrees); + } + else + { + return Create( + Vector64.DegreesToRadians(degrees._lower), + Vector64.DegreesToRadians(degrees._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 DegreesToRadians(Vector128 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, float>(degrees); + } + else + { + return Create( + Vector64.DegreesToRadians(degrees._lower), + Vector64.DegreesToRadians(degrees._upper) + ); + } + } + /// Divides two vectors to compute their quotient. /// The type of the elements in the vector. /// The vector that will be divided by . @@ -2150,10 +2186,10 @@ public static unsafe Vector128 Narrow(Vector128 lower, Vector128 Narrow(Vector128 lower, Vector128 upper) { - return Create( - Vector64.Narrow(lower._lower, lower._upper), - Vector64.Narrow(upper._lower, upper._upper) - ); + return Create( + Vector64.Narrow(lower._lower, lower._upper), + Vector64.Narrow(upper._lower, upper._upper) + ); } /// Narrows two instances into one . @@ -2217,6 +2253,42 @@ public static unsafe Vector128 Narrow(Vector128 lower, Vector128
    OnesComplement(Vector128 vector) => ~vector; + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 RadiansToDegrees(Vector128 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, double>(radians); + } + else + { + return Create( + Vector64.RadiansToDegrees(radians._lower), + Vector64.RadiansToDegrees(radians._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 RadiansToDegrees(Vector128 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, float>(radians); + } + else + { + return Create( + Vector64.RadiansToDegrees(radians._lower), + Vector64.RadiansToDegrees(radians._upper) + ); + } + } + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 7aeb2d4a89ffd5..f9d1ae02ba3ffb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -1385,6 +1385,42 @@ public static Vector256 CreateScalarUnsafe(T value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 CreateSequence(T start, T step) => (Vector256.Indices * step) + Create(start); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 DegreesToRadians(Vector256 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, double>(degrees); + } + else + { + return Create( + Vector128.DegreesToRadians(degrees._lower), + Vector128.DegreesToRadians(degrees._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 DegreesToRadians(Vector256 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, float>(degrees); + } + else + { + return Create( + Vector128.DegreesToRadians(degrees._lower), + Vector128.DegreesToRadians(degrees._upper) + ); + } + } + /// Divides two vectors to compute their quotient. /// The type of the elements in the vector. /// The vector that will be divided by . @@ -2133,6 +2169,42 @@ public static Vector256 Narrow(Vector256 lower, Vector256 up [Intrinsic] public static Vector256 OnesComplement(Vector256 vector) => ~vector; + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 RadiansToDegrees(Vector256 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, double>(radians); + } + else + { + return Create( + Vector128.RadiansToDegrees(radians._lower), + Vector128.RadiansToDegrees(radians._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 RadiansToDegrees(Vector256 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, float>(radians); + } + else + { + return Create( + Vector128.RadiansToDegrees(radians._lower), + Vector128.RadiansToDegrees(radians._upper) + ); + } + } + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index b7ca8703d666e8..2478eb5118b665 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -1447,6 +1447,42 @@ public static Vector512 CreateScalarUnsafe(T value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 CreateSequence(T start, T step) => (Vector512.Indices * step) + Create(start); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 DegreesToRadians(Vector512 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, double>(degrees); + } + else + { + return Create( + Vector256.DegreesToRadians(degrees._lower), + Vector256.DegreesToRadians(degrees._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 DegreesToRadians(Vector512 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, float>(degrees); + } + else + { + return Create( + Vector256.DegreesToRadians(degrees._lower), + Vector256.DegreesToRadians(degrees._upper) + ); + } + } + /// Divides two vectors to compute their quotient. /// The type of the elements in the vector. /// The vector that will be divided by . @@ -2195,6 +2231,42 @@ public static Vector512 Narrow(Vector512 lower, Vector512 up [Intrinsic] public static Vector512 OnesComplement(Vector512 vector) => ~vector; + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 RadiansToDegrees(Vector512 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, double>(radians); + } + else + { + return Create( + Vector256.RadiansToDegrees(radians._lower), + Vector256.RadiansToDegrees(radians._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 RadiansToDegrees(Vector512 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, float>(radians); + } + else + { + return Create( + Vector256.RadiansToDegrees(radians._lower), + Vector256.RadiansToDegrees(radians._upper) + ); + } + } + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index ef42f6fd030ab8..0c306daf84e6f4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -1085,6 +1085,54 @@ public static Vector64 CreateScalarUnsafe(T value) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector64 CreateSequence(T start, T step) => (Vector64.Indices * step) + Create(start); + internal static Vector64 DegreesToRadians(Vector64 degrees) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = T.DegreesToRadians(degrees.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Converts a given vector from degrees to radians. + /// The vector to convert to radians. + /// The vector of converted to radians. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 DegreesToRadians(Vector64 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, double>(degrees); + } + else + { + return DegreesToRadians(degrees); + } + } + + /// Converts a given vector from degrees to radians. + /// The vector to convert to radians. + /// The vector of converted to radians. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 DegreesToRadians(Vector64 degrees) + { + if (IsHardwareAccelerated) + { + return VectorMath.DegreesToRadians, float>(degrees); + } + else + { + return DegreesToRadians(degrees); + } + } + /// Divides two vectors to compute their quotient. /// The type of the elements in the vector. /// The vector that will be divided by . @@ -2071,6 +2119,54 @@ public static unsafe Vector64 Narrow(Vector64 lower, Vector64 OnesComplement(Vector64 vector) => ~vector; + internal static Vector64 RadiansToDegrees(Vector64 radians) + where T : ITrigonometricFunctions + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = T.RadiansToDegrees(radians.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Converts a given vector from radians to degrees. + /// The vector to convert to degrees. + /// The vector of converted to degrees. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 RadiansToDegrees(Vector64 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, double>(radians); + } + else + { + return RadiansToDegrees(radians); + } + } + + /// Converts a given vector from radians to degrees. + /// The vector to convert to degrees. + /// The vector of converted to degrees. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 RadiansToDegrees(Vector64 radians) + { + if (IsHardwareAccelerated) + { + return VectorMath.RadiansToDegrees, float>(radians); + } + else + { + return RadiansToDegrees(radians); + } + } + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index de3fe40fef3a3a..bc1ca2fedd2320 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -36,6 +36,17 @@ public static TVector CopySign(TVector value, TVector sign) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector DegreesToRadians(TVector degrees) + where TVector : unmanaged, ISimdVector + where T : IFloatingPointIeee754 + { + // NOTE: Don't change the algorithm without consulting the DIM + // which elaborates on why this implementation was chosen + + return (degrees * TVector.Create(T.Pi)) / TVector.Create(T.CreateTruncating(180)); + } + public static TVectorDouble ExpDouble(TVectorDouble x) where TVectorDouble : unmanaged, ISimdVector where TVectorUInt64 : unmanaged, ISimdVector @@ -833,6 +844,17 @@ public static TVectorSingle Log2Single(TVector radians) + where TVector : unmanaged, ISimdVector + where T : IFloatingPointIeee754 + { + // NOTE: Don't change the algorithm without consulting the DIM + // which elaborates on why this implementation was chosen + + return (radians * TVector.Create(T.CreateTruncating(180))) / TVector.Create(T.Pi); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static TVectorDouble ConvertToDouble(TVectorInt64 vector) where TVectorDouble : unmanaged, ISimdVector diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index b1aa005ff71c9e..a416172d02b230 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -160,6 +160,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static System.Runtime.Intrinsics.Vector128 Create(T value) { throw null; } public static System.Runtime.Intrinsics.Vector128 Create(T[] values) { throw null; } public static System.Runtime.Intrinsics.Vector128 Create(T[] values, int index) { throw null; } + public static System.Runtime.Intrinsics.Vector128 DegreesToRadians(System.Runtime.Intrinsics.Vector128 degrees) { throw null; } + public static System.Runtime.Intrinsics.Vector128 DegreesToRadians(System.Runtime.Intrinsics.Vector128 degrees) { throw null; } public static System.Runtime.Intrinsics.Vector128 Divide(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Divide(System.Runtime.Intrinsics.Vector128 left, T right) { throw null; } public static T Dot(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } @@ -224,6 +226,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static System.Runtime.Intrinsics.Vector128 Narrow(System.Runtime.Intrinsics.Vector128 lower, System.Runtime.Intrinsics.Vector128 upper) { throw null; } public static System.Runtime.Intrinsics.Vector128 Negate(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 OnesComplement(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 RadiansToDegrees(System.Runtime.Intrinsics.Vector128 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector128 RadiansToDegrees(System.Runtime.Intrinsics.Vector128 radians) { throw null; } public static System.Runtime.Intrinsics.Vector128 ShiftLeft(System.Runtime.Intrinsics.Vector128 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector128 ShiftLeft(System.Runtime.Intrinsics.Vector128 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector128 ShiftLeft(System.Runtime.Intrinsics.Vector128 vector, int shiftCount) { throw null; } @@ -508,6 +512,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static System.Runtime.Intrinsics.Vector256 Create(T value) { throw null; } public static System.Runtime.Intrinsics.Vector256 Create(T[] values) { throw null; } public static System.Runtime.Intrinsics.Vector256 Create(T[] values, int index) { throw null; } + public static System.Runtime.Intrinsics.Vector256 DegreesToRadians(System.Runtime.Intrinsics.Vector256 degrees) { throw null; } + public static System.Runtime.Intrinsics.Vector256 DegreesToRadians(System.Runtime.Intrinsics.Vector256 degrees) { throw null; } public static System.Runtime.Intrinsics.Vector256 Divide(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Divide(System.Runtime.Intrinsics.Vector256 left, T right) { throw null; } public static T Dot(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } @@ -572,6 +578,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static System.Runtime.Intrinsics.Vector256 Narrow(System.Runtime.Intrinsics.Vector256 lower, System.Runtime.Intrinsics.Vector256 upper) { throw null; } public static System.Runtime.Intrinsics.Vector256 Negate(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 OnesComplement(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 RadiansToDegrees(System.Runtime.Intrinsics.Vector256 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector256 RadiansToDegrees(System.Runtime.Intrinsics.Vector256 radians) { throw null; } public static System.Runtime.Intrinsics.Vector256 ShiftLeft(System.Runtime.Intrinsics.Vector256 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector256 ShiftLeft(System.Runtime.Intrinsics.Vector256 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector256 ShiftLeft(System.Runtime.Intrinsics.Vector256 vector, int shiftCount) { throw null; } @@ -857,6 +865,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 Create(T value) { throw null; } public static System.Runtime.Intrinsics.Vector512 Create(T[] values) { throw null; } public static System.Runtime.Intrinsics.Vector512 Create(T[] values, int index) { throw null; } + public static System.Runtime.Intrinsics.Vector512 DegreesToRadians(System.Runtime.Intrinsics.Vector512 degrees) { throw null; } + public static System.Runtime.Intrinsics.Vector512 DegreesToRadians(System.Runtime.Intrinsics.Vector512 degrees) { throw null; } public static System.Runtime.Intrinsics.Vector512 Divide(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Divide(System.Runtime.Intrinsics.Vector512 left, T right) { throw null; } public static T Dot(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } @@ -921,6 +931,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 Narrow(System.Runtime.Intrinsics.Vector512 lower, System.Runtime.Intrinsics.Vector512 upper) { throw null; } public static System.Runtime.Intrinsics.Vector512 Negate(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 OnesComplement(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 RadiansToDegrees(System.Runtime.Intrinsics.Vector512 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector512 RadiansToDegrees(System.Runtime.Intrinsics.Vector512 radians) { throw null; } public static System.Runtime.Intrinsics.Vector512 ShiftLeft(System.Runtime.Intrinsics.Vector512 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector512 ShiftLeft(System.Runtime.Intrinsics.Vector512 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector512 ShiftLeft(System.Runtime.Intrinsics.Vector512 vector, int shiftCount) { throw null; } @@ -1177,6 +1189,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static System.Runtime.Intrinsics.Vector64 Create(T value) { throw null; } public static System.Runtime.Intrinsics.Vector64 Create(T[] values) { throw null; } public static System.Runtime.Intrinsics.Vector64 Create(T[] values, int index) { throw null; } + public static System.Runtime.Intrinsics.Vector64 DegreesToRadians(System.Runtime.Intrinsics.Vector64 degrees) { throw null; } + public static System.Runtime.Intrinsics.Vector64 DegreesToRadians(System.Runtime.Intrinsics.Vector64 degrees) { throw null; } public static System.Runtime.Intrinsics.Vector64 Divide(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Divide(System.Runtime.Intrinsics.Vector64 left, T right) { throw null; } public static T Dot(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } @@ -1239,6 +1253,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static System.Runtime.Intrinsics.Vector64 Narrow(System.Runtime.Intrinsics.Vector64 lower, System.Runtime.Intrinsics.Vector64 upper) { throw null; } public static System.Runtime.Intrinsics.Vector64 Negate(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 OnesComplement(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 RadiansToDegrees(System.Runtime.Intrinsics.Vector64 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector64 RadiansToDegrees(System.Runtime.Intrinsics.Vector64 radians) { throw null; } public static System.Runtime.Intrinsics.Vector64 ShiftLeft(System.Runtime.Intrinsics.Vector64 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector64 ShiftLeft(System.Runtime.Intrinsics.Vector64 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector64 ShiftLeft(System.Runtime.Intrinsics.Vector64 vector, int shiftCount) { throw null; } From 87e13a07703983615c97379732de2d0ff15a7471 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Jun 2024 23:19:46 -0700 Subject: [PATCH 06/39] Expose Hypot on the vector types --- .../ref/System.Numerics.Vectors.cs | 5 + .../src/System/Numerics/Vector.cs | 42 +++++ .../src/System/Numerics/Vector2.cs | 5 + .../src/System/Numerics/Vector3.cs | 5 + .../src/System/Numerics/Vector4.cs | 5 + .../System/Runtime/Intrinsics/Vector128.cs | 34 ++++ .../System/Runtime/Intrinsics/Vector256.cs | 34 ++++ .../System/Runtime/Intrinsics/Vector512.cs | 34 ++++ .../src/System/Runtime/Intrinsics/Vector64.cs | 48 +++++ .../System/Runtime/Intrinsics/VectorMath.cs | 164 ++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 8 + 11 files changed, 384 insertions(+) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 440da83d2fe6b2..61e24e38b1775a 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -296,6 +296,8 @@ public static partial class Vector public static bool GreaterThanOrEqualAny(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector GreaterThanOrEqual(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector GreaterThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector Hypot(System.Numerics.Vector x, System.Numerics.Vector y) { throw null; } + public static System.Numerics.Vector Hypot(System.Numerics.Vector x, System.Numerics.Vector y) { throw null; } public static System.Numerics.Vector LessThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector LessThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector LessThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -476,6 +478,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector2 Exp(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 FusedMultiplyAdd(System.Numerics.Vector2 left, System.Numerics.Vector2 right, System.Numerics.Vector2 addend) { throw null; } public override readonly int GetHashCode() { throw null; } + public static System.Numerics.Vector2 Hypot(System.Numerics.Vector2 x, System.Numerics.Vector2 y) { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } public static System.Numerics.Vector2 Lerp(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2, float amount) { throw null; } @@ -561,6 +564,7 @@ public readonly void CopyTo(System.Span destination) { } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } + public static System.Numerics.Vector3 Hypot(System.Numerics.Vector3 x, System.Numerics.Vector3 y) { throw null; } public static System.Numerics.Vector3 Lerp(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2, float amount) { throw null; } public static System.Numerics.Vector3 Log(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 Log2(System.Numerics.Vector3 vector) { throw null; } @@ -645,6 +649,7 @@ public readonly void CopyTo(System.Span destination) { } public override readonly int GetHashCode() { throw null; } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } + public static System.Numerics.Vector4 Hypot(System.Numerics.Vector4 x, System.Numerics.Vector4 y) { throw null; } public static System.Numerics.Vector4 Lerp(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2, float amount) { throw null; } public static System.Numerics.Vector4 Log(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 Log2(System.Numerics.Vector4 vector) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index c65c26ef445ec2..a974d0b30ff24c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -1128,6 +1128,48 @@ public static bool GreaterThanOrEqualAny(Vector left, Vector right) return false; } + internal static Vector Hypot(Vector x, Vector y) + where T : IRootFunctions + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.Hypot(x.GetElementUnsafe(index), y.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Hypot(Vector x, Vector y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotDouble, Vector>(x, y); + } + else + { + return Hypot(x, y); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Hypot(Vector x, Vector y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector>(x, y); + } + else + { + return Hypot(x, y); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The vector to compare with . /// The vector to compare with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index 2e19c93c746544..8f298b24d96974 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -370,6 +370,11 @@ public static Vector2 Create(ReadOnlySpan values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 FusedMultiplyAdd(Vector2 left, Vector2 right, Vector2 addend) => Vector128.FusedMultiplyAdd(left.AsVector128Unsafe(), right.AsVector128Unsafe(), addend.AsVector128Unsafe()).AsVector2(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Hypot(Vector2 x, Vector2 y) => Vector128.Hypot(x.AsVector128Unsafe(), y.AsVector128Unsafe()).AsVector2(); + /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index d9695ed0f88fce..885958fd1e968a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -427,6 +427,11 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 FusedMultiplyAdd(Vector3 left, Vector3 right, Vector3 addend) => Vector128.FusedMultiplyAdd(left.AsVector128Unsafe(), right.AsVector128Unsafe(), addend.AsVector128Unsafe()).AsVector3(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Hypot(Vector3 x, Vector3 y) => Vector128.Hypot(x.AsVector128Unsafe(), y.AsVector128Unsafe()).AsVector3(); + /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 870511616c434b..20dec14a924c03 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -432,6 +432,11 @@ public static Vector4 Create(Vector3 vector, float w) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 FusedMultiplyAdd(Vector4 left, Vector4 right, Vector4 addend) => Vector128.FusedMultiplyAdd(left.AsVector128(), right.AsVector128(), addend.AsVector128()).AsVector4(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Hypot(Vector4 x, Vector4 y) => Vector128.Hypot(x.AsVector128(), y.AsVector128()).AsVector4(); + /// Performs a linear interpolation between two vectors based on the given weighting. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 49929407eb1284..1d0fb4f1197224 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -1816,6 +1816,40 @@ public static bool GreaterThanOrEqualAny(Vector128 left, Vector128 righ || Vector64.GreaterThanOrEqualAny(left._upper, right._upper); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Hypot(Vector128 x, Vector128 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotDouble, Vector128>(x, y); + } + else + { + return Create( + Vector64.Hypot(x._lower, y._lower), + Vector64.Hypot(x._upper, y._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Hypot(Vector128 x, Vector128 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector128>(x, y); + } + else + { + return Create( + Vector64.Hypot(x._lower, y._lower), + Vector64.Hypot(x._upper, y._upper) + ); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index f9d1ae02ba3ffb..88f50a36ecb45e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -1732,6 +1732,40 @@ public static bool GreaterThanOrEqualAny(Vector256 left, Vector256 righ || Vector128.GreaterThanOrEqualAny(left._upper, right._upper); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Hypot(Vector256 x, Vector256 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotDouble, Vector256>(x, y); + } + else + { + return Create( + Vector128.Hypot(x._lower, y._lower), + Vector128.Hypot(x._upper, y._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Hypot(Vector256 x, Vector256 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector256>(x, y); + } + else + { + return Create( + Vector128.Hypot(x._lower, y._lower), + Vector128.Hypot(x._upper, y._upper) + ); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index 2478eb5118b665..108ded6cf40552 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -1795,6 +1795,40 @@ public static bool GreaterThanOrEqualAny(Vector512 left, Vector512 righ || Vector256.GreaterThanOrEqualAny(left._upper, right._upper); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Hypot(Vector512 x, Vector512 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotDouble, Vector512>(x, y); + } + else + { + return Create( + Vector256.Hypot(x._lower, y._lower), + Vector256.Hypot(x._upper, y._upper) + ); + } + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Hypot(Vector512 x, Vector512 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector512>(x, y); + } + else + { + return Create( + Vector256.Hypot(x._lower, y._lower), + Vector256.Hypot(x._upper, y._upper) + ); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index 0c306daf84e6f4..6f327112883156 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -1518,6 +1518,54 @@ public static bool GreaterThanOrEqualAny(Vector64 left, Vector64 right) return false; } + internal static Vector64 Hypot(Vector64 x, Vector64 y) + where T : IRootFunctions + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = T.Hypot(x.GetElementUnsafe(index), y.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Computes the hypotenuse given two vectors representing the lengths of the shorter sides in a right-angled triangle. + /// The vector to square and add to . + /// The vector to square and add to . + /// The square root of -squared plus -squared. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Hypot(Vector64 x, Vector64 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotDouble, Vector64>(x, y); + } + else + { + return Hypot(x, y); + } + } + + /// Computes the hypotenuse given two vectors representing the lengths of the shorter sides in a right-angled triangle. + /// The vector to square and add to . + /// The vector to square and add to . + /// The square root of -squared plus -squared. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Hypot(Vector64 x, Vector64 y) + { + if (IsHardwareAccelerated) + { + return VectorMath.HypotSingle, Vector64>(x, y); + } + else + { + return Hypot(x, y); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index bc1ca2fedd2320..49e67d649df70f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -282,6 +282,170 @@ public static TVectorSingle ExpSingle(TVectorDouble x, TVectorDouble y) + where TVectorDouble : unmanaged, ISimdVector + where TVectorUInt64 : unmanaged, ISimdVector + { + // This code is based on `hypot` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + TVectorDouble ax = TVectorDouble.Abs(x); + TVectorDouble ay = TVectorDouble.Abs(y); + + TVectorDouble positiveInfinity = TVectorDouble.Create(float.PositiveInfinity); + TVectorDouble infinityMask = TVectorDouble.Equals(ax, positiveInfinity) | TVectorDouble.Equals(ay, positiveInfinity); + TVectorDouble notNaNMask = TVectorDouble.Equals(ax, ax) & TVectorDouble.Equals(ay, ay); + + TVectorUInt64 xBits = Unsafe.BitCast(ax); + TVectorUInt64 yBits = Unsafe.BitCast(ay); + + TVectorUInt64 shiftedExponentMask = TVectorUInt64.Create(double.ShiftedExponentMask); + TVectorUInt64 xExp = (xBits >> double.BiasedExponentShift) & shiftedExponentMask; + TVectorUInt64 yExp = (yBits >> double.BiasedExponentShift) & shiftedExponentMask; + + TVectorUInt64 expDiff = xExp - yExp; + + // To prevent overflow, scale down by 2^+600 + TVectorUInt64 expBiasP500 = TVectorUInt64.Create(double.ExponentBias + 500); + TVectorUInt64 scaleDownMask = TVectorUInt64.GreaterThan(xExp, expBiasP500) | TVectorUInt64.GreaterThan(yExp, expBiasP500); + TVectorDouble expFix = TVectorDouble.ConditionalSelect(Unsafe.BitCast(scaleDownMask), TVectorDouble.Create(4.149515568880993E+180), TVectorDouble.One); + TVectorUInt64 bitsFix = scaleDownMask & TVectorUInt64.Create(0xDA80000000000000); + + // To prevent underflow, scale up by 2^-600, but only if we didn't scale down already + TVectorUInt64 expBiasM500 = TVectorUInt64.Create(double.ExponentBias - 500); + TVectorUInt64 scaleUpMask = TVectorUInt64.AndNot(TVectorUInt64.LessThan(xExp, expBiasM500) | TVectorUInt64.LessThan(yExp, expBiasM500), scaleDownMask); + expFix = TVectorDouble.ConditionalSelect(Unsafe.BitCast(scaleUpMask), TVectorDouble.Create(2.409919865102884E-181), expFix); + bitsFix = TVectorUInt64.ConditionalSelect(scaleUpMask, TVectorUInt64.Create(0x2580000000000000), bitsFix); + + xBits += bitsFix; + yBits += bitsFix; + + // For subnormal values when scaling up, do an additional fixing + // up changing the adjustment to scale up by 2^601 instead and then + // subtract a correction of 2^601 to account for the implicit bit. + + TVectorDouble subnormalFix = TVectorDouble.Create(9.232978617785736E-128); + TVectorUInt64 subnormalBitsFix = TVectorUInt64.Create(0x0010000000000000); + + TVectorUInt64 xSubnormalMask = TVectorUInt64.Equals(xExp, TVectorUInt64.Zero) & scaleUpMask; + xBits += subnormalBitsFix & xSubnormalMask; + ax = Unsafe.BitCast(xBits); + ax -= subnormalFix & Unsafe.BitCast(xSubnormalMask); + + TVectorUInt64 ySubnormalMask = TVectorUInt64.Equals(yExp, TVectorUInt64.Zero) & scaleUpMask; + yBits += subnormalBitsFix & ySubnormalMask; + ay = Unsafe.BitCast(yBits); + ay -= subnormalFix & Unsafe.BitCast(ySubnormalMask); + + xBits = Unsafe.BitCast(ax); + yBits = Unsafe.BitCast(ay); + + // Sort so ax is greater than ay + TVectorDouble lessThanMask = TVectorDouble.LessThan(ax, ay); + + TVectorDouble tmp = ax; + ax = TVectorDouble.ConditionalSelect(lessThanMask, ay, ax); + ay = TVectorDouble.ConditionalSelect(lessThanMask, tmp, ay); + + TVectorUInt64 tmpBits = xBits; + xBits = TVectorUInt64.ConditionalSelect(Unsafe.BitCast(lessThanMask), yBits, xBits); + yBits = TVectorUInt64.ConditionalSelect(Unsafe.BitCast(lessThanMask), tmpBits, yBits); + + Debug.Assert(TVectorDouble.GreaterThanOrEqualAll(ax, ay)); + + // Split ax and ay into a head and tail portion + + TVectorUInt64 headMask = TVectorUInt64.Create(0xFFFF_FFFF_F800_0000); + TVectorDouble xHead = Unsafe.BitCast(xBits & headMask); + TVectorDouble yHead = Unsafe.BitCast(yBits & headMask); + + TVectorDouble xTail = ax - xHead; + TVectorDouble yTail = ay - yHead; + + // Compute (x * x) + (y * y) with extra precision + // + // This includes taking into account expFix which may + // cause an underflow or overflow, but if it does that + // will still be the correct result. + + TVectorDouble xx = ax * ax; + TVectorDouble yy = ay * ay; + + TVectorDouble rHead = xx + yy; + TVectorDouble rTail = (xx - rHead) + yy; + + rTail += (xHead * xHead) - xx; + rTail += xHead * 2 * xTail; + rTail += xTail * xTail; + + // We only need to do extra accounting when ax and ay have equal exponents + TVectorDouble equalExponentsMask = Unsafe.BitCast(TVectorUInt64.Equals(expDiff, TVectorUInt64.Zero)); + + TVectorDouble rTailTmp = rTail; + + rTailTmp += (yHead * yHead) - yy; + rTailTmp += yHead * 2 * yTail; + rTailTmp += yTail * yTail; + + rTail = TVectorDouble.ConditionalSelect(equalExponentsMask, rTailTmp, rTail); + + TVectorDouble result = TVectorDouble.Sqrt(rHead + rTail) * expFix; + + // IEEE 754 requires that we return +Infinity + // if either input is Infinity, even if one of + // the inputs is NaN. Otherwise if either input + // is NaN, we return NaN + + result = TVectorDouble.ConditionalSelect(notNaNMask, result, TVectorDouble.Create(double.NaN)); + result = TVectorDouble.ConditionalSelect(infinityMask, TVectorDouble.Create(double.PositiveInfinity), result); + + return result; + } + + public static TVectorSingle HypotSingle(TVectorSingle x, TVectorSingle y) + where TVectorSingle : unmanaged, ISimdVector + where TVectorDouble : unmanaged, ISimdVector + { + // This code is based on `hypotf` from amd/aocl-libm-ose + // Copyright (C) 2008-2020 Advanced Micro Devices, Inc. All rights reserved. + // + // Licensed under the BSD 3-Clause "New" or "Revised" License + // See THIRD-PARTY-NOTICES.TXT for the full license text + + TVectorSingle ax = TVectorSingle.Abs(x); + TVectorSingle ay = TVectorSingle.Abs(y); + + TVectorSingle positiveInfinity = TVectorSingle.Create(float.PositiveInfinity); + TVectorSingle infinityMask = TVectorSingle.Equals(ax, positiveInfinity) | TVectorSingle.Equals(ay, positiveInfinity); + TVectorSingle notNaNMask = TVectorSingle.Equals(ax, ax) & TVectorSingle.Equals(ay, ay); + + (TVectorDouble xxLower, TVectorDouble xxUpper) = Widen(ax); + xxLower *= xxLower; + xxUpper *= xxUpper; + + (TVectorDouble yyLower, TVectorDouble yyUpper) = Widen(ay); + yyLower *= yyLower; + yyUpper *= yyUpper; + + TVectorSingle result = Narrow( + TVectorDouble.Sqrt(xxLower + yyLower), + TVectorDouble.Sqrt(xxUpper + yyUpper) + ); + + // IEEE 754 requires that we return +Infinity + // if either input is Infinity, even if one of + // the inputs is NaN. Otherwise if either input + // is NaN, we return NaN + + result = TVectorSingle.ConditionalSelect(notNaNMask, result, TVectorSingle.Create(float.NaN)); + result = TVectorSingle.ConditionalSelect(infinityMask, TVectorSingle.Create(float.PositiveInfinity), result); + + return result; + } + public static TVectorDouble LogDouble(TVectorDouble x) where TVectorDouble : unmanaged, ISimdVector where TVectorInt64 : unmanaged, ISimdVector diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index a416172d02b230..db529dfb11bca8 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -185,6 +185,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static bool GreaterThanOrEqualAny(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 GreaterThanOrEqual(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 GreaterThan(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Hypot(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Hypot(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } @@ -537,6 +539,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static bool GreaterThanOrEqualAny(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 GreaterThanOrEqual(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 GreaterThan(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Hypot(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Hypot(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } @@ -890,6 +894,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static bool GreaterThanOrEqualAny(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 GreaterThanOrEqual(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 GreaterThan(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Hypot(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Hypot(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } @@ -1212,6 +1218,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static bool GreaterThanOrEqualAny(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 GreaterThanOrEqual(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 GreaterThan(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Hypot(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Hypot(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } From 5bad72da78663d4dda77cacb5cb5b83bab31a84f Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 20 Jun 2024 00:26:00 -0700 Subject: [PATCH 07/39] Expose Lerp on the vector types --- src/coreclr/jit/hwintrinsicarm64.cpp | 22 ++++-- src/coreclr/jit/hwintrinsicxarch.cpp | 3 +- .../ref/System.Numerics.Vectors.cs | 5 ++ .../src/System/Numerics/Vector.cs | 67 +++++++++++++++++++ .../src/System/Numerics/Vector2.cs | 16 ++--- .../src/System/Numerics/Vector3.cs | 13 ++-- .../src/System/Numerics/Vector4.cs | 13 ++-- .../src/System/Numerics/Vector_1.cs | 3 + .../Runtime/Intrinsics/ISimdVector_2.cs | 11 +++ .../src/System/Runtime/Intrinsics/Scalar.cs | 58 ++++++++++++++++ .../System/Runtime/Intrinsics/Vector128.cs | 46 +++++++++++++ .../System/Runtime/Intrinsics/Vector128_1.cs | 3 + .../System/Runtime/Intrinsics/Vector256.cs | 46 +++++++++++++ .../System/Runtime/Intrinsics/Vector256_1.cs | 3 + .../System/Runtime/Intrinsics/Vector512.cs | 46 +++++++++++++ .../System/Runtime/Intrinsics/Vector512_1.cs | 3 + .../src/System/Runtime/Intrinsics/Vector64.cs | 67 +++++++++++++++++++ .../System/Runtime/Intrinsics/Vector64_1.cs | 3 + .../System/Runtime/Intrinsics/VectorMath.cs | 7 ++ .../ref/System.Runtime.Intrinsics.cs | 8 +++ 20 files changed, 414 insertions(+), 29 deletions(-) diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index fae9ebcba44f6f..5b246b148dd87c 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1791,24 +1791,34 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector128_MultiplyAddEstimate: { assert(sig->numArgs == 3); - assert(varTypeIsFloating(simdBaseType)); if (BlockNonDeterministicIntrinsics(mustExpand)) { break; } - impSpillSideEffect(true, verCurrentState.esStackDepth - - 3 DEBUGARG("Spilling op1 side effects for MultiplyAddEstimate")); + if (varTypeIsFloating(simdBaseType)) + { + impSpillSideEffect(true, verCurrentState.esStackDepth - + 3 DEBUGARG("Spilling op1 side effects for MultiplyAddEstimate")); - impSpillSideEffect(true, verCurrentState.esStackDepth - - 2 DEBUGARG("Spilling op2 side effects for MultiplyAddEstimate")); + impSpillSideEffect(true, verCurrentState.esStackDepth - + 2 DEBUGARG("Spilling op2 side effects for MultiplyAddEstimate")); + } op3 = impSIMDPopStack(); op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); - retNode = gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + if (varTypeIsFloating(simdBaseType)) + { + retNode = gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); + } + else + { + GenTree* mulNode = gtNewSimdBinOpNode(GT_MUL, retType, op1, op2, simdBaseJitType, simdSize); + retNode = gtNewSimdBinOpNode(GT_ADD, retType, mulNode, op3, simdBaseJitType, simdSize); + } break; } diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 99f0409464f94b..eeda97fad22762 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2805,7 +2805,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_Vector512_MultiplyAddEstimate: { assert(sig->numArgs == 3); - assert(varTypeIsFloating(simdBaseType)); if (BlockNonDeterministicIntrinsics(mustExpand)) { @@ -2816,7 +2815,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, op2 = impSIMDPopStack(); op1 = impSIMDPopStack(); - if (compExactlyDependsOn(InstructionSet_FMA)) + if (varTypeIsFloating(simdBaseType) && compExactlyDependsOn(InstructionSet_FMA)) { retNode = gtNewSimdFmaNode(retType, op1, op2, op3, simdBaseJitType, simdSize); } diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 61e24e38b1775a..66b1b0e7ef76d0 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -298,6 +298,8 @@ public static partial class Vector public static System.Numerics.Vector GreaterThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Hypot(System.Numerics.Vector x, System.Numerics.Vector y) { throw null; } public static System.Numerics.Vector Hypot(System.Numerics.Vector x, System.Numerics.Vector y) { throw null; } + public static System.Numerics.Vector Lerp(System.Numerics.Vector x, System.Numerics.Vector y, System.Numerics.Vector amount) { throw null; } + public static System.Numerics.Vector Lerp(System.Numerics.Vector x, System.Numerics.Vector y, System.Numerics.Vector amount) { throw null; } public static System.Numerics.Vector LessThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector LessThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector LessThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -482,6 +484,7 @@ public readonly void CopyTo(System.Span destination) { } public readonly float Length() { throw null; } public readonly float LengthSquared() { throw null; } public static System.Numerics.Vector2 Lerp(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2, float amount) { throw null; } + public static System.Numerics.Vector2 Lerp(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2, System.Numerics.Vector2 amount) { throw null; } public static System.Numerics.Vector2 Log(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 Log2(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 Max(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } @@ -566,6 +569,7 @@ public readonly void CopyTo(System.Span destination) { } public readonly float LengthSquared() { throw null; } public static System.Numerics.Vector3 Hypot(System.Numerics.Vector3 x, System.Numerics.Vector3 y) { throw null; } public static System.Numerics.Vector3 Lerp(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2, float amount) { throw null; } + public static System.Numerics.Vector3 Lerp(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2, System.Numerics.Vector3 amount) { throw null; } public static System.Numerics.Vector3 Log(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 Log2(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 Max(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } @@ -651,6 +655,7 @@ public readonly void CopyTo(System.Span destination) { } public readonly float LengthSquared() { throw null; } public static System.Numerics.Vector4 Hypot(System.Numerics.Vector4 x, System.Numerics.Vector4 y) { throw null; } public static System.Numerics.Vector4 Lerp(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2, float amount) { throw null; } + public static System.Numerics.Vector4 Lerp(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2, System.Numerics.Vector4 amount) { throw null; } public static System.Numerics.Vector4 Log(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 Log2(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 Max(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index a974d0b30ff24c..8763b556bee8e9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -1170,6 +1170,58 @@ public static Vector Hypot(Vector x, Vector y) } } + internal static Vector Lerp(Vector x, Vector y, Vector amount) + where T : IFloatingPointIeee754 + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = T.Lerp(x.GetElementUnsafe(index), y.GetElementUnsafe(index), amount.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Performs a linear interpolation between two vectors based on the given weighting. + /// The first vector. + /// The second vector. + /// A value between 0 and 1 that indicates the weight of . + /// The interpolated vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Lerp(Vector x, Vector y, Vector amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, double>(x, y, amount); + } + else + { + return Lerp(x, y, amount); + } + } + + /// Performs a linear interpolation between two vectors based on the given weighting. + /// The first vector. + /// The second vector. + /// A value between 0 and 1 that indicates the weight of . + /// The interpolated vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector Lerp(Vector x, Vector y, Vector amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, float>(x, y, amount); + } + else + { + return Lerp(x, y, amount); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The vector to compare with . /// The vector to compare with . @@ -1565,6 +1617,21 @@ public static Vector Min(Vector left, Vector right) [Intrinsic] public static Vector Multiply(T left, Vector right) => right * left; + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector MultiplyAddEstimate(Vector left, Vector right, Vector addend) + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.MultiplyAddEstimate(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index 8f298b24d96974..df51b79b2814a0 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -375,17 +375,15 @@ public static Vector2 Create(ReadOnlySpan values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Hypot(Vector2 x, Vector2 y) => Vector128.Hypot(x.AsVector128Unsafe(), y.AsVector128Unsafe()).AsVector2(); - /// Performs a linear interpolation between two vectors based on the given weighting. - /// The first vector. - /// The second vector. - /// A value between 0 and 1 that indicates the weight of . - /// The interpolated vector. - /// + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) => Lerp(value1, value2, Create(amount)); + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector2 Lerp(Vector2 value1, Vector2 value2, float amount) => MultiplyAddEstimate(value1, Create(1.0f - amount), value2 * amount); + public static Vector2 Lerp(Vector2 value1, Vector2 value2, Vector2 amount) => Vector128.Lerp(value1.AsVector128Unsafe(), value2.AsVector128Unsafe(), amount.AsVector128Unsafe()).AsVector2(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index 885958fd1e968a..6010ed30a14317 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -432,14 +432,15 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Hypot(Vector3 x, Vector3 y) => Vector128.Hypot(x.AsVector128Unsafe(), y.AsVector128Unsafe()).AsVector3(); - /// Performs a linear interpolation between two vectors based on the given weighting. - /// The first vector. - /// The second vector. - /// A value between 0 and 1 that indicates the weight of . - /// The interpolated vector. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) => Lerp(value1, value2, Create(amount)); + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector3 Lerp(Vector3 value1, Vector3 value2, float amount) => MultiplyAddEstimate(value1, Create(1.0f - amount), value2 * amount); + public static Vector3 Lerp(Vector3 value1, Vector3 value2, Vector3 amount) => Vector128.Lerp(value1.AsVector128Unsafe(), value2.AsVector128Unsafe(), amount.AsVector128Unsafe()).AsVector3(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 20dec14a924c03..ee43092bbff16c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -437,17 +437,18 @@ public static Vector4 Create(Vector3 vector, float w) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Hypot(Vector4 x, Vector4 y) => Vector128.Hypot(x.AsVector128(), y.AsVector128()).AsVector4(); - /// Performs a linear interpolation between two vectors based on the given weighting. - /// The first vector. - /// The second vector. - /// A value between 0 and 1 that indicates the weight of . - /// The interpolated vector. + /// /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector4 Lerp(Vector4 value1, Vector4 value2, float amount) => MultiplyAddEstimate(value1, Create(1.0f - amount), value2 * amount); + public static Vector4 Lerp(Vector4 value1, Vector4 value2, float amount) => Lerp(value1, value2, Create(amount)); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Lerp(Vector4 value1, Vector4 value2, Vector4 amount) => Vector128.Lerp(value1.AsVector128(), value2.AsVector128(), amount.AsVector128()).AsVector4(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index 7b92f20c53f0b6..72a0bcc806c38b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -954,6 +954,9 @@ public bool TryCopyTo(Span destination) /// static Vector ISimdVector, T>.Multiply(Vector left, T right) => left * right; + /// + static Vector ISimdVector, T>.MultiplyAddEstimate(Vector left, Vector right, Vector addend) => Vector.MultiplyAddEstimate(left, right, addend); + /// static Vector ISimdVector, T>.Negate(Vector vector) => -vector; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs index ca606a4c396ad5..6b22dafb7aa54c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs @@ -427,6 +427,17 @@ static virtual TSelf LoadAligned(T* source) /// The type of and () is not supported. static virtual TSelf Multiply(TSelf left, T right) => left * right; + /// Computes an estimate of ( * ) + . + /// The vector to be multiplied with . + /// The vector to be multiplied with . + /// The vector to be added to the result of multiplied by . + /// An estimate of ( * ) + . + /// + /// On hardware that natively supports FusedMultiplyAdd, this may return a result that was rounded as one ternary operation. + /// On hardware without specialized support, this may just return ( * ) + . + /// + static abstract TSelf MultiplyAddEstimate(TSelf left, TSelf right, TSelf addend); + /// Negates a vector. /// The vector to negate. /// A vector whose elements are the negation of the corresponding elements in . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs index c5cb087094fd6d..ef37c2993a6759 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs @@ -878,6 +878,64 @@ public static T Multiply(T left, T right) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T MultiplyAddEstimate(T left, T right, T addend) + { + if (typeof(T) == typeof(byte)) + { + return (T)(object)(byte)((((byte)(object)left * (byte)(object)right)) + (byte)(object)addend); + } + else if (typeof(T) == typeof(double)) + { + return (T)(object)double.MultiplyAddEstimate((double)(object)left, (double)(object)right, (double)(object)addend); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)(short)((((short)(object)left * (short)(object)right)) + (short)(object)addend); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)(int)((((int)(object)left * (int)(object)right)) + (int)(object)addend); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)(long)((((long)(object)left * (long)(object)right)) + (long)(object)addend); + } + else if (typeof(T) == typeof(nint)) + { + return (T)(object)(nint)((((nint)(object)left * (nint)(object)right)) + (nint)(object)addend); + } + else if (typeof(T) == typeof(nuint)) + { + return (T)(object)(nuint)((((nuint)(object)left * (nuint)(object)right)) + (nuint)(object)addend); + } + else if (typeof(T) == typeof(sbyte)) + { + return (T)(object)(sbyte)((((sbyte)(object)left * (sbyte)(object)right)) + (sbyte)(object)addend); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.MultiplyAddEstimate((float)(object)left, (float)(object)right, (float)(object)addend); + } + else if (typeof(T) == typeof(ushort)) + { + return (T)(object)(ushort)((((ushort)(object)left * (ushort)(object)right)) + (ushort)(object)addend); + } + else if (typeof(T) == typeof(uint)) + { + return (T)(object)(uint)((((uint)(object)left * (uint)(object)right)) + (uint)(object)addend); + } + else if (typeof(T) == typeof(ulong)) + { + return (T)(object)(ulong)((((ulong)(object)left * (ulong)(object)right)) + (ulong)(object)addend); + } + else + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); + return default!; + } + } + public static bool ObjectEquals(T left, T right) { if (typeof(T) == typeof(byte)) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 1d0fb4f1197224..88476db75fdb8e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -1850,6 +1850,42 @@ public static Vector128 Hypot(Vector128 x, Vector128 y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Lerp(Vector128 x, Vector128 y, Vector128 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, double>(x, y, amount); + } + else + { + return Create( + Vector64.Lerp(x._lower, y._lower, amount._lower), + Vector64.Lerp(x._upper, y._upper, amount._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Lerp(Vector128 x, Vector128 y, Vector128 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, float>(x, y, amount); + } + else + { + return Create( + Vector64.Lerp(x._lower, y._lower, amount._lower), + Vector64.Lerp(x._upper, y._upper, amount._upper) + ); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . @@ -2147,6 +2183,16 @@ public static Vector128 Min(Vector128 left, Vector128 right) [Intrinsic] public static Vector128 Multiply(T left, Vector128 right) => right * left; + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 MultiplyAddEstimate(Vector128 left, Vector128 right, Vector128 addend) + { + return Create( + Vector64.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector64.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index 5ca6ba4200b91b..e52a8d1de1dabc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -601,6 +601,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector128 ISimdVector, T>.Multiply(Vector128 left, T right) => left * right; + /// + static Vector128 ISimdVector, T>.MultiplyAddEstimate(Vector128 left, Vector128 right, Vector128 addend) => Vector128.MultiplyAddEstimate(left, right, addend); + /// static Vector128 ISimdVector, T>.Negate(Vector128 vector) => -vector; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 88f50a36ecb45e..39617de0042b3b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -1766,6 +1766,42 @@ public static Vector256 Hypot(Vector256 x, Vector256 y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Lerp(Vector256 x, Vector256 y, Vector256 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, double>(x, y, amount); + } + else + { + return Create( + Vector128.Lerp(x._lower, y._lower, amount._lower), + Vector128.Lerp(x._upper, y._upper, amount._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Lerp(Vector256 x, Vector256 y, Vector256 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, float>(x, y, amount); + } + else + { + return Create( + Vector128.Lerp(x._lower, y._lower, amount._lower), + Vector128.Lerp(x._upper, y._upper, amount._upper) + ); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . @@ -2063,6 +2099,16 @@ public static Vector256 Min(Vector256 left, Vector256 right) [Intrinsic] public static Vector256 Multiply(T left, Vector256 right) => right * left; + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 MultiplyAddEstimate(Vector256 left, Vector256 right, Vector256 addend) + { + return Create( + Vector128.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector128.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index 9b66fb21e2fd38..103902326d81af 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -590,6 +590,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector256 ISimdVector, T>.Multiply(Vector256 left, T right) => left * right; + /// + static Vector256 ISimdVector, T>.MultiplyAddEstimate(Vector256 left, Vector256 right, Vector256 addend) => Vector256.MultiplyAddEstimate(left, right, addend); + /// static Vector256 ISimdVector, T>.Negate(Vector256 vector) => -vector; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index 108ded6cf40552..61ea749a991cbe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -1829,6 +1829,42 @@ public static Vector512 Hypot(Vector512 x, Vector512 y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Lerp(Vector512 x, Vector512 y, Vector512 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, double>(x, y, amount); + } + else + { + return Create( + Vector256.Lerp(x._lower, y._lower, amount._lower), + Vector256.Lerp(x._upper, y._upper, amount._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Lerp(Vector512 x, Vector512 y, Vector512 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, float>(x, y, amount); + } + else + { + return Create( + Vector256.Lerp(x._lower, y._lower, amount._lower), + Vector256.Lerp(x._upper, y._upper, amount._upper) + ); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . @@ -2126,6 +2162,16 @@ public static Vector512 Min(Vector512 left, Vector512 right) [Intrinsic] public static Vector512 Multiply(T left, Vector512 right) => right * left; + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 MultiplyAddEstimate(Vector512 left, Vector512 right, Vector512 addend) + { + return Create( + Vector256.MultiplyAddEstimate(left._lower, right._lower, addend._lower), + Vector256.MultiplyAddEstimate(left._upper, right._upper, addend._upper) + ); + } + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs index 0d3f622d852537..21431c8044a968 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs @@ -590,6 +590,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector512 ISimdVector, T>.Multiply(Vector512 left, T right) => left * right; + /// + static Vector512 ISimdVector, T>.MultiplyAddEstimate(Vector512 left, Vector512 right, Vector512 addend) => Vector512.MultiplyAddEstimate(left, right, addend); + /// static Vector512 ISimdVector, T>.Negate(Vector512 vector) => -vector; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index 6f327112883156..e7c5df6646b0e2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -1566,6 +1566,58 @@ public static Vector64 Hypot(Vector64 x, Vector64 y) } } + internal static Vector64 Lerp(Vector64 x, Vector64 y, Vector64 amount) + where T : IFloatingPointIeee754 + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = T.Lerp(x.GetElementUnsafe(index), y.GetElementUnsafe(index), amount.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + + /// Performs a linear interpolation between two vectors based on the given weighting. + /// The first vector. + /// The second vector. + /// A value between 0 and 1 that indicates the weight of . + /// The interpolated vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Lerp(Vector64 x, Vector64 y, Vector64 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, double>(x, y, amount); + } + else + { + return Lerp(x, y, amount); + } + } + + /// Performs a linear interpolation between two vectors based on the given weighting. + /// The first vector. + /// The second vector. + /// A value between 0 and 1 that indicates the weight of . + /// The interpolated vector. + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 Lerp(Vector64 x, Vector64 y, Vector64 amount) + { + if (IsHardwareAccelerated) + { + return VectorMath.Lerp, float>(x, y, amount); + } + else + { + return Lerp(x, y, amount); + } + } + /// Compares two vectors to determine which is less on a per-element basis. /// The type of the elements in the vector. /// The vector to compare with . @@ -1924,6 +1976,21 @@ public static Vector64 Min(Vector64 left, Vector64 right) [Intrinsic] public static Vector64 Multiply(T left, Vector64 right) => right * left; + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 MultiplyAddEstimate(Vector64 left, Vector64 right, Vector64 addend) + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.MultiplyAddEstimate(left.GetElementUnsafe(index), right.GetElementUnsafe(index), addend.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + /// Computes an estimate of ( * ) + . /// The vector to be multiplied with . /// The vector to be multiplied with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index 984a8d2b06129d..2483ca6d7a5db2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -658,6 +658,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector64 ISimdVector, T>.Multiply(Vector64 left, T right) => left * right; + /// + static Vector64 ISimdVector, T>.MultiplyAddEstimate(Vector64 left, Vector64 right, Vector64 addend) => Vector64.MultiplyAddEstimate(left, right, addend); + /// static Vector64 ISimdVector, T>.Negate(Vector64 vector) => -vector; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index 49e67d649df70f..e661863370c958 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -446,6 +446,13 @@ public static TVectorSingle HypotSingle(TVectorSin return result; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector Lerp(TVector x, TVector y, TVector amount) + where TVector : unmanaged, ISimdVector + { + return TVector.MultiplyAddEstimate(x, TVector.One - amount, y * amount); + } + public static TVectorDouble LogDouble(TVectorDouble x) where TVectorDouble : unmanaged, ISimdVector where TVectorInt64 : unmanaged, ISimdVector diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index db529dfb11bca8..6d7d0c8d862b84 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -187,6 +187,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static System.Runtime.Intrinsics.Vector128 GreaterThan(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Hypot(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y) { throw null; } public static System.Runtime.Intrinsics.Vector128 Hypot(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Lerp(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y, System.Runtime.Intrinsics.Vector128 amount) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Lerp(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y, System.Runtime.Intrinsics.Vector128 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } @@ -541,6 +543,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static System.Runtime.Intrinsics.Vector256 GreaterThan(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Hypot(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y) { throw null; } public static System.Runtime.Intrinsics.Vector256 Hypot(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Lerp(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y, System.Runtime.Intrinsics.Vector256 amount) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Lerp(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y, System.Runtime.Intrinsics.Vector256 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } @@ -896,6 +900,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 GreaterThan(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Hypot(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y) { throw null; } public static System.Runtime.Intrinsics.Vector512 Hypot(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Lerp(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y, System.Runtime.Intrinsics.Vector512 amount) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Lerp(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y, System.Runtime.Intrinsics.Vector512 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } @@ -1220,6 +1226,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static System.Runtime.Intrinsics.Vector64 GreaterThan(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Hypot(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y) { throw null; } public static System.Runtime.Intrinsics.Vector64 Hypot(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Lerp(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y, System.Runtime.Intrinsics.Vector64 amount) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Lerp(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y, System.Runtime.Intrinsics.Vector64 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static bool LessThanAny(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static bool LessThanOrEqualAll(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } From 34879f6a00bfc8913482d87759ef6146cc940173 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 20 Jun 2024 01:05:38 -0700 Subject: [PATCH 08/39] Expose Truncate and Round on the vector types --- .../ref/System.Numerics.Vectors.cs | 15 +++ .../src/System/Numerics/Vector.cs | 86 +++++++++++++++++ .../src/System/Numerics/Vector2.cs | 12 +++ .../src/System/Numerics/Vector3.cs | 12 +++ .../src/System/Numerics/Vector4.cs | 12 +++ .../src/System/Numerics/Vector_1.cs | 6 ++ .../Runtime/Intrinsics/ISimdVector_2.cs | 10 ++ .../src/System/Runtime/Intrinsics/Scalar.cs | 36 +++++++ .../System/Runtime/Intrinsics/Vector128.cs | 76 +++++++++++++++ .../System/Runtime/Intrinsics/Vector128_1.cs | 6 ++ .../System/Runtime/Intrinsics/Vector256.cs | 76 +++++++++++++++ .../System/Runtime/Intrinsics/Vector256_1.cs | 6 ++ .../System/Runtime/Intrinsics/Vector512.cs | 76 +++++++++++++++ .../System/Runtime/Intrinsics/Vector512_1.cs | 6 ++ .../src/System/Runtime/Intrinsics/Vector64.cs | 92 ++++++++++++++++++ .../System/Runtime/Intrinsics/Vector64_1.cs | 6 ++ .../System/Runtime/Intrinsics/VectorMath.cs | 93 +++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 24 +++++ 18 files changed, 650 insertions(+) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index 66b1b0e7ef76d0..ff824db621e44f 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -351,6 +351,10 @@ public static partial class Vector public static System.Numerics.Vector OnesComplement(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector RadiansToDegrees(System.Numerics.Vector radians) { throw null; } public static System.Numerics.Vector RadiansToDegrees(System.Numerics.Vector radians) { throw null; } + public static System.Numerics.Vector Round(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Round(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Round(System.Numerics.Vector vector, System.MidpointRounding mode) { throw null; } + public static System.Numerics.Vector Round(System.Numerics.Vector vector, System.MidpointRounding mode) { throw null; } public static System.Numerics.Vector ShiftLeft(System.Numerics.Vector value, int shiftCount) { throw null; } public static System.Numerics.Vector ShiftLeft(System.Numerics.Vector value, int shiftCount) { throw null; } public static System.Numerics.Vector ShiftLeft(System.Numerics.Vector value, int shiftCount) { throw null; } @@ -402,6 +406,8 @@ public static partial class Vector public static System.Numerics.Vector Subtract(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static T Sum(System.Numerics.Vector value) { throw null; } public static T ToScalar(this System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Truncate(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector Truncate(System.Numerics.Vector vector) { throw null; } [System.CLSCompliantAttribute(false)] public static void Widen(System.Numerics.Vector source, out System.Numerics.Vector low, out System.Numerics.Vector high) { throw null; } public static void Widen(System.Numerics.Vector source, out System.Numerics.Vector low, out System.Numerics.Vector high) { throw null; } @@ -506,6 +512,8 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector2 operator -(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } public static System.Numerics.Vector2 operator -(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 RadiansToDegrees(System.Numerics.Vector2 radians) { throw null; } + public static System.Numerics.Vector2 Round(System.Numerics.Vector2 vector) { throw null; } + public static System.Numerics.Vector2 Round(System.Numerics.Vector2 vector, System.MidpointRounding mode) { throw null; } public static System.Numerics.Vector2 Reflect(System.Numerics.Vector2 vector, System.Numerics.Vector2 normal) { throw null; } public static System.Numerics.Vector2 SquareRoot(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 Subtract(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } @@ -517,6 +525,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector2 Transform(System.Numerics.Vector2 value, System.Numerics.Quaternion rotation) { throw null; } public static System.Numerics.Vector2 TransformNormal(System.Numerics.Vector2 normal, System.Numerics.Matrix3x2 matrix) { throw null; } public static System.Numerics.Vector2 TransformNormal(System.Numerics.Vector2 normal, System.Numerics.Matrix4x4 matrix) { throw null; } + public static System.Numerics.Vector2 Truncate(System.Numerics.Vector2 vector) { throw null; } } public partial struct Vector3 : System.IEquatable, System.IFormattable { @@ -592,6 +601,8 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector3 operator -(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 RadiansToDegrees(System.Numerics.Vector3 radians) { throw null; } public static System.Numerics.Vector3 Reflect(System.Numerics.Vector3 vector, System.Numerics.Vector3 normal) { throw null; } + public static System.Numerics.Vector3 Round(System.Numerics.Vector3 vector) { throw null; } + public static System.Numerics.Vector3 Round(System.Numerics.Vector3 vector, System.MidpointRounding mode) { throw null; } public static System.Numerics.Vector3 SquareRoot(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 Subtract(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } public override readonly string ToString() { throw null; } @@ -600,6 +611,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector3 Transform(System.Numerics.Vector3 position, System.Numerics.Matrix4x4 matrix) { throw null; } public static System.Numerics.Vector3 Transform(System.Numerics.Vector3 value, System.Numerics.Quaternion rotation) { throw null; } public static System.Numerics.Vector3 TransformNormal(System.Numerics.Vector3 normal, System.Numerics.Matrix4x4 matrix) { throw null; } + public static System.Numerics.Vector3 Truncate(System.Numerics.Vector3 vector) { throw null; } } public partial struct Vector4 : System.IEquatable, System.IFormattable { @@ -677,6 +689,8 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector4 operator -(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public static System.Numerics.Vector4 operator -(System.Numerics.Vector4 value) { throw null; } public static System.Numerics.Vector4 RadiansToDegrees(System.Numerics.Vector4 radians) { throw null; } + public static System.Numerics.Vector4 Round(System.Numerics.Vector4 vector) { throw null; } + public static System.Numerics.Vector4 Round(System.Numerics.Vector4 vector, System.MidpointRounding mode) { throw null; } public static System.Numerics.Vector4 SquareRoot(System.Numerics.Vector4 value) { throw null; } public static System.Numerics.Vector4 Subtract(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public override readonly string ToString() { throw null; } @@ -688,6 +702,7 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector4 Transform(System.Numerics.Vector3 value, System.Numerics.Quaternion rotation) { throw null; } public static System.Numerics.Vector4 Transform(System.Numerics.Vector4 vector, System.Numerics.Matrix4x4 matrix) { throw null; } public static System.Numerics.Vector4 Transform(System.Numerics.Vector4 value, System.Numerics.Quaternion rotation) { throw null; } + public static System.Numerics.Vector4 Truncate(System.Numerics.Vector4 vector) { throw null; } } public readonly partial struct Vector : System.IEquatable>, System.IFormattable { diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 8763b556bee8e9..72e8b4ba6668e6 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -1899,6 +1899,53 @@ public static Vector RadiansToDegrees(Vector radians) } } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector Round(Vector vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.Round(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + public static Vector Round(Vector vector) => Round(vector); + + /// + [Intrinsic] + public static Vector Round(Vector vector) => Round(vector); + + /// + [Intrinsic] + public static Vector Round(Vector vector, MidpointRounding mode) => VectorMath.RoundDouble(vector, mode); + + /// + [Intrinsic] + public static Vector Round(Vector vector, MidpointRounding mode) => VectorMath.RoundSingle(vector, mode); + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. @@ -2212,6 +2259,45 @@ public static T ToScalar(this Vector vector) return vector.GetElementUnsafe(0); } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector Truncate(Vector vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.Truncate(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + public static Vector Truncate(Vector vector) => Truncate(vector); + + /// + [Intrinsic] + public static Vector Truncate(Vector vector) => Truncate(vector); + /// Widens a into two . /// The vector whose elements are to be widened. /// A pair of vectors that contain the widened lower and upper halves of . diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index df51b79b2814a0..bfb351fd84d665 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -467,6 +467,14 @@ public static Vector2 Reflect(Vector2 vector, Vector2 normal) return MultiplyAddEstimate(-tmp, normal, vector); } + /// + [Intrinsic] + public static Vector2 Round(Vector2 vector) => Vector128.Round(vector.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + public static Vector2 Round(Vector2 vector, MidpointRounding mode) => Vector128.Round(vector.AsVector128Unsafe(), mode).AsVector2(); + /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. @@ -537,6 +545,10 @@ internal static Vector2 TransformNormal(Vector2 normal, in Matrix4x4.Impl matrix return result.AsVector2(); } + /// + [Intrinsic] + public static Vector2 Truncate(Vector2 vector) => Vector128.Truncate(vector.AsVector128Unsafe()).AsVector2(); + /// Copies the elements of the vector to a specified array. /// The destination array. /// must have at least two elements. The method copies the vector's elements starting at index 0. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index 6010ed30a14317..31134f20d88f86 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -524,6 +524,14 @@ public static Vector3 Reflect(Vector3 vector, Vector3 normal) return MultiplyAddEstimate(-tmp, normal, vector); } + /// + [Intrinsic] + public static Vector3 Round(Vector3 vector) => Vector128.Round(vector.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + public static Vector3 Round(Vector3 vector, MidpointRounding mode) => Vector128.Round(vector.AsVector128Unsafe(), mode).AsVector3(); + /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. @@ -570,6 +578,10 @@ internal static Vector3 TransformNormal(Vector3 normal, in Matrix4x4.Impl matrix return result.AsVector3(); } + /// + [Intrinsic] + public static Vector3 Truncate(Vector3 vector) => Vector128.Truncate(vector.AsVector128Unsafe()).AsVector3(); + /// Copies the elements of the vector to a specified array. /// The destination array. /// must have at least three elements. The method copies the vector's elements starting at index 0. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index ee43092bbff16c..cf84e97dea218d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -517,6 +517,14 @@ public static Vector4 Create(Vector3 vector, float w) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 RadiansToDegrees(Vector4 radians) => Vector128.RadiansToDegrees(radians.AsVector128()).AsVector4(); + /// + [Intrinsic] + public static Vector4 Round(Vector4 vector) => Vector128.Round(vector.AsVector128()).AsVector4(); + + /// + [Intrinsic] + public static Vector4 Round(Vector4 vector, MidpointRounding mode) => Vector128.Round(vector.AsVector128(), mode).AsVector4(); + /// Returns a vector whose elements are the square root of each of a specified vector's elements. /// A vector. /// The square root vector. @@ -614,6 +622,10 @@ public static Vector4 Transform(Vector4 value, Quaternion rotation) return Quaternion.Concatenate(temp, rotation).AsVector4(); } + /// + [Intrinsic] + public static Vector4 Truncate(Vector4 vector) => Vector128.Truncate(vector.AsVector128()).AsVector4(); + /// Copies the elements of the vector to a specified array. /// The destination array. /// must have at least four elements. The method copies the vector's elements starting at index 0. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index 72a0bcc806c38b..aaf0f7fd33ea7f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -963,6 +963,9 @@ public bool TryCopyTo(Span destination) /// static Vector ISimdVector, T>.OnesComplement(Vector vector) => ~vector; + /// + static Vector ISimdVector, T>.Round(Vector vector) => Vector.Round(vector); + /// static Vector ISimdVector, T>.ShiftLeft(Vector vector, int shiftCount) => vector << shiftCount; @@ -1001,6 +1004,9 @@ public bool TryCopyTo(Span destination) /// static T ISimdVector, T>.ToScalar(Vector vector) => vector.ToScalar(); + /// + static Vector ISimdVector, T>.Truncate(Vector vector) => Vector.Truncate(vector); + /// static bool ISimdVector, T>.TryCopyTo(Vector vector, Span destination) => vector.TryCopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs index 6b22dafb7aa54c..192507af6f5a66 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs @@ -450,6 +450,11 @@ static virtual TSelf LoadAligned(T* source) /// The type of () is not supported. static virtual TSelf OnesComplement(TSelf vector) => ~vector; + /// Rounds each element in a vector to the nearest integer using the default rounding mode (). + /// The vector to round. + /// The result of rounding each element in to the nearest integer using the default rounding mode. + static abstract TSelf Round(TSelf vector); + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. @@ -534,6 +539,11 @@ static virtual void StoreAligned(TSelf source, T* destination) /// The type of the elements in the vector () is not supported. static virtual T ToScalar(TSelf vector) => TSelf.GetElement(vector, 0); + /// Truncates each element in a vector. + /// The vector to truncate. + /// The truncation of each element in . + static abstract TSelf Truncate(TSelf vector); + /// Tries to copy a to a given span. /// The vector to copy. /// The span to which is copied. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs index ef37c2993a6759..0d694dc1e130df 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs @@ -993,6 +993,24 @@ public static bool ObjectEquals(T left, T right) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Round(T value) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)Math.Round((double)(object)value); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)MathF.Round((float)(object)value); + } + else + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); + return default!; + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T ShiftLeft(T value, int shiftCount) { @@ -1294,6 +1312,24 @@ public static T Subtract(T left, T right) return default!; } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Truncate(T value) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)Math.Truncate((double)(object)value); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)MathF.Truncate((float)(object)value); + } + else + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); + return default!; + } + } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 88476db75fdb8e..793639d9527c1c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -2369,6 +2369,48 @@ public static Vector128 RadiansToDegrees(Vector128 radians) } } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 Round(Vector128 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + return Create( + Vector64.Round(vector._lower), + Vector64.Round(vector._upper) + ); + } + } + + /// + [Intrinsic] + public static Vector128 Round(Vector128 vector) => Round(vector); + + /// + [Intrinsic] + public static Vector128 Round(Vector128 vector) => Round(vector); + + /// + [Intrinsic] + public static Vector128 Round(Vector128 vector, MidpointRounding mode) => VectorMath.RoundDouble(vector, mode); + + /// + [Intrinsic] + public static Vector128 Round(Vector128 vector, MidpointRounding mode) => VectorMath.RoundSingle(vector, mode); + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. @@ -3029,6 +3071,40 @@ public static unsafe Vector256 ToVector256Unsafe(this Vector128 vector) return result; } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 Truncate(Vector128 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + return Create( + Vector64.Truncate(vector._lower), + Vector64.Truncate(vector._upper) + ); + } + } + + /// + [Intrinsic] + public static Vector128 Truncate(Vector128 vector) => Truncate(vector); + + /// + [Intrinsic] + public static Vector128 Truncate(Vector128 vector) => Truncate(vector); + /// Tries to copy a to a given span. /// The type of the input vector. /// The vector to copy. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index e52a8d1de1dabc..81a1ab4d3a4b08 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -610,6 +610,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector128 ISimdVector, T>.OnesComplement(Vector128 vector) => ~vector; + /// + static Vector128 ISimdVector, T>.Round(Vector128 vector) => Vector128.Round(vector); + /// static Vector128 ISimdVector, T>.ShiftLeft(Vector128 vector, int shiftCount) => vector << shiftCount; @@ -648,6 +651,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static T ISimdVector, T>.ToScalar(Vector128 vector) => vector.ToScalar(); + /// + static Vector128 ISimdVector, T>.Truncate(Vector128 vector) => Vector128.Truncate(vector); + /// static bool ISimdVector, T>.TryCopyTo(Vector128 vector, Span destination) => vector.TryCopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 39617de0042b3b..e68c3dda4b8dd3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -2285,6 +2285,48 @@ public static Vector256 RadiansToDegrees(Vector256 radians) } } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 Round(Vector256 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + return Create( + Vector128.Round(vector._lower), + Vector128.Round(vector._upper) + ); + } + } + + /// + [Intrinsic] + public static Vector256 Round(Vector256 vector) => Round(vector); + + /// + [Intrinsic] + public static Vector256 Round(Vector256 vector) => Round(vector); + + /// + [Intrinsic] + public static Vector256 Round(Vector256 vector, MidpointRounding mode) => VectorMath.RoundDouble(vector, mode); + + /// + [Intrinsic] + public static Vector256 Round(Vector256 vector, MidpointRounding mode) => VectorMath.RoundSingle(vector, mode); + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. @@ -2894,6 +2936,40 @@ public static unsafe Vector512 ToVector512Unsafe(this Vector256 vector) return result; } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 Truncate(Vector256 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + return Create( + Vector128.Truncate(vector._lower), + Vector128.Truncate(vector._upper) + ); + } + } + + /// + [Intrinsic] + public static Vector256 Truncate(Vector256 vector) => Truncate(vector); + + /// + [Intrinsic] + public static Vector256 Truncate(Vector256 vector) => Truncate(vector); + /// Tries to copy a to a given span. /// The type of the input vector. /// The vector to copy. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index 103902326d81af..1dcd26a09e63ba 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -599,6 +599,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector256 ISimdVector, T>.OnesComplement(Vector256 vector) => ~vector; + /// + static Vector256 ISimdVector, T>.Round(Vector256 vector) => Vector256.Round(vector); + /// static Vector256 ISimdVector, T>.ShiftLeft(Vector256 vector, int shiftCount) => vector << shiftCount; @@ -637,6 +640,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static T ISimdVector, T>.ToScalar(Vector256 vector) => vector.ToScalar(); + /// + static Vector256 ISimdVector, T>.Truncate(Vector256 vector) => Vector256.Truncate(vector); + /// static bool ISimdVector, T>.TryCopyTo(Vector256 vector, Span destination) => vector.TryCopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index 61ea749a991cbe..dafc4eb1a9a9f9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -2347,6 +2347,48 @@ public static Vector512 RadiansToDegrees(Vector512 radians) } } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 Round(Vector512 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + return Create( + Vector256.Round(vector._lower), + Vector256.Round(vector._upper) + ); + } + } + + /// + [Intrinsic] + public static Vector512 Round(Vector512 vector) => Round(vector); + + /// + [Intrinsic] + public static Vector512 Round(Vector512 vector) => Round(vector); + + /// + [Intrinsic] + public static Vector512 Round(Vector512 vector, MidpointRounding mode) => VectorMath.RoundDouble(vector, mode); + + /// + [Intrinsic] + public static Vector512 Round(Vector512 vector, MidpointRounding mode) => VectorMath.RoundSingle(vector, mode); + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. @@ -2923,6 +2965,40 @@ public static T ToScalar(this Vector512 vector) return vector.GetElementUnsafe(0); } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 Truncate(Vector512 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + return Create( + Vector256.Truncate(vector._lower), + Vector256.Truncate(vector._upper) + ); + } + } + + /// + [Intrinsic] + public static Vector512 Truncate(Vector512 vector) => Truncate(vector); + + /// + [Intrinsic] + public static Vector512 Truncate(Vector512 vector) => Truncate(vector); + /// Tries to copy a to a given span. /// The type of the input vector. /// The vector to copy. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs index 21431c8044a968..9900c187a7eec3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs @@ -599,6 +599,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector512 ISimdVector, T>.OnesComplement(Vector512 vector) => ~vector; + /// + static Vector512 ISimdVector, T>.Round(Vector512 vector) => Vector512.Round(vector); + /// static Vector512 ISimdVector, T>.ShiftLeft(Vector512 vector, int shiftCount) => vector << shiftCount; @@ -637,6 +640,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static T ISimdVector, T>.ToScalar(Vector512 vector) => vector.ToScalar(); + /// + static Vector512 ISimdVector, T>.Truncate(Vector512 vector) => Vector512.Truncate(vector); + /// static bool ISimdVector, T>.TryCopyTo(Vector512 vector, Span destination) => vector.TryCopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index e7c5df6646b0e2..35f7c817998d2c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -2282,6 +2282,59 @@ public static Vector64 RadiansToDegrees(Vector64 radians) } } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 Round(Vector64 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.Round(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + public static Vector64 Round(Vector64 vector) => Round(vector); + + /// + [Intrinsic] + public static Vector64 Round(Vector64 vector) => Round(vector); + + /// Rounds each element in a vector to the nearest integer using the specified rounding mode. + /// The vector to round. + /// The mode under which should be rounded. + /// The result of rounding each element in to the nearest integer using . + [Intrinsic] + public static Vector64 Round(Vector64 vector, MidpointRounding mode) => VectorMath.RoundDouble(vector, mode); + + /// Rounds each element in a vector to the nearest integer using the specified rounding mode. + /// The vector to round. + /// The mode under which should be rounded. + /// The result of rounding each element in to the nearest integer using . + [Intrinsic] + public static Vector64 Round(Vector64 vector, MidpointRounding mode) => VectorMath.RoundSingle(vector, mode); + /// Shifts each element of a vector left by the specified amount. /// The vector whose elements are to be shifted. /// The number of bits by which to shift each element. @@ -2826,6 +2879,45 @@ public static unsafe Vector128 ToVector128Unsafe(this Vector64 vector) return result; } + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 Truncate(Vector64 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint)) + || (typeof(T) == typeof(nuint)) + || (typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong))) + { + return vector; + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.Truncate(vector.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + public static Vector64 Truncate(Vector64 vector) => Truncate(vector); + + /// + [Intrinsic] + public static Vector64 Truncate(Vector64 vector) => Truncate(vector); + /// Tries to copy a to a given span. /// The type of the input vector. /// The vector to copy. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index 2483ca6d7a5db2..2193bd1d868e67 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -667,6 +667,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector64 ISimdVector, T>.OnesComplement(Vector64 vector) => ~vector; + /// + static Vector64 ISimdVector, T>.Round(Vector64 vector) => Vector64.Round(vector); + /// static Vector64 ISimdVector, T>.ShiftLeft(Vector64 vector, int shiftCount) => vector << shiftCount; @@ -705,6 +708,9 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static T ISimdVector, T>.ToScalar(Vector64 vector) => vector.ToScalar(); + /// + static Vector64 ISimdVector, T>.Truncate(Vector64 vector) => Vector64.Truncate(vector); + /// static bool ISimdVector, T>.TryCopyTo(Vector64 vector, Span destination) => vector.TryCopyTo(destination); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index e661863370c958..6d47c7fa57f46b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -4,6 +4,7 @@ using System.Diagnostics; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics.Arm; namespace System.Runtime.Intrinsics { @@ -1026,6 +1027,98 @@ public static TVector RadiansToDegrees(TVector radians) return (radians * TVector.Create(T.CreateTruncating(180))) / TVector.Create(T.Pi); } + public static TVectorDouble RoundDouble(TVectorDouble vector, MidpointRounding mode) + where TVectorDouble : unmanaged, ISimdVector + { + switch (mode) + { + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value above (for positive numbers) or below (for negative numbers) + case MidpointRounding.AwayFromZero: + { + // manually fold BitDecrement(0.5) + return TVectorDouble.Truncate(vector + CopySign(TVectorDouble.Create(0.49999999999999994), vector)); + } + + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value with an even least significant digit + case MidpointRounding.ToEven: + { + return TVectorDouble.Round(vector); + } + + // Directed rounding: Round to the nearest value, toward to zero + case MidpointRounding.ToZero: + { + return TVectorDouble.Truncate(vector); + } + + // Directed Rounding: Round down to the next value, toward negative infinity + case MidpointRounding.ToNegativeInfinity: + { + return TVectorDouble.Floor(vector); + } + + // Directed rounding: Round up to the next value, toward positive infinity + case MidpointRounding.ToPositiveInfinity: + { + return TVectorDouble.Ceiling(vector); + } + + default: + { + ThrowHelper.ThrowArgumentException_InvalidEnumValue(mode); + return default; + } + } + } + + public static TVectorSingle RoundSingle(TVectorSingle vector, MidpointRounding mode) + where TVectorSingle : unmanaged, ISimdVector + { + switch (mode) + { + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value above (for positive numbers) or below (for negative numbers) + case MidpointRounding.AwayFromZero: + { + // manually fold BitDecrement(0.5) + return TVectorSingle.Truncate(vector + CopySign(TVectorSingle.Create(0.49999997f), vector)); + } + + // Rounds to the nearest value; if the number falls midway, + // it is rounded to the nearest value with an even least significant digit + case MidpointRounding.ToEven: + { + return TVectorSingle.Round(vector); + } + + // Directed rounding: Round to the nearest value, toward to zero + case MidpointRounding.ToZero: + { + return TVectorSingle.Truncate(vector); + } + + // Directed Rounding: Round down to the next value, toward negative infinity + case MidpointRounding.ToNegativeInfinity: + { + return TVectorSingle.Floor(vector); + } + + // Directed rounding: Round up to the next value, toward positive infinity + case MidpointRounding.ToPositiveInfinity: + { + return TVectorSingle.Ceiling(vector); + } + + default: + { + ThrowHelper.ThrowArgumentException_InvalidEnumValue(mode); + return default; + } + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static TVectorDouble ConvertToDouble(TVectorInt64 vector) where TVectorDouble : unmanaged, ISimdVector diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 6d7d0c8d862b84..c34338fdafe236 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -232,6 +232,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static System.Runtime.Intrinsics.Vector128 OnesComplement(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 RadiansToDegrees(System.Runtime.Intrinsics.Vector128 radians) { throw null; } public static System.Runtime.Intrinsics.Vector128 RadiansToDegrees(System.Runtime.Intrinsics.Vector128 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Round(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Round(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Round(System.Runtime.Intrinsics.Vector128 vector, System.MidpointRounding mode) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Round(System.Runtime.Intrinsics.Vector128 vector, System.MidpointRounding mode) { throw null; } public static System.Runtime.Intrinsics.Vector128 ShiftLeft(System.Runtime.Intrinsics.Vector128 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector128 ShiftLeft(System.Runtime.Intrinsics.Vector128 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector128 ShiftLeft(System.Runtime.Intrinsics.Vector128 vector, int shiftCount) { throw null; } @@ -299,6 +303,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static T ToScalar(this System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 ToVector256Unsafe(this System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 ToVector256(this System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Truncate(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Truncate(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static bool TryCopyTo(this System.Runtime.Intrinsics.Vector128 vector, System.Span destination) { throw null; } [System.CLSCompliantAttribute(false)] public static (System.Runtime.Intrinsics.Vector128 Lower, System.Runtime.Intrinsics.Vector128 Upper) Widen(System.Runtime.Intrinsics.Vector128 source) { throw null; } @@ -588,6 +594,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static System.Runtime.Intrinsics.Vector256 OnesComplement(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 RadiansToDegrees(System.Runtime.Intrinsics.Vector256 radians) { throw null; } public static System.Runtime.Intrinsics.Vector256 RadiansToDegrees(System.Runtime.Intrinsics.Vector256 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Round(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Round(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Round(System.Runtime.Intrinsics.Vector256 vector, System.MidpointRounding mode) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Round(System.Runtime.Intrinsics.Vector256 vector, System.MidpointRounding mode) { throw null; } public static System.Runtime.Intrinsics.Vector256 ShiftLeft(System.Runtime.Intrinsics.Vector256 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector256 ShiftLeft(System.Runtime.Intrinsics.Vector256 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector256 ShiftLeft(System.Runtime.Intrinsics.Vector256 vector, int shiftCount) { throw null; } @@ -655,6 +665,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static T ToScalar(this System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 ToVector512Unsafe(this System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 ToVector512(this System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Truncate(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Truncate(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static bool TryCopyTo(this System.Runtime.Intrinsics.Vector256 vector, System.Span destination) { throw null; } [System.CLSCompliantAttribute(false)] public static (System.Runtime.Intrinsics.Vector256 Lower, System.Runtime.Intrinsics.Vector256 Upper) Widen(System.Runtime.Intrinsics.Vector256 source) { throw null; } @@ -945,6 +957,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 OnesComplement(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 RadiansToDegrees(System.Runtime.Intrinsics.Vector512 radians) { throw null; } public static System.Runtime.Intrinsics.Vector512 RadiansToDegrees(System.Runtime.Intrinsics.Vector512 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Round(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Round(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Round(System.Runtime.Intrinsics.Vector512 vector, System.MidpointRounding mode) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Round(System.Runtime.Intrinsics.Vector512 vector, System.MidpointRounding mode) { throw null; } public static System.Runtime.Intrinsics.Vector512 ShiftLeft(System.Runtime.Intrinsics.Vector512 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector512 ShiftLeft(System.Runtime.Intrinsics.Vector512 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector512 ShiftLeft(System.Runtime.Intrinsics.Vector512 vector, int shiftCount) { throw null; } @@ -1010,6 +1026,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 Subtract(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static T Sum(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static T ToScalar(this System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Truncate(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Truncate(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static bool TryCopyTo(this System.Runtime.Intrinsics.Vector512 vector, System.Span destination) { throw null; } [System.CLSCompliantAttribute(false)] public static (System.Runtime.Intrinsics.Vector512 Lower, System.Runtime.Intrinsics.Vector512 Upper) Widen(System.Runtime.Intrinsics.Vector512 source) { throw null; } @@ -1271,6 +1289,10 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static System.Runtime.Intrinsics.Vector64 OnesComplement(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 RadiansToDegrees(System.Runtime.Intrinsics.Vector64 radians) { throw null; } public static System.Runtime.Intrinsics.Vector64 RadiansToDegrees(System.Runtime.Intrinsics.Vector64 radians) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Round(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Round(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Round(System.Runtime.Intrinsics.Vector64 vector, System.MidpointRounding mode) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Round(System.Runtime.Intrinsics.Vector64 vector, System.MidpointRounding mode) { throw null; } public static System.Runtime.Intrinsics.Vector64 ShiftLeft(System.Runtime.Intrinsics.Vector64 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector64 ShiftLeft(System.Runtime.Intrinsics.Vector64 vector, int shiftCount) { throw null; } public static System.Runtime.Intrinsics.Vector64 ShiftLeft(System.Runtime.Intrinsics.Vector64 vector, int shiftCount) { throw null; } @@ -1334,6 +1356,8 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static T ToScalar(this System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 ToVector128Unsafe(this System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 ToVector128(this System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Truncate(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Truncate(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static bool TryCopyTo(this System.Runtime.Intrinsics.Vector64 vector, System.Span destination) { throw null; } [System.CLSCompliantAttribute(false)] public static (System.Runtime.Intrinsics.Vector64 Lower, System.Runtime.Intrinsics.Vector64 Upper) Widen(System.Runtime.Intrinsics.Vector64 source) { throw null; } From 3e304c28cabc32a71207497948244153b13cc933 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 08:16:28 -0700 Subject: [PATCH 09/39] Cleanup some of the implementations to use helper functions where possible --- .../src/System/Numerics/Vector.cs | 87 +++++ .../src/System/Numerics/Vector_1.cs | 10 + .../Runtime/Intrinsics/ISimdVector_2.cs | 25 ++ .../System/Runtime/Intrinsics/Vector128.cs | 87 +++++ .../System/Runtime/Intrinsics/Vector128_1.cs | 10 + .../System/Runtime/Intrinsics/Vector256.cs | 87 +++++ .../System/Runtime/Intrinsics/Vector256_1.cs | 10 + .../System/Runtime/Intrinsics/Vector512.cs | 87 +++++ .../System/Runtime/Intrinsics/Vector512_1.cs | 10 + .../src/System/Runtime/Intrinsics/Vector64.cs | 87 +++++ .../System/Runtime/Intrinsics/Vector64_1.cs | 10 + .../System/Runtime/Intrinsics/VectorMath.cs | 358 +++++++++++------- 12 files changed, 738 insertions(+), 130 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 72e8b4ba6668e6..818f2feae1fe67 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -1170,6 +1170,93 @@ public static Vector Hypot(Vector x, Vector y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector IsNaN(Vector vector) + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return ~Equals(vector, vector); + } + return Vector.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector IsNegative(Vector vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector.Zero; + } + else if (typeof(T) == typeof(float)) + { + return LessThan(vector.As(), Vector.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return LessThan(vector.As(), Vector.Zero).As(); + } + else + { + return LessThan(vector, Vector.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector IsPositive(Vector vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector.AllBitsSet; + } + else if (typeof(T) == typeof(float)) + { + return GreaterThanOrEqual(vector.As(), Vector.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return GreaterThanOrEqual(vector.As(), Vector.Zero).As(); + } + else + { + return GreaterThanOrEqual(vector, Vector.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector IsPositiveInfinity(Vector vector) + { + if (typeof(T) == typeof(float)) + { + return Equals(vector, Create(float.PositiveInfinity).As()); + } + else if (typeof(T) == typeof(double)) + { + return Equals(vector, Create(double.PositiveInfinity).As()); + } + return Vector.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector IsZero(Vector vector) => Equals(vector, Vector.Zero); + internal static Vector Lerp(Vector x, Vector y, Vector amount) where T : IFloatingPointIeee754 { diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index aaf0f7fd33ea7f..7707106a1e0112 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -1043,5 +1043,15 @@ static int ISimdVector, T>.IndexOfLastMatch(Vector vector) return 31 - BitOperations.LeadingZeroCount(mask); // 31 = 32 (bits in Int32) - 1 (indexing from zero) } } + + static Vector ISimdVector, T>.IsNaN(Vector vector) => Vector.IsNaN(vector); + + static Vector ISimdVector, T>.IsNegative(Vector vector) => Vector.IsNegative(vector); + + static Vector ISimdVector, T>.IsPositive(Vector vector) => Vector.IsPositive(vector); + + static Vector ISimdVector, T>.IsPositiveInfinity(Vector vector) => Vector.IsPositiveInfinity(vector); + + static Vector ISimdVector, T>.IsZero(Vector vector) => Vector.IsZero(vector); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs index 192507af6f5a66..c65f9f3179e34a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs @@ -316,6 +316,31 @@ static virtual TSelf CreateScalarUnsafe(T value) /// The type of the elements in the vector () is not supported. static abstract bool GreaterThanOrEqualAny(TSelf left, TSelf right); + /// Determines which elements in a vector are NaN. + /// The vector to be checked. + /// A vector whose elements are all-bits-set or zero, depending on if the corresponding elements in were NaN. + static abstract TSelf IsNaN(TSelf vector); + + /// Determines which elements in a vector represents negative real numbers. + /// The vector to be checked. + /// A vector whose elements are all-bits-set or zero, depending on if the corresponding elements in were negative. + static abstract TSelf IsNegative(TSelf vector); + + /// Determines which elements in a vector represents positive real numbers. + /// The vector to be checked. + /// A vector whose elements are all-bits-set or zero, depending on if the corresponding elements in were positive. + static abstract TSelf IsPositive(TSelf vector); + + /// Determines which elements in a vector are positive infinity. + /// The vector to be checked. + /// A vector whose elements are all-bits-set or zero, depending on if the corresponding elements in were positive infinity. + static abstract TSelf IsPositiveInfinity(TSelf vector); + + /// Determines which elements in a vector are zero. + /// The vector to be checked. + /// A vector whose elements are all-bits-set or zero, depending on if the corresponding elements in were zero. + static abstract TSelf IsZero(TSelf vector); + /// Compares two vectors to determine which is less on a per-element basis. /// The vector to compare with . /// The vector to compare with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 793639d9527c1c..7e36cd0d1cb0be 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -1850,6 +1850,93 @@ public static Vector128 Hypot(Vector128 x, Vector128 y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 IsNaN(Vector128 vector) + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return ~Equals(vector, vector); + } + return Vector128.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 IsNegative(Vector128 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector128.Zero; + } + else if (typeof(T) == typeof(float)) + { + return LessThan(vector.AsInt32(), Vector128.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return LessThan(vector.AsInt64(), Vector128.Zero).As(); + } + else + { + return LessThan(vector, Vector128.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 IsPositive(Vector128 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector128.AllBitsSet; + } + else if (typeof(T) == typeof(float)) + { + return GreaterThanOrEqual(vector.AsInt32(), Vector128.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return GreaterThanOrEqual(vector.AsInt64(), Vector128.Zero).As(); + } + else + { + return GreaterThanOrEqual(vector, Vector128.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 IsPositiveInfinity(Vector128 vector) + { + if (typeof(T) == typeof(float)) + { + return Equals(vector, Create(float.PositiveInfinity).As()); + } + else if (typeof(T) == typeof(double)) + { + return Equals(vector, Create(double.PositiveInfinity).As()); + } + return Vector128.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector128 IsZero(Vector128 vector) => Equals(vector, Vector128.Zero); + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index 81a1ab4d3a4b08..64828c80e63a87 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -676,5 +676,15 @@ static int ISimdVector, T>.IndexOfLastMatch(Vector128 vector) uint mask = vector.ExtractMostSignificantBits(); return 31 - BitOperations.LeadingZeroCount(mask); // 31 = 32 (bits in Int32) - 1 (indexing from zero) } + + static Vector128 ISimdVector, T>.IsNaN(Vector128 vector) => Vector128.IsNaN(vector); + + static Vector128 ISimdVector, T>.IsNegative(Vector128 vector) => Vector128.IsNegative(vector); + + static Vector128 ISimdVector, T>.IsPositive(Vector128 vector) => Vector128.IsPositive(vector); + + static Vector128 ISimdVector, T>.IsPositiveInfinity(Vector128 vector) => Vector128.IsPositiveInfinity(vector); + + static Vector128 ISimdVector, T>.IsZero(Vector128 vector) => Vector128.IsZero(vector); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index e68c3dda4b8dd3..c5657b9d85e03a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -1766,6 +1766,93 @@ public static Vector256 Hypot(Vector256 x, Vector256 y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 IsNaN(Vector256 vector) + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return ~Equals(vector, vector); + } + return Vector256.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 IsNegative(Vector256 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector256.Zero; + } + else if (typeof(T) == typeof(float)) + { + return LessThan(vector.AsInt32(), Vector256.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return LessThan(vector.AsInt64(), Vector256.Zero).As(); + } + else + { + return LessThan(vector, Vector256.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 IsPositive(Vector256 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector256.AllBitsSet; + } + else if (typeof(T) == typeof(float)) + { + return GreaterThanOrEqual(vector.AsInt32(), Vector256.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return GreaterThanOrEqual(vector.AsInt64(), Vector256.Zero).As(); + } + else + { + return GreaterThanOrEqual(vector, Vector256.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 IsPositiveInfinity(Vector256 vector) + { + if (typeof(T) == typeof(float)) + { + return Equals(vector, Create(float.PositiveInfinity).As()); + } + else if (typeof(T) == typeof(double)) + { + return Equals(vector, Create(double.PositiveInfinity).As()); + } + return Vector256.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector256 IsZero(Vector256 vector) => Equals(vector, Vector256.Zero); + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index 1dcd26a09e63ba..07c8872d98ee2a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -665,5 +665,15 @@ static int ISimdVector, T>.IndexOfLastMatch(Vector256 vector) uint mask = vector.ExtractMostSignificantBits(); return 31 - BitOperations.LeadingZeroCount(mask); // 31 = 32 (bits in Int32) - 1 (indexing from zero) } + + static Vector256 ISimdVector, T>.IsNaN(Vector256 vector) => Vector256.IsNaN(vector); + + static Vector256 ISimdVector, T>.IsNegative(Vector256 vector) => Vector256.IsNegative(vector); + + static Vector256 ISimdVector, T>.IsPositive(Vector256 vector) => Vector256.IsPositive(vector); + + static Vector256 ISimdVector, T>.IsPositiveInfinity(Vector256 vector) => Vector256.IsPositiveInfinity(vector); + + static Vector256 ISimdVector, T>.IsZero(Vector256 vector) => Vector256.IsZero(vector); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index dafc4eb1a9a9f9..5437b459b88f0c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -1829,6 +1829,93 @@ public static Vector512 Hypot(Vector512 x, Vector512 y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 IsNaN(Vector512 vector) + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return ~Equals(vector, vector); + } + return Vector512.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 IsNegative(Vector512 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector512.Zero; + } + else if (typeof(T) == typeof(float)) + { + return LessThan(vector.AsInt32(), Vector512.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return LessThan(vector.AsInt64(), Vector512.Zero).As(); + } + else + { + return LessThan(vector, Vector512.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 IsPositive(Vector512 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector512.AllBitsSet; + } + else if (typeof(T) == typeof(float)) + { + return GreaterThanOrEqual(vector.AsInt32(), Vector512.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return GreaterThanOrEqual(vector.AsInt64(), Vector512.Zero).As(); + } + else + { + return GreaterThanOrEqual(vector, Vector512.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 IsPositiveInfinity(Vector512 vector) + { + if (typeof(T) == typeof(float)) + { + return Equals(vector, Create(float.PositiveInfinity).As()); + } + else if (typeof(T) == typeof(double)) + { + return Equals(vector, Create(double.PositiveInfinity).As()); + } + return Vector512.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector512 IsZero(Vector512 vector) => Equals(vector, Vector512.Zero); + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs index 9900c187a7eec3..a3db1e9bd92db3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs @@ -665,5 +665,15 @@ static int ISimdVector, T>.IndexOfLastMatch(Vector512 vector) ulong mask = vector.ExtractMostSignificantBits(); return 63 - BitOperations.LeadingZeroCount(mask); // 63 = 64 (bits in Int64) - 1 (indexing from zero) } + + static Vector512 ISimdVector, T>.IsNaN(Vector512 vector) => Vector512.IsNaN(vector); + + static Vector512 ISimdVector, T>.IsNegative(Vector512 vector) => Vector512.IsNegative(vector); + + static Vector512 ISimdVector, T>.IsPositive(Vector512 vector) => Vector512.IsPositive(vector); + + static Vector512 ISimdVector, T>.IsPositiveInfinity(Vector512 vector) => Vector512.IsPositiveInfinity(vector); + + static Vector512 ISimdVector, T>.IsZero(Vector512 vector) => Vector512.IsZero(vector); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index 35f7c817998d2c..e69aaeb4c03824 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -1566,6 +1566,93 @@ public static Vector64 Hypot(Vector64 x, Vector64 y) } } + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 IsNaN(Vector64 vector) + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return ~Equals(vector, vector); + } + return Vector64.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 IsNegative(Vector64 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector64.Zero; + } + else if (typeof(T) == typeof(float)) + { + return LessThan(vector.AsInt32(), Vector64.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return LessThan(vector.AsInt64(), Vector64.Zero).As(); + } + else + { + return LessThan(vector, Vector64.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 IsPositive(Vector64 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector64.AllBitsSet; + } + else if (typeof(T) == typeof(float)) + { + return GreaterThanOrEqual(vector.AsInt32(), Vector64.Zero).As(); + } + else if (typeof(T) == typeof(double)) + { + return GreaterThanOrEqual(vector.AsInt64(), Vector64.Zero).As(); + } + else + { + return GreaterThanOrEqual(vector, Vector64.Zero); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 IsPositiveInfinity(Vector64 vector) + { + if (typeof(T) == typeof(float)) + { + return Equals(vector, Create(float.PositiveInfinity).As()); + } + else if (typeof(T) == typeof(double)) + { + return Equals(vector, Create(double.PositiveInfinity).As()); + } + return Vector64.Zero; + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static Vector64 IsZero(Vector64 vector) => Equals(vector, Vector64.Zero); + internal static Vector64 Lerp(Vector64 x, Vector64 y, Vector64 amount) where T : IFloatingPointIeee754 { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index 2193bd1d868e67..f3ab67a27de940 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -733,5 +733,15 @@ static int ISimdVector, T>.IndexOfLastMatch(Vector64 vector) uint mask = vector.ExtractMostSignificantBits(); return 31 - BitOperations.LeadingZeroCount(mask); // 31 = 32 (bits in Int32) - 1 (indexing from zero) } + + static Vector64 ISimdVector, T>.IsNaN(Vector64 vector) => Vector64.IsNaN(vector); + + static Vector64 ISimdVector, T>.IsNegative(Vector64 vector) => Vector64.IsNegative(vector); + + static Vector64 ISimdVector, T>.IsPositive(Vector64 vector) => Vector64.IsPositive(vector); + + static Vector64 ISimdVector, T>.IsPositiveInfinity(Vector64 vector) => Vector64.IsPositiveInfinity(vector); + + static Vector64 ISimdVector, T>.IsZero(Vector64 vector) => Vector64.IsZero(vector); } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index 6d47c7fa57f46b..07e6fc2dda9e9c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -5,10 +5,11 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; namespace System.Runtime.Intrinsics { - internal static class VectorMath + internal static unsafe class VectorMath { [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TVector CopySign(TVector value, TVector sign) @@ -33,7 +34,7 @@ public static TVector CopySign(TVector value, TVector sign) // All values are two's complement and so `value ^ sign` will produce a positive // number if the signs match and a negative number if the signs differ. When the // signs differ we want to negate the value and otherwise take the value as is. - return TVector.ConditionalSelect(TVector.LessThan(value ^ sign, TVector.Zero), -value, value); + return TVector.ConditionalSelect(TVector.IsNegative(value ^ sign), -value, value); } } @@ -99,21 +100,19 @@ public static TVectorDouble ExpDouble(dn); @@ -123,18 +122,33 @@ public static TVectorDouble ExpDouble( @@ -296,9 +323,8 @@ public static TVectorDouble HypotDouble(TVectorDou TVectorDouble ax = TVectorDouble.Abs(x); TVectorDouble ay = TVectorDouble.Abs(y); - TVectorDouble positiveInfinity = TVectorDouble.Create(float.PositiveInfinity); - TVectorDouble infinityMask = TVectorDouble.Equals(ax, positiveInfinity) | TVectorDouble.Equals(ay, positiveInfinity); - TVectorDouble notNaNMask = TVectorDouble.Equals(ax, ax) & TVectorDouble.Equals(ay, ay); + TVectorDouble infinityMask = TVectorDouble.IsPositiveInfinity(ax) | TVectorDouble.IsPositiveInfinity(ay); + TVectorDouble nanMask = TVectorDouble.IsNaN(ax) | TVectorDouble.IsNaN(ay); TVectorUInt64 xBits = Unsafe.BitCast(ax); TVectorUInt64 yBits = Unsafe.BitCast(ay); @@ -331,12 +357,12 @@ public static TVectorDouble HypotDouble(TVectorDou TVectorDouble subnormalFix = TVectorDouble.Create(9.232978617785736E-128); TVectorUInt64 subnormalBitsFix = TVectorUInt64.Create(0x0010000000000000); - TVectorUInt64 xSubnormalMask = TVectorUInt64.Equals(xExp, TVectorUInt64.Zero) & scaleUpMask; + TVectorUInt64 xSubnormalMask = TVectorUInt64.IsZero(xExp) & scaleUpMask; xBits += subnormalBitsFix & xSubnormalMask; ax = Unsafe.BitCast(xBits); ax -= subnormalFix & Unsafe.BitCast(xSubnormalMask); - TVectorUInt64 ySubnormalMask = TVectorUInt64.Equals(yExp, TVectorUInt64.Zero) & scaleUpMask; + TVectorUInt64 ySubnormalMask = TVectorUInt64.IsZero(yExp) & scaleUpMask; yBits += subnormalBitsFix & ySubnormalMask; ay = Unsafe.BitCast(yBits); ay -= subnormalFix & Unsafe.BitCast(ySubnormalMask); @@ -378,18 +404,18 @@ public static TVectorDouble HypotDouble(TVectorDou TVectorDouble rHead = xx + yy; TVectorDouble rTail = (xx - rHead) + yy; - rTail += (xHead * xHead) - xx; - rTail += xHead * 2 * xTail; - rTail += xTail * xTail; + rTail += TVectorDouble.MultiplyAddEstimate(xHead, xHead, -xx); + rTail = TVectorDouble.MultiplyAddEstimate(xHead * 2, xTail, rTail); + rTail = TVectorDouble.MultiplyAddEstimate(xTail, xTail, rTail); // We only need to do extra accounting when ax and ay have equal exponents - TVectorDouble equalExponentsMask = Unsafe.BitCast(TVectorUInt64.Equals(expDiff, TVectorUInt64.Zero)); + TVectorDouble equalExponentsMask = Unsafe.BitCast(TVectorUInt64.IsZero(expDiff)); TVectorDouble rTailTmp = rTail; - rTailTmp += (yHead * yHead) - yy; - rTailTmp += yHead * 2 * yTail; - rTailTmp += yTail * yTail; + rTailTmp += TVectorDouble.MultiplyAddEstimate(yHead, yHead, -yy); + rTailTmp = TVectorDouble.MultiplyAddEstimate(yHead * 2, yTail, rTailTmp); + rTailTmp = TVectorDouble.MultiplyAddEstimate(yTail, yTail, rTailTmp); rTail = TVectorDouble.ConditionalSelect(equalExponentsMask, rTailTmp, rTail); @@ -400,7 +426,7 @@ public static TVectorDouble HypotDouble(TVectorDou // the inputs is NaN. Otherwise if either input // is NaN, we return NaN - result = TVectorDouble.ConditionalSelect(notNaNMask, result, TVectorDouble.Create(double.NaN)); + result = TVectorDouble.ConditionalSelect(nanMask, TVectorDouble.Create(double.NaN), result); result = TVectorDouble.ConditionalSelect(infinityMask, TVectorDouble.Create(double.PositiveInfinity), result); return result; @@ -419,21 +445,15 @@ public static TVectorSingle HypotSingle(TVectorSin TVectorSingle ax = TVectorSingle.Abs(x); TVectorSingle ay = TVectorSingle.Abs(y); - TVectorSingle positiveInfinity = TVectorSingle.Create(float.PositiveInfinity); - TVectorSingle infinityMask = TVectorSingle.Equals(ax, positiveInfinity) | TVectorSingle.Equals(ay, positiveInfinity); - TVectorSingle notNaNMask = TVectorSingle.Equals(ax, ax) & TVectorSingle.Equals(ay, ay); + TVectorSingle infinityMask = TVectorSingle.IsPositiveInfinity(ax) | TVectorSingle.IsPositiveInfinity(ay); + TVectorSingle nanMask = TVectorSingle.IsNaN(ax) | TVectorSingle.IsNaN(ay); (TVectorDouble xxLower, TVectorDouble xxUpper) = Widen(ax); - xxLower *= xxLower; - xxUpper *= xxUpper; - (TVectorDouble yyLower, TVectorDouble yyUpper) = Widen(ay); - yyLower *= yyLower; - yyUpper *= yyUpper; TVectorSingle result = Narrow( - TVectorDouble.Sqrt(xxLower + yyLower), - TVectorDouble.Sqrt(xxUpper + yyUpper) + TVectorDouble.Sqrt(TVectorDouble.MultiplyAddEstimate(xxLower, xxLower, yyLower * yyLower)), + TVectorDouble.Sqrt(TVectorDouble.MultiplyAddEstimate(xxUpper, xxUpper, yyUpper * yyUpper)) ); // IEEE 754 requires that we return +Infinity @@ -441,7 +461,7 @@ public static TVectorSingle HypotSingle(TVectorSin // the inputs is NaN. Otherwise if either input // is NaN, we return NaN - result = TVectorSingle.ConditionalSelect(notNaNMask, result, TVectorSingle.Create(float.NaN)); + result = TVectorSingle.ConditionalSelect(nanMask, TVectorSingle.Create(float.NaN), result); result = TVectorSingle.ConditionalSelect(infinityMask, TVectorSingle.Create(float.PositiveInfinity), result); return result; @@ -521,19 +541,17 @@ public static TVectorDouble LogDouble(x); - - // (x < 0) ? float.NaN : x - TVectorDouble lessThanZeroMask = Unsafe.BitCast(TVectorInt64.LessThan(xBits, TVectorInt64.Zero)); + // double.IsNegative(x) ? double.NaN : x + TVectorDouble isNegativeMask = TVectorDouble.IsNegative(x); specialResult = TVectorDouble.ConditionalSelect( - lessThanZeroMask, + isNegativeMask, TVectorDouble.Create(double.NaN), specialResult ); // double.IsZero(x) ? double.NegativeInfinity : x - TVectorDouble zeroMask = Unsafe.BitCast(TVectorInt64.Equals(xBits << 1, TVectorInt64.Zero)); + TVectorDouble zeroMask = TVectorDouble.IsZero(x); specialResult = TVectorDouble.ConditionalSelect( zeroMask, @@ -541,10 +559,11 @@ public static TVectorDouble LogDouble(TVectorInt64.GreaterThanOrEqual(xBits, TVectorInt64.Create((long)double.PositiveInfinityBits))); + | isNegativeMask + | TVectorDouble.IsNaN(x) + | TVectorDouble.IsPositiveInfinity(x); // subnormal TVectorDouble subnormalMask = TVectorDouble.AndNot(Unsafe.BitCast(specialMask), temp); @@ -575,21 +594,50 @@ public static TVectorDouble LogDouble(specialMask), specialResult, - (n * LN2_HEAD) + ((n * LN2_TAIL) + poly) + TVectorDouble.MultiplyAddEstimate( + n, + TVectorDouble.Create(LN2_HEAD), + TVectorDouble.MultiplyAddEstimate(n, TVectorDouble.Create(LN2_TAIL), poly) + ) ); } @@ -657,16 +705,14 @@ public static TVectorSingle LogSingle(specialMask), temp); @@ -723,16 +769,30 @@ public static TVectorSingle LogSingle(specialMask), specialResult, - n * TVectorSingle.Create(V_LN2) + q + TVectorSingle.MultiplyAddEstimate(n, TVectorSingle.Create(V_LN2), q) ); } @@ -801,19 +861,17 @@ public static TVectorDouble Log2Double(x); - - // (x < 0) ? float.NaN : x - TVectorDouble lessThanZeroMask = Unsafe.BitCast(TVectorInt64.LessThan(xBits, TVectorInt64.Zero)); + // double.IsNegative(x) ? double.NaN : x + TVectorDouble isNegativeMask = TVectorDouble.IsNegative(x); specialResult = TVectorDouble.ConditionalSelect( - lessThanZeroMask, + isNegativeMask, TVectorDouble.Create(double.NaN), specialResult ); // double.IsZero(x) ? double.NegativeInfinity : x - TVectorDouble zeroMask = Unsafe.BitCast(TVectorInt64.Equals(xBits << 1, TVectorInt64.Zero)); + TVectorDouble zeroMask = TVectorDouble.IsZero(x); specialResult = TVectorDouble.ConditionalSelect( zeroMask, @@ -821,10 +879,11 @@ public static TVectorDouble Log2Double(TVectorInt64.GreaterThanOrEqual(xBits, TVectorInt64.Create((long)double.PositiveInfinityBits))); + | isNegativeMask + | TVectorDouble.IsNaN(x) + | TVectorDouble.IsPositiveInfinity(x); // subnormal TVectorDouble subnormalMask = TVectorDouble.AndNot(Unsafe.BitCast(specialMask), temp); @@ -855,21 +914,50 @@ public static TVectorDouble Log2Double(specialMask), specialResult, - (poly * LN2_HEAD) + ((poly * LN2_TAIL) + n) + TVectorDouble.MultiplyAddEstimate( + poly, + TVectorDouble.Create(LN2_HEAD), + TVectorDouble.MultiplyAddEstimate(poly, TVectorDouble.Create(LN2_TAIL), n) + ) ); } @@ -950,19 +1038,17 @@ public static TVectorSingle Log2Single(x); - - // (x < 0) ? float.NaN : x - TVectorSingle lessThanZeroMask = Unsafe.BitCast(TVectorInt32.LessThan(xBits, TVectorInt32.Zero)); + // float.IsNegative(x) ? float.NaN : x + TVectorSingle isNegativeMask = TVectorSingle.IsNegative(x); specialResult = TVectorSingle.ConditionalSelect( - lessThanZeroMask, + isNegativeMask, TVectorSingle.Create(float.NaN), specialResult ); // float.IsZero(x) ? float.NegativeInfinity : x - TVectorSingle zeroMask = Unsafe.BitCast(TVectorInt32.Equals(xBits << 1, TVectorInt32.Zero)); + TVectorSingle zeroMask = TVectorSingle.IsZero(x); specialResult = TVectorSingle.ConditionalSelect( zeroMask, @@ -970,10 +1056,11 @@ public static TVectorSingle Log2Single(TVectorInt32.GreaterThanOrEqual(xBits, TVectorInt32.Create((int)float.PositiveInfinityBits))); + | isNegativeMask + | TVectorSingle.IsNaN(x) + | TVectorSingle.IsPositiveInfinity(x); // subnormal TVectorSingle subnormalMask = TVectorSingle.AndNot(Unsafe.BitCast(specialMask), temp); @@ -1003,11 +1090,22 @@ public static TVectorSingle Log2Single(specialMask), From 43d4696ae9a0d4c1c604dc4a1fcd5851b034dae0 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 08:19:27 -0700 Subject: [PATCH 10/39] Expose Max, MaxMagnitude, MaxMagnitudeNumber, MaxNumber, Min, MinMagnitude, MinMagnitudeNumber, and MinNumber for the vector types --- src/coreclr/jit/compiler.h | 12 + src/coreclr/jit/gentree.cpp | 88 ++++++ src/coreclr/jit/hwintrinsicarm64.cpp | 35 +++ src/coreclr/jit/hwintrinsiclistarm64.h | 4 + src/coreclr/jit/hwintrinsiclistxarch.h | 6 + src/coreclr/jit/hwintrinsicxarch.cpp | 44 +++ src/coreclr/jit/simdashwintrinsic.cpp | 12 + src/coreclr/jit/simdashwintrinsiclistarm64.h | 2 + src/coreclr/jit/simdashwintrinsiclistxarch.h | 2 + .../ref/System.Numerics.Vectors.cs | 32 +++ .../src/System/Numerics/Vector.cs | 230 +++++++++++++-- .../src/System/Numerics/Vector2.cs | 50 +++- .../src/System/Numerics/Vector3.cs | 50 +++- .../src/System/Numerics/Vector4.cs | 50 +++- .../src/System/Numerics/Vector_1.cs | 24 ++ .../Runtime/Intrinsics/ISimdVector_2.cs | 74 ++++- .../src/System/Runtime/Intrinsics/Scalar.cs | 266 ++++++++++++++++++ .../System/Runtime/Intrinsics/Vector128.cs | 188 +++++++++++-- .../System/Runtime/Intrinsics/Vector128_1.cs | 24 ++ .../System/Runtime/Intrinsics/Vector256.cs | 188 +++++++++++-- .../System/Runtime/Intrinsics/Vector256_1.cs | 24 ++ .../System/Runtime/Intrinsics/Vector512.cs | 188 +++++++++++-- .../System/Runtime/Intrinsics/Vector512_1.cs | 24 ++ .../src/System/Runtime/Intrinsics/Vector64.cs | 232 +++++++++++++-- .../System/Runtime/Intrinsics/Vector64_1.cs | 24 ++ .../System/Runtime/Intrinsics/VectorMath.cs | 173 ++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 32 +++ src/mono/mono/mini/simd-intrinsics.c | 26 +- src/mono/mono/mini/simd-methods.h | 6 +- 29 files changed, 1976 insertions(+), 134 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 21db592533614f..76819a08c95ec8 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3329,12 +3329,24 @@ class Compiler CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdMaxNativeNode(var_types type, + GenTree* op1, + GenTree* op2, + CorInfoType simdBaseJitType, + unsigned simdSize); + GenTree* gtNewSimdMinNode(var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdMinNativeNode(var_types type, + GenTree* op1, + GenTree* op2, + CorInfoType simdBaseJitType, + unsigned simdSize); + GenTree* gtNewSimdNarrowNode(var_types type, GenTree* op1, GenTree* op2, diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 759391984ec1ce..1bfa176b5715b8 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -24955,6 +24955,50 @@ GenTree* Compiler::gtNewSimdMaxNode( var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); +#if defined(TARGET_XARCH) + if (varTypeIsFloating(simdBaseType)) + { + GenTree* op1Dup1 = fgMakeMultiUse(&op1); + GenTree* op1Dup2 = fgMakeMultiUse(&op1); + GenTree* op1Dup3 = fgMakeMultiUse(&op1); + + GenTree* op2Dup1 = fgMakeMultiUse(&op2); + GenTree* op2Dup2 = fgMakeMultiUse(&op2); + GenTree* op2Dup3 = fgMakeMultiUse(&op2); + + GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); + GenTree* isNegativeMask = gtNewSimdIsNegativeNode(type, op2Dup1, simdBaseJitType, simdSize); + GenTree* isNaNMask = gtNewSimdIsNaNNode(type, op1Dup1, simdBaseJitType, simdSize); + GenTree* lessThanMask = gtNewSimdCmpOpNode(GT_LT, type, op2Dup2, op1Dup2, simdBaseJitType, simdSize); + + GenTree* mask = gtNewSimdBinOpNode(GT_AND, type, equalsMask, isNegativeMask, simdBaseJitType, simdSize); + mask = gtNewSimdBinOpNode(GT_OR, type, mask, isNaNMask, simdBaseJitType, simdSize); + mask = gtNewSimdBinOpNode(GT_OR, type, mask, lessThanMask, simdBaseJitType, simdSize); + + return gtNewSimdCndSelNode(type, mask, op1Dup3, op2Dup3, simdBaseJitType, simdSize); + } +#endif // TARGET_XARCH + + return gtNewSimdMaxNativeNode(type, op1, op2, simdBaseJitType, simdSize); +} + +GenTree* Compiler::gtNewSimdMaxNativeNode( + var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + assert(op2 != nullptr); + assert(op2->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); + NamedIntrinsic intrinsic = NI_Illegal; #if defined(TARGET_XARCH) @@ -25170,6 +25214,50 @@ GenTree* Compiler::gtNewSimdMinNode( var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); assert(varTypeIsArithmetic(simdBaseType)); +#if defined(TARGET_XARCH) + if (varTypeIsFloating(simdBaseType)) + { + GenTree* op1Dup1 = fgMakeMultiUse(&op1); + GenTree* op1Dup2 = fgMakeMultiUse(&op1); + GenTree* op1Dup3 = fgMakeMultiUse(&op1); + GenTree* op1Dup4 = fgMakeMultiUse(&op1); + + GenTree* op2Dup1 = fgMakeMultiUse(&op2); + GenTree* op2Dup2 = fgMakeMultiUse(&op2); + + GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); + GenTree* isNegativeMask = gtNewSimdIsNegativeNode(type, op1Dup1, simdBaseJitType, simdSize); + GenTree* isNaNMask = gtNewSimdIsNaNNode(type, op1Dup2, simdBaseJitType, simdSize); + GenTree* lessThanMask = gtNewSimdCmpOpNode(GT_LT, type, op1Dup3, op2Dup1, simdBaseJitType, simdSize); + + GenTree* mask = gtNewSimdBinOpNode(GT_AND, type, equalsMask, isNegativeMask, simdBaseJitType, simdSize); + mask = gtNewSimdBinOpNode(GT_OR, type, mask, isNaNMask, simdBaseJitType, simdSize); + mask = gtNewSimdBinOpNode(GT_OR, type, mask, lessThanMask, simdBaseJitType, simdSize); + + return gtNewSimdCndSelNode(type, mask, op1Dup4, op2Dup2, simdBaseJitType, simdSize); + } +#endif // TARGET_XARCH + + return gtNewSimdMinNativeNode(type, op1, op2, simdBaseJitType, simdSize); +} + +GenTree* Compiler::gtNewSimdMinNativeNode( + var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + assert(op2 != nullptr); + assert(op2->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); + NamedIntrinsic intrinsic = NI_Illegal; #if defined(TARGET_XARCH) diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 5b246b148dd87c..a75c24831d3add 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1749,6 +1749,23 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector64_MaxNative: + case NI_Vector128_MaxNative: + { + assert(sig->numArgs == 2); + + if (BlockNonDeterministicIntrinsics(mustExpand)) + { + break; + } + + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdMaxNativeNode(retType, op1, op2, simdBaseJitType, simdSize); + break; + } + case NI_Vector64_Min: case NI_Vector128_Min: { @@ -1761,6 +1778,24 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + + case NI_Vector64_MinNative: + case NI_Vector128_MinNative: + { + assert(sig->numArgs == 2); + + if (BlockNonDeterministicIntrinsics(mustExpand)) + { + break; + } + + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdMinNativeNode(retType, op1, op2, simdBaseJitType, simdSize); + break; + } + case NI_Vector64_op_Multiply: case NI_Vector128_op_Multiply: { diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index c778087accc4a9..9b7bdd37a94ba0 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -78,7 +78,9 @@ HARDWARE_INTRINSIC(Vector64, LoadAligned, HARDWARE_INTRINSIC(Vector64, LoadAlignedNonTemporal, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, LoadUnsafe, 8, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Max, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, MaxNative, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Min, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, MinNative, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, MultiplyAddEstimate, 8, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Narrow, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, op_Addition, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -186,7 +188,9 @@ HARDWARE_INTRINSIC(Vector128, LoadAligned, HARDWARE_INTRINSIC(Vector128, LoadAlignedNonTemporal, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, LoadUnsafe, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Max, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, MaxNative, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Min, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, MinNative, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, MultiplyAddEstimate, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Narrow, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, op_Addition, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 96a9d2febd30a7..191dce19f725e4 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -98,7 +98,9 @@ HARDWARE_INTRINSIC(Vector128, LoadAligned, HARDWARE_INTRINSIC(Vector128, LoadAlignedNonTemporal, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, LoadUnsafe, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Max, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, MaxNative, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Min, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, MinNative, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, MultiplyAddEstimate, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Narrow, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, op_Addition, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -202,7 +204,9 @@ HARDWARE_INTRINSIC(Vector256, LoadAligned, HARDWARE_INTRINSIC(Vector256, LoadAlignedNonTemporal, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, LoadUnsafe, 32, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, Max, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, MaxNative, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, Min, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, MinNative, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, MultiplyAddEstimate, 32, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, Narrow, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, op_Addition, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) @@ -307,7 +311,9 @@ HARDWARE_INTRINSIC(Vector512, LoadAligned, HARDWARE_INTRINSIC(Vector512, LoadAlignedNonTemporal, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, LoadUnsafe, 64, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Max, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, MaxNative, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Min, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, MinNative, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, MultiplyAddEstimate, 64, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Narrow, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, op_Addition, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index eeda97fad22762..e888a5b8fac7f8 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2738,6 +2738,28 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_MaxNative: + case NI_Vector256_MaxNative: + case NI_Vector512_MaxNative: + { + assert(sig->numArgs == 2); + + if (BlockNonDeterministicIntrinsics(mustExpand)) + { + break; + } + + if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || + compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdMaxNativeNode(retType, op1, op2, simdBaseJitType, simdSize); + } + break; + } + case NI_Vector128_Min: case NI_Vector256_Min: case NI_Vector512_Min: @@ -2755,6 +2777,28 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_MinNative: + case NI_Vector256_MinNative: + case NI_Vector512_MinNative: + { + assert(sig->numArgs == 2); + + if (BlockNonDeterministicIntrinsics(mustExpand)) + { + break; + } + + if ((simdSize != 32) || varTypeIsFloating(simdBaseType) || + compOpportunisticallyDependsOn(InstructionSet_AVX2)) + { + op2 = impSIMDPopStack(); + op1 = impSIMDPopStack(); + + retNode = gtNewSimdMinNativeNode(retType, op1, op2, simdBaseJitType, simdSize); + } + break; + } + case NI_Vector128_op_Multiply: case NI_Vector256_op_Multiply: case NI_Vector512_op_Multiply: diff --git a/src/coreclr/jit/simdashwintrinsic.cpp b/src/coreclr/jit/simdashwintrinsic.cpp index cfdca6e34677eb..d11bdb3f78c8a1 100644 --- a/src/coreclr/jit/simdashwintrinsic.cpp +++ b/src/coreclr/jit/simdashwintrinsic.cpp @@ -447,6 +447,8 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, switch (intrinsic) { case NI_VectorT_ConvertToInt32Native: + case NI_VectorT_MaxNative: + case NI_VectorT_MinNative: { if (BlockNonDeterministicIntrinsics(mustExpand)) { @@ -1343,11 +1345,21 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, return gtNewSimdMaxNode(retType, op1, op2, simdBaseJitType, simdSize); } + case NI_VectorT_MaxNative: + { + return gtNewSimdMaxNativeNode(retType, op1, op2, simdBaseJitType, simdSize); + } + case NI_VectorT_Min: { return gtNewSimdMinNode(retType, op1, op2, simdBaseJitType, simdSize); } + case NI_VectorT_MinNative: + { + return gtNewSimdMinNativeNode(retType, op1, op2, simdBaseJitType, simdSize); + } + case NI_VectorT_op_Multiply: { return gtNewSimdBinOpNode(GT_MUL, retType, op1, op2, simdBaseJitType, simdSize); diff --git a/src/coreclr/jit/simdashwintrinsiclistarm64.h b/src/coreclr/jit/simdashwintrinsiclistarm64.h index efb3107930b03c..14cb7f68f957c7 100644 --- a/src/coreclr/jit/simdashwintrinsiclistarm64.h +++ b/src/coreclr/jit/simdashwintrinsiclistarm64.h @@ -93,7 +93,9 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, LoadAlignedNonTemporal, SIMD_AS_HWINTRINSIC_ID(VectorT, LoadUnsafe, 1, {NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_NM(VectorT, LoadUnsafeIndex, "LoadUnsafe", 2, {NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_ID(VectorT, Max, 2, {NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, MaxNative, 2, {NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Min, 2, {NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, MinNative, 2, {NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_MultiplyAddEstimate, NI_VectorT_MultiplyAddEstimate}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Narrow, 2, {NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_ID(VectorT, op_Addition, 2, {NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition}, SimdAsHWIntrinsicFlag::None) diff --git a/src/coreclr/jit/simdashwintrinsiclistxarch.h b/src/coreclr/jit/simdashwintrinsiclistxarch.h index 4074204e29ea4a..a5689429e240a6 100644 --- a/src/coreclr/jit/simdashwintrinsiclistxarch.h +++ b/src/coreclr/jit/simdashwintrinsiclistxarch.h @@ -93,7 +93,9 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, LoadAlignedNonTemporal, SIMD_AS_HWINTRINSIC_ID(VectorT, LoadUnsafe, 1, {NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe, NI_VectorT_LoadUnsafe}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_NM(VectorT, LoadUnsafeIndex, "LoadUnsafe", 2, {NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex, NI_VectorT_LoadUnsafeIndex}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_ID(VectorT, Max, 2, {NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max, NI_VectorT_Max}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, MaxNative, 2, {NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative, NI_VectorT_MaxNative}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Min, 2, {NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min, NI_VectorT_Min}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, MinNative, 2, {NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative, NI_VectorT_MinNative}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, MultiplyAddEstimate, 3, {NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_Illegal, NI_VectorT_MultiplyAddEstimate, NI_VectorT_MultiplyAddEstimate}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, Narrow, 2, {NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow, NI_VectorT_Narrow}, SimdAsHWIntrinsicFlag::KeepBaseTypeFromRet) SIMD_AS_HWINTRINSIC_ID(VectorT, op_Addition, 2, {NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition, NI_VectorT_op_Addition}, SimdAsHWIntrinsicFlag::None) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index ff824db621e44f..df5e98e6978194 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -330,7 +330,15 @@ public static partial class Vector public static System.Numerics.Vector Log2(System.Numerics.Vector vector) { throw null; } public static System.Numerics.Vector Log2(System.Numerics.Vector vector) { throw null; } public static System.Numerics.Vector Max(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MaxMagnitude(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MaxMagnitudeNumber(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MaxNative(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MaxNumber(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Min(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MinMagnitude(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MinMagnitudeNumber(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MinNative(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } + public static System.Numerics.Vector MinNumber(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Multiply(System.Numerics.Vector left, T right) { throw null; } public static System.Numerics.Vector Multiply(T left, System.Numerics.Vector right) { throw null; } @@ -494,7 +502,15 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector2 Log(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 Log2(System.Numerics.Vector2 vector) { throw null; } public static System.Numerics.Vector2 Max(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MaxMagnitude(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MaxMagnitudeNumber(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MaxNative(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MaxNumber(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public static System.Numerics.Vector2 Min(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MinMagnitude(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MinMagnitudeNumber(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MinNative(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } + public static System.Numerics.Vector2 MinNumber(System.Numerics.Vector2 value1, System.Numerics.Vector2 value2) { throw null; } public static System.Numerics.Vector2 Multiply(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } public static System.Numerics.Vector2 Multiply(System.Numerics.Vector2 left, float right) { throw null; } public static System.Numerics.Vector2 Multiply(float left, System.Numerics.Vector2 right) { throw null; } @@ -582,7 +598,15 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector3 Log(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 Log2(System.Numerics.Vector3 vector) { throw null; } public static System.Numerics.Vector3 Max(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MaxMagnitude(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MaxMagnitudeNumber(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MaxNative(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MaxNumber(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } public static System.Numerics.Vector3 Min(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MinMagnitude(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MinMagnitudeNumber(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MinNative(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } + public static System.Numerics.Vector3 MinNumber(System.Numerics.Vector3 value1, System.Numerics.Vector3 value2) { throw null; } public static System.Numerics.Vector3 Multiply(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } public static System.Numerics.Vector3 Multiply(System.Numerics.Vector3 left, float right) { throw null; } public static System.Numerics.Vector3 Multiply(float left, System.Numerics.Vector3 right) { throw null; } @@ -671,7 +695,15 @@ public readonly void CopyTo(System.Span destination) { } public static System.Numerics.Vector4 Log(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 Log2(System.Numerics.Vector4 vector) { throw null; } public static System.Numerics.Vector4 Max(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MaxMagnitude(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MaxMagnitudeNumber(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MaxNative(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MaxNumber(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } public static System.Numerics.Vector4 Min(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MinMagnitude(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MinMagnitudeNumber(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MinNative(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } + public static System.Numerics.Vector4 MinNumber(System.Numerics.Vector4 value1, System.Numerics.Vector4 value2) { throw null; } public static System.Numerics.Vector4 Multiply(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public static System.Numerics.Vector4 Multiply(System.Numerics.Vector4 left, float right) { throw null; } public static System.Numerics.Vector4 Multiply(float left, System.Numerics.Vector4 right) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 818f2feae1fe67..dfb8a4e3580044 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -1640,44 +1640,234 @@ public static Vector Log2(Vector vector) } } - /// Computes the maximum of two vectors on a per-element basis. - /// The vector to compare with . - /// The vector to compare with . - /// The type of the elements in the vector. - /// A vector whose elements are the maximum of the corresponding elements in and . + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector Max(Vector left, Vector right) { - Unsafe.SkipInit(out Vector result); + if (IsHardwareAccelerated) + { + return VectorMath.Max, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector result); - for (int index = 0; index < Vector.Count; index++) + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.Max(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MaxMagnitude(Vector left, Vector right) + { + if (IsHardwareAccelerated) { - T value = Scalar.GreaterThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); - result.SetElementUnsafe(index, value); + return VectorMath.MaxMagnitude, T>(left, right); } + else + { + Unsafe.SkipInit(out Vector result); - return result; + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.MaxMagnitude(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } } - /// Computes the minimum of two vectors on a per-element basis. - /// The vector to compare with . - /// The vector to compare with . - /// The type of the elements in the vector. - /// A vector whose elements are the minimum of the corresponding elements in and . + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MaxMagnitudeNumber(Vector left, Vector right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitudeNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.MaxMagnitudeNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MaxNative(Vector left, Vector right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(GreaterThan(left, right), left, right); + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.GreaterThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MaxNumber(Vector left, Vector right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.MaxNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector Min(Vector left, Vector right) { - Unsafe.SkipInit(out Vector result); + if (IsHardwareAccelerated) + { + return VectorMath.Min, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector result); - for (int index = 0; index < Vector.Count; index++) + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.Min(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MinMagnitude(Vector left, Vector right) + { + if (IsHardwareAccelerated) { - T value = Scalar.LessThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); - result.SetElementUnsafe(index, value); + return VectorMath.MinMagnitude, T>(left, right); } + else + { + Unsafe.SkipInit(out Vector result); - return result; + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.MinMagnitude(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MinMagnitudeNumber(Vector left, Vector right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitudeNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.MinMagnitudeNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MinNative(Vector left, Vector right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(LessThan(left, right), left, right); + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.LessThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector MinNumber(Vector left, Vector right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector result); + + for (int index = 0; index < Vector.Count; index++) + { + T value = Scalar.MinNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } } /// Multiplies two vectors to compute their element-wise product. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index bfb351fd84d665..0a096c91066b48 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -393,22 +393,56 @@ public static Vector2 Create(ReadOnlySpan values) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Log2(Vector2 vector) => Vector128.Log2(vector.AsVector128Unsafe()).AsVector2(); - /// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors. - /// The first vector. - /// The second vector. - /// The maximized vector. + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Max(Vector2 value1, Vector2 value2) => Vector128.Max(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); - /// Returns a vector whose elements are the minimum of each of the pairs of elements in two specified vectors. - /// The first vector. - /// The second vector. - /// The minimized vector. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MaxMagnitude(Vector2 value1, Vector2 value2) => Vector128.MaxMagnitude(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MaxMagnitudeNumber(Vector2 value1, Vector2 value2) => Vector128.MaxMagnitudeNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MaxNative(Vector2 value1, Vector2 value2) => Vector128.MaxNative(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MaxNumber(Vector2 value1, Vector2 value2) => Vector128.MaxNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector2 Min(Vector2 value1, Vector2 value2) => Vector128.Min(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MinMagnitude(Vector2 value1, Vector2 value2) => Vector128.MinMagnitude(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MinMagnitudeNumber(Vector2 value1, Vector2 value2) => Vector128.MinMagnitudeNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MinNative(Vector2 value1, Vector2 value2) => Vector128.MinNative(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 MinNumber(Vector2 value1, Vector2 value2) => Vector128.MinNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector2(); + /// Returns a new vector whose values are the product of each pair of elements in two specified vectors. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index 31134f20d88f86..14a3aeca6cbf97 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -450,22 +450,56 @@ public static Vector3 Cross(Vector3 vector1, Vector3 vector2) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Log2(Vector3 vector) => Vector128.Log2(vector.AsVector128Unsafe()).AsVector3(); - /// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors. - /// The first vector. - /// The second vector. - /// The maximized vector. + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Max(Vector3 value1, Vector3 value2) => Vector128.Max(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); - /// Returns a vector whose elements are the minimum of each of the pairs of elements in two specified vectors. - /// The first vector. - /// The second vector. - /// The minimized vector. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MaxMagnitude(Vector3 value1, Vector3 value2) => Vector128.MaxMagnitude(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MaxMagnitudeNumber(Vector3 value1, Vector3 value2) => Vector128.MaxMagnitudeNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MaxNative(Vector3 value1, Vector3 value2) => Vector128.MaxNative(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MaxNumber(Vector3 value1, Vector3 value2) => Vector128.MaxNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector3 Min(Vector3 value1, Vector3 value2) => Vector128.Min(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MinMagnitude(Vector3 value1, Vector3 value2) => Vector128.MinMagnitude(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MinMagnitudeNumber(Vector3 value1, Vector3 value2) => Vector128.MinMagnitudeNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MinNative(Vector3 value1, Vector3 value2) => Vector128.MinNative(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 MinNumber(Vector3 value1, Vector3 value2) => Vector128.MinNumber(value1.AsVector128Unsafe(), value2.AsVector128Unsafe()).AsVector3(); + /// Returns a new vector whose values are the product of each pair of elements in two specified vectors. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index cf84e97dea218d..16d023f8c78a57 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -458,22 +458,56 @@ public static Vector4 Create(Vector3 vector, float w) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Log2(Vector4 vector) => Vector128.Log2(vector.AsVector128()).AsVector4(); - /// Returns a vector whose elements are the maximum of each of the pairs of elements in two specified vectors. - /// The first vector. - /// The second vector. - /// The maximized vector. + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Max(Vector4 value1, Vector4 value2) => Vector128.Max(value1.AsVector128(), value2.AsVector128()).AsVector4(); - /// Returns a vector whose elements are the minimum of each of the pairs of elements in two specified vectors. - /// The first vector. - /// The second vector. - /// The minimized vector. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MaxMagnitude(Vector4 value1, Vector4 value2) => Vector128.MaxMagnitude(value1.AsVector128(), value2.AsVector128()).AsVector4(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MaxMagnitudeNumber(Vector4 value1, Vector4 value2) => Vector128.MaxMagnitudeNumber(value1.AsVector128(), value2.AsVector128()).AsVector4(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MaxNative(Vector4 value1, Vector4 value2) => Vector128.MaxNative(value1.AsVector128(), value2.AsVector128()).AsVector4(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MaxNumber(Vector4 value1, Vector4 value2) => Vector128.MaxNumber(value1.AsVector128(), value2.AsVector128()).AsVector4(); + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Min(Vector4 value1, Vector4 value2) => Vector128.Min(value1.AsVector128(), value2.AsVector128()).AsVector4(); + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MinMagnitude(Vector4 value1, Vector4 value2) => Vector128.MinMagnitude(value1.AsVector128(), value2.AsVector128()).AsVector4(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MinMagnitudeNumber(Vector4 value1, Vector4 value2) => Vector128.MinMagnitudeNumber(value1.AsVector128(), value2.AsVector128()).AsVector4(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MinNative(Vector4 value1, Vector4 value2) => Vector128.MinNative(value1.AsVector128(), value2.AsVector128()).AsVector4(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 MinNumber(Vector4 value1, Vector4 value2) => Vector128.MinNumber(value1.AsVector128(), value2.AsVector128()).AsVector4(); + /// Returns a new vector whose values are the product of each pair of elements in two specified vectors. /// The first vector. /// The second vector. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index 7707106a1e0112..f96c7b16f70a45 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -945,9 +945,33 @@ public bool TryCopyTo(Span destination) /// static Vector ISimdVector, T>.Max(Vector left, Vector right) => Vector.Max(left, right); + /// + static Vector ISimdVector, T>.MaxMagnitude(Vector left, Vector right) => Vector.MaxMagnitude(left, right); + + /// + static Vector ISimdVector, T>.MaxMagnitudeNumber(Vector left, Vector right) => Vector.MaxMagnitudeNumber(left, right); + + /// + static Vector ISimdVector, T>.MaxNative(Vector left, Vector right) => Vector.MaxNative(left, right); + + /// + static Vector ISimdVector, T>.MaxNumber(Vector left, Vector right) => Vector.MaxNumber(left, right); + /// static Vector ISimdVector, T>.Min(Vector left, Vector right) => Vector.Min(left, right); + /// + static Vector ISimdVector, T>.MinMagnitude(Vector left, Vector right) => Vector.MinMagnitude(left, right); + + /// + static Vector ISimdVector, T>.MinMagnitudeNumber(Vector left, Vector right) => Vector.MinMagnitudeNumber(left, right); + + /// + static Vector ISimdVector, T>.MinNative(Vector left, Vector right) => Vector.MinNative(left, right); + + /// + static Vector ISimdVector, T>.MinNumber(Vector left, Vector right) => Vector.MinNumber(left, right); + /// static Vector ISimdVector, T>.Multiply(Vector left, Vector right) => left * right; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs index c65f9f3179e34a..267d209a9dbfb3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs @@ -124,7 +124,7 @@ internal unsafe interface ISimdVector /// The vector that is selected when the corresponding bit in is zero. /// A vector whose bits come from or based on the value of . /// The type of the elements in the vector () is not supported. - static virtual TSelf ConditionalSelect(TSelf condition, TSelf left, TSelf right) => (left & condition) | And(right & ~condition); + static virtual TSelf ConditionalSelect(TSelf condition, TSelf left, TSelf right) => (left & condition) | (right & ~condition); /// Copies the per-element sign of a vector to the per-element sign of another vector. /// The vector whose magnitude is used in the result. @@ -424,20 +424,84 @@ static virtual TSelf LoadAligned(T* source) /// The type of the elements in the vector () is not supported. static abstract TSelf LoadUnsafe(ref readonly T source, nuint elementOffset); - /// Computes the maximum of two vectors on a per-element basis. + /// Compare two vectors to determine which is greater on a per-element basis. /// The vector to compare with . /// The vector to compare with . - /// A vector whose elements are the maximum of the corresponding elements in and . + /// A vector where the corresponding element comes from if it is greater than ; otherwise, . + /// For this method matches the IEEE 754:2019 maximum function.This requires NaN inputs to be propagated back to the caller and for -0.0 to be treated as less than +0.0. /// The type of the elements in the vector () is not supported. static abstract TSelf Max(TSelf left, TSelf right); - /// Computes the minimum of two vectors on a per-element basis. + /// Compares two vectors to compute which has the greater magnitude on a per-element basis. /// The vector to compare with . /// The vector to compare with . - /// A vector whose elements are the minimum of the corresponding elements in and . + /// A vector where the corresponding element comes from if it has a greater magnitude than ; otherwise, . + /// For this method matches the IEEE 754:2019 maximumMagnitude function. This requires NaN inputs to be propagated back to the caller and for -0.0 to be treated as less than +0.0. + /// The type of the elements in the vector () is not supported. + static abstract TSelf MaxMagnitude(TSelf left, TSelf right); + + /// Compares two vectors, on a per-element basis, to compute which has the greater magnitude and returning the other value if an input is NaN. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it has a greater magnitude than ; otherwise, . + /// For this method matches the IEEE 754:2019 maximumMagnitudeNumber function. This requires NaN inputs to not be propagated back to the caller and for -0.0 to be treated as less than +0.0. + /// The type of the elements in the vector () is not supported. + static abstract TSelf MaxMagnitudeNumber(TSelf left, TSelf right); + + /// Compare two vectors to determine which is greater on a per-element basis using platform specific behavior for NaN and NegativeZero. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it is greater than ; otherwise, . + /// The type of the elements in the vector () is not supported. + static abstract TSelf MaxNative(TSelf left, TSelf right); + + /// Compares two vectors, on a per-element basis, to compute which is greater and returning the other value if an element is NaN. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it is greater than ; otherwise, . + /// For this method matches the IEEE 754:2019 maximumNumber function. This requires NaN inputs to not be propagated back to the caller and for -0.0 to be treated as less than +0.0. + /// The type of the elements in the vector () is not supported. + static abstract TSelf MaxNumber(TSelf left, TSelf right); + + /// Compare two vectors to determine which is lesser on a per-element basis. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it is lesser than ; otherwise, . + /// For this method matches the IEEE 754:2019 minimum function.This requires NaN inputs to be propagated back to the caller and for -0.0 to be treated as less than +0.0. /// The type of the elements in the vector () is not supported. static abstract TSelf Min(TSelf left, TSelf right); + /// Compares two vectors to compute which has the lesser magnitude on a per-element basis. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it has a lesser magnitude than ; otherwise, . + /// For this method matches the IEEE 754:2019 minimumMagnitude function. This requires NaN inputs to be propagated back to the caller and for -0.0 to be treated as less than +0.0. + /// The type of the elements in the vector () is not supported. + static abstract TSelf MinMagnitude(TSelf left, TSelf right); + + /// Compares two vectors, on a per-element basis, to compute which has the lesser magnitude and returning the other value if an input is NaN. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it has a lesser magnitude than ; otherwise, . + /// For this method matches the IEEE 754:2019 minimumMagnitudeNumber function. This requires NaN inputs to not be propagated back to the caller and for -0.0 to be treated as less than +0.0. + /// The type of the elements in the vector () is not supported. + static abstract TSelf MinMagnitudeNumber(TSelf left, TSelf right); + + /// Compare two vectors to determine which is lesser on a per-element basis using platform specific behavior for NaN and NegativeZero. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it is lesser than ; otherwise, . + /// The type of the elements in the vector () is not supported. + static abstract TSelf MinNative(TSelf left, TSelf right); + + /// Compares two vectors, on a per-element basis, to compute which is lesser and returning the other value if an element is NaN. + /// The vector to compare with . + /// The vector to compare with . + /// A vector where the corresponding element comes from if it is lesser than ; otherwise, . + /// For this method matches the IEEE 754:2019 minimumNumber function. This requires NaN inputs to not be propagated back to the caller and for -0.0 to be treated as less than +0.0. + /// The type of the elements in the vector () is not supported. + static abstract TSelf MinNumber(TSelf left, TSelf right); + /// Multiplies two vectors to compute their element-wise product. /// The vector to multiply with . /// The vector to multiply with . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs index 0d694dc1e130df..deb6ef6af4d3d7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Scalar.cs @@ -820,6 +820,272 @@ public static bool LessThanOrEqual(T left, T right) } } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Max(T left, T right) + { + if (typeof(T) == typeof(byte)) + { + return (T)(object)byte.Max((byte)(object)left, (byte)(object)right); + } + else if (typeof(T) == typeof(double)) + { + return (T)(object)double.Max((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)short.Max((short)(object)left, (short)(object)right); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)int.Max((int)(object)left, (int)(object)right); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)long.Max((long)(object)left, (long)(object)right); + } + else if (typeof(T) == typeof(nint)) + { + return (T)(object)nint.Max((nint)(object)left, (nint)(object)right); + } + else if (typeof(T) == typeof(nuint)) + { + return (T)(object)nuint.Max((nuint)(object)left, (nuint)(object)right); + } + else if (typeof(T) == typeof(sbyte)) + { + return (T)(object)sbyte.Max((sbyte)(object)left, (sbyte)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.Max((float)(object)left, (float)(object)right); + } + else if (typeof(T) == typeof(ushort)) + { + return (T)(object)ushort.Max((ushort)(object)left, (ushort)(object)right); + } + else if (typeof(T) == typeof(uint)) + { + return (T)(object)uint.Max((uint)(object)left, (uint)(object)right); + } + else if (typeof(T) == typeof(ulong)) + { + return (T)(object)ulong.Max((ulong)(object)left, (ulong)(object)right); + } + else + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); + return default!; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T MaxMagnitude(T left, T right) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)double.MaxMagnitude((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)short.MaxMagnitude((short)(object)left, (short)(object)right); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)int.MaxMagnitude((int)(object)left, (int)(object)right); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)long.MaxMagnitude((long)(object)left, (long)(object)right); + } + else if (typeof(T) == typeof(nint)) + { + return (T)(object)nint.MaxMagnitude((nint)(object)left, (nint)(object)right); + } + else if (typeof(T) == typeof(nuint)) + { + return (T)(object)nuint.Max((nuint)(object)left, (nuint)(object)right); + } + else if (typeof(T) == typeof(sbyte)) + { + return (T)(object)sbyte.MaxMagnitude((sbyte)(object)left, (sbyte)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.MaxMagnitude((float)(object)left, (float)(object)right); + } + else + { + return Max(left, right); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T MaxMagnitudeNumber(T left, T right) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)double.MaxMagnitudeNumber((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.MaxMagnitudeNumber((float)(object)left, (float)(object)right); + } + else + { + return MaxMagnitude(left, right); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T MaxNumber(T left, T right) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)double.MaxNumber((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.MaxNumber((float)(object)left, (float)(object)right); + } + else + { + return Max(left, right); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Min(T left, T right) + { + if (typeof(T) == typeof(byte)) + { + return (T)(object)byte.Min((byte)(object)left, (byte)(object)right); + } + else if (typeof(T) == typeof(double)) + { + return (T)(object)double.Min((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)short.Min((short)(object)left, (short)(object)right); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)int.Min((int)(object)left, (int)(object)right); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)long.Min((long)(object)left, (long)(object)right); + } + else if (typeof(T) == typeof(nint)) + { + return (T)(object)nint.Min((nint)(object)left, (nint)(object)right); + } + else if (typeof(T) == typeof(nuint)) + { + return (T)(object)nuint.Min((nuint)(object)left, (nuint)(object)right); + } + else if (typeof(T) == typeof(sbyte)) + { + return (T)(object)sbyte.Min((sbyte)(object)left, (sbyte)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.Min((float)(object)left, (float)(object)right); + } + else if (typeof(T) == typeof(ushort)) + { + return (T)(object)ushort.Min((ushort)(object)left, (ushort)(object)right); + } + else if (typeof(T) == typeof(uint)) + { + return (T)(object)uint.Min((uint)(object)left, (uint)(object)right); + } + else if (typeof(T) == typeof(ulong)) + { + return (T)(object)ulong.Min((ulong)(object)left, (ulong)(object)right); + } + else + { + ThrowHelper.ThrowNotSupportedException(ExceptionResource.Arg_TypeNotSupported); + return default!; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T MinMagnitude(T left, T right) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)double.MinMagnitude((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(short)) + { + return (T)(object)short.MinMagnitude((short)(object)left, (short)(object)right); + } + else if (typeof(T) == typeof(int)) + { + return (T)(object)int.MinMagnitude((int)(object)left, (int)(object)right); + } + else if (typeof(T) == typeof(long)) + { + return (T)(object)long.MinMagnitude((long)(object)left, (long)(object)right); + } + else if (typeof(T) == typeof(nint)) + { + return (T)(object)nint.MinMagnitude((nint)(object)left, (nint)(object)right); + } + else if (typeof(T) == typeof(nuint)) + { + return (T)(object)nuint.Min((nuint)(object)left, (nuint)(object)right); + } + else if (typeof(T) == typeof(sbyte)) + { + return (T)(object)sbyte.MinMagnitude((sbyte)(object)left, (sbyte)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.MinMagnitude((float)(object)left, (float)(object)right); + } + else + { + return Min(left, right); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T MinMagnitudeNumber(T left, T right) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)double.MinMagnitudeNumber((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.MinMagnitudeNumber((float)(object)left, (float)(object)right); + } + else + { + return MinMagnitude(left, right); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T MinNumber(T left, T right) + { + if (typeof(T) == typeof(double)) + { + return (T)(object)double.MinNumber((double)(object)left, (double)(object)right); + } + else if (typeof(T) == typeof(float)) + { + return (T)(object)float.MinNumber((float)(object)left, (float)(object)right); + } + else + { + return Min(left, right); + } + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static T Multiply(T left, T right) { diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 7e36cd0d1cb0be..55a434158b50df 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -2211,36 +2211,184 @@ public static Vector128 Log2(Vector128 vector) } } - /// Computes the maximum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the maximum of the corresponding elements in and . - /// The type of and () is not supported. + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Max(Vector128 left, Vector128 right) { - return Create( - Vector64.Max(left._lower, right._lower), - Vector64.Max(left._upper, right._upper) - ); + if (IsHardwareAccelerated) + { + return VectorMath.Max, T>(left, right); + } + else + { + return Create( + Vector64.Max(left._lower, right._lower), + Vector64.Max(left._upper, right._upper) + ); + } } - /// Computes the minimum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the minimum of the corresponding elements in and . - /// The type of and () is not supported. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MaxMagnitude(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitude, T>(left, right); + } + else + { + return Create( + Vector64.MaxMagnitude(left._lower, right._lower), + Vector64.MaxMagnitude(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MaxMagnitudeNumber(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitudeNumber, T>(left, right); + } + else + { + return Create( + Vector64.MaxMagnitudeNumber(left._lower, right._lower), + Vector64.MaxMagnitudeNumber(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MaxNative(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(GreaterThan(left, right), left, right); + } + else + { + return Create( + Vector64.MaxNative(left._lower, right._lower), + Vector64.MaxNative(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MaxNumber(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxNumber, T>(left, right); + } + else + { + return Create( + Vector64.MaxNumber(left._lower, right._lower), + Vector64.MaxNumber(left._upper, right._upper) + ); + } + } + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Min(Vector128 left, Vector128 right) { - return Create( - Vector64.Min(left._lower, right._lower), - Vector64.Min(left._upper, right._upper) - ); + if (IsHardwareAccelerated) + { + return VectorMath.Min, T>(left, right); + } + else + { + return Create( + Vector64.Min(left._lower, right._lower), + Vector64.Min(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MinMagnitude(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitude, T>(left, right); + } + else + { + return Create( + Vector64.MinMagnitude(left._lower, right._lower), + Vector64.MinMagnitude(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MinMagnitudeNumber(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitudeNumber, T>(left, right); + } + else + { + return Create( + Vector64.MinMagnitudeNumber(left._lower, right._lower), + Vector64.MinMagnitudeNumber(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MinNative(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(LessThan(left, right), left, right); + } + else + { + return Create( + Vector64.MinNative(left._lower, right._lower), + Vector64.MinNative(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 MinNumber(Vector128 left, Vector128 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinNumber, T>(left, right); + } + else + { + return Create( + Vector64.MinNumber(left._lower, right._lower), + Vector64.MinNumber(left._upper, right._upper) + ); + } } /// Multiplies two vectors to compute their element-wise product. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index 64828c80e63a87..df560784be9141 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -592,9 +592,33 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector128 ISimdVector, T>.Max(Vector128 left, Vector128 right) => Vector128.Max(left, right); + /// + static Vector128 ISimdVector, T>.MaxMagnitude(Vector128 left, Vector128 right) => Vector128.MaxMagnitude(left, right); + + /// + static Vector128 ISimdVector, T>.MaxMagnitudeNumber(Vector128 left, Vector128 right) => Vector128.MaxMagnitudeNumber(left, right); + + /// + static Vector128 ISimdVector, T>.MaxNative(Vector128 left, Vector128 right) => Vector128.MaxNative(left, right); + + /// + static Vector128 ISimdVector, T>.MaxNumber(Vector128 left, Vector128 right) => Vector128.MaxNumber(left, right); + /// static Vector128 ISimdVector, T>.Min(Vector128 left, Vector128 right) => Vector128.Min(left, right); + /// + static Vector128 ISimdVector, T>.MinMagnitude(Vector128 left, Vector128 right) => Vector128.MinMagnitude(left, right); + + /// + static Vector128 ISimdVector, T>.MinMagnitudeNumber(Vector128 left, Vector128 right) => Vector128.MinMagnitudeNumber(left, right); + + /// + static Vector128 ISimdVector, T>.MinNative(Vector128 left, Vector128 right) => Vector128.MinNative(left, right); + + /// + static Vector128 ISimdVector, T>.MinNumber(Vector128 left, Vector128 right) => Vector128.MinNumber(left, right); + /// static Vector128 ISimdVector, T>.Multiply(Vector128 left, Vector128 right) => left * right; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index c5657b9d85e03a..bb491e11b9641b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -2127,36 +2127,184 @@ public static Vector256 Log2(Vector256 vector) } } - /// Computes the maximum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the maximum of the corresponding elements in and . - /// The type of and () is not supported. + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Max(Vector256 left, Vector256 right) { - return Create( - Vector128.Max(left._lower, right._lower), - Vector128.Max(left._upper, right._upper) - ); + if (IsHardwareAccelerated) + { + return VectorMath.Max, T>(left, right); + } + else + { + return Create( + Vector128.Max(left._lower, right._lower), + Vector128.Max(left._upper, right._upper) + ); + } } - /// Computes the minimum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the minimum of the corresponding elements in and . - /// The type of and () is not supported. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MaxMagnitude(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitude, T>(left, right); + } + else + { + return Create( + Vector128.MaxMagnitude(left._lower, right._lower), + Vector128.MaxMagnitude(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MaxMagnitudeNumber(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitudeNumber, T>(left, right); + } + else + { + return Create( + Vector128.MaxMagnitudeNumber(left._lower, right._lower), + Vector128.MaxMagnitudeNumber(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MaxNative(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(GreaterThan(left, right), left, right); + } + else + { + return Create( + Vector128.MaxNative(left._lower, right._lower), + Vector128.MaxNative(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MaxNumber(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxNumber, T>(left, right); + } + else + { + return Create( + Vector128.MaxNumber(left._lower, right._lower), + Vector128.MaxNumber(left._upper, right._upper) + ); + } + } + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Min(Vector256 left, Vector256 right) { - return Create( - Vector128.Min(left._lower, right._lower), - Vector128.Min(left._upper, right._upper) - ); + if (IsHardwareAccelerated) + { + return VectorMath.Min, T>(left, right); + } + else + { + return Create( + Vector128.Min(left._lower, right._lower), + Vector128.Min(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MinMagnitude(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitude, T>(left, right); + } + else + { + return Create( + Vector128.MinMagnitude(left._lower, right._lower), + Vector128.MinMagnitude(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MinMagnitudeNumber(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitudeNumber, T>(left, right); + } + else + { + return Create( + Vector128.MinMagnitudeNumber(left._lower, right._lower), + Vector128.MinMagnitudeNumber(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MinNative(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(LessThan(left, right), left, right); + } + else + { + return Create( + Vector128.MinNative(left._lower, right._lower), + Vector128.MinNative(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 MinNumber(Vector256 left, Vector256 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinNumber, T>(left, right); + } + else + { + return Create( + Vector128.MinNumber(left._lower, right._lower), + Vector128.MinNumber(left._upper, right._upper) + ); + } } /// Multiplies two vectors to compute their element-wise product. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index 07c8872d98ee2a..b649fb9a755c44 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -581,9 +581,33 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector256 ISimdVector, T>.Max(Vector256 left, Vector256 right) => Vector256.Max(left, right); + /// + static Vector256 ISimdVector, T>.MaxMagnitude(Vector256 left, Vector256 right) => Vector256.MaxMagnitude(left, right); + + /// + static Vector256 ISimdVector, T>.MaxMagnitudeNumber(Vector256 left, Vector256 right) => Vector256.MaxMagnitudeNumber(left, right); + + /// + static Vector256 ISimdVector, T>.MaxNative(Vector256 left, Vector256 right) => Vector256.MaxNative(left, right); + + /// + static Vector256 ISimdVector, T>.MaxNumber(Vector256 left, Vector256 right) => Vector256.MaxNumber(left, right); + /// static Vector256 ISimdVector, T>.Min(Vector256 left, Vector256 right) => Vector256.Min(left, right); + /// + static Vector256 ISimdVector, T>.MinMagnitude(Vector256 left, Vector256 right) => Vector256.MinMagnitude(left, right); + + /// + static Vector256 ISimdVector, T>.MinMagnitudeNumber(Vector256 left, Vector256 right) => Vector256.MinMagnitudeNumber(left, right); + + /// + static Vector256 ISimdVector, T>.MinNative(Vector256 left, Vector256 right) => Vector256.MinNative(left, right); + + /// + static Vector256 ISimdVector, T>.MinNumber(Vector256 left, Vector256 right) => Vector256.MinNumber(left, right); + /// static Vector256 ISimdVector, T>.Multiply(Vector256 left, Vector256 right) => left * right; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index 5437b459b88f0c..0e42a020f6aa06 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -2190,36 +2190,184 @@ public static Vector512 Log2(Vector512 vector) } } - /// Computes the maximum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the maximum of the corresponding elements in and . - /// The type of and () is not supported. + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Max(Vector512 left, Vector512 right) { - return Create( - Vector256.Max(left._lower, right._lower), - Vector256.Max(left._upper, right._upper) - ); + if (IsHardwareAccelerated) + { + return VectorMath.Max, T>(left, right); + } + else + { + return Create( + Vector256.Max(left._lower, right._lower), + Vector256.Max(left._upper, right._upper) + ); + } } - /// Computes the minimum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the minimum of the corresponding elements in and . - /// The type of and () is not supported. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MaxMagnitude(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitude, T>(left, right); + } + else + { + return Create( + Vector256.MaxMagnitude(left._lower, right._lower), + Vector256.MaxMagnitude(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MaxMagnitudeNumber(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitudeNumber, T>(left, right); + } + else + { + return Create( + Vector256.MaxMagnitudeNumber(left._lower, right._lower), + Vector256.MaxMagnitudeNumber(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MaxNative(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(GreaterThan(left, right), left, right); + } + else + { + return Create( + Vector256.MaxNative(left._lower, right._lower), + Vector256.MaxNative(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MaxNumber(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxNumber, T>(left, right); + } + else + { + return Create( + Vector256.MaxNumber(left._lower, right._lower), + Vector256.MaxNumber(left._upper, right._upper) + ); + } + } + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Min(Vector512 left, Vector512 right) { - return Create( - Vector256.Min(left._lower, right._lower), - Vector256.Min(left._upper, right._upper) - ); + if (IsHardwareAccelerated) + { + return VectorMath.Min, T>(left, right); + } + else + { + return Create( + Vector256.Min(left._lower, right._lower), + Vector256.Min(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MinMagnitude(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitude, T>(left, right); + } + else + { + return Create( + Vector256.MinMagnitude(left._lower, right._lower), + Vector256.MinMagnitude(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MinMagnitudeNumber(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitudeNumber, T>(left, right); + } + else + { + return Create( + Vector256.MinMagnitudeNumber(left._lower, right._lower), + Vector256.MinMagnitudeNumber(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MinNative(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(LessThan(left, right), left, right); + } + else + { + return Create( + Vector256.MinNative(left._lower, right._lower), + Vector256.MinNative(left._upper, right._upper) + ); + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 MinNumber(Vector512 left, Vector512 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinNumber, T>(left, right); + } + else + { + return Create( + Vector256.MinNumber(left._lower, right._lower), + Vector256.MinNumber(left._upper, right._upper) + ); + } } /// Multiplies two vectors to compute their element-wise product. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs index a3db1e9bd92db3..4ff88c0dc3d279 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs @@ -581,9 +581,33 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector512 ISimdVector, T>.Max(Vector512 left, Vector512 right) => Vector512.Max(left, right); + /// + static Vector512 ISimdVector, T>.MaxMagnitude(Vector512 left, Vector512 right) => Vector512.MaxMagnitude(left, right); + + /// + static Vector512 ISimdVector, T>.MaxMagnitudeNumber(Vector512 left, Vector512 right) => Vector512.MaxMagnitudeNumber(left, right); + + /// + static Vector512 ISimdVector, T>.MaxNative(Vector512 left, Vector512 right) => Vector512.MaxNative(left, right); + + /// + static Vector512 ISimdVector, T>.MaxNumber(Vector512 left, Vector512 right) => Vector512.MaxNumber(left, right); + /// static Vector512 ISimdVector, T>.Min(Vector512 left, Vector512 right) => Vector512.Min(left, right); + /// + static Vector512 ISimdVector, T>.MinMagnitude(Vector512 left, Vector512 right) => Vector512.MinMagnitude(left, right); + + /// + static Vector512 ISimdVector, T>.MinMagnitudeNumber(Vector512 left, Vector512 right) => Vector512.MinMagnitudeNumber(left, right); + + /// + static Vector512 ISimdVector, T>.MinNative(Vector512 left, Vector512 right) => Vector512.MinNative(left, right); + + /// + static Vector512 ISimdVector, T>.MinNumber(Vector512 left, Vector512 right) => Vector512.MinNumber(left, right); + /// static Vector512 ISimdVector, T>.Multiply(Vector512 left, Vector512 right) => left * right; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index e69aaeb4c03824..6c2d334e765342 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -1994,46 +1994,234 @@ public static Vector64 Log2(Vector64 vector) } } - /// Computes the maximum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the maximum of the corresponding elements in and . - /// The type of and () is not supported. + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector64 Max(Vector64 left, Vector64 right) { - Unsafe.SkipInit(out Vector64 result); + if (IsHardwareAccelerated) + { + return VectorMath.Max, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); - for (int index = 0; index < Vector64.Count; index++) + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.Max(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MaxMagnitude(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) { - T value = Scalar.GreaterThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); - result.SetElementUnsafe(index, value); + return VectorMath.MaxMagnitude, T>(left, right); } + else + { + Unsafe.SkipInit(out Vector64 result); - return result; + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.MaxMagnitude(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } } - /// Computes the minimum of two vectors on a per-element basis. - /// The type of the elements in the vector. - /// The vector to compare with . - /// The vector to compare with . - /// A vector whose elements are the minimum of the corresponding elements in and . - /// The type of and () is not supported. + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MaxMagnitudeNumber(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxMagnitudeNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.MaxMagnitudeNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MaxNative(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(GreaterThan(left, right), left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.GreaterThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MaxNumber(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MaxNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.MaxNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector64 Min(Vector64 left, Vector64 right) { - Unsafe.SkipInit(out Vector64 result); + if (IsHardwareAccelerated) + { + return VectorMath.Min, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); - for (int index = 0; index < Vector64.Count; index++) + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.Min(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MinMagnitude(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) { - T value = Scalar.LessThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); - result.SetElementUnsafe(index, value); + return VectorMath.MinMagnitude, T>(left, right); } + else + { + Unsafe.SkipInit(out Vector64 result); - return result; + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.MinMagnitude(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MinMagnitudeNumber(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinMagnitudeNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.MinMagnitudeNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MinNative(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) + { + return ConditionalSelect(LessThan(left, right), left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.LessThan(left.GetElementUnsafe(index), right.GetElementUnsafe(index)) ? left.GetElementUnsafe(index) : right.GetElementUnsafe(index); + result.SetElementUnsafe(index, value); + } + + return result; + } + } + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector64 MinNumber(Vector64 left, Vector64 right) + { + if (IsHardwareAccelerated) + { + return VectorMath.MinNumber, T>(left, right); + } + else + { + Unsafe.SkipInit(out Vector64 result); + + for (int index = 0; index < Vector64.Count; index++) + { + T value = Scalar.MinNumber(left.GetElementUnsafe(index), right.GetElementUnsafe(index)); + result.SetElementUnsafe(index, value); + } + + return result; + } } /// Multiplies two vectors to compute their element-wise product. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index f3ab67a27de940..42d0045cc28b08 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -649,9 +649,33 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector64 ISimdVector, T>.Max(Vector64 left, Vector64 right) => Vector64.Max(left, right); + /// + static Vector64 ISimdVector, T>.MaxMagnitude(Vector64 left, Vector64 right) => Vector64.MaxMagnitude(left, right); + + /// + static Vector64 ISimdVector, T>.MaxMagnitudeNumber(Vector64 left, Vector64 right) => Vector64.MaxMagnitudeNumber(left, right); + + /// + static Vector64 ISimdVector, T>.MaxNative(Vector64 left, Vector64 right) => Vector64.MaxNative(left, right); + + /// + static Vector64 ISimdVector, T>.MaxNumber(Vector64 left, Vector64 right) => Vector64.MaxNumber(left, right); + /// static Vector64 ISimdVector, T>.Min(Vector64 left, Vector64 right) => Vector64.Min(left, right); + /// + static Vector64 ISimdVector, T>.MinMagnitude(Vector64 left, Vector64 right) => Vector64.MinMagnitude(left, right); + + /// + static Vector64 ISimdVector, T>.MinMagnitudeNumber(Vector64 left, Vector64 right) => Vector64.MinMagnitudeNumber(left, right); + + /// + static Vector64 ISimdVector, T>.MinNative(Vector64 left, Vector64 right) => Vector64.MinNative(left, right); + + /// + static Vector64 ISimdVector, T>.MinNumber(Vector64 left, Vector64 right) => Vector64.MinNumber(left, right); + /// static Vector64 ISimdVector, T>.Multiply(Vector64 left, Vector64 right) => left * right; diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index 07e6fc2dda9e9c..21994c9610f5eb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -3,6 +3,7 @@ using System.Diagnostics; using System.Numerics; +using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; @@ -1114,6 +1115,178 @@ public static TVectorSingle Log2Single(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return TVector.ConditionalSelect( + (TVector.Equals(x, y) & TVector.IsNegative(y)) | TVector.IsNaN(x) | TVector.LessThan(y, x), + x, + y + ); + } + return TVector.ConditionalSelect(TVector.GreaterThan(x, y), x, y); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector MaxMagnitude(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + TVector xMag = TVector.Abs(x); + TVector yMag = TVector.Abs(y); + return TVector.ConditionalSelect( + TVector.GreaterThan(xMag, yMag) | TVector.IsNaN(xMag) | (TVector.Equals(xMag, yMag) & TVector.IsPositive(x)), + x, + y + ); + } + return MaxMagnitudeNumber(x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector MaxMagnitudeNumber(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return TVector.ConditionalSelect(TVector.LessThan(y, x), x, y); + } + + TVector xMag = TVector.Abs(x); + TVector yMag = TVector.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) + ) + { + return TVector.ConditionalSelect( + TVector.GreaterThan(xMag, yMag) | TVector.IsNaN(yMag) | (TVector.Equals(xMag, yMag) & TVector.IsPositive(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return TVector.ConditionalSelect( + (TVector.GreaterThan(xMag, yMag) & TVector.IsPositive(yMag)) | TVector.IsNegative(xMag), + x, + y + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector MaxNumber(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return TVector.ConditionalSelect( + (TVector.Equals(x, y) & TVector.IsNegative(y)) | TVector.IsNaN(y) | TVector.LessThan(y, x), + x, + y + ); + } + + return TVector.ConditionalSelect(TVector.LessThan(y, x), x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector Min(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return TVector.ConditionalSelect( + (TVector.Equals(x, y) & TVector.IsNegative(x)) | TVector.IsNaN(x) | TVector.LessThan(x, y), + x, + y + ); + } + return TVector.ConditionalSelect(TVector.LessThan(x, y), x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector MinMagnitude(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + TVector xMag = TVector.Abs(x); + TVector yMag = TVector.Abs(y); + + return TVector.ConditionalSelect( + TVector.LessThan(xMag, yMag) | TVector.IsNaN(xMag) | (TVector.Equals(xMag, yMag) & TVector.IsNegative(x)), + x, + y + ); + } + return MinMagnitudeNumber(x, y); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector MinMagnitudeNumber(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return TVector.ConditionalSelect(TVector.LessThan(x, y), x, y); + } + + TVector xMag = TVector.Abs(x); + TVector yMag = TVector.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return TVector.ConditionalSelect( + TVector.LessThan(xMag, yMag) | TVector.IsNaN(yMag) | (TVector.Equals(xMag, yMag) & TVector.IsNegative(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return TVector.ConditionalSelect( + (TVector.LessThan(xMag, yMag) & TVector.IsPositive(xMag)) | TVector.IsNegative(yMag), + x, + y + ); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TVector MinNumber(TVector x, TVector y) + where TVector : unmanaged, ISimdVector + { + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return TVector.ConditionalSelect( + (TVector.Equals(x, y) & TVector.IsNegative(x)) | TVector.IsNaN(y) | TVector.LessThan(x, y), + x, + y + ); + } + return TVector.ConditionalSelect(TVector.LessThan(x, y), x, y); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TVector RadiansToDegrees(TVector radians) where TVector : unmanaged, ISimdVector diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index c34338fdafe236..f98edfa3cb85cc 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -211,7 +211,15 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static System.Runtime.Intrinsics.Vector128 Log2(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Log2(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Max(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MaxMagnitude(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MaxMagnitudeNumber(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MaxNative(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MaxNumber(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Min(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MinMagnitude(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MinMagnitudeNumber(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MinNative(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } + public static System.Runtime.Intrinsics.Vector128 MinNumber(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Multiply(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Multiply(System.Runtime.Intrinsics.Vector128 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Multiply(T left, System.Runtime.Intrinsics.Vector128 right) { throw null; } @@ -573,7 +581,15 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static System.Runtime.Intrinsics.Vector256 Log2(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Log2(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Max(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MaxMagnitude(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MaxMagnitudeNumber(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MaxNative(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MaxNumber(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Min(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MinMagnitude(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MinMagnitudeNumber(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MinNative(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } + public static System.Runtime.Intrinsics.Vector256 MinNumber(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Multiply(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Multiply(System.Runtime.Intrinsics.Vector256 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Multiply(T left, System.Runtime.Intrinsics.Vector256 right) { throw null; } @@ -936,7 +952,15 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 Log2(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Log2(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Max(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MaxMagnitude(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MaxMagnitudeNumber(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MaxNative(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MaxNumber(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Min(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MinMagnitude(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MinMagnitudeNumber(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MinNative(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } + public static System.Runtime.Intrinsics.Vector512 MinNumber(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Multiply(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Multiply(System.Runtime.Intrinsics.Vector512 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Multiply(T left, System.Runtime.Intrinsics.Vector512 right) { throw null; } @@ -1268,7 +1292,15 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static System.Runtime.Intrinsics.Vector64 Log2(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Log2(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Max(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MaxMagnitude(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MaxMagnitudeNumber(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MaxNative(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MaxNumber(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Min(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MinMagnitude(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MinMagnitudeNumber(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MinNative(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } + public static System.Runtime.Intrinsics.Vector64 MinNumber(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Multiply(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Multiply(System.Runtime.Intrinsics.Vector64 left, T right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Multiply(T left, System.Runtime.Intrinsics.Vector64 right) { throw null; } diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 00c8669e672a2e..dae5e780412cff 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -355,10 +355,16 @@ emit_simd_ins_for_binary_op (MonoCompile *cfg, MonoClass *klass, MonoMethodSigna instc0 = OP_FDIV; break; } +#ifdef TARGET_ARM64 case SN_Max: +#endif + case SN_MaxNative: instc0 = OP_FMAX; break; +#ifdef TARGET_ARM64 case SN_Min: +#endif + case SN_MinNative: instc0 = OP_FMIN; break; case SN_Multiply: @@ -396,6 +402,7 @@ emit_simd_ins_for_binary_op (MonoCompile *cfg, MonoClass *klass, MonoMethodSigna case SN_op_Division: return NULL; case SN_Max: + case SN_MaxNative: instc0 = type_enum_is_unsigned (arg_type) ? OP_IMAX_UN : OP_IMAX; #ifdef TARGET_AMD64 if (!COMPILE_LLVM (cfg) && instc0 == OP_IMAX_UN) @@ -403,6 +410,7 @@ emit_simd_ins_for_binary_op (MonoCompile *cfg, MonoClass *klass, MonoMethodSigna #endif break; case SN_Min: + case SN_MinNative: instc0 = type_enum_is_unsigned (arg_type) ? OP_IMIN_UN : OP_IMIN; #ifdef TARGET_AMD64 if (!COMPILE_LLVM (cfg) && instc0 == OP_IMIN_UN) @@ -1231,7 +1239,9 @@ static guint16 sri_vector_methods [] = { SN_LessThanOrEqualAll, SN_LessThanOrEqualAny, SN_Max, + SN_MaxNative, SN_Min, + SN_MinNative, SN_Multiply, SN_Narrow, SN_Negate, @@ -1593,12 +1603,18 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_BitwiseOr: case SN_Divide: case SN_Max: + case SN_MaxNative: case SN_Min: + case SN_MinNative: case SN_Multiply: case SN_Subtract: case SN_Xor: if (!is_element_type_primitive (fsig->params [0])) return NULL; +#ifndef TARGET_ARM64 + if (((id == SN_Max) || (id == SN_Min)) && type_enum_is_float(arg0_type)) + return NULL; +#endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, arg0_type, id); case SN_AndNot: { if (!is_element_type_primitive (fsig->params [0])) @@ -2752,7 +2768,9 @@ static guint16 vector_2_3_4_methods[] = { SN_LengthSquared, SN_Lerp, SN_Max, + SN_MaxNative, SN_Min, + SN_MinNative, SN_Multiply, SN_Negate, SN_Normalize, @@ -3047,11 +3065,17 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f case SN_op_Multiply: case SN_op_Subtraction: case SN_Max: - case SN_Min: { + case SN_MaxNative: + case SN_Min: + case SN_MinNative: { const char *klass_name = m_class_get_name (klass); // FIXME https://github.com/dotnet/runtime/issues/82408 if ((id == SN_op_Multiply || id == SN_Multiply || id == SN_op_Division || id == SN_Divide) && !strcmp (klass_name, "Quaternion")) return NULL; +#ifndef TARGET_ARM64 + if ((id == SN_Max) || (id == SN_Min)) + return NULL; +#endif return emit_simd_ins_for_binary_op (cfg, klass, fsig, args, MONO_TYPE_R4, id); } case SN_Dot: { diff --git a/src/mono/mono/mini/simd-methods.h b/src/mono/mono/mini/simd-methods.h index 82fe74ebf415c2..9e04b423a187cf 100644 --- a/src/mono/mono/mini/simd-methods.h +++ b/src/mono/mono/mini/simd-methods.h @@ -25,10 +25,12 @@ METHOD(LessThanOrEqualAny) METHOD(Length) METHOD(LengthSquared) METHOD(Lerp) -METHOD(Min) METHOD(Max) -METHOD(MinScalar) +METHOD(MaxNative) METHOD(MaxScalar) +METHOD(Min) +METHOD(MinNative) +METHOD(MinScalar) METHOD(Normalize) METHOD(PopCount) METHOD(LeadingZeroCount) From 283301d6e3a81b03754380f77f865c9fcd8eb21d Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 19 Jun 2024 16:21:32 -0700 Subject: [PATCH 11/39] Expose Clamp on the various vector types --- .../ref/System.Numerics.Vectors.cs | 5 +++++ .../src/System/Numerics/Vector.cs | 16 ++++++++++++++++ .../src/System/Numerics/Vector2.cs | 18 ++++++++---------- .../src/System/Numerics/Vector3.cs | 18 ++++++++---------- .../src/System/Numerics/Vector4.cs | 18 ++++++++---------- .../src/System/Numerics/Vector_1.cs | 6 ++++++ .../System/Runtime/Intrinsics/ISimdVector_2.cs | 16 ++++++++++++++++ .../src/System/Runtime/Intrinsics/Vector128.cs | 16 ++++++++++++++++ .../System/Runtime/Intrinsics/Vector128_1.cs | 6 ++++++ .../src/System/Runtime/Intrinsics/Vector256.cs | 16 ++++++++++++++++ .../System/Runtime/Intrinsics/Vector256_1.cs | 6 ++++++ .../src/System/Runtime/Intrinsics/Vector512.cs | 16 ++++++++++++++++ .../System/Runtime/Intrinsics/Vector512_1.cs | 6 ++++++ .../src/System/Runtime/Intrinsics/Vector64.cs | 16 ++++++++++++++++ .../System/Runtime/Intrinsics/Vector64_1.cs | 6 ++++++ .../ref/System.Runtime.Intrinsics.cs | 8 ++++++++ 16 files changed, 163 insertions(+), 30 deletions(-) diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index df5e98e6978194..a0d3ae85e99af7 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -238,6 +238,8 @@ public static partial class Vector public static System.Numerics.Vector BitwiseOr(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Ceiling(System.Numerics.Vector value) { throw null; } public static System.Numerics.Vector Ceiling(System.Numerics.Vector value) { throw null; } + public static System.Numerics.Vector Clamp(System.Numerics.Vector value, System.Numerics.Vector min, System.Numerics.Vector max) { throw null; } + public static System.Numerics.Vector ClampNative(System.Numerics.Vector value, System.Numerics.Vector min, System.Numerics.Vector max) { throw null; } public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector condition, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector condition, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector ConditionalSelect(System.Numerics.Vector condition, System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } @@ -475,6 +477,7 @@ public partial struct Vector2 : System.IEquatable, Syst public static System.Numerics.Vector2 Abs(System.Numerics.Vector2 value) { throw null; } public static System.Numerics.Vector2 Add(System.Numerics.Vector2 left, System.Numerics.Vector2 right) { throw null; } public static System.Numerics.Vector2 Clamp(System.Numerics.Vector2 value1, System.Numerics.Vector2 min, System.Numerics.Vector2 max) { throw null; } + public static System.Numerics.Vector2 ClampNative(System.Numerics.Vector2 value1, System.Numerics.Vector2 min, System.Numerics.Vector2 max) { throw null; } public static System.Numerics.Vector2 CopySign(System.Numerics.Vector2 value, System.Numerics.Vector2 sign) { throw null; } public static System.Numerics.Vector2 Create(float value) { throw null; } public static System.Numerics.Vector2 Create(float x, float y) { throw null; } @@ -569,6 +572,7 @@ public partial struct Vector3 : System.IEquatable, Syst public static System.Numerics.Vector3 Abs(System.Numerics.Vector3 value) { throw null; } public static System.Numerics.Vector3 Add(System.Numerics.Vector3 left, System.Numerics.Vector3 right) { throw null; } public static System.Numerics.Vector3 Clamp(System.Numerics.Vector3 value1, System.Numerics.Vector3 min, System.Numerics.Vector3 max) { throw null; } + public static System.Numerics.Vector3 ClampNative(System.Numerics.Vector3 value1, System.Numerics.Vector3 min, System.Numerics.Vector3 max) { throw null; } public static System.Numerics.Vector3 CopySign(System.Numerics.Vector3 value, System.Numerics.Vector3 sign) { throw null; } public static System.Numerics.Vector3 Create(float value) { throw null; } public static System.Numerics.Vector3 Create(System.Numerics.Vector2 vector, float z) { throw null; } @@ -666,6 +670,7 @@ public partial struct Vector4 : System.IEquatable, Syst public static System.Numerics.Vector4 Abs(System.Numerics.Vector4 value) { throw null; } public static System.Numerics.Vector4 Add(System.Numerics.Vector4 left, System.Numerics.Vector4 right) { throw null; } public static System.Numerics.Vector4 Clamp(System.Numerics.Vector4 value1, System.Numerics.Vector4 min, System.Numerics.Vector4 max) { throw null; } + public static System.Numerics.Vector4 ClampNative(System.Numerics.Vector4 value1, System.Numerics.Vector4 min, System.Numerics.Vector4 max) { throw null; } public static System.Numerics.Vector4 CopySign(System.Numerics.Vector4 value, System.Numerics.Vector4 sign) { throw null; } public static System.Numerics.Vector4 Create(float value) { throw null; } public static System.Numerics.Vector4 Create(System.Numerics.Vector2 vector, float z, float w) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index dfb8a4e3580044..3ab21caa4e5866 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -279,6 +279,22 @@ public static Vector Ceiling(Vector value) return result; } + /// + [Intrinsic] + public static Vector Clamp(Vector value, Vector min, Vector max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return Min(Max(value, min), max); + } + + /// + [Intrinsic] + public static Vector ClampNative(Vector value, Vector min, Vector max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return MinNative(MaxNative(value, min), max); + } + /// Conditionally selects a value from two vectors on a bitwise basis. /// The mask that is used to select a value from or . /// The vector that is selected when the corresponding bit in is one. diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs index 0a096c91066b48..e101a75ea91544 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector2.cs @@ -265,17 +265,15 @@ readonly get [Intrinsic] public static Vector2 Add(Vector2 left, Vector2 right) => left + right; - /// Restricts a vector between a minimum and a maximum value. - /// The vector to restrict. - /// The minimum value. - /// The maximum value. - /// The restricted vector. + /// [Intrinsic] - public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) - { - // We must follow HLSL behavior in the case user specified min value is bigger than max value. - return Min(Max(value1, min), max); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 Clamp(Vector2 value1, Vector2 min, Vector2 max) => Vector128.Clamp(value1.AsVector128Unsafe(), min.AsVector128Unsafe(), max.AsVector128Unsafe()).AsVector2(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector2 ClampNative(Vector2 value1, Vector2 min, Vector2 max) => Vector128.ClampNative(value1.AsVector128Unsafe(), min.AsVector128Unsafe(), max.AsVector128Unsafe()).AsVector2(); /// [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs index 14a3aeca6cbf97..8519f382655dec 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector3.cs @@ -286,17 +286,15 @@ readonly get [Intrinsic] public static Vector3 Add(Vector3 left, Vector3 right) => left + right; - /// Restricts a vector between a minimum and a maximum value. - /// The vector to restrict. - /// The minimum value. - /// The maximum value. - /// The restricted vector. + /// [Intrinsic] - public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) - { - // We must follow HLSL behavior in the case user specified min value is bigger than max value. - return Min(Max(value1, min), max); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 Clamp(Vector3 value1, Vector3 min, Vector3 max) => Vector128.Clamp(value1.AsVector128Unsafe(), min.AsVector128Unsafe(), max.AsVector128Unsafe()).AsVector3(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector3 ClampNative(Vector3 value1, Vector3 min, Vector3 max) => Vector128.ClampNative(value1.AsVector128Unsafe(), min.AsVector128Unsafe(), max.AsVector128Unsafe()).AsVector3(); /// [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs index 16d023f8c78a57..9c7028520f7623 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector4.cs @@ -305,17 +305,15 @@ public float this[int index] [Intrinsic] public static Vector4 Add(Vector4 left, Vector4 right) => left + right; - /// Restricts a vector between a minimum and a maximum value. - /// The vector to restrict. - /// The minimum value. - /// The maximum value. - /// The restricted vector. + /// [Intrinsic] - public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max) - { - // We must follow HLSL behavior in the case user specified min value is bigger than max value. - return Min(Max(value1, min), max); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 Clamp(Vector4 value1, Vector4 min, Vector4 max) => Vector128.Clamp(value1.AsVector128(), min.AsVector128(), max.AsVector128()).AsVector4(); + + /// + [Intrinsic] + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector4 ClampNative(Vector4 value1, Vector4 min, Vector4 max) => Vector128.ClampNative(value1.AsVector128(), min.AsVector128(), max.AsVector128()).AsVector4(); /// [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs index f96c7b16f70a45..0910caadcf37cb 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector_1.cs @@ -832,6 +832,12 @@ public bool TryCopyTo(Span destination) /// static Vector ISimdVector, T>.Ceiling(Vector vector) => Vector.Ceiling(vector); + /// + static Vector ISimdVector, T>.Clamp(Vector value, Vector min, Vector max) => Vector.Clamp(value, min, max); + + /// + static Vector ISimdVector, T>.ClampNative(Vector value, Vector min, Vector max) => Vector.ClampNative(value, min, max); + /// static Vector ISimdVector, T>.ConditionalSelect(Vector condition, Vector left, Vector right) => Vector.ConditionalSelect(condition, left, right); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs index 267d209a9dbfb3..eaa9a524be175a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/ISimdVector_2.cs @@ -118,6 +118,22 @@ internal unsafe interface ISimdVector /// A vector whose elements are the ceiling of the elements in . static abstract TSelf Ceiling(TSelf vector); + /// Restricts a vector between a minimum and a maximum value. + /// The vector to restrict. + /// The minimum value. + /// The maximum value. + /// The restricted vector. + /// The type of the elements in the vector () is not supported. + static abstract TSelf Clamp(TSelf value, TSelf min, TSelf max); + + /// Restricts a vector between a minimum and a maximum value using platform specific behavior for NaN and NegativeZero.. + /// The vector to restrict. + /// The minimum value. + /// The maximum value. + /// The restricted vector. + /// The type of the elements in the vector () is not supported. + static abstract TSelf ClampNative(TSelf value, TSelf min, TSelf max); + /// Conditionally selects bits from two vectors based on a given condition. /// The mask that is used to select a value from or . /// The vector that is selected when the corresponding bit in is one. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 55a434158b50df..2d88498cc229f3 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -448,6 +448,22 @@ internal static Vector128 Ceiling(Vector128 vector) [Intrinsic] public static Vector128 Ceiling(Vector128 vector) => Ceiling(vector); + /// + [Intrinsic] + public static Vector128 Clamp(Vector128 value, Vector128 min, Vector128 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return Min(Max(value, min), max); + } + + /// + [Intrinsic] + public static Vector128 ClampNative(Vector128 value, Vector128 min, Vector128 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return MinNative(MaxNative(value, min), max); + } + /// Conditionally selects a value from two vectors on a bitwise basis. /// The type of the elements in the vector. /// The mask that is used to select a value from or . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs index df560784be9141..7cc09d5c742a5d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128_1.cs @@ -479,6 +479,12 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector128 ISimdVector, T>.Ceiling(Vector128 vector) => Vector128.Ceiling(vector); + /// + static Vector128 ISimdVector, T>.Clamp(Vector128 value, Vector128 min, Vector128 max) => Vector128.Clamp(value, min, max); + + /// + static Vector128 ISimdVector, T>.ClampNative(Vector128 value, Vector128 min, Vector128 max) => Vector128.ClampNative(value, min, max); + /// static Vector128 ISimdVector, T>.ConditionalSelect(Vector128 condition, Vector128 left, Vector128 right) => Vector128.ConditionalSelect(condition, left, right); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index bb491e11b9641b..1a69fc6069731a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -313,6 +313,22 @@ internal static Vector256 Ceiling(Vector256 vector) [Intrinsic] public static Vector256 Ceiling(Vector256 vector) => Ceiling(vector); + /// + [Intrinsic] + public static Vector256 Clamp(Vector256 value, Vector256 min, Vector256 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return Min(Max(value, min), max); + } + + /// + [Intrinsic] + public static Vector256 ClampNative(Vector256 value, Vector256 min, Vector256 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return MinNative(MaxNative(value, min), max); + } + /// Conditionally selects a value from two vectors on a bitwise basis. /// The type of the elements in the vector. /// The mask that is used to select a value from or . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs index b649fb9a755c44..f886b55e18d914 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256_1.cs @@ -468,6 +468,12 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector256 ISimdVector, T>.Ceiling(Vector256 vector) => Vector256.Ceiling(vector); + /// + static Vector256 ISimdVector, T>.Clamp(Vector256 value, Vector256 min, Vector256 max) => Vector256.Clamp(value, min, max); + + /// + static Vector256 ISimdVector, T>.ClampNative(Vector256 value, Vector256 min, Vector256 max) => Vector256.ClampNative(value, min, max); + /// static Vector256 ISimdVector, T>.ConditionalSelect(Vector256 condition, Vector256 left, Vector256 right) => Vector256.ConditionalSelect(condition, left, right); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index 0e42a020f6aa06..e63af15c915dcc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -313,6 +313,22 @@ internal static Vector512 Ceiling(Vector512 vector) [Intrinsic] public static Vector512 Ceiling(Vector512 vector) => Ceiling(vector); + /// + [Intrinsic] + public static Vector512 Clamp(Vector512 value, Vector512 min, Vector512 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return Min(Max(value, min), max); + } + + /// + [Intrinsic] + public static Vector512 ClampNative(Vector512 value, Vector512 min, Vector512 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return MinNative(MaxNative(value, min), max); + } + /// Conditionally selects a value from two vectors on a bitwise basis. /// The type of the elements in the vector. /// The mask that is used to select a value from or . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs index 4ff88c0dc3d279..7fb65ad7583e06 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512_1.cs @@ -468,6 +468,12 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector512 ISimdVector, T>.Ceiling(Vector512 vector) => Vector512.Ceiling(vector); + /// + static Vector512 ISimdVector, T>.Clamp(Vector512 value, Vector512 min, Vector512 max) => Vector512.Clamp(value, min, max); + + /// + static Vector512 ISimdVector, T>.ClampNative(Vector512 value, Vector512 min, Vector512 max) => Vector512.ClampNative(value, min, max); + /// static Vector512 ISimdVector, T>.ConditionalSelect(Vector512 condition, Vector512 left, Vector512 right) => Vector512.ConditionalSelect(condition, left, right); diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index 6c2d334e765342..65854c8e0f0775 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -263,6 +263,22 @@ internal static Vector64 Ceiling(Vector64 vector) [Intrinsic] public static Vector64 Ceiling(Vector64 vector) => Ceiling(vector); + /// + [Intrinsic] + public static Vector64 Clamp(Vector64 value, Vector64 min, Vector64 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return Min(Max(value, min), max); + } + + /// + [Intrinsic] + public static Vector64 ClampNative(Vector64 value, Vector64 min, Vector64 max) + { + // We must follow HLSL behavior in the case user specified min value is bigger than max value. + return MinNative(MaxNative(value, min), max); + } + /// Conditionally selects a value from two vectors on a bitwise basis. /// The type of the elements in the vector. /// The mask that is used to select a value from or . diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs index 42d0045cc28b08..64fc7f07b7ffe4 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64_1.cs @@ -536,6 +536,12 @@ private string ToString([StringSyntax(StringSyntaxAttribute.NumericFormat)] stri /// static Vector64 ISimdVector, T>.Ceiling(Vector64 vector) => Vector64.Ceiling(vector); + /// + static Vector64 ISimdVector, T>.Clamp(Vector64 value, Vector64 min, Vector64 max) => Vector64.Clamp(value, min, max); + + /// + static Vector64 ISimdVector, T>.ClampNative(Vector64 value, Vector64 min, Vector64 max) => Vector64.ClampNative(value, min, max); + /// static Vector64 ISimdVector, T>.ConditionalSelect(Vector64 condition, Vector64 left, Vector64 right) => Vector64.ConditionalSelect(condition, left, right); diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index f98edfa3cb85cc..49c009b62d8038 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -46,6 +46,8 @@ public static partial class Vector128 public static System.Runtime.Intrinsics.Vector128 BitwiseOr(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Ceiling(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Ceiling(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 Clamp(System.Runtime.Intrinsics.Vector128 value, System.Runtime.Intrinsics.Vector128 min, System.Runtime.Intrinsics.Vector128 max) { throw null; } + public static System.Runtime.Intrinsics.Vector128 ClampNative(System.Runtime.Intrinsics.Vector128 value, System.Runtime.Intrinsics.Vector128 min, System.Runtime.Intrinsics.Vector128 max) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConditionalSelect(System.Runtime.Intrinsics.Vector128 condition, System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 ConvertToDouble(System.Runtime.Intrinsics.Vector128 vector) { throw null; } [System.CLSCompliantAttribute(false)] @@ -415,6 +417,8 @@ public static partial class Vector256 public static System.Runtime.Intrinsics.Vector256 BitwiseOr(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Ceiling(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Ceiling(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 Clamp(System.Runtime.Intrinsics.Vector256 value, System.Runtime.Intrinsics.Vector256 min, System.Runtime.Intrinsics.Vector256 max) { throw null; } + public static System.Runtime.Intrinsics.Vector256 ClampNative(System.Runtime.Intrinsics.Vector256 value, System.Runtime.Intrinsics.Vector256 min, System.Runtime.Intrinsics.Vector256 max) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConditionalSelect(System.Runtime.Intrinsics.Vector256 condition, System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 ConvertToDouble(System.Runtime.Intrinsics.Vector256 vector) { throw null; } [System.CLSCompliantAttribute(false)] @@ -785,6 +789,8 @@ public static partial class Vector512 public static System.Runtime.Intrinsics.Vector512 BitwiseOr(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Ceiling(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Ceiling(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 Clamp(System.Runtime.Intrinsics.Vector512 value, System.Runtime.Intrinsics.Vector512 min, System.Runtime.Intrinsics.Vector512 max) { throw null; } + public static System.Runtime.Intrinsics.Vector512 ClampNative(System.Runtime.Intrinsics.Vector512 value, System.Runtime.Intrinsics.Vector512 min, System.Runtime.Intrinsics.Vector512 max) { throw null; } public static System.Runtime.Intrinsics.Vector512 ConditionalSelect(System.Runtime.Intrinsics.Vector512 condition, System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 ConvertToDouble(System.Runtime.Intrinsics.Vector512 vector) { throw null; } [System.CLSCompliantAttribute(false)] @@ -1152,6 +1158,8 @@ public static partial class Vector64 public static System.Runtime.Intrinsics.Vector64 BitwiseOr(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Ceiling(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Ceiling(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 Clamp(System.Runtime.Intrinsics.Vector64 value, System.Runtime.Intrinsics.Vector64 min, System.Runtime.Intrinsics.Vector64 max) { throw null; } + public static System.Runtime.Intrinsics.Vector64 ClampNative(System.Runtime.Intrinsics.Vector64 value, System.Runtime.Intrinsics.Vector64 min, System.Runtime.Intrinsics.Vector64 max) { throw null; } public static System.Runtime.Intrinsics.Vector64 ConditionalSelect(System.Runtime.Intrinsics.Vector64 condition, System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 ConvertToDouble(System.Runtime.Intrinsics.Vector64 vector) { throw null; } [System.CLSCompliantAttribute(false)] From b513e5c20481b08d632ab9818b5ffbb26f1fa187 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 12:44:41 -0700 Subject: [PATCH 12/39] Ensure mono handles the various zero and low-cost vector conversions --- src/mono/mono/mini/simd-intrinsics.c | 66 +++++++++++++++++++++++++++- src/mono/mono/mini/simd-methods.h | 6 +++ 2 files changed, 71 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index dae5e780412cff..24393eb9b7ba90 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1193,11 +1193,21 @@ static guint16 sri_vector_methods [] = { SN_AsInt16, SN_AsInt32, SN_AsInt64, + SN_AsNInt, + SN_AsNUInt, + SN_AsPlane, + SN_AsQuaternion, SN_AsSByte, SN_AsSingle, SN_AsUInt16, SN_AsUInt32, SN_AsUInt64, + SN_AsVector, + SN_AsVector128, + SN_AsVector128Unsafe, + SN_AsVector2, + SN_AsVector3, + SN_AsVector4, SN_BitwiseAnd, SN_BitwiseOr, SN_Ceiling, @@ -1639,15 +1649,69 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_AsInt16: case SN_AsInt32: case SN_AsInt64: + case SN_AsNInt: + case SN_AsNUInt: + case SN_AsPlane: + case SN_AsQuaternion: case SN_AsSByte: case SN_AsSingle: case SN_AsUInt16: case SN_AsUInt32: - case SN_AsUInt64: { + case SN_AsUInt64: + case SN_AsVector: + case SN_AsVector4: { if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) return NULL; return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); } + case SN_AsVector2: + case SN_AsVector3: { + if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->ret))) { + // FIXME: Support Vector2 and Vector3 for WASM and AMD64 + return NULL; + } + return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); + } + case SN_AsVector128: { + if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) + return NULL; + if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->params [0]))) { + // FIXME: Support Vector2 and Vector3 for WASM and AMD64 + return NULL; + } + MonoClass *input_class = mono_class_from_mono_type_internal (fsig->params [0]); + int input_size = mono_class_value_size (vector_class, NULL); + if (input_size == 16) + return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); + if (COMPILE_LLVM (cfg) && (inputSize == 8)) { + return emit_simd_ins (cfg, klass, OP_XWIDEN, args [0]->dreg, -1); + } + static float r4_0 = 0; + MonoInst *zero; + int zero_dreg = alloc_freg (cfg); + MONO_INST_NEW (cfg, zero, OP_R4CONST); + zero->inst_p0 = (void*)&r4_0; + zero->dreg = zero_dreg; + MONO_ADD_INS (cfg->cbb, zero); + if (input_size == 8) { + args [0] = emit_vector_insert_element (cfg, klass, args [0], MONO_TYPE_R4, zero, 2, FALSE); + } + return emit_vector_insert_element (cfg, klass, args [0], MONO_TYPE_R4, zero, 3, FALSE); + } + case SN_AsVector128Unsafe: { + if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) + return NULL; + if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->params [0]))) { + // FIXME: Support Vector2 and Vector3 for WASM and AMD64 + return NULL; + } + MonoClass *input_class = mono_class_from_mono_type_internal (fsig->params [0]); + int input_size = mono_class_value_size (vector_class, NULL); + if (COMPILE_LLVM (cfg) && (inputSize == 8)) { + return emit_simd_ins (cfg, klass, OP_XWIDEN_UNSAFE, args [0]->dreg, -1); + } + return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); + } case SN_Ceiling: case SN_Floor: { if (!type_enum_is_float (arg0_type)) diff --git a/src/mono/mono/mini/simd-methods.h b/src/mono/mono/mini/simd-methods.h index 9e04b423a187cf..6ca019068a933f 100644 --- a/src/mono/mono/mini/simd-methods.h +++ b/src/mono/mono/mini/simd-methods.h @@ -78,12 +78,18 @@ METHOD(AsDouble) METHOD(AsInt16) METHOD(AsInt32) METHOD(AsInt64) +METHOD(AsNInt) +METHOD(AsNUInt) +METHOD(AsPlane) +METHOD(AsQuaternion) METHOD(AsSByte) METHOD(AsSingle) METHOD(AsUInt16) METHOD(AsUInt32) METHOD(AsUInt64) +METHOD(AsVector) METHOD(AsVector128) +METHOD(AsVector128Unsafe) METHOD(AsVector2) METHOD(AsVector256) METHOD(AsVector3) From 0816d549d7031d68d5fe27f9bb3bcb909c6585d9 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 12:48:43 -0700 Subject: [PATCH 13/39] Apply formatting patch --- src/coreclr/jit/gentree.cpp | 32 +++++++++------------------- src/coreclr/jit/hwintrinsicarm64.cpp | 5 ++--- 2 files changed, 12 insertions(+), 25 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 1bfa176b5715b8..973ebe5f03ffb5 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -24571,10 +24571,7 @@ GenTree* Compiler::gtNewSimdGetUpperNode(var_types type, GenTree* op1, CorInfoTy // Returns: // The created IsNaN node // -GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, - GenTree* op1, - CorInfoType simdBaseJitType, - unsigned simdSize) +GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(IsBaselineSimdIsaSupportedDebugOnly()); @@ -24607,10 +24604,7 @@ GenTree* Compiler::gtNewSimdIsNaNNode(var_types type, // Returns: // The created IsNegative node // -GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, - GenTree* op1, - CorInfoType simdBaseJitType, - unsigned simdSize) +GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(IsBaselineSimdIsaSupportedDebugOnly()); @@ -24651,10 +24645,7 @@ GenTree* Compiler::gtNewSimdIsNegativeNode(var_types type, // Returns: // The created IsPositive node // -GenTree* Compiler::gtNewSimdIsPositiveNode(var_types type, - GenTree* op1, - CorInfoType simdBaseJitType, - unsigned simdSize) +GenTree* Compiler::gtNewSimdIsPositiveNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(IsBaselineSimdIsaSupportedDebugOnly()); @@ -24733,10 +24724,7 @@ GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, // Returns: // The created IsZero node // -GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, - GenTree* op1, - CorInfoType simdBaseJitType, - unsigned simdSize) +GenTree* Compiler::gtNewSimdIsZeroNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { assert(IsBaselineSimdIsaSupportedDebugOnly()); @@ -24966,10 +24954,10 @@ GenTree* Compiler::gtNewSimdMaxNode( GenTree* op2Dup2 = fgMakeMultiUse(&op2); GenTree* op2Dup3 = fgMakeMultiUse(&op2); - GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); + GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); GenTree* isNegativeMask = gtNewSimdIsNegativeNode(type, op2Dup1, simdBaseJitType, simdSize); - GenTree* isNaNMask = gtNewSimdIsNaNNode(type, op1Dup1, simdBaseJitType, simdSize); - GenTree* lessThanMask = gtNewSimdCmpOpNode(GT_LT, type, op2Dup2, op1Dup2, simdBaseJitType, simdSize); + GenTree* isNaNMask = gtNewSimdIsNaNNode(type, op1Dup1, simdBaseJitType, simdSize); + GenTree* lessThanMask = gtNewSimdCmpOpNode(GT_LT, type, op2Dup2, op1Dup2, simdBaseJitType, simdSize); GenTree* mask = gtNewSimdBinOpNode(GT_AND, type, equalsMask, isNegativeMask, simdBaseJitType, simdSize); mask = gtNewSimdBinOpNode(GT_OR, type, mask, isNaNMask, simdBaseJitType, simdSize); @@ -25225,10 +25213,10 @@ GenTree* Compiler::gtNewSimdMinNode( GenTree* op2Dup1 = fgMakeMultiUse(&op2); GenTree* op2Dup2 = fgMakeMultiUse(&op2); - GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); + GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); GenTree* isNegativeMask = gtNewSimdIsNegativeNode(type, op1Dup1, simdBaseJitType, simdSize); - GenTree* isNaNMask = gtNewSimdIsNaNNode(type, op1Dup2, simdBaseJitType, simdSize); - GenTree* lessThanMask = gtNewSimdCmpOpNode(GT_LT, type, op1Dup3, op2Dup1, simdBaseJitType, simdSize); + GenTree* isNaNMask = gtNewSimdIsNaNNode(type, op1Dup2, simdBaseJitType, simdSize); + GenTree* lessThanMask = gtNewSimdCmpOpNode(GT_LT, type, op1Dup3, op2Dup1, simdBaseJitType, simdSize); GenTree* mask = gtNewSimdBinOpNode(GT_AND, type, equalsMask, isNegativeMask, simdBaseJitType, simdSize); mask = gtNewSimdBinOpNode(GT_OR, type, mask, isNaNMask, simdBaseJitType, simdSize); diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index a75c24831d3add..8734b4c05d8a2f 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1778,7 +1778,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } - case NI_Vector64_MinNative: case NI_Vector128_MinNative: { @@ -1835,10 +1834,10 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, if (varTypeIsFloating(simdBaseType)) { impSpillSideEffect(true, verCurrentState.esStackDepth - - 3 DEBUGARG("Spilling op1 side effects for MultiplyAddEstimate")); + 3 DEBUGARG("Spilling op1 side effects for MultiplyAddEstimate")); impSpillSideEffect(true, verCurrentState.esStackDepth - - 2 DEBUGARG("Spilling op2 side effects for MultiplyAddEstimate")); + 2 DEBUGARG("Spilling op2 side effects for MultiplyAddEstimate")); } op3 = impSIMDPopStack(); From 8e211ce248a973f5bcd5cb6453a2fc81e927413f Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 13:43:44 -0700 Subject: [PATCH 14/39] Ensure that TensorPrimitives uses the in-box vector operations on .NET 9+ --- .../src/System.Numerics.Tensors.csproj | 2 + .../Tensors/TensorPrimitives.Single.cs | 8 +- .../netcore/TensorPrimitives.CopySign.cs | 12 + .../TensorPrimitives.DegreesToRadians.cs | 56 +++- .../Tensors/netcore/TensorPrimitives.Hypot.cs | 56 +++- .../Tensors/netcore/TensorPrimitives.Lerp.cs | 55 +++- .../Tensors/netcore/TensorPrimitives.Max.cs | 284 +++++++++++------- .../netcore/TensorPrimitives.MaxMagnitude.cs | 178 +++-------- .../TensorPrimitives.MaxMagnitudeNumber.cs | 152 ++++++++++ .../netcore/TensorPrimitives.MaxNumber.cs | 95 ++---- .../Tensors/netcore/TensorPrimitives.Min.cs | 157 +++------- .../netcore/TensorPrimitives.MinMagnitude.cs | 166 +++------- .../TensorPrimitives.MinMagnitudeNumber.cs | 151 ++++++++++ .../netcore/TensorPrimitives.MinNumber.cs | 95 ++---- .../TensorPrimitives.RadiansToDegrees.cs | 56 +++- .../Tensors/netcore/TensorPrimitives.Round.cs | 36 +++ .../TensorPrimitives.Single.netcore.cs | 8 +- .../netcore/TensorPrimitives.Truncate.cs | 36 +++ .../System/Runtime/Intrinsics/VectorMath.cs | 8 +- 19 files changed, 979 insertions(+), 632 deletions(-) create mode 100644 src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs create mode 100644 src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs diff --git a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj index 2b656cc1d3ee5c..8eef4ed0de9c84 100644 --- a/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj +++ b/src/libraries/System.Numerics.Tensors/src/System.Numerics.Tensors.csproj @@ -97,9 +97,11 @@ + + diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs index ae6df0ed43f5c0..a8d4c6815ca406 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs @@ -440,7 +440,7 @@ public static float Max(ReadOnlySpan x) => /// /// public static void Max(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Searches for the single-precision floating-point number with the largest magnitude in the specified tensor. /// The tensor, represented as a span. @@ -476,7 +476,7 @@ public static float MaxMagnitude(ReadOnlySpan x) => /// /// public static void MaxMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Searches for the smallest single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. @@ -517,7 +517,7 @@ public static float Min(ReadOnlySpan x) => /// /// public static void Min(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Searches for the single-precision floating-point number with the smallest magnitude in the specified tensor. /// The tensor, represented as a span. @@ -558,7 +558,7 @@ public static float MinMagnitude(ReadOnlySpan x) => /// /// public static void MinMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Computes the element-wise product of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CopySign.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CopySign.cs index 0277c729a17aa4..e914e271bd0156 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CopySign.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.CopySign.cs @@ -47,6 +47,9 @@ public static void CopySign(ReadOnlySpan x, T sign, Span destination) public static Vector128 Invoke(Vector128 x, Vector128 y) { +#if NET9_0_OR_GREATER + return Vector128.CopySign(x, y); +#else if (typeof(T) == typeof(float)) { return Vector128.ConditionalSelect(Vector128.Create(-0.0f).As(), y, x); @@ -71,10 +74,14 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) } return x; +#endif } public static Vector256 Invoke(Vector256 x, Vector256 y) { +#if NET9_0_OR_GREATER + return Vector256.CopySign(x, y); +#else if (typeof(T) == typeof(float)) { return Vector256.ConditionalSelect(Vector256.Create(-0.0f).As(), y, x); @@ -99,10 +106,14 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) } return x; +#endif } public static Vector512 Invoke(Vector512 x, Vector512 y) { +#if NET9_0_OR_GREATER + return Vector512.CopySign(x, y); +#else if (typeof(T) == typeof(float)) { return Vector512.ConditionalSelect(Vector512.Create(-0.0f).As(), y, x); @@ -127,6 +138,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) } return x; +#endif } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs index 27d11cf14ce72c..bf21253c4436a6 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.DegreesToRadians.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Runtime.Intrinsics; namespace System.Numerics.Tensors @@ -25,10 +26,59 @@ public static void DegreesToRadians(ReadOnlySpan x, Span destination) private readonly struct DegreesToRadiansOperator : IUnaryOperator where T : ITrigonometricFunctions { public static bool Vectorizable => true; + public static T Invoke(T x) => T.DegreesToRadians(x); - public static Vector128 Invoke(Vector128 x) => (x * T.Pi) / T.CreateChecked(180); - public static Vector256 Invoke(Vector256 x) => (x * T.Pi) / T.CreateChecked(180); - public static Vector512 Invoke(Vector512 x) => (x * T.Pi) / T.CreateChecked(180); + + public static Vector128 Invoke(Vector128 x) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.DegreesToRadians(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.DegreesToRadians(x.AsSingle()).As(); + } +#else + return (x * T.Pi) / T.CreateChecked(180); +#endif + } + + public static Vector256 Invoke(Vector256 x) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.DegreesToRadians(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.DegreesToRadians(x.AsSingle()).As(); + } +#else + return (x * T.Pi) / T.CreateChecked(180); +#endif + } + + public static Vector512 Invoke(Vector512 x) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.DegreesToRadians(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.DegreesToRadians(x.AsSingle()).As(); + } +#else + return (x * T.Pi) / T.CreateChecked(180); +#endif + } } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs index f0c46347ac2448..c806856672f90b 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Hypot.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Runtime.Intrinsics; namespace System.Numerics.Tensors @@ -29,10 +30,59 @@ public static void Hypot(ReadOnlySpan x, ReadOnlySpan y, Span destin where T : IRootFunctions { public static bool Vectorizable => true; + public static T Invoke(T x, T y) => T.Hypot(x, y); - public static Vector128 Invoke(Vector128 x, Vector128 y) => Vector128.Sqrt((x * x) + (y * y)); - public static Vector256 Invoke(Vector256 x, Vector256 y) => Vector256.Sqrt((x * x) + (y * y)); - public static Vector512 Invoke(Vector512 x, Vector512 y) => Vector512.Sqrt((x * x) + (y * y)); + + public static Vector128 Invoke(Vector128 x, Vector128 y) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.Hypot(x.AsDouble(), y.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.Hypot(x.AsSingle(), y.AsSingle()).As(); + } +#else + return Vector128.Sqrt((x * x) + (y * y)); +#endif + } + + public static Vector256 Invoke(Vector256 x, Vector256 y) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.Hypot(x.AsDouble(), y.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.Hypot(x.AsSingle(), y.AsSingle()).As(); + } +#else + return Vector256.Sqrt((x * x) + (y * y)); +#endif + } + + public static Vector512 Invoke(Vector512 x, Vector512 y) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.Hypot(x.AsDouble(), y.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.Hypot(x.AsSingle(), y.AsSingle()).As(); + } +#else + return Vector512.Sqrt((x * x) + (y * y)); +#endif + } } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs index a605b62430d3fa..f31b3e50f77d2d 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Runtime.Intrinsics; namespace System.Numerics.Tensors @@ -75,9 +76,57 @@ public static void Lerp(ReadOnlySpan x, T y, ReadOnlySpan amount, Span< private readonly struct LerpOperator : ITernaryOperator where T : IFloatingPointIeee754 { public static T Invoke(T x, T y, T amount) => T.Lerp(x, y, amount); - public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 amount) => (x * (Vector128.One - amount)) + (y * amount); - public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 amount) => (x * (Vector256.One - amount)) + (y * amount); - public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 amount) => (x * (Vector512.One - amount)) + (y * amount); + + public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 amount) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.Lerp(x.AsDouble(), y.AsDouble(), amount.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As(); + } +#else + return (x * (Vector128.One - amount)) + (y * amount); +#endif + } + + public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 amount) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.Lerp(x.AsDouble(), y.AsDouble(), amount.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As(); + } +#else + return (x * (Vector256.One - amount)) + (y * amount); +#endif + } + + public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 amount) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.Lerp(x.AsDouble(), y.AsDouble(), amount.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As(); + } +#else + return (x * (Vector512.One - amount)) + (y * amount); +#endif + } } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs index 2e760e30fb7c60..3a9c370e0078dd 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; @@ -51,7 +52,7 @@ public static T Max(ReadOnlySpan x) /// public static void Max(ReadOnlySpan x, ReadOnlySpan y, Span destination) where T : INumber => - InvokeSpanSpanIntoSpan>(x, y, destination); + InvokeSpanSpanIntoSpan>(x, y, destination); /// Computes the element-wise maximum of the numbers in the specified tensors. /// The first tensor, represented as a span. @@ -74,45 +75,30 @@ public static void Max(ReadOnlySpan x, ReadOnlySpan y, Span destinat /// public static void Max(ReadOnlySpan x, T y, Span destination) where T : INumber => - InvokeSpanScalarIntoSpan>(x, y, destination); + InvokeSpanScalarIntoSpan>(x, y, destination); - /// T.Max(x, y) (but NaNs may not be propagated) - internal readonly struct MaxOperator : IAggregationOperator where T : INumber + /// Max(x, y) + internal readonly struct MaxOperator : IAggregationOperator + where T : INumber { public static bool Vectorizable => true; - public static T Invoke(T x, T y) - { - if (typeof(T) == typeof(Half) || typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - return x == y ? - (IsNegative(x) ? y : x) : - (y > x ? y : x); - } - - return T.Max(x, y); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Invoke(T x, T y) => T.Max(x, y); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if !NET9_0_OR_GREATER + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - if (AdvSimd.IsSupported && typeof(T) == typeof(float)) - { - return AdvSimd.Max(x.AsSingle(), y.AsSingle()).As(); - } - - if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) - { - return AdvSimd.Arm64.Max(x.AsDouble(), y.AsDouble()).As(); - } - - return - Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(x), y, x), - Vector128.Max(x, y)); + return Vector128.ConditionalSelect( + (Vector128.Equals(x, y) & IsNegative(y)) | IsNaN(x) | Vector128.LessThan(y, x), + x, + y + ); } +#endif return Vector128.Max(x, y); } @@ -120,13 +106,16 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if !NET9_0_OR_GREATER + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - return - Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(x), y, x), - Vector256.Max(x, y)); + return Vector256.ConditionalSelect( + (Vector256.Equals(x, y) & IsNegative(y)) | ~Vector256.Equals(x, x) | Vector256.LessThan(y, x), + x, + y + ); } +#endif return Vector256.Max(x, y); } @@ -134,13 +123,16 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if !NET9_0_OR_GREATER + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - return - Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(x), y, x), - Vector512.Max(x, y)); + return Vector512.ConditionalSelect( + (Vector512.Equals(x, y) & IsNegative(y)) | ~Vector512.Equals(x, x) | Vector512.LessThan(y, x), + x, + y + ); } +#endif return Vector512.Max(x, y); } @@ -150,84 +142,65 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) public static T Invoke(Vector512 x) => HorizontalAggregate>(x); } - /// Max(x, y) - internal readonly struct MaxPropagateNaNOperator : IBinaryOperator - where T : INumber + /// Gets whether each specified is NaN. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 IsNaN(Vector128 vector) { - public static bool Vectorizable => true; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T Invoke(T x, T y) => T.Max(x, y); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Invoke(Vector128 x, Vector128 y) +#if NET9_0_OR_GREATER + return Vector128.IsNaN(vector); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - if (AdvSimd.IsSupported && typeof(T) == typeof(float)) - { - return AdvSimd.Max(x.AsSingle(), y.AsSingle()).As(); - } - - if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) - { - return AdvSimd.Arm64.Max(x.AsDouble(), y.AsDouble()).As(); - } - - return - Vector128.ConditionalSelect(Vector128.Equals(x, x), - Vector128.ConditionalSelect(Vector128.Equals(y, y), - Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(x), y, x), - Vector128.Max(x, y)), - y), - x); - } - - return Vector128.Max(x, y); + return ~Vector128.Equals(vector, vector); } + return Vector128.Zero; +#endif + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector256 Invoke(Vector256 x, Vector256 y) + /// Gets whether each specified is NaN. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 IsNaN(Vector256 vector) + { +#if NET9_0_OR_GREATER + return Vector256.IsNaN(vector); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - return - Vector256.ConditionalSelect(Vector256.Equals(x, x), - Vector256.ConditionalSelect(Vector256.Equals(y, y), - Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(x), y, x), - Vector256.Max(x, y)), - y), - x); - } - - return Vector256.Max(x, y); + return ~Vector256.Equals(vector, vector); } + return Vector256.Zero; +#endif + } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector512 Invoke(Vector512 x, Vector512 y) + /// Gets whether each specified is NaN. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector512 IsNaN(Vector512 vector) + { +#if NET9_0_OR_GREATER + return Vector512.IsNaN(vector); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - return - Vector512.ConditionalSelect(Vector512.Equals(x, x), - Vector512.ConditionalSelect(Vector512.Equals(y, y), - Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(x), y, x), - Vector512.Max(x, y)), - y), - x); - } - - return Vector512.Max(x, y); + return ~Vector512.Equals(vector, vector); } + return Vector512.Zero; +#endif } +#if !NET9_0_OR_GREATER /// Gets whether each specified is negative. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 IsNegative(Vector128 vector) { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector128.Zero; + } + if (typeof(T) == typeof(float)) { return Vector128.LessThan(vector.AsInt32(), Vector128.Zero).As(); @@ -245,6 +218,15 @@ private static Vector128 IsNegative(Vector128 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 IsNegative(Vector256 vector) { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector256.Zero; + } + if (typeof(T) == typeof(float)) { return Vector256.LessThan(vector.AsInt32(), Vector256.Zero).As(); @@ -262,6 +244,15 @@ private static Vector256 IsNegative(Vector256 vector) [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector512 IsNegative(Vector512 vector) { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector512.Zero; + } + if (typeof(T) == typeof(float)) { return Vector512.LessThan(vector.AsInt32(), Vector512.Zero).As(); @@ -275,6 +266,85 @@ private static Vector512 IsNegative(Vector512 vector) return Vector512.LessThan(vector, Vector512.Zero); } + /// Gets whether each specified is positive. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector128 IsPositive(Vector128 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector128.AllBitsSet; + } + + if (typeof(T) == typeof(float)) + { + return Vector128.GreaterThanOrEqual(vector.AsInt32(), Vector128.Zero).As(); + } + + if (typeof(T) == typeof(double)) + { + return Vector128.GreaterThanOrEqual(vector.AsInt64(), Vector128.Zero).As(); + } + + return Vector128.GreaterThanOrEqual(vector, Vector128.Zero); + } + + /// Gets whether each specified is positive. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector256 IsPositive(Vector256 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector256.AllBitsSet; + } + + if (typeof(T) == typeof(float)) + { + return Vector256.GreaterThanOrEqual(vector.AsInt32(), Vector256.Zero).As(); + } + + if (typeof(T) == typeof(double)) + { + return Vector256.GreaterThanOrEqual(vector.AsInt64(), Vector256.Zero).As(); + } + + return Vector256.GreaterThanOrEqual(vector, Vector256.Zero); + } + + /// Gets whether each specified is positive. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Vector512 IsPositive(Vector512 vector) + { + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector512.AllBitsSet; + } + + if (typeof(T) == typeof(float)) + { + return Vector512.GreaterThanOrEqual(vector.AsInt32(), Vector512.Zero).As(); + } + + if (typeof(T) == typeof(double)) + { + return Vector512.GreaterThanOrEqual(vector.AsInt64(), Vector512.Zero).As(); + } + + return Vector512.GreaterThanOrEqual(vector, Vector512.Zero); + } +#endif + /// /// This is the same as /// with an identity transform, except it early exits on NaN. @@ -306,7 +376,7 @@ private static T MinMaxCore(ReadOnlySpan x) if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { // Check for NaNs - nanMask = ~Vector512.Equals(result, result); + nanMask = IsNaN(result); if (nanMask != Vector512.Zero) { return result.GetElement(IndexOfFirstMatch(nanMask)); @@ -437,7 +507,7 @@ private static T MinMaxCore(ReadOnlySpan x) if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { // Check for NaNs - nanMask = ~Vector128.Equals(result, result); + nanMask = IsNaN(result); if (nanMask != Vector128.Zero) { return result.GetElement(IndexOfFirstMatch(nanMask)); @@ -456,7 +526,7 @@ private static T MinMaxCore(ReadOnlySpan x) if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { // Check for NaNs - nanMask = ~Vector128.Equals(current, current); + nanMask = IsNaN(current); if (nanMask != Vector128.Zero) { return current.GetElement(IndexOfFirstMatch(nanMask)); @@ -475,7 +545,7 @@ private static T MinMaxCore(ReadOnlySpan x) if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) { // Check for NaNs - nanMask = ~Vector128.Equals(current, current); + nanMask = IsNaN(current); if (nanMask != Vector128.Zero) { return current.GetElement(IndexOfFirstMatch(nanMask)); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitude.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitude.cs index eb28249ed1ea43..29a50e32f2ca9e 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitude.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitude.cs @@ -44,7 +44,7 @@ public static T MaxMagnitude(ReadOnlySpan x) /// public static void MaxMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) where T : INumberBase => - InvokeSpanSpanIntoSpan>(x, y, destination); + InvokeSpanSpanIntoSpan>(x, y, destination); /// Computes the element-wise number with the largest magnitude in the specified tensors. /// The first tensor, represented as a span. @@ -61,27 +61,9 @@ public static void MaxMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span /// public static void MaxMagnitude(ReadOnlySpan x, T y, Span destination) where T : INumberBase => - InvokeSpanScalarIntoSpan>(x, y, destination); + InvokeSpanScalarIntoSpan>(x, y, destination); - /// Searches for the smallest number in the specified tensor. - /// The tensor, represented as a span. - /// The minimum element in . - /// Length of must be greater than zero. - /// - /// - /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any value is equal to - /// is present, the first is returned. Negative 0 is considered smaller than positive 0. - /// - /// - /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different - /// operating systems or architectures. - /// - /// - public static T Min(ReadOnlySpan x) - where T : INumber => - MinMaxCore>(x); - - /// Operator to get x or y based on which has the larger MathF.Abs (but NaNs may not be propagated) + /// Operator to get x or y based on which has the larger MathF.Abs internal readonly struct MaxMagnitudeOperator : IAggregationOperator where T : INumberBase { @@ -93,151 +75,69 @@ public static T Min(ReadOnlySpan x) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - Vector128 xMag = Vector128.Abs(x), yMag = Vector128.Abs(y); - - Vector128 result = - Vector128.ConditionalSelect(Vector128.Equals(xMag, yMag), - Vector128.ConditionalSelect(IsNegative(x), y, x), - Vector128.ConditionalSelect(Vector128.GreaterThan(xMag, yMag), x, y)); - - // Handle minimum signed value that should have the largest magnitude - if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(short) || typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(nint)) +#if NET9_0_OR_GREATER + return Vector128.MaxMagnitude(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector128 negativeMagnitudeX = Vector128.LessThan(xMag, Vector128.Zero); - Vector128 negativeMagnitudeY = Vector128.LessThan(yMag, Vector128.Zero); - result = Vector128.ConditionalSelect(negativeMagnitudeX, + Vector128 xMag = Vector128.Abs(x); + Vector128 yMag = Vector128.Abs(y); + return Vector128.ConditionalSelect( + Vector128.GreaterThan(xMag, yMag) | IsNaN(xMag) | (Vector128.Equals(xMag, yMag) & IsPositive(x)), x, - Vector128.ConditionalSelect(negativeMagnitudeY, - y, - result)); + y + ); } - return result; + return MaxMagnitudeNumberOperator.Invoke(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y) { - Vector256 xMag = Vector256.Abs(x), yMag = Vector256.Abs(y); - - Vector256 result = - Vector256.ConditionalSelect(Vector256.Equals(xMag, yMag), - Vector256.ConditionalSelect(IsNegative(x), y, x), - Vector256.ConditionalSelect(Vector256.GreaterThan(xMag, yMag), x, y)); - - // Handle minimum signed value that should have the largest magnitude - if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(short) || typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(nint)) +#if NET9_0_OR_GREATER + return Vector256.MaxMagnitude(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector256 negativeMagnitudeX = Vector256.LessThan(xMag, Vector256.Zero); - Vector256 negativeMagnitudeY = Vector256.LessThan(yMag, Vector256.Zero); - result = Vector256.ConditionalSelect(negativeMagnitudeX, + Vector256 xMag = Vector256.Abs(x); + Vector256 yMag = Vector256.Abs(y); + return Vector256.ConditionalSelect( + Vector256.GreaterThan(xMag, yMag) | IsNaN(xMag) | (Vector256.Equals(xMag, yMag) & IsPositive(x)), x, - Vector256.ConditionalSelect(negativeMagnitudeY, - y, - result)); + y + ); } - return result; + return MaxMagnitudeNumberOperator.Invoke(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y) { - Vector512 xMag = Vector512.Abs(x), yMag = Vector512.Abs(y); - - Vector512 result = - Vector512.ConditionalSelect(Vector512.Equals(xMag, yMag), - Vector512.ConditionalSelect(IsNegative(x), y, x), - Vector512.ConditionalSelect(Vector512.GreaterThan(xMag, yMag), x, y)); - - // Handle minimum signed value that should have the largest magnitude - if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(short) || typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(nint)) +#if NET9_0_OR_GREATER + return Vector512.MaxMagnitude(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector512 negativeMagnitudeX = Vector512.LessThan(xMag, Vector512.Zero); - Vector512 negativeMagnitudeY = Vector512.LessThan(yMag, Vector512.Zero); - result = Vector512.ConditionalSelect(negativeMagnitudeX, + Vector512 xMag = Vector512.Abs(x); + Vector512 yMag = Vector512.Abs(y); + return Vector512.ConditionalSelect( + Vector512.GreaterThan(xMag, yMag) | IsNaN(xMag) | (Vector512.Equals(xMag, yMag) & IsPositive(x)), x, - Vector512.ConditionalSelect(negativeMagnitudeY, - y, - result)); + y + ); } - return result; + return MaxMagnitudeNumberOperator.Invoke(x, y); +#endif } public static T Invoke(Vector128 x) => HorizontalAggregate>(x); public static T Invoke(Vector256 x) => HorizontalAggregate>(x); public static T Invoke(Vector512 x) => HorizontalAggregate>(x); } - - /// Operator to get x or y based on which has the larger MathF.Abs - internal readonly struct MaxMagnitudePropagateNaNOperator : IBinaryOperator - where T : INumberBase - { - public static bool Vectorizable => true; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T Invoke(T x, T y) => T.MaxMagnitude(x, y); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Invoke(Vector128 x, Vector128 y) - { - // Handle NaNs - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - Vector128 xMag = Vector128.Abs(x), yMag = Vector128.Abs(y); - return - Vector128.ConditionalSelect(Vector128.Equals(x, x), - Vector128.ConditionalSelect(Vector128.Equals(y, y), - Vector128.ConditionalSelect(Vector128.Equals(yMag, xMag), - Vector128.ConditionalSelect(IsNegative(x), y, x), - Vector128.ConditionalSelect(Vector128.GreaterThan(yMag, xMag), y, x)), - y), - x); - } - - return MaxMagnitudeOperator.Invoke(x, y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector256 Invoke(Vector256 x, Vector256 y) - { - // Handle NaNs - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - Vector256 xMag = Vector256.Abs(x), yMag = Vector256.Abs(y); - return - Vector256.ConditionalSelect(Vector256.Equals(x, x), - Vector256.ConditionalSelect(Vector256.Equals(y, y), - Vector256.ConditionalSelect(Vector256.Equals(xMag, yMag), - Vector256.ConditionalSelect(IsNegative(x), y, x), - Vector256.ConditionalSelect(Vector256.GreaterThan(xMag, yMag), x, y)), - y), - x); - } - - return MaxMagnitudeOperator.Invoke(x, y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector512 Invoke(Vector512 x, Vector512 y) - { - // Handle NaNs - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - Vector512 xMag = Vector512.Abs(x), yMag = Vector512.Abs(y); - return - Vector512.ConditionalSelect(Vector512.Equals(x, x), - Vector512.ConditionalSelect(Vector512.Equals(y, y), - Vector512.ConditionalSelect(Vector512.Equals(xMag, yMag), - Vector512.ConditionalSelect(IsNegative(x), y, x), - Vector512.ConditionalSelect(Vector512.GreaterThan(xMag, yMag), x, y)), - y), - x); - } - - return MaxMagnitudeOperator.Invoke(x, y); - } - } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs new file mode 100644 index 00000000000000..0e9c91613ad7ef --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs @@ -0,0 +1,152 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +namespace System.Numerics.Tensors +{ + public static partial class TensorPrimitives + { + /// Operator to get x or y based on which has the larger MathF.Abs + internal readonly struct MaxMagnitudeNumberOperator : IAggregationOperator + where T : INumberBase + { + public static bool Vectorizable => true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Invoke(T x, T y) => T.MaxMagnitudeNumber(x, y); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Invoke(Vector128 x, Vector128 y) + { +#if NET9_0_OR_GREATER + return Vector128.MaxMagnitudeNumber(x, y); +#else + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector128.Max(x, y); + } + + Vector128 xMag = Vector128.Abs(x); + Vector128 yMag = Vector128.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) + ) + { + return Vector128.ConditionalSelect( + Vector128.GreaterThan(xMag, yMag) | IsNaN(yMag) | (Vector128.Equals(xMag, yMag) & IsPositive(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return Vector128.ConditionalSelect( + (Vector128.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + x, + y + ); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Invoke(Vector256 x, Vector256 y) + { +#if NET9_0_OR_GREATER + return Vector256.MaxMagnitudeNumber(x, y); +#else + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector256.Max(x, y); + } + + Vector256 xMag = Vector256.Abs(x); + Vector256 yMag = Vector256.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) + ) + { + return Vector256.ConditionalSelect( + Vector256.GreaterThan(xMag, yMag) | IsNaN(yMag) | (Vector256.Equals(xMag, yMag) & IsPositive(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return Vector256.ConditionalSelect( + (Vector256.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + x, + y + ); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Invoke(Vector512 x, Vector512 y) + { +#if NET9_0_OR_GREATER + return Vector512.MaxMagnitudeNumber(x, y); +#else + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector512.Max(x, y); + } + + Vector512 xMag = Vector512.Abs(x); + Vector512 yMag = Vector512.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) + ) + { + return Vector512.ConditionalSelect( + Vector512.GreaterThan(xMag, yMag) | IsNaN(yMag) | (Vector512.Equals(xMag, yMag) & IsPositive(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return Vector512.ConditionalSelect( + (Vector512.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + x, + y + ); +#endif + } + + public static T Invoke(Vector128 x) => HorizontalAggregate>(x); + public static T Invoke(Vector256 x) => HorizontalAggregate>(x); + public static T Invoke(Vector512 x) => HorizontalAggregate>(x); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs index dc0019ce66016f..52df9ea1f1b5c2 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs @@ -86,93 +86,58 @@ public static void MaxNumber(ReadOnlySpan x, T y, Span destination) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if NET9_0_OR_GREATER + return Vector128.MaxNumber(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - // We can't use AdvSimd.MaxNumber here because it doesn't correctly - // handle sNaN (it converts it to qNaN as per the now deprecated - // maxNum function defined by IEEE 754:2008, but which is not inline - // with the maximumNumber function that replaces it in IEEE 754:2019) - - Vector128 max; - - if (Sse.IsSupported && typeof(T) == typeof(float)) - { - max = Sse.Max(x.AsSingle(), y.AsSingle()).As(); - } - else if (Sse2.IsSupported && typeof(T) == typeof(double)) - { - max = Sse2.Max(x.AsDouble(), y.AsDouble()).As(); - } - else - { - max = Vector128.ConditionalSelect(Vector128.LessThan(y, x), x, y); - } - - return - Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(y), x, y), - Vector128.ConditionalSelect(Vector128.Equals(y, y), max, x)); + return Vector128.ConditionalSelect( + (Vector128.Equals(x, y) & IsNegative(y)) | IsNaN(y) | Vector128.LessThan(y, x), + x, + y + ); } return Vector128.Max(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if NET9_0_OR_GREATER + return Vector256.MaxNumber(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector256 max; - - if (Avx.IsSupported && typeof(T) == typeof(float)) - { - max = Avx.Max(x.AsSingle(), y.AsSingle()).As(); - } - else if (Avx.IsSupported && typeof(T) == typeof(double)) - { - max = Avx.Max(x.AsDouble(), y.AsDouble()).As(); - } - else - { - max = Vector256.ConditionalSelect(Vector256.LessThan(y, x), x, y); - } - - return - Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(y), x, y), - Vector256.ConditionalSelect(Vector256.Equals(y, y), max, x)); + return Vector256.ConditionalSelect( + (Vector256.Equals(x, y) & IsNegative(y)) | IsNaN(y) | Vector256.LessThan(y, x), + x, + y + ); } return Vector256.Max(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if NET9_0_OR_GREATER + return Vector512.MaxNumber(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector512 max; - - if (Avx512F.IsSupported && typeof(T) == typeof(float)) - { - max = Avx512F.Max(x.AsSingle(), y.AsSingle()).As(); - } - else if (Avx512F.IsSupported && typeof(T) == typeof(double)) - { - max = Avx512F.Max(x.AsDouble(), y.AsDouble()).As(); - } - else - { - max = Vector512.ConditionalSelect(Vector512.LessThan(y, x), x, y); - } - - return - Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(y), x, y), - Vector512.ConditionalSelect(Vector512.Equals(y, y), max, x)); + return Vector512.ConditionalSelect( + (Vector512.Equals(x, y) & IsNegative(y)) | IsNaN(y) | Vector512.LessThan(y, x), + x, + y + ); } return Vector512.Max(x, y); +#endif } public static T Invoke(Vector128 x) => HorizontalAggregate>(x); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs index fd3931fa3d194e..2159d81b3f49fc 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs @@ -9,6 +9,24 @@ namespace System.Numerics.Tensors { public static partial class TensorPrimitives { + /// Searches for the smallest number in the specified tensor. + /// The tensor, represented as a span. + /// The minimum element in . + /// Length of must be greater than zero. + /// + /// + /// The determination of the minimum element matches the IEEE 754:2019 `minimum` function. If any value is equal to + /// is present, the first is returned. Negative 0 is considered smaller than positive 0. + /// + /// + /// This method may call into the underlying C runtime or employ instructions specific to the current architecture. Exact results may differ between different + /// operating systems or architectures. + /// + /// + public static T Min(ReadOnlySpan x) + where T : INumber => + MinMaxCore>(x); + /// Computes the element-wise minimum of the numbers in the specified tensors. /// The first tensor, represented as a span. /// The second tensor, represented as a span. @@ -32,7 +50,7 @@ public static partial class TensorPrimitives /// public static void Min(ReadOnlySpan x, ReadOnlySpan y, Span destination) where T : INumber => - InvokeSpanSpanIntoSpan>(x, y, destination); + InvokeSpanSpanIntoSpan>(x, y, destination); /// Computes the element-wise minimum of the numbers in the specified tensors. /// The first tensor, represented as a span. @@ -55,47 +73,30 @@ public static void Min(ReadOnlySpan x, ReadOnlySpan y, Span destinat /// public static void Min(ReadOnlySpan x, T y, Span destination) where T : INumber => - InvokeSpanScalarIntoSpan>(x, y, destination); + InvokeSpanScalarIntoSpan>(x, y, destination); - /// T.Min(x, y) (but NaNs may not be propagated) + /// T.Min(x, y) internal readonly struct MinOperator : IAggregationOperator where T : INumber { public static bool Vectorizable => true; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T Invoke(T x, T y) - { - if (typeof(T) == typeof(Half) || typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - return x == y ? - (IsNegative(y) ? y : x) : - (y < x ? y : x); - } - - return T.Min(x, y); - } + public static T Invoke(T x, T y) => T.Min(x, y); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if !NET9_0_OR_GREATER + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - if (AdvSimd.IsSupported && typeof(T) == typeof(float)) - { - return AdvSimd.Min(x.AsSingle(), y.AsSingle()).As(); - } - - if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) - { - return AdvSimd.Arm64.Min(x.AsDouble(), y.AsDouble()).As(); - } - - return - Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(y), y, x), - Vector128.Min(x, y)); + return Vector128.ConditionalSelect( + (Vector128.Equals(x, y) & Vector128.IsNegative(x)) | Vector128.IsNaN(x) | Vector128.LessThan(x, y), + x, + y + ); } +#endif return Vector128.Min(x, y); } @@ -103,12 +104,16 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if !NET9_0_OR_GREATER + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - return Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(y), y, x), - Vector256.Min(x, y)); + return Vector256.ConditionalSelect( + (Vector256.Equals(x, y) & Vector256.IsNegative(x)) | Vector256.IsNaN(x) | Vector256.LessThan(x, y), + x, + y + ); } +#endif return Vector256.Min(x, y); } @@ -116,12 +121,16 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if !NET9_0_OR_GREATER + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - return Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(y), y, x), - Vector512.Min(x, y)); + return Vector512.ConditionalSelect( + (Vector512.Equals(x, y) & Vector512.IsNegative(x)) | Vector512.IsNaN(x) | Vector512.LessThan(x, y), + x, + y + ); } +#endif return Vector512.Min(x, y); } @@ -130,79 +139,5 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) public static T Invoke(Vector256 x) => HorizontalAggregate>(x); public static T Invoke(Vector512 x) => HorizontalAggregate>(x); } - - /// T.Min(x, y) - internal readonly struct MinPropagateNaNOperator : IBinaryOperator - where T : INumber - { - public static bool Vectorizable => true; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T Invoke(T x, T y) => T.Min(x, y); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Invoke(Vector128 x, Vector128 y) - { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - if (AdvSimd.IsSupported && typeof(T) == typeof(float)) - { - return AdvSimd.Min(x.AsSingle(), y.AsSingle()).As(); - } - - if (AdvSimd.Arm64.IsSupported && typeof(T) == typeof(double)) - { - return AdvSimd.Arm64.Min(x.AsDouble(), y.AsDouble()).As(); - } - - return - Vector128.ConditionalSelect(Vector128.Equals(x, x), - Vector128.ConditionalSelect(Vector128.Equals(y, y), - Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(x), x, y), - Vector128.Min(x, y)), - y), - x); - } - - return Vector128.Min(x, y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector256 Invoke(Vector256 x, Vector256 y) - { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - return - Vector256.ConditionalSelect(Vector256.Equals(x, x), - Vector256.ConditionalSelect(Vector256.Equals(y, y), - Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(x), x, y), - Vector256.Min(x, y)), - y), - x); - } - - return Vector256.Min(x, y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector512 Invoke(Vector512 x, Vector512 y) - { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - return - Vector512.ConditionalSelect(Vector512.Equals(x, x), - Vector512.ConditionalSelect(Vector512.Equals(y, y), - Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(x), x, y), - Vector512.Min(x, y)), - y), - x); - } - - return Vector512.Min(x, y); - } - } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs index 47b492eaffb8a4..8b4cae6ee22c2d 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs @@ -49,7 +49,7 @@ public static T MinMagnitude(ReadOnlySpan x) /// public static void MinMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) where T : INumberBase => - InvokeSpanSpanIntoSpan>(x, y, destination); + InvokeSpanSpanIntoSpan>(x, y, destination); /// Computes the element-wise number with the smallest magnitude in the specified tensors. /// The first tensor, represented as a span. @@ -71,9 +71,9 @@ public static void MinMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span /// public static void MinMagnitude(ReadOnlySpan x, T y, Span destination) where T : INumberBase => - InvokeSpanScalarIntoSpan>(x, y, destination); + InvokeSpanScalarIntoSpan>(x, y, destination); - /// Operator to get x or y based on which has the smaller MathF.Abs (but NaNs may not be propagated) + /// Operator to get x or y based on which has the smaller MathF.Abs internal readonly struct MinMagnitudeOperator : IAggregationOperator where T : INumberBase { @@ -85,148 +85,72 @@ public static void MinMagnitude(ReadOnlySpan x, T y, Span destination) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - Vector128 xMag = Vector128.Abs(x), yMag = Vector128.Abs(y); - - Vector128 result = - Vector128.ConditionalSelect(Vector128.Equals(yMag, xMag), - Vector128.ConditionalSelect(IsNegative(y), y, x), - Vector128.ConditionalSelect(Vector128.LessThan(yMag, xMag), y, x)); +#if NET9_0_OR_GREATER + return Vector128.MinMagnitude(x, y); +#else - if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(short) || typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(nint)) + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector128 negativeMagnitudeX = Vector128.LessThan(xMag, Vector128.Zero); - Vector128 negativeMagnitudeY = Vector128.LessThan(yMag, Vector128.Zero); - result = Vector128.ConditionalSelect(negativeMagnitudeX, - y, - Vector128.ConditionalSelect(negativeMagnitudeY, - x, - result)); + Vector128 xMag = Vector128.Abs(x); + Vector128 yMag = Vector128.Abs(y); + + return Vector128.ConditionalSelect( + Vector128.LessThan(xMag, yMag) | IsNaN(xMag) | (Vector128.Equals(xMag, yMag) & IsNegative(x)), + x, + y + ); } - - return result; + return MinMagnitudeOperator.Invoke(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y) { - Vector256 xMag = Vector256.Abs(x), yMag = Vector256.Abs(y); - - Vector256 result = - Vector256.ConditionalSelect(Vector256.Equals(yMag, xMag), - Vector256.ConditionalSelect(IsNegative(y), y, x), - Vector256.ConditionalSelect(Vector256.LessThan(yMag, xMag), y, x)); +#if NET9_0_OR_GREATER + return Vector256.MinMagnitude(x, y); +#else - if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(short) || typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(nint)) + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector256 negativeMagnitudeX = Vector256.LessThan(xMag, Vector256.Zero); - Vector256 negativeMagnitudeY = Vector256.LessThan(yMag, Vector256.Zero); - result = Vector256.ConditionalSelect(negativeMagnitudeX, - y, - Vector256.ConditionalSelect(negativeMagnitudeY, - x, - result)); + Vector256 xMag = Vector256.Abs(x); + Vector256 yMag = Vector256.Abs(y); + + return Vector256.ConditionalSelect( + Vector256.LessThan(xMag, yMag) | IsNaN(xMag) | (Vector256.Equals(xMag, yMag) & IsNegative(x)), + x, + y + ); } - - return result; + return MinMagnitudeOperator.Invoke(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y) { - Vector512 xMag = Vector512.Abs(x), yMag = Vector512.Abs(y); - - Vector512 result = - Vector512.ConditionalSelect(Vector512.Equals(yMag, xMag), - Vector512.ConditionalSelect(IsNegative(y), y, x), - Vector512.ConditionalSelect(Vector512.LessThan(yMag, xMag), y, x)); +#if NET9_0_OR_GREATER + return Vector512.MinMagnitude(x, y); +#else - if (typeof(T) == typeof(sbyte) || typeof(T) == typeof(short) || typeof(T) == typeof(int) || typeof(T) == typeof(long) || typeof(T) == typeof(nint)) + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector512 negativeMagnitudeX = Vector512.LessThan(xMag, Vector512.Zero); - Vector512 negativeMagnitudeY = Vector512.LessThan(yMag, Vector512.Zero); - result = Vector512.ConditionalSelect(negativeMagnitudeX, - y, - Vector512.ConditionalSelect(negativeMagnitudeY, - x, - result)); + Vector512 xMag = Vector512.Abs(x); + Vector512 yMag = Vector512.Abs(y); + + return Vector512.ConditionalSelect( + Vector512.LessThan(xMag, yMag) | IsNaN(xMag) | (Vector512.Equals(xMag, yMag) & IsNegative(x)), + x, + y + ); } - - return result; + return MinMagnitudeOperator.Invoke(x, y); +#endif } public static T Invoke(Vector128 x) => HorizontalAggregate>(x); public static T Invoke(Vector256 x) => HorizontalAggregate>(x); public static T Invoke(Vector512 x) => HorizontalAggregate>(x); } - - /// Operator to get x or y based on which has the smaller MathF.Abs - internal readonly struct MinMagnitudePropagateNaNOperator : IBinaryOperator - where T : INumberBase - { - public static bool Vectorizable => true; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static T Invoke(T x, T y) => T.MinMagnitude(x, y); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector128 Invoke(Vector128 x, Vector128 y) - { - // Handle NaNs - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - Vector128 xMag = Vector128.Abs(x), yMag = Vector128.Abs(y); - return - Vector128.ConditionalSelect(Vector128.Equals(x, x), - Vector128.ConditionalSelect(Vector128.Equals(y, y), - Vector128.ConditionalSelect(Vector128.Equals(yMag, xMag), - Vector128.ConditionalSelect(IsNegative(x), x, y), - Vector128.ConditionalSelect(Vector128.LessThan(xMag, yMag), x, y)), - y), - x); - } - - return MinMagnitudeOperator.Invoke(x, y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector256 Invoke(Vector256 x, Vector256 y) - { - // Handle NaNs - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - Vector256 xMag = Vector256.Abs(x), yMag = Vector256.Abs(y); - return - Vector256.ConditionalSelect(Vector256.Equals(x, x), - Vector256.ConditionalSelect(Vector256.Equals(y, y), - Vector256.ConditionalSelect(Vector256.Equals(yMag, xMag), - Vector256.ConditionalSelect(IsNegative(x), x, y), - Vector256.ConditionalSelect(Vector256.LessThan(xMag, yMag), x, y)), - y), - x); - } - - return MinMagnitudeOperator.Invoke(x, y); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector512 Invoke(Vector512 x, Vector512 y) - { - // Handle NaNs - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) - { - Vector512 xMag = Vector512.Abs(x), yMag = Vector512.Abs(y); - return - Vector512.ConditionalSelect(Vector512.Equals(x, x), - Vector512.ConditionalSelect(Vector512.Equals(y, y), - Vector512.ConditionalSelect(Vector512.Equals(yMag, xMag), - Vector512.ConditionalSelect(IsNegative(x), x, y), - Vector512.ConditionalSelect(Vector512.LessThan(xMag, yMag), x, y)), - y), - x); - } - - return MinMagnitudeOperator.Invoke(x, y); - } - } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs new file mode 100644 index 00000000000000..b9ab89b52743c4 --- /dev/null +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +namespace System.Numerics.Tensors +{ + public static partial class TensorPrimitives + { + /// Operator to get x or y based on which has the smaller MathF.Abs + internal readonly struct MinMagnitudeNumberOperator : IAggregationOperator + where T : INumberBase + { + public static bool Vectorizable => true; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static T Invoke(T x, T y) => T.MinMagnitudeNumber(x, y); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 Invoke(Vector128 x, Vector128 y) + { +#if NET9_0_OR_GREATER + return Vector128.MinMagnitudeNumber(x, y); +#else + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector128.Min(x, y); + } + + Vector128 xMag = Vector128.Abs(x); + Vector128 yMag = Vector128.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) + { + return Vector128.ConditionalSelect( + Vector128.LessThan(xMag, yMag) | IsNaN(yMag) | (Vector128.Equals(xMag, yMag) & IsNegative(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return Vector128.ConditionalSelect( + (Vector128.LessThan(xMag, yMag) & IsPositive(xMag)) | IsNegative(yMag), + x, + y + ); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 Invoke(Vector256 x, Vector256 y) + { +#if NET9_0_OR_GREATER + return Vector256.MinMagnitudeNumber(x, y); +#else + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector256.ConditionalSelect(Vector256.LessThan(y, x), x, y); + } + + Vector256 xMag = Vector256.Abs(x); + Vector256 yMag = Vector256.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) + ) + { + return Vector256.ConditionalSelect( + Vector256.GreaterThan(xMag, yMag) | IsNaN(yMag) | (Vector256.Equals(xMag, yMag) & IsPositive(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return Vector256.ConditionalSelect( + (Vector256.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + x, + y + ); +#endif + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Invoke(Vector512 x, Vector512 y) + { +#if NET9_0_OR_GREATER + return Vector512.MinMagnitudeNumber(x, y); +#else + if ((typeof(T) == typeof(byte)) + || (typeof(T) == typeof(ushort)) + || (typeof(T) == typeof(uint)) + || (typeof(T) == typeof(ulong)) + || (typeof(T) == typeof(nuint))) + { + return Vector512.ConditionalSelect(Vector512.LessThan(y, x), x, y); + } + + Vector512 xMag = Vector512.Abs(x); + Vector512 yMag = Vector512.Abs(y); + + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) + ) + { + return Vector512.ConditionalSelect( + Vector512.GreaterThan(xMag, yMag) | IsNaN(yMag) | (Vector512.Equals(xMag, yMag) & IsPositive(x)), + x, + y + ); + } + + Debug.Assert((typeof(T) == typeof(sbyte)) + || (typeof(T) == typeof(short)) + || (typeof(T) == typeof(int)) + || (typeof(T) == typeof(long)) + || (typeof(T) == typeof(nint))); + + return Vector512.ConditionalSelect( + (Vector512.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + x, + y + ); +#endif + } + + public static T Invoke(Vector128 x) => HorizontalAggregate>(x); + public static T Invoke(Vector256 x) => HorizontalAggregate>(x); + public static T Invoke(Vector512 x) => HorizontalAggregate>(x); + } + } +} diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinNumber.cs index 79e04bf6d747d6..653e8c7383eae6 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinNumber.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinNumber.cs @@ -86,93 +86,58 @@ public static void MinNumber(ReadOnlySpan x, T y, Span destination) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Invoke(Vector128 x, Vector128 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if NET9_0_OR_GREATER + return Vector128.MinNumber(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - // We can't use AdvSimd.MinNumber here because it doesn't correctly - // handle sNaN (it converts it to qNaN as per the now deprecated - // minNum function defined by IEEE 754:2008, but which is not inline - // with the minimumNumber function that replaces it in IEEE 754:2019) - - Vector128 min; - - if (Sse.IsSupported && typeof(T) == typeof(float)) - { - min = Sse.Min(x.AsSingle(), y.AsSingle()).As(); - } - else if (Sse2.IsSupported && typeof(T) == typeof(double)) - { - min = Sse2.Min(x.AsDouble(), y.AsDouble()).As(); - } - else - { - min = Vector128.ConditionalSelect(Vector128.LessThan(x, y), x, y); - } - - return - Vector128.ConditionalSelect(Vector128.Equals(x, y), - Vector128.ConditionalSelect(IsNegative(x), x, y), - Vector128.ConditionalSelect(Vector128.Equals(y, y), min, x)); + return Vector128.ConditionalSelect( + (Vector128.Equals(x, y) & IsNegative(x)) | IsNaN(y) | Vector128.LessThan(x, y), + x, + y + ); } return Vector128.Min(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Invoke(Vector256 x, Vector256 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if NET9_0_OR_GREATER + return Vector256.MinNumber(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector256 min; - - if (Avx.IsSupported && typeof(T) == typeof(float)) - { - min = Avx.Min(x.AsSingle(), y.AsSingle()).As(); - } - else if (Avx.IsSupported && typeof(T) == typeof(double)) - { - min = Avx.Min(x.AsDouble(), y.AsDouble()).As(); - } - else - { - min = Vector256.ConditionalSelect(Vector256.LessThan(x, y), x, y); - } - - return - Vector256.ConditionalSelect(Vector256.Equals(x, y), - Vector256.ConditionalSelect(IsNegative(x), x, y), - Vector256.ConditionalSelect(Vector256.Equals(y, y), min, x)); + return Vector256.ConditionalSelect( + (Vector256.Equals(x, y) & IsNegative(x)) | IsNaN(y) | Vector256.LessThan(x, y), + x, + y + ); } return Vector256.Min(x, y); +#endif } [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector512 Invoke(Vector512 x, Vector512 y) { - if (typeof(T) == typeof(float) || typeof(T) == typeof(double)) +#if NET9_0_OR_GREATER + return Vector512.MinNumber(x, y); +#else + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { - Vector512 min; - - if (Avx512F.IsSupported && typeof(T) == typeof(float)) - { - min = Avx512F.Min(x.AsSingle(), y.AsSingle()).As(); - } - else if (Avx512F.IsSupported && typeof(T) == typeof(double)) - { - min = Avx512F.Min(x.AsDouble(), y.AsDouble()).As(); - } - else - { - min = Vector512.ConditionalSelect(Vector512.LessThan(x, y), x, y); - } - - return - Vector512.ConditionalSelect(Vector512.Equals(x, y), - Vector512.ConditionalSelect(IsNegative(x), x, y), - Vector512.ConditionalSelect(Vector512.Equals(y, y), min, x)); + return Vector512.ConditionalSelect( + (Vector512.Equals(x, y) & IsNegative(x)) | IsNaN(y) | Vector512.LessThan(x, y), + x, + y + ); } return Vector512.Min(x, y); +#endif } public static T Invoke(Vector128 x) => HorizontalAggregate>(x); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RadiansToDegrees.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RadiansToDegrees.cs index 53298f5cf3c0e5..077934dd1099ba 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RadiansToDegrees.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.RadiansToDegrees.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. +using System.Diagnostics; using System.Runtime.Intrinsics; namespace System.Numerics.Tensors @@ -25,10 +26,59 @@ public static void RadiansToDegrees(ReadOnlySpan x, Span destination) private readonly struct RadiansToDegreesOperator : IUnaryOperator where T : ITrigonometricFunctions { public static bool Vectorizable => true; + public static T Invoke(T x) => T.RadiansToDegrees(x); - public static Vector128 Invoke(Vector128 x) => (x * T.CreateChecked(180)) / T.Pi; - public static Vector256 Invoke(Vector256 x) => (x * T.CreateChecked(180)) / T.Pi; - public static Vector512 Invoke(Vector512 x) => (x * T.CreateChecked(180)) / T.Pi; + + public static Vector128 Invoke(Vector128 x) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.RadiansToDegrees(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.RadiansToDegrees(x.AsSingle()).As(); + } +#else + return (x * T.CreateChecked(180)) / T.Pi; +#endif + } + + public static Vector256 Invoke(Vector256 x) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.RadiansToDegrees(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.RadiansToDegrees(x.AsSingle()).As(); + } +#else + return (x * T.CreateChecked(180)) / T.Pi; +#endif + } + + public static Vector512 Invoke(Vector512 x) + { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.RadiansToDegrees(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.RadiansToDegrees(x.AsSingle()).As(); + } +#else + return (x * T.CreateChecked(180)) / T.Pi; +#endif + } } } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs index 83cd73d184435f..439b5dbfdcfb11 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs @@ -176,23 +176,59 @@ public static void Round(ReadOnlySpan x, int digits, MidpointRounding mode public static Vector128 Invoke(Vector128 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.Round(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.Round(x.AsSingle()).As(); + } +#else Vector128 boundary = Vector128.Create(typeof(T) == typeof(float) ? T.CreateTruncating(SingleBoundary) : T.CreateTruncating(DoubleBoundary)); Vector128 temp = CopySignOperator.Invoke(boundary, x); return Vector128.ConditionalSelect(Vector128.GreaterThan(Vector128.Abs(x), boundary), x, CopySignOperator.Invoke((x + temp) - temp, x)); +#endif } public static Vector256 Invoke(Vector256 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.Round(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.Round(x.AsSingle()).As(); + } +#else Vector256 boundary = Vector256.Create(typeof(T) == typeof(float) ? T.CreateTruncating(SingleBoundary) : T.CreateTruncating(DoubleBoundary)); Vector256 temp = CopySignOperator.Invoke(boundary, x); return Vector256.ConditionalSelect(Vector256.GreaterThan(Vector256.Abs(x), boundary), x, CopySignOperator.Invoke((x + temp) - temp, x)); +#endif } public static Vector512 Invoke(Vector512 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.Round(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.Round(x.AsSingle()).As(); + } +#else Vector512 boundary = Vector512.Create(typeof(T) == typeof(float) ? T.CreateTruncating(SingleBoundary) : T.CreateTruncating(DoubleBoundary)); Vector512 temp = CopySignOperator.Invoke(boundary, x); return Vector512.ConditionalSelect(Vector512.GreaterThan(Vector512.Abs(x), boundary), x, CopySignOperator.Invoke((x + temp) - temp, x)); +#endif } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs index b1f6309e6dbca7..67d09e0ce4a181 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs @@ -21,13 +21,13 @@ global using LogOperator_Single = System.Numerics.Tensors.TensorPrimitives.LogOperator; global using Log2Operator_Single = System.Numerics.Tensors.TensorPrimitives.Log2Operator; global using MaxOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxOperator; -global using MaxPropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxPropagateNaNOperator; +global using MaxPropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxOperator; global using MaxMagnitudeOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxMagnitudeOperator; -global using MaxMagnitudePropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxMagnitudePropagateNaNOperator; +global using MaxMagnitudePropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxMagnitudeOperator; global using MinOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinOperator; -global using MinPropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinPropagateNaNOperator; +global using MinPropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinOperator; global using MinMagnitudeOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinMagnitudeOperator; -global using MinMagnitudePropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinMagnitudePropagateNaNOperator; +global using MinMagnitudePropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinMagnitudeOperator; global using MultiplyAddOperator_Single = System.Numerics.Tensors.TensorPrimitives.MultiplyAddOperator; global using NegateOperator_Single = System.Numerics.Tensors.TensorPrimitives.NegateOperator; global using IdentityOperator_Single = System.Numerics.Tensors.TensorPrimitives.IdentityOperator; diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Truncate.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Truncate.cs index 3a2e3cea290afb..f50c9b6e20d856 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Truncate.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Truncate.cs @@ -32,6 +32,17 @@ public static void Truncate(ReadOnlySpan x, Span destination) public static Vector128 Invoke(Vector128 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector128.Truncate(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector128.Truncate(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { if (Sse41.IsSupported) return Sse41.RoundToZero(x.AsSingle()).As(); @@ -52,10 +63,22 @@ public static Vector128 Invoke(Vector128 x) Vector128.Floor(x.AsDouble()).As(), Vector128.Ceiling(x.AsDouble()).As()); } +#endif } public static Vector256 Invoke(Vector256 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector256.Truncate(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector256.Truncate(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { if (Avx.IsSupported) return Avx.RoundToZero(x.AsSingle()).As(); @@ -74,10 +97,22 @@ public static Vector256 Invoke(Vector256 x) Vector256.Floor(x.AsDouble()).As(), Vector256.Ceiling(x.AsDouble()).As()); } +#endif } public static Vector512 Invoke(Vector512 x) { +#if NET9_0_OR_GREATER + if (typeof(T) == typeof(double)) + { + return Vector512.Truncate(x.AsDouble()).As(); + } + else + { + Debug.Assert(typeof(T) == typeof(float)); + return Vector512.Truncate(x.AsSingle()).As(); + } +#else if (typeof(T) == typeof(float)) { if (Avx512F.IsSupported) return Avx512F.RoundScale(x.AsSingle(), 0b11).As(); @@ -96,6 +131,7 @@ public static Vector512 Invoke(Vector512 x) Vector512.Floor(x.AsDouble()).As(), Vector512.Ceiling(x.AsDouble()).As()); } +#endif } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index 21994c9610f5eb..4b45e834627bc9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -1156,7 +1156,7 @@ public static TVector MaxMagnitudeNumber(TVector x, TVector y) || (typeof(T) == typeof(ulong)) || (typeof(T) == typeof(nuint))) { - return TVector.ConditionalSelect(TVector.LessThan(y, x), x, y); + return TVector.Max(x, y); } TVector xMag = TVector.Abs(x); @@ -1198,7 +1198,7 @@ public static TVector MaxNumber(TVector x, TVector y) ); } - return TVector.ConditionalSelect(TVector.LessThan(y, x), x, y); + return TVector.Max(x, y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -1244,7 +1244,7 @@ public static TVector MinMagnitudeNumber(TVector x, TVector y) || (typeof(T) == typeof(ulong)) || (typeof(T) == typeof(nuint))) { - return TVector.ConditionalSelect(TVector.LessThan(x, y), x, y); + return TVector.Min(x, y); } TVector xMag = TVector.Abs(x); @@ -1284,7 +1284,7 @@ public static TVector MinNumber(TVector x, TVector y) y ); } - return TVector.ConditionalSelect(TVector.LessThan(x, y), x, y); + return TVector.Min(x, y); } [MethodImpl(MethodImplOptions.AggressiveInlining)] From 16e27d80044384ac6b8941b10d2fa802e142c752 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 14:03:08 -0700 Subject: [PATCH 15/39] Fix some build failures --- src/coreclr/jit/compiler.h | 6 + src/coreclr/jit/gentree.cpp | 122 ++++++++++++++++++ src/coreclr/jit/hwintrinsicarm64.cpp | 32 +++++ src/coreclr/jit/hwintrinsiclistarm64.h | 4 + src/coreclr/jit/hwintrinsiclistxarch.h | 6 + src/coreclr/jit/hwintrinsicxarch.cpp | 46 +++++++ .../Tensors/TensorPrimitives.Single.cs | 8 +- .../Tensors/netcore/TensorPrimitives.Max.cs | 42 ++++-- .../netcore/TensorPrimitives.MaxNumber.cs | 6 +- .../Tensors/netcore/TensorPrimitives.Min.cs | 6 +- .../TensorPrimitives.MinMagnitudeNumber.cs | 4 +- .../Tensors/netcore/TensorPrimitives.Round.cs | 2 + .../TensorPrimitives.Single.netcore.cs | 4 - .../ref/System.Numerics.Vectors.cs | 5 + .../src/System/Numerics/Vector.cs | 10 +- .../System/Runtime/Intrinsics/Vector128.cs | 10 +- .../System/Runtime/Intrinsics/Vector256.cs | 10 +- .../System/Runtime/Intrinsics/Vector512.cs | 10 +- .../src/System/Runtime/Intrinsics/Vector64.cs | 10 +- .../System/Runtime/Intrinsics/VectorMath.cs | 8 +- .../ref/System.Runtime.Intrinsics.cs | 20 +++ src/mono/mono/mini/simd-intrinsics.c | 40 ++++-- src/mono/mono/mini/simd-methods.h | 1 + 23 files changed, 345 insertions(+), 67 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 76819a08c95ec8..aafcfab6043f90 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3353,6 +3353,9 @@ class Compiler CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdRoundNode( + var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdShuffleNode(var_types type, GenTree* op1, GenTree* op2, @@ -3390,6 +3393,9 @@ class Compiler CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdTruncNode( + var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize); + GenTree* gtNewSimdUnOpNode(genTreeOps op, var_types type, GenTree* op1, diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 973ebe5f03ffb5..8ef56019bff5fc 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -25965,6 +25965,67 @@ GenTree* Compiler::gtNewSimdNarrowNode( #endif // !TARGET_XARCH && !TARGET_ARM64 } +//------------------------------------------------------------------------ +// gtNewSimdRoundNode: Creates a new simd Round node +// +// Arguments: +// type -- The type of the node +// op1 -- The node to round +// simdBaseJitType -- the base jit type of the node +// simdSize -- the simd size of the node +// +// Return Value: +// The round node +// +GenTree* Compiler::gtNewSimdRoundNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsFloating(simdBaseType)); + + NamedIntrinsic intrinsic = NI_Illegal; + +#if defined(TARGET_XARCH) + if (simdSize == 32) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); + intrinsic = NI_AVX_RoundToNearestInteger; + } + else if (simdSize == 64) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX512F)); + GenTree* op2 = gtNewIconNode(static_cast(FloatRoundingMode::ToNearestInteger)); + return gtNewSimdHWIntrinsicNode(type, op1, op2, NI_AVX512F_RoundScale, simdBaseJitType, simdSize); + } + else + { + assert(compIsaSupportedDebugOnly(InstructionSet_SSE41)); + intrinsic = NI_SSE41_RoundToNearestInteger; + } +#elif defined(TARGET_ARM64) + if (simdBaseType == TYP_DOUBLE) + { + intrinsic = (simdSize == 8) ? NI_AdvSimd_RoundToNearestScalar : NI_AdvSimd_Arm64_RoundToNearest; + } + else + { + intrinsic = NI_AdvSimd_RoundToNearest; + } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + assert(intrinsic != NI_Illegal); + return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdBaseJitType, simdSize); +} + GenTree* Compiler::gtNewSimdShuffleNode( var_types type, GenTree* op1, GenTree* op2, CorInfoType simdBaseJitType, unsigned simdSize) { @@ -26904,6 +26965,67 @@ GenTree* Compiler::gtNewSimdToScalarNode(var_types type, GenTree* op1, CorInfoTy return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdBaseJitType, simdSize); } +//------------------------------------------------------------------------ +// gtNewSimdTruncNode: Creates a new simd Truncate node +// +// Arguments: +// type -- The type of the node +// op1 -- The node to truncate +// simdBaseJitType -- the base jit type of the node +// simdSize -- the simd size of the node +// +// Return Value: +// The truncate node +// +GenTree* Compiler::gtNewSimdTruncNode(var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) +{ + assert(IsBaselineSimdIsaSupportedDebugOnly()); + + assert(varTypeIsSIMD(type)); + assert(getSIMDTypeForSize(simdSize) == type); + + assert(op1 != nullptr); + assert(op1->TypeIs(type)); + + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsFloating(simdBaseType)); + + NamedIntrinsic intrinsic = NI_Illegal; + +#if defined(TARGET_XARCH) + if (simdSize == 32) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); + intrinsic = NI_AVX_RoundToZero; + } + else if (simdSize == 64) + { + assert(compIsaSupportedDebugOnly(InstructionSet_AVX512F)); + GenTree* op2 = gtNewIconNode(static_cast(FloatRoundingMode::ToZero)); + return gtNewSimdHWIntrinsicNode(type, op1, op2, NI_AVX512F_RoundScale, simdBaseJitType, simdSize); + } + else + { + assert(compIsaSupportedDebugOnly(InstructionSet_SSE41)); + intrinsic = NI_SSE41_RoundToZero; + } +#elif defined(TARGET_ARM64) + if (simdBaseType == TYP_DOUBLE) + { + intrinsic = (simdSize == 8) ? NI_AdvSimd_RoundToZeroScalar : NI_AdvSimd_Arm64_RoundToZero; + } + else + { + intrinsic = NI_AdvSimd_RoundToZero; + } +#else +#error Unsupported platform +#endif // !TARGET_XARCH && !TARGET_ARM64 + + assert(intrinsic != NI_Illegal); + return gtNewSimdHWIntrinsicNode(type, op1, intrinsic, simdBaseJitType, simdSize); +} + GenTree* Compiler::gtNewSimdUnOpNode( genTreeOps op, var_types type, GenTree* op1, CorInfoType simdBaseJitType, unsigned simdSize) { diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 8734b4c05d8a2f..dd6941ac03f4b6 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1956,6 +1956,22 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector64_Round: + case NI_Vector128_Round: + { + assert(sig->numArgs == 1); + + if (!varTypeIsFloating(simdBaseType)) + { + retNode = impSIMDPopStack(); + break; + } + + op1 = impSIMDPopStack(); + retNode = gtNewSimdRoundNode(retType, op1, simdBaseJitType, simdSize); + break; + } + case NI_Vector64_Shuffle: case NI_Vector128_Shuffle: { @@ -2298,6 +2314,22 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector64_Truncate: + case NI_Vector128_Truncate: + { + assert(sig->numArgs == 1); + + if (!varTypeIsFloating(simdBaseType)) + { + retNode = impSIMDPopStack(); + break; + } + + op1 = impSIMDPopStack(); + retNode = gtNewSimdTruncNode(retType, op1, simdBaseJitType, simdSize); + break; + } + case NI_Vector64_WidenLower: case NI_Vector128_WidenLower: { diff --git a/src/coreclr/jit/hwintrinsiclistarm64.h b/src/coreclr/jit/hwintrinsiclistarm64.h index 9b7bdd37a94ba0..7de5af49252f07 100644 --- a/src/coreclr/jit/hwintrinsiclistarm64.h +++ b/src/coreclr/jit/hwintrinsiclistarm64.h @@ -98,6 +98,7 @@ HARDWARE_INTRINSIC(Vector64, op_Subtraction, HARDWARE_INTRINSIC(Vector64, op_UnaryNegation, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, op_UnaryPlus, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, op_UnsignedRightShift, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector64, Round, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, Shuffle, 8, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector64, Sqrt, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, StoreAligned, 8, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) @@ -107,6 +108,7 @@ HARDWARE_INTRINSIC(Vector64, Sum, HARDWARE_INTRINSIC(Vector64, ToScalar, 8, 1, true, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SIMDScalar|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector64, ToVector128, 8, 1, true, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SIMD, HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector64, ToVector128Unsafe, 8, 1, true, {INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov, INS_mov}, HW_Category_SIMD, HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector64, Truncate, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector64, WidenLower, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, WidenUpper, 8, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector64, WithElement, 8, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) @@ -208,6 +210,7 @@ HARDWARE_INTRINSIC(Vector128, op_OnesComplement, HARDWARE_INTRINSIC(Vector128, op_Subtraction, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, op_UnaryNegation, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, op_UnaryPlus, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, Round, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Shuffle, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector128, Sqrt, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, StoreAligned, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) @@ -215,6 +218,7 @@ HARDWARE_INTRINSIC(Vector128, StoreAlignedNonTemporal, HARDWARE_INTRINSIC(Vector128, StoreUnsafe, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, Sum, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, ToScalar, 16, 1, true, {INS_smov, INS_umov, INS_smov, INS_umov, INS_smov, INS_umov, INS_umov, INS_umov, INS_dup, INS_dup}, HW_Category_SIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SIMDScalar|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(Vector128, Truncate, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, WidenLower, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, WidenUpper, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, WithElement, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_BaseTypeFromFirstArg|HW_Flag_SpecialImport) diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 191dce19f725e4..afc1eacebb85d9 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -118,6 +118,7 @@ HARDWARE_INTRINSIC(Vector128, op_Subtraction, HARDWARE_INTRINSIC(Vector128, op_UnaryNegation, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, op_UnaryPlus, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, op_UnsignedRightShift, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector128, Round, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, Shuffle, 16, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector128, Sqrt, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, StoreAligned, 16, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) @@ -128,6 +129,7 @@ HARDWARE_INTRINSIC(Vector128, ToScalar, HARDWARE_INTRINSIC(Vector128, ToVector256, 16, 1, true, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector128, ToVector256Unsafe, 16, 1, true, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(Vector128, ToVector512, 16, 1, true, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_vmovdqu64, INS_vmovdqu64, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(Vector128, Truncate, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector128, WidenLower, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, WidenUpper, 16, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector128, WithElement, 16, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) @@ -224,6 +226,7 @@ HARDWARE_INTRINSIC(Vector256, op_Subtraction, HARDWARE_INTRINSIC(Vector256, op_UnaryNegation, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, op_UnaryPlus, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, op_UnsignedRightShift, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector256, Round, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, Shuffle, 32, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector256, Sqrt, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, StoreAligned, 32, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg|HW_Flag_AvxOnlyCompatible) @@ -233,6 +236,7 @@ HARDWARE_INTRINSIC(Vector256, Sum, HARDWARE_INTRINSIC(Vector256, ToScalar, 32, 1, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsd_simd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg|HW_Flag_AvxOnlyCompatible) HARDWARE_INTRINSIC(Vector256, ToVector512, 32, 1, true, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_vmovdqu64, INS_vmovdqu64, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, ToVector512Unsafe, 32, 1, true, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_vmovdqu64, INS_vmovdqu64, INS_movups, INS_movupd}, HW_Category_SimpleSIMD, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector256, Truncate, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector256, WidenLower, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, WidenUpper, 32, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector256, WithElement, 32, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg|HW_Flag_AvxOnlyCompatible) @@ -331,6 +335,7 @@ HARDWARE_INTRINSIC(Vector512, op_Subtraction, HARDWARE_INTRINSIC(Vector512, op_UnaryNegation, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, op_UnaryPlus, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, op_UnsignedRightShift, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) +HARDWARE_INTRINSIC(Vector512, Round, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, Shuffle, 64, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(Vector512, Sqrt, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, StoreAligned, 64, 2, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) @@ -338,6 +343,7 @@ HARDWARE_INTRINSIC(Vector512, StoreAlignedNonTemporal, HARDWARE_INTRINSIC(Vector512, StoreUnsafe, 64, -1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, Sum, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, ToScalar, 64, 1, true, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_movsd_simd}, HW_Category_SIMDScalar, HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen|HW_Flag_BaseTypeFromFirstArg) +HARDWARE_INTRINSIC(Vector512, Truncate, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId) HARDWARE_INTRINSIC(Vector512, WidenLower, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, WidenUpper, 64, 1, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_InvalidNodeId|HW_Flag_BaseTypeFromFirstArg) HARDWARE_INTRINSIC(Vector512, WithElement, 64, 3, false, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_SpecialImport|HW_Flag_NoContainment|HW_Flag_BaseTypeFromFirstArg) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index e888a5b8fac7f8..2060c0ba273f47 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -3047,6 +3047,29 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_Round: + case NI_Vector256_Round: + case NI_Vector512_Round: + { + assert(sig->numArgs == 1); + + if (!varTypeIsFloating(simdBaseType)) + { + retNode = impSIMDPopStack(); + break; + } + + if ((simdSize < 32) && !compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + // Round is only supported for floating-point types on SSE4.1 or later + break; + } + + op1 = impSIMDPopStack(); + retNode = gtNewSimdRoundNode(retType, op1, simdBaseJitType, simdSize); + break; + } + case NI_Vector128_Shuffle: case NI_Vector256_Shuffle: case NI_Vector512_Shuffle: @@ -3278,6 +3301,29 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } + case NI_Vector128_Truncate: + case NI_Vector256_Truncate: + case NI_Vector512_Truncate: + { + assert(sig->numArgs == 1); + + if (!varTypeIsFloating(simdBaseType)) + { + retNode = impSIMDPopStack(); + break; + } + + if ((simdSize < 32) && !compOpportunisticallyDependsOn(InstructionSet_SSE41)) + { + // Truncate is only supported for floating-point types on SSE4.1 or later + break; + } + + op1 = impSIMDPopStack(); + retNode = gtNewSimdTruncNode(retType, op1, simdBaseJitType, simdSize); + break; + } + case NI_Vector256_GetLower: { assert(sig->numArgs == 1); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs index a8d4c6815ca406..96150e89108aad 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/TensorPrimitives.Single.cs @@ -440,7 +440,7 @@ public static float Max(ReadOnlySpan x) => /// /// public static void Max(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Searches for the single-precision floating-point number with the largest magnitude in the specified tensor. /// The tensor, represented as a span. @@ -476,7 +476,7 @@ public static float MaxMagnitude(ReadOnlySpan x) => /// /// public static void MaxMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Searches for the smallest single-precision floating-point number in the specified tensor. /// The tensor, represented as a span. @@ -517,7 +517,7 @@ public static float Min(ReadOnlySpan x) => /// /// public static void Min(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Searches for the single-precision floating-point number with the smallest magnitude in the specified tensor. /// The tensor, represented as a span. @@ -558,7 +558,7 @@ public static float MinMagnitude(ReadOnlySpan x) => /// /// public static void MinMagnitude(ReadOnlySpan x, ReadOnlySpan y, Span destination) => - InvokeSpanSpanIntoSpan(x, y, destination); + InvokeSpanSpanIntoSpan(x, y, destination); /// Computes the element-wise product of single-precision floating-point numbers in the specified tensors. /// The first tensor, represented as a span. diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs index 3a9c370e0078dd..c939936c698046 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Max.cs @@ -93,7 +93,7 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector128.ConditionalSelect( - (Vector128.Equals(x, y) & IsNegative(y)) | IsNaN(x) | Vector128.LessThan(y, x), + Vector128.LessThan(y, x) | IsNaN(x) | (Vector128.Equals(x, y) & IsNegative(y)), x, y ); @@ -110,7 +110,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector256.ConditionalSelect( - (Vector256.Equals(x, y) & IsNegative(y)) | ~Vector256.Equals(x, x) | Vector256.LessThan(y, x), + Vector256.LessThan(y, x) | IsNaN(x) | (Vector256.Equals(x, y) & IsNegative(y)), x, y ); @@ -127,7 +127,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector512.ConditionalSelect( - (Vector512.Equals(x, y) & IsNegative(y)) | ~Vector512.Equals(x, x) | Vector512.LessThan(y, x), + Vector512.LessThan(y, x) | IsNaN(x) | (Vector512.Equals(x, y) & IsNegative(y)), x, y ); @@ -187,11 +187,13 @@ private static Vector512 IsNaN(Vector512 vector) #endif } -#if !NET9_0_OR_GREATER /// Gets whether each specified is negative. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 IsNegative(Vector128 vector) { +#if NET9_0_OR_GREATER + return Vector128.IsNegative(vector); +#else if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) || (typeof(T) == typeof(uint)) @@ -212,12 +214,16 @@ private static Vector128 IsNegative(Vector128 vector) } return Vector128.LessThan(vector, Vector128.Zero); +#endif } /// Gets whether each specified is negative. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 IsNegative(Vector256 vector) { +#if NET9_0_OR_GREATER + return Vector256.IsNegative(vector); +#else if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) || (typeof(T) == typeof(uint)) @@ -238,12 +244,16 @@ private static Vector256 IsNegative(Vector256 vector) } return Vector256.LessThan(vector, Vector256.Zero); +#endif } /// Gets whether each specified is negative. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector512 IsNegative(Vector512 vector) { +#if NET9_0_OR_GREATER + return Vector512.IsNegative(vector); +#else if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) || (typeof(T) == typeof(uint)) @@ -264,12 +274,16 @@ private static Vector512 IsNegative(Vector512 vector) } return Vector512.LessThan(vector, Vector512.Zero); +#endif } /// Gets whether each specified is positive. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 IsPositive(Vector128 vector) { +#if NET9_0_OR_GREATER + return Vector128.IsPositive(vector); +#else if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) || (typeof(T) == typeof(uint)) @@ -290,12 +304,16 @@ private static Vector128 IsPositive(Vector128 vector) } return Vector128.GreaterThanOrEqual(vector, Vector128.Zero); +#endif } /// Gets whether each specified is positive. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector256 IsPositive(Vector256 vector) { +#if NET9_0_OR_GREATER + return Vector256.IsPositive(vector); +#else if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) || (typeof(T) == typeof(uint)) @@ -316,12 +334,16 @@ private static Vector256 IsPositive(Vector256 vector) } return Vector256.GreaterThanOrEqual(vector, Vector256.Zero); +#endif } /// Gets whether each specified is positive. [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector512 IsPositive(Vector512 vector) { +#if NET9_0_OR_GREATER + return Vector512.IsPositive(vector); +#else if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) || (typeof(T) == typeof(uint)) @@ -342,14 +364,14 @@ private static Vector512 IsPositive(Vector512 vector) } return Vector512.GreaterThanOrEqual(vector, Vector512.Zero); - } #endif + } - /// - /// This is the same as - /// with an identity transform, except it early exits on NaN. - /// - private static T MinMaxCore(ReadOnlySpan x) + /// + /// This is the same as + /// with an identity transform, except it early exits on NaN. + /// + private static T MinMaxCore(ReadOnlySpan x) where T : INumberBase where TMinMaxOperator : struct, IAggregationOperator { diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs index 52df9ea1f1b5c2..92da165265601a 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxNumber.cs @@ -92,7 +92,7 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector128.ConditionalSelect( - (Vector128.Equals(x, y) & IsNegative(y)) | IsNaN(y) | Vector128.LessThan(y, x), + Vector128.LessThan(y, x) | IsNaN(y) | (Vector128.Equals(x, y) & IsNegative(y)), x, y ); @@ -111,7 +111,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector256.ConditionalSelect( - (Vector256.Equals(x, y) & IsNegative(y)) | IsNaN(y) | Vector256.LessThan(y, x), + Vector256.LessThan(y, x) | IsNaN(y) | (Vector256.Equals(x, y) & IsNegative(y)), x, y ); @@ -130,7 +130,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector512.ConditionalSelect( - (Vector512.Equals(x, y) & IsNegative(y)) | IsNaN(y) | Vector512.LessThan(y, x), + Vector512.LessThan(y, x) | IsNaN(y) | (Vector512.Equals(x, y) & IsNegative(y)), x, y ); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs index 2159d81b3f49fc..f51e9797aebf39 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Min.cs @@ -91,7 +91,7 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector128.ConditionalSelect( - (Vector128.Equals(x, y) & Vector128.IsNegative(x)) | Vector128.IsNaN(x) | Vector128.LessThan(x, y), + Vector128.LessThan(x, y) | IsNaN(x) | (Vector128.Equals(x, y) & IsNegative(x)), x, y ); @@ -108,7 +108,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector256.ConditionalSelect( - (Vector256.Equals(x, y) & Vector256.IsNegative(x)) | Vector256.IsNaN(x) | Vector256.LessThan(x, y), + Vector256.LessThan(x, y) | IsNaN(x) | (Vector256.Equals(x, y) & IsNegative(x)), x, y ); @@ -125,7 +125,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector512.ConditionalSelect( - (Vector512.Equals(x, y) & Vector512.IsNegative(x)) | Vector512.IsNaN(x) | Vector512.LessThan(x, y), + Vector512.LessThan(x, y) | IsNaN(x) | (Vector512.Equals(x, y) & IsNegative(x)), x, y ); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs index b9ab89b52743c4..71425c88bd01bb 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs @@ -94,7 +94,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) || (typeof(T) == typeof(nint))); return Vector256.ConditionalSelect( - (Vector256.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + (Vector256.LessThan(xMag, yMag) & IsPositive(xMag)) | IsNegative(yMag), x, y ); @@ -136,7 +136,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) || (typeof(T) == typeof(nint))); return Vector512.ConditionalSelect( - (Vector512.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + (Vector512.LessThan(xMag, yMag) & IsPositive(xMag)) | IsNegative(yMag), x, y ); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs index 439b5dbfdcfb11..bd39bd0cdf9f2f 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Round.cs @@ -171,8 +171,10 @@ public static void Round(ReadOnlySpan x, int digits, MidpointRounding mode public static T Invoke(T x) => T.Round(x); +#if !NET9_0_OR_GREATER private const float SingleBoundary = 8388608.0f; // 2^23 private const double DoubleBoundary = 4503599627370496.0; // 2^52 +#endif public static Vector128 Invoke(Vector128 x) { diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs index 67d09e0ce4a181..a15a43d2178a00 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Single.netcore.cs @@ -21,13 +21,9 @@ global using LogOperator_Single = System.Numerics.Tensors.TensorPrimitives.LogOperator; global using Log2Operator_Single = System.Numerics.Tensors.TensorPrimitives.Log2Operator; global using MaxOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxOperator; -global using MaxPropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxOperator; global using MaxMagnitudeOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxMagnitudeOperator; -global using MaxMagnitudePropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MaxMagnitudeOperator; global using MinOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinOperator; -global using MinPropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinOperator; global using MinMagnitudeOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinMagnitudeOperator; -global using MinMagnitudePropagateNaNOperator_Single = System.Numerics.Tensors.TensorPrimitives.MinMagnitudeOperator; global using MultiplyAddOperator_Single = System.Numerics.Tensors.TensorPrimitives.MultiplyAddOperator; global using NegateOperator_Single = System.Numerics.Tensors.TensorPrimitives.NegateOperator; global using IdentityOperator_Single = System.Numerics.Tensors.TensorPrimitives.IdentityOperator; diff --git a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs index a0d3ae85e99af7..fba0c8dbcd4be6 100644 --- a/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs +++ b/src/libraries/System.Numerics.Vectors/ref/System.Numerics.Vectors.cs @@ -300,6 +300,11 @@ public static partial class Vector public static System.Numerics.Vector GreaterThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } public static System.Numerics.Vector Hypot(System.Numerics.Vector x, System.Numerics.Vector y) { throw null; } public static System.Numerics.Vector Hypot(System.Numerics.Vector x, System.Numerics.Vector y) { throw null; } + public static System.Numerics.Vector IsNaN(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector IsNegative(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector IsPositive(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector IsPositiveInfinity(System.Numerics.Vector vector) { throw null; } + public static System.Numerics.Vector IsZero(System.Numerics.Vector vector) { throw null; } public static System.Numerics.Vector Lerp(System.Numerics.Vector x, System.Numerics.Vector y, System.Numerics.Vector amount) { throw null; } public static System.Numerics.Vector Lerp(System.Numerics.Vector x, System.Numerics.Vector y, System.Numerics.Vector amount) { throw null; } public static System.Numerics.Vector LessThan(System.Numerics.Vector left, System.Numerics.Vector right) { throw null; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs index 3ab21caa4e5866..9bfd7b581070cc 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/Vector.cs @@ -1189,7 +1189,7 @@ public static Vector Hypot(Vector x, Vector y) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector IsNaN(Vector vector) + public static Vector IsNaN(Vector vector) { if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { @@ -1201,7 +1201,7 @@ internal static Vector IsNaN(Vector vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector IsNegative(Vector vector) + public static Vector IsNegative(Vector vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1228,7 +1228,7 @@ internal static Vector IsNegative(Vector vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector IsPositive(Vector vector) + public static Vector IsPositive(Vector vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1255,7 +1255,7 @@ internal static Vector IsPositive(Vector vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector IsPositiveInfinity(Vector vector) + public static Vector IsPositiveInfinity(Vector vector) { if (typeof(T) == typeof(float)) { @@ -1271,7 +1271,7 @@ internal static Vector IsPositiveInfinity(Vector vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector IsZero(Vector vector) => Equals(vector, Vector.Zero); + public static Vector IsZero(Vector vector) => Equals(vector, Vector.Zero); internal static Vector Lerp(Vector x, Vector y, Vector amount) where T : IFloatingPointIeee754 diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs index 2d88498cc229f3..ea69cf1528c54f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector128.cs @@ -1869,7 +1869,7 @@ public static Vector128 Hypot(Vector128 x, Vector128 y) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector128 IsNaN(Vector128 vector) + public static Vector128 IsNaN(Vector128 vector) { if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { @@ -1881,7 +1881,7 @@ internal static Vector128 IsNaN(Vector128 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector128 IsNegative(Vector128 vector) + public static Vector128 IsNegative(Vector128 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1908,7 +1908,7 @@ internal static Vector128 IsNegative(Vector128 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector128 IsPositive(Vector128 vector) + public static Vector128 IsPositive(Vector128 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1935,7 +1935,7 @@ internal static Vector128 IsPositive(Vector128 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector128 IsPositiveInfinity(Vector128 vector) + public static Vector128 IsPositiveInfinity(Vector128 vector) { if (typeof(T) == typeof(float)) { @@ -1951,7 +1951,7 @@ internal static Vector128 IsPositiveInfinity(Vector128 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector128 IsZero(Vector128 vector) => Equals(vector, Vector128.Zero); + public static Vector128 IsZero(Vector128 vector) => Equals(vector, Vector128.Zero); /// [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs index 1a69fc6069731a..a2d708b6a88d43 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector256.cs @@ -1785,7 +1785,7 @@ public static Vector256 Hypot(Vector256 x, Vector256 y) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector256 IsNaN(Vector256 vector) + public static Vector256 IsNaN(Vector256 vector) { if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { @@ -1797,7 +1797,7 @@ internal static Vector256 IsNaN(Vector256 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector256 IsNegative(Vector256 vector) + public static Vector256 IsNegative(Vector256 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1824,7 +1824,7 @@ internal static Vector256 IsNegative(Vector256 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector256 IsPositive(Vector256 vector) + public static Vector256 IsPositive(Vector256 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1851,7 +1851,7 @@ internal static Vector256 IsPositive(Vector256 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector256 IsPositiveInfinity(Vector256 vector) + public static Vector256 IsPositiveInfinity(Vector256 vector) { if (typeof(T) == typeof(float)) { @@ -1867,7 +1867,7 @@ internal static Vector256 IsPositiveInfinity(Vector256 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector256 IsZero(Vector256 vector) => Equals(vector, Vector256.Zero); + public static Vector256 IsZero(Vector256 vector) => Equals(vector, Vector256.Zero); /// [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs index e63af15c915dcc..86cb45ba617876 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector512.cs @@ -1848,7 +1848,7 @@ public static Vector512 Hypot(Vector512 x, Vector512 y) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector512 IsNaN(Vector512 vector) + public static Vector512 IsNaN(Vector512 vector) { if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { @@ -1860,7 +1860,7 @@ internal static Vector512 IsNaN(Vector512 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector512 IsNegative(Vector512 vector) + public static Vector512 IsNegative(Vector512 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1887,7 +1887,7 @@ internal static Vector512 IsNegative(Vector512 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector512 IsPositive(Vector512 vector) + public static Vector512 IsPositive(Vector512 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1914,7 +1914,7 @@ internal static Vector512 IsPositive(Vector512 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector512 IsPositiveInfinity(Vector512 vector) + public static Vector512 IsPositiveInfinity(Vector512 vector) { if (typeof(T) == typeof(float)) { @@ -1930,7 +1930,7 @@ internal static Vector512 IsPositiveInfinity(Vector512 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector512 IsZero(Vector512 vector) => Equals(vector, Vector512.Zero); + public static Vector512 IsZero(Vector512 vector) => Equals(vector, Vector512.Zero); /// [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs index 65854c8e0f0775..b58700fc2050a1 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/Vector64.cs @@ -1585,7 +1585,7 @@ public static Vector64 Hypot(Vector64 x, Vector64 y) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector64 IsNaN(Vector64 vector) + public static Vector64 IsNaN(Vector64 vector) { if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { @@ -1597,7 +1597,7 @@ internal static Vector64 IsNaN(Vector64 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector64 IsNegative(Vector64 vector) + public static Vector64 IsNegative(Vector64 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1624,7 +1624,7 @@ internal static Vector64 IsNegative(Vector64 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector64 IsPositive(Vector64 vector) + public static Vector64 IsPositive(Vector64 vector) { if ((typeof(T) == typeof(byte)) || (typeof(T) == typeof(ushort)) @@ -1651,7 +1651,7 @@ internal static Vector64 IsPositive(Vector64 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector64 IsPositiveInfinity(Vector64 vector) + public static Vector64 IsPositiveInfinity(Vector64 vector) { if (typeof(T) == typeof(float)) { @@ -1667,7 +1667,7 @@ internal static Vector64 IsPositiveInfinity(Vector64 vector) /// [Intrinsic] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static Vector64 IsZero(Vector64 vector) => Equals(vector, Vector64.Zero); + public static Vector64 IsZero(Vector64 vector) => Equals(vector, Vector64.Zero); internal static Vector64 Lerp(Vector64 x, Vector64 y, Vector64 amount) where T : IFloatingPointIeee754 diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index 4b45e834627bc9..a85fe13b626b71 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -1122,7 +1122,7 @@ public static TVector Max(TVector x, TVector y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return TVector.ConditionalSelect( - (TVector.Equals(x, y) & TVector.IsNegative(y)) | TVector.IsNaN(x) | TVector.LessThan(y, x), + TVector.LessThan(y, x) | TVector.IsNaN(x) | (TVector.Equals(x, y) & TVector.IsNegative(y)), x, y ); @@ -1192,7 +1192,7 @@ public static TVector MaxNumber(TVector x, TVector y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return TVector.ConditionalSelect( - (TVector.Equals(x, y) & TVector.IsNegative(y)) | TVector.IsNaN(y) | TVector.LessThan(y, x), + TVector.LessThan(y, x) | TVector.IsNaN(y) | (TVector.Equals(x, y) & TVector.IsNegative(y)), x, y ); @@ -1208,7 +1208,7 @@ public static TVector Min(TVector x, TVector y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return TVector.ConditionalSelect( - (TVector.Equals(x, y) & TVector.IsNegative(x)) | TVector.IsNaN(x) | TVector.LessThan(x, y), + TVector.LessThan(x, y) | TVector.IsNaN(x) | (TVector.Equals(x, y) & TVector.IsNegative(x)), x, y ); @@ -1279,7 +1279,7 @@ public static TVector MinNumber(TVector x, TVector y) if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return TVector.ConditionalSelect( - (TVector.Equals(x, y) & TVector.IsNegative(x)) | TVector.IsNaN(y) | TVector.LessThan(x, y), + TVector.LessThan(x, y) | TVector.IsNaN(y) | (TVector.Equals(x, y) & TVector.IsNegative(x)), x, y ); diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 49c009b62d8038..3e97b7aa4f437d 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -189,6 +189,11 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector128 vector, public static System.Runtime.Intrinsics.Vector128 GreaterThan(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } public static System.Runtime.Intrinsics.Vector128 Hypot(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y) { throw null; } public static System.Runtime.Intrinsics.Vector128 Hypot(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y) { throw null; } + public static System.Runtime.Intrinsics.Vector128 IsNaN(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 IsNegative(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 IsPositive(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 IsPositiveInfinity(System.Runtime.Intrinsics.Vector128 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector128 IsZero(System.Runtime.Intrinsics.Vector128 vector) { throw null; } public static System.Runtime.Intrinsics.Vector128 Lerp(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y, System.Runtime.Intrinsics.Vector128 amount) { throw null; } public static System.Runtime.Intrinsics.Vector128 Lerp(System.Runtime.Intrinsics.Vector128 x, System.Runtime.Intrinsics.Vector128 y, System.Runtime.Intrinsics.Vector128 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) { throw null; } @@ -561,6 +566,11 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector256 vector, public static System.Runtime.Intrinsics.Vector256 GreaterThan(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } public static System.Runtime.Intrinsics.Vector256 Hypot(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y) { throw null; } public static System.Runtime.Intrinsics.Vector256 Hypot(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y) { throw null; } + public static System.Runtime.Intrinsics.Vector256 IsNaN(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 IsNegative(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 IsPositive(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 IsPositiveInfinity(System.Runtime.Intrinsics.Vector256 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector256 IsZero(System.Runtime.Intrinsics.Vector256 vector) { throw null; } public static System.Runtime.Intrinsics.Vector256 Lerp(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y, System.Runtime.Intrinsics.Vector256 amount) { throw null; } public static System.Runtime.Intrinsics.Vector256 Lerp(System.Runtime.Intrinsics.Vector256 x, System.Runtime.Intrinsics.Vector256 y, System.Runtime.Intrinsics.Vector256 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) { throw null; } @@ -934,6 +944,11 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector512 vector, public static System.Runtime.Intrinsics.Vector512 GreaterThan(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } public static System.Runtime.Intrinsics.Vector512 Hypot(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y) { throw null; } public static System.Runtime.Intrinsics.Vector512 Hypot(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y) { throw null; } + public static System.Runtime.Intrinsics.Vector512 IsNaN(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 IsNegative(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 IsPositive(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 IsPositiveInfinity(System.Runtime.Intrinsics.Vector512 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector512 IsZero(System.Runtime.Intrinsics.Vector512 vector) { throw null; } public static System.Runtime.Intrinsics.Vector512 Lerp(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y, System.Runtime.Intrinsics.Vector512 amount) { throw null; } public static System.Runtime.Intrinsics.Vector512 Lerp(System.Runtime.Intrinsics.Vector512 x, System.Runtime.Intrinsics.Vector512 y, System.Runtime.Intrinsics.Vector512 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector512 left, System.Runtime.Intrinsics.Vector512 right) { throw null; } @@ -1276,6 +1291,11 @@ public static void CopyTo(this System.Runtime.Intrinsics.Vector64 vector, public static System.Runtime.Intrinsics.Vector64 GreaterThan(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } public static System.Runtime.Intrinsics.Vector64 Hypot(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y) { throw null; } public static System.Runtime.Intrinsics.Vector64 Hypot(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y) { throw null; } + public static System.Runtime.Intrinsics.Vector64 IsNaN(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 IsNegative(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 IsPositive(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 IsPositiveInfinity(System.Runtime.Intrinsics.Vector64 vector) { throw null; } + public static System.Runtime.Intrinsics.Vector64 IsZero(System.Runtime.Intrinsics.Vector64 vector) { throw null; } public static System.Runtime.Intrinsics.Vector64 Lerp(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y, System.Runtime.Intrinsics.Vector64 amount) { throw null; } public static System.Runtime.Intrinsics.Vector64 Lerp(System.Runtime.Intrinsics.Vector64 x, System.Runtime.Intrinsics.Vector64 y, System.Runtime.Intrinsics.Vector64 amount) { throw null; } public static bool LessThanAll(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) { throw null; } diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 24393eb9b7ba90..34da7c8b8cbfaf 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1664,7 +1664,13 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); } - case SN_AsVector2: + case SN_AsVector2: { + if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->ret))) { + // FIXME: Support Vector2 and Vector3 for WASM and AMD64 + return NULL; + } + return emit_simd_ins_for_sig (cfg, klass, OP_XLOWER, 0, arg0_type, fsig, args); + } case SN_AsVector3: { if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->ret))) { // FIXME: Support Vector2 and Vector3 for WASM and AMD64 @@ -1680,11 +1686,12 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; } MonoClass *input_class = mono_class_from_mono_type_internal (fsig->params [0]); - int input_size = mono_class_value_size (vector_class, NULL); + int input_size = mono_class_value_size (input_class, NULL); if (input_size == 16) return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); - if (COMPILE_LLVM (cfg) && (inputSize == 8)) { - return emit_simd_ins (cfg, klass, OP_XWIDEN, args [0]->dreg, -1); + if (input_size == 8) { + if (COMPILE_LLVM (cfg)) + return emit_simd_ins (cfg, klass, OP_XWIDEN, args [0]->dreg, -1); } static float r4_0 = 0; MonoInst *zero; @@ -1693,10 +1700,11 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi zero->inst_p0 = (void*)&r4_0; zero->dreg = zero_dreg; MONO_ADD_INS (cfg->cbb, zero); + MonoInst* vec_ins = args [0]; if (input_size == 8) { - args [0] = emit_vector_insert_element (cfg, klass, args [0], MONO_TYPE_R4, zero, 2, FALSE); + vec_ins = emit_vector_insert_element (cfg, klass, vec_ins, MONO_TYPE_R4, zero, 2, FALSE); } - return emit_vector_insert_element (cfg, klass, args [0], MONO_TYPE_R4, zero, 3, FALSE); + return emit_vector_insert_element (cfg, klass, vec_ins, MONO_TYPE_R4, zero, 3, FALSE); } case SN_AsVector128Unsafe: { if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) @@ -1706,9 +1714,10 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; } MonoClass *input_class = mono_class_from_mono_type_internal (fsig->params [0]); - int input_size = mono_class_value_size (vector_class, NULL); - if (COMPILE_LLVM (cfg) && (inputSize == 8)) { - return emit_simd_ins (cfg, klass, OP_XWIDEN_UNSAFE, args [0]->dreg, -1); + int input_size = mono_class_value_size (input_class, NULL); + if (input_size == 8) { + if (COMPILE_LLVM (cfg)) + return emit_simd_ins (cfg, klass, OP_XWIDEN_UNSAFE, args [0]->dreg, -1); } return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); } @@ -2229,7 +2238,8 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_IsPositiveInfinity: { if (!is_element_type_primitive (fsig->params [0])) return NULL; - if (etype == MONO_TYPE_R4) { + MonoType *etype = get_vector_t_elem_type(fsig->params [0]); + if (etype->type == MONO_TYPE_R4) { guint32 value[4]; value [0] = 0x7F800000; @@ -2240,7 +2250,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi MonoInst* arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); return emit_xcompare (cfg, klass, arg0_type, args [0], arg1); } - if (etype == MONO_TYPE_R8) { + if (etype->type == MONO_TYPE_R8) { guint64 value[2]; value [0] = 0x7FF0000000000000; @@ -2822,6 +2832,7 @@ static guint16 vector_2_3_4_methods[] = { SN_Abs, SN_Add, SN_Clamp, + SN_ClampNative, SN_Conjugate, SN_CopyTo, SN_Distance, @@ -3196,9 +3207,14 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f } case SN_CopyTo: return NULL; - case SN_Clamp: { + case SN_Clamp: + case SN_ClampNative: { if (!(!fsig->hasthis && fsig->param_count == 3 && mono_metadata_type_equal (fsig->ret, type) && mono_metadata_type_equal (fsig->params [0], type) && mono_metadata_type_equal (fsig->params [1], type) && mono_metadata_type_equal (fsig->params [2], type))) return NULL; +#ifndef TARGET_ARM64 + if (id == SN_Clamp) + return NULL; +#endif MonoInst *max = emit_simd_ins (cfg, klass, OP_XBINOP, args[0]->dreg, args[1]->dreg); max->inst_c0 = OP_FMAX; diff --git a/src/mono/mono/mini/simd-methods.h b/src/mono/mono/mini/simd-methods.h index 6ca019068a933f..dde128d6c48262 100644 --- a/src/mono/mono/mini/simd-methods.h +++ b/src/mono/mono/mini/simd-methods.h @@ -1,5 +1,6 @@ METHOD2(".ctor", ctor) METHOD(Clamp) +METHOD(ClampNative) METHOD(Conjugate) METHOD(CopyTo) METHOD(Distance) From 753df42de28d3e4aeae1685e9c34d90c1dce6769 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 18:54:43 -0700 Subject: [PATCH 16/39] Workaround a MonoJIT assertion --- src/mono/mono/mini/simd-intrinsics.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 34da7c8b8cbfaf..8a71c7d8cd5dc6 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1659,7 +1659,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_AsUInt32: case SN_AsUInt64: case SN_AsVector: - case SN_AsVector4: { + { if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) return NULL; return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); @@ -1678,6 +1678,13 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi } return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); } + case SN_AsVector4: { + if (!COMPILE_LLVM (cfg)) { + // This can assert for load opcodes needing OP_LOADV_MEMBASE + return NULL; + } + return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); + } case SN_AsVector128: { if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) return NULL; From 574c15cba41029dad2caee1905478b2a4ee49c84 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 21 Jun 2024 19:28:07 -0700 Subject: [PATCH 17/39] Ensure Hypot for double handles insignificant results --- src/coreclr/jit/gentree.cpp | 19 ++++++------- .../Tensors/netcore/TensorPrimitives.Lerp.cs | 6 ++-- .../TensorPrimitives.MaxMagnitudeNumber.cs | 6 ++-- .../netcore/TensorPrimitives.MinMagnitude.cs | 6 ++-- .../TensorPrimitives.MinMagnitudeNumber.cs | 14 +++++----- .../src/System/Double.cs | 2 +- .../System/Numerics/IFloatingPointIeee754.cs | 2 +- .../System/Runtime/Intrinsics/VectorMath.cs | 28 +++++++++++-------- .../src/System/Single.cs | 2 +- 9 files changed, 45 insertions(+), 40 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 8ef56019bff5fc..e826e9e4eb9b87 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -20857,7 +20857,7 @@ GenTree* Compiler::gtNewSimdAbsNode(var_types type, GenTree* op1, CorInfoType si GenTree* op1Dup2 = fgMakeMultiUse(&op1Dup1); // op1 = IsNegative(op1) - op1 = gtNewSimdIsPositiveInfinityNode(type, op1, simdBaseJitType, simdSize); + op1 = gtNewSimdIsNegativeNode(type, op1, simdBaseJitType, simdSize); // tmp = -op1Dup1 tmp = gtNewSimdUnOpNode(GT_NEG, type, op1Dup1, simdBaseJitType, simdSize); @@ -23138,18 +23138,17 @@ GenTree* Compiler::gtNewSimdCmpOpNode( case GT_NE: { - if (!varTypeIsFloating(simdBaseType) && (simdSize != 64)) - { - GenTree* result = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); - return gtNewSimdUnOpNode(GT_NEG, type, result, simdBaseJitType, simdSize); - } - if (simdSize == 64) { assert(canUseEvexEncodingDebugOnly()); intrinsic = NI_EVEX_CompareNotEqualMask; needsConvertMaskToVector = true; } + else if (!varTypeIsFloating(simdBaseType)) + { + GenTree* result = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); + return gtNewSimdUnOpNode(GT_NOT, type, result, simdBaseJitType, simdSize); + } else if (simdSize == 32) { assert(compIsaSupportedDebugOnly(InstructionSet_AVX)); @@ -23240,7 +23239,7 @@ GenTree* Compiler::gtNewSimdCmpOpNode( case GT_NE: { GenTree* result = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); - return gtNewSimdUnOpNode(GT_NEG, type, result, simdBaseJitType, simdSize); + return gtNewSimdUnOpNode(GT_NOT, type, result, simdBaseJitType, simdSize); } #else #error Unsupported platform @@ -24704,7 +24703,7 @@ GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, if (varTypeIsFloating(simdBaseType)) { - double infinity = FloatingPointUtils::convertUInt64ToDouble(0x7FF0000000000000); + double infinity = BitOperations::UInt64BitsToDouble(0x7FF0000000000000); GenTree* cnsNode = gtNewDconNode(infinity, simdBaseType); cnsNode = gtNewSimdCreateBroadcastNode(type, cnsNode, simdBaseJitType, simdSize); return gtNewSimdCmpOpNode(GT_EQ, type, op1, cnsNode, simdBaseJitType, simdSize); @@ -24713,7 +24712,7 @@ GenTree* Compiler::gtNewSimdIsPositiveInfinityNode(var_types type, } //---------------------------------------------------------------------------------------------- -// Compiler::gtNewSimdIsPositiveInfinityNode: Creates a new simd IsZero node +// Compiler::gtNewSimdIsZeroNode: Creates a new simd IsZero node // // Arguments: // type - The return type of SIMD node being created diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs index f31b3e50f77d2d..f4acf4adbe029b 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.Lerp.cs @@ -90,7 +90,7 @@ public static Vector128 Invoke(Vector128 x, Vector128 y, Vector128 a return Vector128.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As(); } #else - return (x * (Vector128.One - amount)) + (y * amount); + return MultiplyAddEstimateOperator.Invoke(x, Vector128.One - amount, y * amount); #endif } @@ -107,7 +107,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y, Vector256 a return Vector256.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As(); } #else - return (x * (Vector256.One - amount)) + (y * amount); + return MultiplyAddEstimateOperator.Invoke(x, Vector256.One - amount, y * amount); #endif } @@ -124,7 +124,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y, Vector512 a return Vector512.Lerp(x.AsSingle(), y.AsSingle(), amount.AsSingle()).As(); } #else - return (x * (Vector512.One - amount)) + (y * amount); + return MultiplyAddEstimateOperator.Invoke(x, Vector512.One - amount, y * amount); #endif } } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs index 0e9c91613ad7ef..53eb31e5dc2a2f 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MaxMagnitudeNumber.cs @@ -53,7 +53,7 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) || (typeof(T) == typeof(nint))); return Vector128.ConditionalSelect( - (Vector128.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + (Vector128.GreaterThan(xMag, yMag) & IsPositive(yMag)) | (Vector128.Equals(xMag, yMag) & IsNegative(y)) | IsNegative(xMag), x, y ); @@ -95,7 +95,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) || (typeof(T) == typeof(nint))); return Vector256.ConditionalSelect( - (Vector256.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + (Vector256.GreaterThan(xMag, yMag) & IsPositive(yMag)) | (Vector256.Equals(xMag, yMag) & IsNegative(y)) | IsNegative(xMag), x, y ); @@ -137,7 +137,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) || (typeof(T) == typeof(nint))); return Vector512.ConditionalSelect( - (Vector512.GreaterThan(xMag, yMag) & IsPositive(yMag)) | IsNegative(xMag), + (Vector512.GreaterThan(xMag, yMag) & IsPositive(yMag)) | (Vector512.Equals(xMag, yMag) & IsNegative(y)) | IsNegative(xMag), x, y ); diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs index 8b4cae6ee22c2d..d3158f6e12bb4a 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitude.cs @@ -100,7 +100,7 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) y ); } - return MinMagnitudeOperator.Invoke(x, y); + return MinMagnitudeNumberOperator.Invoke(x, y); #endif } @@ -122,7 +122,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) y ); } - return MinMagnitudeOperator.Invoke(x, y); + return MinMagnitudeNumberOperator.Invoke(x, y); #endif } @@ -144,7 +144,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) y ); } - return MinMagnitudeOperator.Invoke(x, y); + return MinMagnitudeNumberOperator.Invoke(x, y); #endif } diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs index 71425c88bd01bb..4777db78e8ada2 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs @@ -52,7 +52,7 @@ public static Vector128 Invoke(Vector128 x, Vector128 y) || (typeof(T) == typeof(nint))); return Vector128.ConditionalSelect( - (Vector128.LessThan(xMag, yMag) & IsPositive(xMag)) | IsNegative(yMag), + (Vector128.LessThan(xMag, yMag) & IsPositive(xMag)) | (Vector128.Equals(xMag, yMag) & IsNegative(x)) | IsNegative(yMag), x, y ); @@ -71,7 +71,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) || (typeof(T) == typeof(ulong)) || (typeof(T) == typeof(nuint))) { - return Vector256.ConditionalSelect(Vector256.LessThan(y, x), x, y); + return Vector256.Min(x, y); } Vector256 xMag = Vector256.Abs(x); @@ -81,7 +81,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) ) { return Vector256.ConditionalSelect( - Vector256.GreaterThan(xMag, yMag) | IsNaN(yMag) | (Vector256.Equals(xMag, yMag) & IsPositive(x)), + Vector256.LessThan(xMag, yMag) | IsNaN(yMag) | (Vector256.Equals(xMag, yMag) & IsNegative(x)), x, y ); @@ -94,7 +94,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) || (typeof(T) == typeof(nint))); return Vector256.ConditionalSelect( - (Vector256.LessThan(xMag, yMag) & IsPositive(xMag)) | IsNegative(yMag), + (Vector256.LessThan(xMag, yMag) & IsPositive(xMag)) | (Vector256.Equals(xMag, yMag) & IsNegative(x)) | IsNegative(yMag), x, y ); @@ -113,7 +113,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) || (typeof(T) == typeof(ulong)) || (typeof(T) == typeof(nuint))) { - return Vector512.ConditionalSelect(Vector512.LessThan(y, x), x, y); + return Vector512.Min(x, y); } Vector512 xMag = Vector512.Abs(x); @@ -123,7 +123,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) ) { return Vector512.ConditionalSelect( - Vector512.GreaterThan(xMag, yMag) | IsNaN(yMag) | (Vector512.Equals(xMag, yMag) & IsPositive(x)), + Vector512.LessThan(xMag, yMag) | IsNaN(yMag) | (Vector512.Equals(xMag, yMag) & IsNegative(x)), x, y ); @@ -136,7 +136,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) || (typeof(T) == typeof(nint))); return Vector512.ConditionalSelect( - (Vector512.LessThan(xMag, yMag) & IsPositive(xMag)) | IsNegative(yMag), + (Vector512.LessThan(xMag, yMag) & IsPositive(xMag)) | (Vector512.Equals(xMag, yMag) & IsNegative(x)) | IsNegative(yMag), x, y ); diff --git a/src/libraries/System.Private.CoreLib/src/System/Double.cs b/src/libraries/System.Private.CoreLib/src/System/Double.cs index 8d66af450f327a..d38c67b916b18e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Double.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Double.cs @@ -874,7 +874,7 @@ bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destinati public static int ILogB(double x) => Math.ILogB(x); /// - public static double Lerp(double value1, double value2, double amount) => (value1 * (1.0 - amount)) + (value2 * amount); + public static double Lerp(double value1, double value2, double amount) => MultiplyAddEstimate(value1, 1.0 - amount, value2 * amount); /// [Intrinsic] diff --git a/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs b/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs index 4d3593f5c136fd..08d0289f0c54a7 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Numerics/IFloatingPointIeee754.cs @@ -78,7 +78,7 @@ public interface IFloatingPointIeee754 /// A value, intended to be between 0 and 1, that indicates the weight of the interpolation. /// The interpolated value. /// This method presumes inputs are well formed and does not validate that value1 < value2 nor that 0 <= amount <= 1. - static virtual TSelf Lerp(TSelf value1, TSelf value2, TSelf amount) => (value1 * (TSelf.One - amount)) + (value2 * amount); + static virtual TSelf Lerp(TSelf value1, TSelf value2, TSelf amount) => TSelf.MultiplyAddEstimate(value1, TSelf.One - amount, value2 * amount); /// Computes an estimate of the reciprocal of a value. /// The value whose estimate of the reciprocal is to be computed. diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index a85fe13b626b71..d2b4a32dd8969b 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -101,13 +101,13 @@ public static TVectorDouble ExpDouble(TVectorDou TVectorUInt64 expDiff = xExp - yExp; + // Cover cases where x or y is insignifican compared to the other + TVectorDouble insignificanMask = Unsafe.BitCast( + TVectorUInt64.GreaterThanOrEqual(expDiff, TVectorUInt64.Create(double.SignificandLength + 1)) & + TVectorUInt64.LessThanOrEqual(expDiff, TVectorUInt64.Create(unchecked((ulong)(-double.SignificandLength - 1)))) + ); + TVectorDouble insignificantResult = ax + ay; + // To prevent overflow, scale down by 2^+600 TVectorUInt64 expBiasP500 = TVectorUInt64.Create(double.ExponentBias + 500); TVectorUInt64 scaleDownMask = TVectorUInt64.GreaterThan(xExp, expBiasP500) | TVectorUInt64.GreaterThan(yExp, expBiasP500); @@ -427,6 +432,7 @@ public static TVectorDouble HypotDouble(TVectorDou // the inputs is NaN. Otherwise if either input // is NaN, we return NaN + result = TVectorDouble.ConditionalSelect(insignificanMask, insignificantResult, result); result = TVectorDouble.ConditionalSelect(nanMask, TVectorDouble.Create(double.NaN), result); result = TVectorDouble.ConditionalSelect(infinityMask, TVectorDouble.Create(double.PositiveInfinity), result); @@ -1179,7 +1185,7 @@ public static TVector MaxMagnitudeNumber(TVector x, TVector y) || (typeof(T) == typeof(nint))); return TVector.ConditionalSelect( - (TVector.GreaterThan(xMag, yMag) & TVector.IsPositive(yMag)) | TVector.IsNegative(xMag), + (TVector.GreaterThan(xMag, yMag) & TVector.IsPositive(yMag)) | (TVector.Equals(xMag, yMag) & TVector.IsNegative(y)) | TVector.IsNegative(xMag), x, y ); @@ -1266,7 +1272,7 @@ public static TVector MinMagnitudeNumber(TVector x, TVector y) || (typeof(T) == typeof(nint))); return TVector.ConditionalSelect( - (TVector.LessThan(xMag, yMag) & TVector.IsPositive(xMag)) | TVector.IsNegative(yMag), + (TVector.LessThan(xMag, yMag) & TVector.IsPositive(xMag)) | (TVector.Equals(xMag, yMag) & TVector.IsNegative(x)) | TVector.IsNegative(yMag), x, y ); diff --git a/src/libraries/System.Private.CoreLib/src/System/Single.cs b/src/libraries/System.Private.CoreLib/src/System/Single.cs index 7ee394a0d8f4c3..92cc094044018c 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Single.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Single.cs @@ -857,7 +857,7 @@ bool IFloatingPoint.TryWriteSignificandLittleEndian(Span destinatio public static int ILogB(float x) => MathF.ILogB(x); /// - public static float Lerp(float value1, float value2, float amount) => (value1 * (1.0f - amount)) + (value2 * amount); + public static float Lerp(float value1, float value2, float amount) => MultiplyAddEstimate(value1, 1.0f - amount, value2 * amount); /// [Intrinsic] From 79b225aa27c34acace7a040f55b206e2ce174b63 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Thu, 27 Jun 2024 15:09:31 -0700 Subject: [PATCH 18/39] Remove part of the mono changes that were extracted to a separate PR --- src/mono/mono/mini/simd-intrinsics.c | 82 +--------------------------- src/mono/mono/mini/simd-methods.h | 6 -- 2 files changed, 1 insertion(+), 87 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 8a71c7d8cd5dc6..51794d5c8c47d3 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1193,21 +1193,11 @@ static guint16 sri_vector_methods [] = { SN_AsInt16, SN_AsInt32, SN_AsInt64, - SN_AsNInt, - SN_AsNUInt, - SN_AsPlane, - SN_AsQuaternion, SN_AsSByte, SN_AsSingle, SN_AsUInt16, SN_AsUInt32, SN_AsUInt64, - SN_AsVector, - SN_AsVector128, - SN_AsVector128Unsafe, - SN_AsVector2, - SN_AsVector3, - SN_AsVector4, SN_BitwiseAnd, SN_BitwiseOr, SN_Ceiling, @@ -1649,83 +1639,13 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi case SN_AsInt16: case SN_AsInt32: case SN_AsInt64: - case SN_AsNInt: - case SN_AsNUInt: - case SN_AsPlane: - case SN_AsQuaternion: case SN_AsSByte: case SN_AsSingle: case SN_AsUInt16: case SN_AsUInt32: - case SN_AsUInt64: - case SN_AsVector: - { - if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) - return NULL; - return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); - } - case SN_AsVector2: { - if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->ret))) { - // FIXME: Support Vector2 and Vector3 for WASM and AMD64 - return NULL; - } - return emit_simd_ins_for_sig (cfg, klass, OP_XLOWER, 0, arg0_type, fsig, args); - } - case SN_AsVector3: { - if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->ret))) { - // FIXME: Support Vector2 and Vector3 for WASM and AMD64 - return NULL; - } - return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); - } - case SN_AsVector4: { - if (!COMPILE_LLVM (cfg)) { - // This can assert for load opcodes needing OP_LOADV_MEMBASE - return NULL; - } - return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); - } - case SN_AsVector128: { - if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) - return NULL; - if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->params [0]))) { - // FIXME: Support Vector2 and Vector3 for WASM and AMD64 - return NULL; - } - MonoClass *input_class = mono_class_from_mono_type_internal (fsig->params [0]); - int input_size = mono_class_value_size (input_class, NULL); - if (input_size == 16) - return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); - if (input_size == 8) { - if (COMPILE_LLVM (cfg)) - return emit_simd_ins (cfg, klass, OP_XWIDEN, args [0]->dreg, -1); - } - static float r4_0 = 0; - MonoInst *zero; - int zero_dreg = alloc_freg (cfg); - MONO_INST_NEW (cfg, zero, OP_R4CONST); - zero->inst_p0 = (void*)&r4_0; - zero->dreg = zero_dreg; - MONO_ADD_INS (cfg->cbb, zero); - MonoInst* vec_ins = args [0]; - if (input_size == 8) { - vec_ins = emit_vector_insert_element (cfg, klass, vec_ins, MONO_TYPE_R4, zero, 2, FALSE); - } - return emit_vector_insert_element (cfg, klass, vec_ins, MONO_TYPE_R4, zero, 3, FALSE); - } - case SN_AsVector128Unsafe: { + case SN_AsUInt64: { if (!is_element_type_primitive (fsig->ret) || !is_element_type_primitive (fsig->params [0])) return NULL; - if (!mini_class_is_simd (cfg, mono_class_from_mono_type_internal (fsig->params [0]))) { - // FIXME: Support Vector2 and Vector3 for WASM and AMD64 - return NULL; - } - MonoClass *input_class = mono_class_from_mono_type_internal (fsig->params [0]); - int input_size = mono_class_value_size (input_class, NULL); - if (input_size == 8) { - if (COMPILE_LLVM (cfg)) - return emit_simd_ins (cfg, klass, OP_XWIDEN_UNSAFE, args [0]->dreg, -1); - } return emit_simd_ins (cfg, klass, OP_XCAST, args [0]->dreg, -1); } case SN_Ceiling: diff --git a/src/mono/mono/mini/simd-methods.h b/src/mono/mono/mini/simd-methods.h index dde128d6c48262..c137ddd441a1c6 100644 --- a/src/mono/mono/mini/simd-methods.h +++ b/src/mono/mono/mini/simd-methods.h @@ -79,18 +79,12 @@ METHOD(AsDouble) METHOD(AsInt16) METHOD(AsInt32) METHOD(AsInt64) -METHOD(AsNInt) -METHOD(AsNUInt) -METHOD(AsPlane) -METHOD(AsQuaternion) METHOD(AsSByte) METHOD(AsSingle) METHOD(AsUInt16) METHOD(AsUInt32) METHOD(AsUInt64) -METHOD(AsVector) METHOD(AsVector128) -METHOD(AsVector128Unsafe) METHOD(AsVector2) METHOD(AsVector256) METHOD(AsVector3) From 50434a6fd35f168f175460b6bf4d510284af5155 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Fri, 28 Jun 2024 19:39:32 -0700 Subject: [PATCH 19/39] Apply suggestions from code review Co-authored-by: Stephen Toub --- .../Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs | 6 ++---- .../src/System/Runtime/Intrinsics/VectorMath.cs | 4 ++-- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs index 4777db78e8ada2..b714b8e7d0a64d 100644 --- a/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs +++ b/src/libraries/System.Numerics.Tensors/src/System/Numerics/Tensors/netcore/TensorPrimitives.MinMagnitudeNumber.cs @@ -77,8 +77,7 @@ public static Vector256 Invoke(Vector256 x, Vector256 y) Vector256 xMag = Vector256.Abs(x); Vector256 yMag = Vector256.Abs(y); - if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) - ) + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector256.ConditionalSelect( Vector256.LessThan(xMag, yMag) | IsNaN(yMag) | (Vector256.Equals(xMag, yMag) & IsNegative(x)), @@ -119,8 +118,7 @@ public static Vector512 Invoke(Vector512 x, Vector512 y) Vector512 xMag = Vector512.Abs(x); Vector512 yMag = Vector512.Abs(y); - if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) - ) + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return Vector512.ConditionalSelect( Vector512.LessThan(xMag, yMag) | IsNaN(yMag) | (Vector512.Equals(xMag, yMag) & IsNegative(x)), diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs index d2b4a32dd8969b..fbe07cc62a9af2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/VectorMath.cs @@ -1135,6 +1135,7 @@ public static TVector Max(TVector x, TVector y) } return TVector.ConditionalSelect(TVector.GreaterThan(x, y), x, y); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static TVector MaxMagnitude(TVector x, TVector y) where TVector : unmanaged, ISimdVector @@ -1168,8 +1169,7 @@ public static TVector MaxMagnitudeNumber(TVector x, TVector y) TVector xMag = TVector.Abs(x); TVector yMag = TVector.Abs(y); - if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double)) - ) + if ((typeof(T) == typeof(float)) || (typeof(T) == typeof(double))) { return TVector.ConditionalSelect( TVector.GreaterThan(xMag, yMag) | TVector.IsNaN(yMag) | (TVector.Equals(xMag, yMag) & TVector.IsPositive(x)), From 3f9bd35798dae875bf36c6d18bb843d7a2649bd4 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 11:45:50 -0700 Subject: [PATCH 20/39] Ensure tests are added for the new vector APIs --- .../tests/System/GenericMathTestMemberData.cs | 1687 +++++++++++++++++ .../Intrinsics/VectorTestMemberData.cs | 442 ----- .../tests/GenericVectorTests.cs | 441 ++++- .../System.Numerics.Vectors.Tests.csproj | 2 +- .../tests/Vector2Tests.cs | 189 +- .../tests/Vector3Tests.cs | 189 +- .../tests/Vector4Tests.cs | 189 +- .../System.Runtime.Intrinsics.Tests.csproj | 2 +- .../tests/Vectors/Vector128Tests.cs | 397 +++- .../tests/Vectors/Vector256Tests.cs | 396 +++- .../tests/Vectors/Vector512Tests.cs | 396 +++- .../tests/Vectors/Vector64Tests.cs | 397 +++- .../System.Runtime.Extensions.Tests.csproj | 3 +- .../System/Math.cs | 418 +--- .../System/MathF.cs | 393 +--- .../System.Runtime.Tests.csproj | 1 + .../System/DoubleTests.GenericMath.cs | 369 +--- .../System/DoubleTests.cs | 244 +-- .../System/SingleTests.GenericMath.cs | 369 +--- .../System/SingleTests.cs | 244 +-- 20 files changed, 4449 insertions(+), 2319 deletions(-) create mode 100644 src/libraries/Common/tests/System/GenericMathTestMemberData.cs delete mode 100644 src/libraries/Common/tests/System/Runtime/Intrinsics/VectorTestMemberData.cs diff --git a/src/libraries/Common/tests/System/GenericMathTestMemberData.cs b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs new file mode 100644 index 00000000000000..0ff24e428fb5f7 --- /dev/null +++ b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs @@ -0,0 +1,1687 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using Xunit; + +namespace System.Tests +{ + internal static class GenericMathTestMemberData + { + // binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this + // is slightly too accurate when writing tests meant to run against libm implementations + // for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get. + // + // The tests themselves will take CrossPlatformMachineEpsilon and adjust it according to the expected result + // so that the delta used for comparison will compare the most significant digits and ignore + // any digits that are outside the double precision range (15-17 digits). + // + // For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use + // CrossPlatformMachineEpsilon for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx + // will use CrossPlatformMachineEpsilon / 10 and expected result in the format of x.xxxxxxxxxxxxxxxx will + // use CrossPlatformMachineEpsilon * 10. + internal const double DoubleCrossPlatformMachineEpsilon = 8.8817841970012523e-16; + + // binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this + // is slightly too accurate when writing tests meant to run against libm implementations + // for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get. + // + // The tests themselves will take CrossPlatformMachineEpsilon and adjust it according to the expected result + // so that the delta used for comparison will compare the most significant digits and ignore + // any digits that are outside the single precision range (6-9 digits). + // + // For example, a test with an expect result in the format of 0.xxxxxxxxx will use + // CrossPlatformMachineEpsilon for the variance, while an expected result in the format of 0.0xxxxxxxxx + // will use CrossPlatformMachineEpsilon / 10 and expected result in the format of x.xxxxxx will + // use CrossPlatformMachineEpsilon * 10. + private const float SingleCrossPlatformMachineEpsilon = 4.76837158e-07f; + + internal const double MinNormalDouble = 2.2250738585072014E-308; + internal const float MinNormalSingle = 1.17549435E-38f; + + internal const double MaxSubnormalDouble = 2.2250738585072009E-308; + internal const float MaxSubnormalSingle = 1.17549421E-38f; + + public static IEnumerable ClampDouble + { + get + { + yield return new object[] { double.NegativeInfinity, 1.0f, 63.0f, 1.0f }; + yield return new object[] { double.MinValue, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -1.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -MinNormalDouble, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -MaxSubnormalDouble, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -double.Epsilon, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -0.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { double.NaN, 1.0f, 63.0f, double.NaN }; + yield return new object[] { 0.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { double.Epsilon, 1.0f, 63.0f, 1.0f }; + yield return new object[] { MaxSubnormalDouble, 1.0f, 63.0f, 1.0f }; + yield return new object[] { MinNormalDouble, 1.0f, 63.0f, 1.0f }; + yield return new object[] { 1.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { double.MaxValue, 1.0f, 63.0f, 63.0f }; + yield return new object[] { double.PositiveInfinity, 1.0f, 63.0f, 63.0f }; + } + } + + public static IEnumerable ClampSingle + { + get + { + yield return new object[] { float.NegativeInfinity, 1.0f, 63.0f, 1.0f }; + yield return new object[] { float.MinValue, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -1.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -MinNormalSingle, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -MaxSubnormalSingle, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -float.Epsilon, 1.0f, 63.0f, 1.0f }; + yield return new object[] { -0.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { float.NaN, 1.0f, 63.0f, float.NaN }; + yield return new object[] { 0.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { float.Epsilon, 1.0f, 63.0f, 1.0f }; + yield return new object[] { MaxSubnormalSingle, 1.0f, 63.0f, 1.0f }; + yield return new object[] { MinNormalSingle, 1.0f, 63.0f, 1.0f }; + yield return new object[] { 1.0f, 1.0f, 63.0f, 1.0f }; + yield return new object[] { float.MaxValue, 1.0f, 63.0f, 63.0f }; + yield return new object[] { float.PositiveInfinity, 1.0f, 63.0f, 63.0f }; + } + } + + public static IEnumerable CopySignDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, -3.1415926535897932, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, -0.0, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, 0.0, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, 3.1415926535897932, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { -3.1415926535897932, double.NegativeInfinity, -3.1415926535897932 }; + yield return new object[] { -3.1415926535897932, -3.1415926535897932, -3.1415926535897932 }; + yield return new object[] { -3.1415926535897932, -0.0, -3.1415926535897932 }; + yield return new object[] { -3.1415926535897932, double.NaN, -3.1415926535897932 }; + yield return new object[] { -3.1415926535897932, 0.0, 3.1415926535897932 }; + yield return new object[] { -3.1415926535897932, 3.1415926535897932, 3.1415926535897932 }; + yield return new object[] { -3.1415926535897932, double.PositiveInfinity, 3.1415926535897932 }; + yield return new object[] { -0.0, double.NegativeInfinity, -0.0 }; + yield return new object[] { -0.0, -3.1415926535897932, -0.0 }; + yield return new object[] { -0.0, -0.0, -0.0 }; + yield return new object[] { -0.0, double.NaN, -0.0 }; + yield return new object[] { -0.0, 0.0, 0.0 }; + yield return new object[] { -0.0, 3.1415926535897932, 0.0 }; + yield return new object[] { -0.0, double.PositiveInfinity, 0.0 }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NaN }; + yield return new object[] { double.NaN, -3.1415926535897932, double.NaN }; + yield return new object[] { double.NaN, -0.0, double.NaN }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 0.0, double.NaN }; + yield return new object[] { double.NaN, 3.1415926535897932, double.NaN }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, -0.0 }; + yield return new object[] { 0.0, -3.1415926535897932, -0.0 }; + yield return new object[] { 0.0, -0.0, -0.0 }; + yield return new object[] { 0.0, double.NaN, -0.0 }; + yield return new object[] { 0.0, 0.0, 0.0 }; + yield return new object[] { 0.0, 3.1415926535897932, 0.0 }; + yield return new object[] { 0.0, double.PositiveInfinity, 0.0 }; + yield return new object[] { 3.1415926535897932, double.NegativeInfinity, -3.1415926535897932 }; + yield return new object[] { 3.1415926535897932, -3.1415926535897932, -3.1415926535897932 }; + yield return new object[] { 3.1415926535897932, -0.0, -3.1415926535897932 }; + yield return new object[] { 3.1415926535897932, double.NaN, -3.1415926535897932 }; + yield return new object[] { 3.1415926535897932, 0.0, 3.1415926535897932 }; + yield return new object[] { 3.1415926535897932, 3.1415926535897932, 3.1415926535897932 }; + yield return new object[] { 3.1415926535897932, double.PositiveInfinity, 3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, -3.1415926535897932, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, -0.0, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, 0.0, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, 3.1415926535897932, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity }; + } + } + + public static IEnumerable CopySignSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, -3.14159265f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, 3.14159265f, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { -3.14159265f, float.NegativeInfinity, -3.14159265f }; + yield return new object[] { -3.14159265f, -3.14159265f, -3.14159265f }; + yield return new object[] { -3.14159265f, -0.0f, -3.14159265f }; + yield return new object[] { -3.14159265f, float.NaN, -3.14159265f }; + yield return new object[] { -3.14159265f, 0.0f, 3.14159265f }; + yield return new object[] { -3.14159265f, 3.14159265f, 3.14159265f }; + yield return new object[] { -3.14159265f, float.PositiveInfinity, 3.14159265f }; + yield return new object[] { -0.0f, float.NegativeInfinity, -0.0f }; + yield return new object[] { -0.0f, -3.14159265f, -0.0f }; + yield return new object[] { -0.0f, -0.0f, -0.0f }; + yield return new object[] { -0.0f, float.NaN, -0.0f }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { -0.0f, 3.14159265f, 0.0f }; + yield return new object[] { -0.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NaN }; + yield return new object[] { float.NaN, -3.14159265f, float.NaN }; + yield return new object[] { float.NaN, -0.0f, float.NaN }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 0.0f, float.NaN }; + yield return new object[] { float.NaN, 3.14159265f, float.NaN }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, -0.0f }; + yield return new object[] { 0.0f, -3.14159265f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 0.0f, float.NaN, -0.0f }; + yield return new object[] { 0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, 3.14159265f, 0.0f }; + yield return new object[] { 0.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { 3.14159265f, float.NegativeInfinity, -3.14159265f }; + yield return new object[] { 3.14159265f, -3.14159265f, -3.14159265f }; + yield return new object[] { 3.14159265f, -0.0f, -3.14159265f }; + yield return new object[] { 3.14159265f, float.NaN, -3.14159265f }; + yield return new object[] { 3.14159265f, 0.0f, 3.14159265f }; + yield return new object[] { 3.14159265f, 3.14159265f, 3.14159265f }; + yield return new object[] { 3.14159265f, float.PositiveInfinity, 3.14159265f }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, -3.14159265f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, 3.14159265f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity }; + } + } + + public static IEnumerable DegreesToRadiansDouble + { + get + { + yield return new object[] { double.NaN, double.NaN, 0.0 }; + yield return new object[] { 0.0, 0.0, 0.0 }; + yield return new object[] { 0.31830988618379067, 0.005555555555555556, DoubleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.43429448190325183, 0.007579868632454674, DoubleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.5, 0.008726646259971648, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.63661977236758134, 0.011111111111111112, DoubleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.69314718055994531, 0.01209770050168668, DoubleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.70710678118654752, 0.012341341494884351, DoubleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.78539816339744831, 0.013707783890401885, DoubleCrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { 1.0, 0.017453292519943295, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.1283791670955126, 0.019693931676727953, DoubleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.4142135623730950, 0.024682682989768702, DoubleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.4426950408889634, 0.02517977856570663, DoubleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.5, 0.02617993877991494, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.5707963267948966, 0.02741556778080377, DoubleCrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { 2.0, 0.03490658503988659, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 2.3025850929940457, 0.040187691180085916, DoubleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.5, 0.04363323129985824, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 2.7182818284590452, 0.047442967903742035, DoubleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.0, 0.05235987755982988, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 3.1415926535897932, 0.05483113556160754, DoubleCrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { 3.5, 0.061086523819801536, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; + } + } + + public static IEnumerable DegreesToRadiansSingle + { + get + { + yield return new object[] { float.NaN, float.NaN, 0.0f }; + yield return new object[] { 0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.318309886f, 0.0055555557f, SingleCrossPlatformMachineEpsilon }; // value: (1 / pi) + yield return new object[] { 0.434294482f, 0.007579869f, SingleCrossPlatformMachineEpsilon }; // value: (log10(e)) + yield return new object[] { 0.5f, 0.008726646f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.636619772f, 0.011111111f, SingleCrossPlatformMachineEpsilon }; // value: (2 / pi) + yield return new object[] { 0.693147181f, 0.0120977005f, SingleCrossPlatformMachineEpsilon }; // value: (ln(2)) + yield return new object[] { 0.707106781f, 0.012341342f, SingleCrossPlatformMachineEpsilon }; // value: (1 / sqrt(2)) + yield return new object[] { 0.785398163f, 0.013707785f, SingleCrossPlatformMachineEpsilon }; // value: (pi / 4) + yield return new object[] { 1.0f, 0.017453292f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.12837917f, 0.019693933f, SingleCrossPlatformMachineEpsilon }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.41421356f, 0.024682684f, SingleCrossPlatformMachineEpsilon }; // value: (sqrt(2)) + yield return new object[] { 1.44269504f, 0.025179777f, SingleCrossPlatformMachineEpsilon }; // value: (log2(e)) + yield return new object[] { 1.5f, 0.02617994f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 1.57079633f, 0.02741557f, SingleCrossPlatformMachineEpsilon }; // value: (pi / 2) + yield return new object[] { 2.0f, 0.034906585f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 2.30258509f, 0.040187694f, SingleCrossPlatformMachineEpsilon }; // value: (ln(10)) + yield return new object[] { 2.5f, 0.043633234f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 2.71828183f, 0.047442965f, SingleCrossPlatformMachineEpsilon }; // value: (e) + yield return new object[] { 3.0f, 0.05235988f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 3.14159265f, 0.05483114f, SingleCrossPlatformMachineEpsilon }; // value: (pi) + yield return new object[] { 3.5f, 0.061086528f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; + } + } + + public static IEnumerable ExpDouble + { + get + { + yield return new object[] { double.NegativeInfinity, 0.0, 0.0 }; + yield return new object[] { -3.1415926535897932, 0.043213918263772250, DoubleCrossPlatformMachineEpsilon / 10 }; // value: -(pi) + yield return new object[] { -2.7182818284590452, 0.065988035845312537, DoubleCrossPlatformMachineEpsilon / 10 }; // value: -(e) + yield return new object[] { -2.3025850929940457, 0.1, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.5707963267948966, 0.20787957635076191, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { -1.4426950408889634, 0.23629008834452270, DoubleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.4142135623730950, 0.24311673443421421, DoubleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.1283791670955126, 0.32355726390307110, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0, 0.36787944117144232, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.78539816339744831, 0.45593812776599624, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { -0.70710678118654752, 0.49306869139523979, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.69314718055994531, 0.5, 0.0 }; // value: -(ln(2)) + yield return new object[] { -0.63661977236758134, 0.52907780826773535, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.43429448190325183, 0.64772148514180065, DoubleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.31830988618379067, 0.72737734929521647, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0, 1.0, 0.0 }; + yield return new object[] { double.NaN, double.NaN, 0.0 }; + yield return new object[] { 0.0, 1.0, 0.0 }; + yield return new object[] { 0.31830988618379067, 1.3748022274393586, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (1 / pi) + yield return new object[] { 0.43429448190325183, 1.5438734439711811, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (log10(e)) + yield return new object[] { 0.63661977236758134, 1.8900811645722220, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (2 / pi) + yield return new object[] { 0.69314718055994531, 2.0, 0.0 }; // value: (ln(2)) + yield return new object[] { 0.70710678118654752, 2.0281149816474725, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (1 / sqrt(2)) + yield return new object[] { 0.78539816339744831, 2.1932800507380155, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 4) + yield return new object[] { 1.0, 2.7182818284590452, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (e) + yield return new object[] { 1.1283791670955126, 3.0906430223107976, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.4142135623730950, 4.1132503787829275, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (sqrt(2)) + yield return new object[] { 1.4426950408889634, 4.2320861065570819, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (log2(e)) + yield return new object[] { 1.5707963267948966, 4.8104773809653517, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 2) + yield return new object[] { 2.3025850929940457, 10.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (ln(10)) + yield return new object[] { 2.7182818284590452, 15.154262241479264, DoubleCrossPlatformMachineEpsilon * 100 }; // value: (e) + yield return new object[] { 3.1415926535897932, 23.140692632779269, DoubleCrossPlatformMachineEpsilon * 100 }; // value: (pi) + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; + } + } + + public static IEnumerable ExpSingle + { + get + { + yield return new object[] { float.NegativeInfinity, 0.0f, 0.0f }; + yield return new object[] { -3.14159265f, 0.0432139183f, SingleCrossPlatformMachineEpsilon / 10 }; // value: -(pi) + yield return new object[] { -2.71828183f, 0.0659880358f, SingleCrossPlatformMachineEpsilon / 10 }; // value: -(e) + yield return new object[] { -2.30258509f, 0.1f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(10)) + yield return new object[] { -1.57079633f, 0.207879576f, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 2) + yield return new object[] { -1.44269504f, 0.236290088f, SingleCrossPlatformMachineEpsilon }; // value: -(log2(e)) + yield return new object[] { -1.41421356f, 0.243116734f, SingleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) + yield return new object[] { -1.12837917f, 0.323557264f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) + yield return new object[] { -1.0f, 0.367879441f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { -0.785398163f, 0.455938128f, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 4) + yield return new object[] { -0.707106781f, 0.493068691f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) + yield return new object[] { -0.693147181f, 0.5f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(2)) + yield return new object[] { -0.636619772f, 0.529077808f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / pi) + yield return new object[] { -0.434294482f, 0.647721485f, SingleCrossPlatformMachineEpsilon }; // value: -(log10(e)) + yield return new object[] { -0.318309886f, 0.727377349f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / pi) + yield return new object[] { -0.0f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { float.NaN, float.NaN, 0.0f }; + yield return new object[] { 0.0f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { 0.318309886f, 1.37480223f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (1 / pi) + yield return new object[] { 0.434294482f, 1.54387344f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (log10(e)) + yield return new object[] { 0.636619772f, 1.89008116f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (2 / pi) + yield return new object[] { 0.693147181f, 2.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (ln(2)) + yield return new object[] { 0.707106781f, 2.02811498f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (1 / sqrt(2)) + yield return new object[] { 0.785398163f, 2.19328005f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 4) + yield return new object[] { 1.0f, 2.71828183f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (e) + yield return new object[] { 1.12837917f, 3.09064302f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (2 / sqrt(pi)) + yield return new object[] { 1.41421356f, 4.11325038f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (sqrt(2)) + yield return new object[] { 1.44269504f, 4.23208611f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (log2(e)) + yield return new object[] { 1.57079633f, 4.81047738f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 2) + yield return new object[] { 2.30258509f, 10.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (ln(10)) + yield return new object[] { 2.71828183f, 15.1542622f, SingleCrossPlatformMachineEpsilon * 100 }; // value: (e) + yield return new object[] { 3.14159265f, 23.1406926f, SingleCrossPlatformMachineEpsilon * 100 }; // value: (pi) + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; + } + } + + public static IEnumerable FusedMultiplyAddDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, -0.0, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, -0.0, -3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, -0.0, -0.0 }; + yield return new object[] { double.NegativeInfinity, -0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, 0.0 }; + yield return new object[] { double.NegativeInfinity, -0.0, 3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, -0.0, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, 0.0, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, 0.0, -3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, 0.0, -0.0 }; + yield return new object[] { double.NegativeInfinity, 0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, 0.0 }; + yield return new object[] { double.NegativeInfinity, 0.0, 3.1415926535897932 }; + yield return new object[] { double.NegativeInfinity, 0.0, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] {-1e308, 2.0, 1e308 }; + yield return new object[] {-1e308, 2.0, double.PositiveInfinity }; + yield return new object[] {-5, 4, -3 }; + yield return new object[] {-0.0, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] {-0.0, double.NegativeInfinity, -3.1415926535897932 }; + yield return new object[] {-0.0, double.NegativeInfinity, -0.0 }; + yield return new object[] {-0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] {-0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] {-0.0, double.NegativeInfinity, 3.1415926535897932 }; + yield return new object[] {-0.0, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] {-0.0, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] {-0.0, double.PositiveInfinity, -3.1415926535897932 }; + yield return new object[] {-0.0, double.PositiveInfinity, -0.0 }; + yield return new object[] {-0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] {-0.0, double.PositiveInfinity, 0.0 }; + yield return new object[] {-0.0, double.PositiveInfinity, 3.1415926535897932 }; + yield return new object[] {-0.0, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { 0.0, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { 0.0, double.NegativeInfinity, -3.1415926535897932 }; + yield return new object[] { 0.0, double.NegativeInfinity, -0.0 }; + yield return new object[] { 0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] { 0.0, double.NegativeInfinity, 3.1415926535897932 }; + yield return new object[] { 0.0, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { 0.0, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] { 0.0, double.PositiveInfinity, -3.1415926535897932 }; + yield return new object[] { 0.0, double.PositiveInfinity, -0.0 }; + yield return new object[] { 0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, 0.0 }; + yield return new object[] { 0.0, double.PositiveInfinity, 3.1415926535897932 }; + yield return new object[] { 0.0, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { 5, 4, 3 }; + yield return new object[] { 1e308, 2.0, -1e308 }; + yield return new object[] { 1e308, 2.0, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, -0.0, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, -0.0, -3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, -0.0, -0.0 }; + yield return new object[] { double.PositiveInfinity, -0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, 0.0 }; + yield return new object[] { double.PositiveInfinity, -0.0, 3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, -0.0, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, 0.0, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, 0.0, -3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, 0.0, -0.0 }; + yield return new object[] { double.PositiveInfinity, 0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, 0.0 }; + yield return new object[] { double.PositiveInfinity, 0.0, 3.1415926535897932 }; + yield return new object[] { double.PositiveInfinity, 0.0, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, double.NegativeInfinity }; + } + } + + public static IEnumerable FusedMultiplyAddSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, -0.0f, -3.14159265f }; + yield return new object[] { float.NegativeInfinity, -0.0f, -0.0f }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, 0.0f }; + yield return new object[] { float.NegativeInfinity, -0.0f, 3.14159265f }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, 0.0f, -3.14159265f }; + yield return new object[] { float.NegativeInfinity, 0.0f, -0.0f }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, 0.0f }; + yield return new object[] { float.NegativeInfinity, 0.0f, 3.14159265f }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { -1e38f, 2.0f, 1e38f }; + yield return new object[] { -1e38f, 2.0f, float.PositiveInfinity }; + yield return new object[] { -5, 4, -3 }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, float.NegativeInfinity, -3.14159265f }; + yield return new object[] { -0.0f, float.NegativeInfinity, -0.0f }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { -0.0f, float.NegativeInfinity, 3.14159265f }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, float.PositiveInfinity, -3.14159265f }; + yield return new object[] { -0.0f, float.PositiveInfinity, -0.0f }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { -0.0f, float.PositiveInfinity, 3.14159265f }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 0.0f, float.NegativeInfinity, -3.14159265f }; + yield return new object[] { 0.0f, float.NegativeInfinity, -0.0f }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { 0.0f, float.NegativeInfinity, 3.14159265f }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { 0.0f, float.PositiveInfinity, -3.14159265f }; + yield return new object[] { 0.0f, float.PositiveInfinity, -0.0f }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { 0.0f, float.PositiveInfinity, 3.14159265f }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { 5, 4, 3 }; + yield return new object[] { 1e38f, 2.0f, -1e38f }; + yield return new object[] { 1e38f, 2.0f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, -0.0f, -3.14159265f }; + yield return new object[] { float.PositiveInfinity, -0.0f, -0.0f }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, 0.0f }; + yield return new object[] { float.PositiveInfinity, -0.0f, 3.14159265f }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, 0.0f, -3.14159265f }; + yield return new object[] { float.PositiveInfinity, 0.0f, -0.0f }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, 0.0f }; + yield return new object[] { float.PositiveInfinity, 0.0f, 3.14159265f }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity }; + } + } + + public static IEnumerable HypotDouble + { + get + { + yield return new object[] { double.NaN, double.NaN, double.NaN, 0.0 }; + yield return new object[] { double.NaN, 0.0f, double.NaN, 0.0 }; + yield return new object[] { double.NaN, 1.0f, double.NaN, 0.0 }; + yield return new object[] { double.NaN, 2.7182818284590452, double.NaN, 0.0 }; + yield return new object[] { double.NaN, 10.0, double.NaN, 0.0 }; + yield return new object[] { 0.0, 0.0, 0.0, 0.0 }; + yield return new object[] { 0.0, 1.0, 1.0, 0.0 }; + yield return new object[] { 0.0, 1.5707963267948966, 1.5707963267948966, 0.0 }; + yield return new object[] { 0.0, 2.0, 2.0, 0.0 }; + yield return new object[] { 0.0, 2.7182818284590452, 2.7182818284590452, 0.0 }; + yield return new object[] { 0.0, 3.0, 3.0, 0.0 }; + yield return new object[] { 0.0, 10.0, 10.0, 0.0 }; + yield return new object[] { 1.0, 1.0, 1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { 1.0, 1e+10, 1e+10, 0.0 }; // dotnet/runtime#75651 + yield return new object[] { 1.0, 1e+20, 1e+20, 0.0 }; // dotnet/runtime#75651 + yield return new object[] { 2.7182818284590452, 0.31830988618379067, 2.7368553638387594, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (1 / pi) + yield return new object[] { 2.7182818284590452, 0.43429448190325183, 2.7527563996732919, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (log10(e)) + yield return new object[] { 2.7182818284590452, 0.63661977236758134, 2.7918346715914253, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (2 / pi) + yield return new object[] { 2.7182818284590452, 0.69314718055994531, 2.8052645352709344, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (ln(2)) + yield return new object[] { 2.7182818284590452, 0.70710678118654752, 2.8087463571726533, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (1 / sqrt(2)) + yield return new object[] { 2.7182818284590452, 0.78539816339744831, 2.8294710413783590, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (pi / 4) + yield return new object[] { 2.7182818284590452, 1.0, 2.8963867315900082, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) + yield return new object[] { 2.7182818284590452, 1.1283791670955126, 2.9431778138036127, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (2 / sqrt(pi)) + yield return new object[] { 2.7182818284590452, 1.4142135623730950, 3.0641566701020120, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (sqrt(2)) + yield return new object[] { 2.7182818284590452, 1.4426950408889634, 3.0774055761202907, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (log2(e)) + yield return new object[] { 2.7182818284590452, 1.5707963267948966, 3.1394995141268918, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (pi / 2) + yield return new object[] { 2.7182818284590452, 2.3025850929940457, 3.5624365551415857, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (ln(10)) + yield return new object[] { 2.7182818284590452, 2.7182818284590452, 3.8442310281591168, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (e) + yield return new object[] { 2.7182818284590452, 3.1415926535897932, 4.1543544023133136, DoubleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (pi) + yield return new object[] { 10.0, 0.31830988618379067, 10.005064776584025, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (1 / pi) + yield return new object[] { 10.0, 0.43429448190325183, 10.009426142242702, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (log10(e)) + yield return new object[] { 10.0, 0.63661977236758134, 10.020243746265325, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (2 / pi) + yield return new object[] { 10.0, 0.69314718055994531, 10.023993865417028, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (ln(2)) + yield return new object[] { 10.0, 0.70710678118654752, 10.024968827881711, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (1 / sqrt(2)) + yield return new object[] { 10.0, 0.78539816339744831, 10.030795096853892, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (pi / 4) + yield return new object[] { 10.0, 1.0, 10.049875621120890, DoubleCrossPlatformMachineEpsilon * 100 }; // + yield return new object[] { 10.0, 1.1283791670955126, 10.063460614755501, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (2 / sqrt(pi)) + yield return new object[] { 10.0, 1.4142135623730950, 10.099504938362078, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (sqrt(2)) + yield return new object[] { 10.0, 1.4426950408889634, 10.103532500121213, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (log2(e)) + yield return new object[] { 10.0, 1.5707963267948966, 10.122618292728040, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (pi / 2) + yield return new object[] { 10.0, 2.3025850929940457, 10.261671311754163, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (ln(10)) + yield return new object[] { 10.0, 2.7182818284590452, 10.362869105558106, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (e) + yield return new object[] { 10.0, 3.1415926535897932, 10.481870272097884, DoubleCrossPlatformMachineEpsilon * 100 }; // y: (pi) + yield return new object[] { double.PositiveInfinity, double.NaN, double.PositiveInfinity, 0.0 }; + yield return new object[] { double.PositiveInfinity, 0.0, double.PositiveInfinity, 0.0 }; + yield return new object[] { double.PositiveInfinity, 1.0, double.PositiveInfinity, 0.0 }; + yield return new object[] { double.PositiveInfinity, 2.7182818284590452, double.PositiveInfinity, 0.0 }; + yield return new object[] { double.PositiveInfinity, 10.0, double.PositiveInfinity, 0.0 }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity, 0.0 }; + } + } + + public static IEnumerable HypotSingle + { + get + { + yield return new object[] { float.NaN, float.NaN, float.NaN, 0.0f }; + yield return new object[] { float.NaN, 0.0f, float.NaN, 0.0f }; + yield return new object[] { float.NaN, 1.0f, float.NaN, 0.0f }; + yield return new object[] { float.NaN, 2.71828183f, float.NaN, 0.0f }; + yield return new object[] { float.NaN, 10.0f, float.NaN, 0.0f }; + yield return new object[] { 0.0f, 0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, 1.0f, 1.0f, 0.0f }; + yield return new object[] { 0.0f, 1.57079633f, 1.57079633f, 0.0f }; + yield return new object[] { 0.0f, 2.0f, 2.0f, 0.0f }; + yield return new object[] { 0.0f, 2.71828183f, 2.71828183f, 0.0f }; + yield return new object[] { 0.0f, 3.0f, 3.0f, 0.0f }; + yield return new object[] { 0.0f, 10.0f, 10.0f, 0.0f }; + yield return new object[] { 1.0f, 1.0f, 1.41421356f, SingleCrossPlatformMachineEpsilon * 10 }; + yield return new object[] { 1.0f, 1e+10f, 1e+10f, 0.0 }; // dotnet/runtime#75651 + yield return new object[] { 1.0f, 1e+20f, 1e+20f, 0.0 }; // dotnet/runtime#75651 + yield return new object[] { 2.71828183f, 0.318309886f, 2.73685536f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (1 / pi) + yield return new object[] { 2.71828183f, 0.434294482f, 2.75275640f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (log10(e)) + yield return new object[] { 2.71828183f, 0.636619772f, 2.79183467f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (2 / pi) + yield return new object[] { 2.71828183f, 0.693147181f, 2.80526454f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (ln(2)) + yield return new object[] { 2.71828183f, 0.707106781f, 2.80874636f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (1 / sqrt(2)) + yield return new object[] { 2.71828183f, 0.785398163f, 2.82947104f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (pi / 4) + yield return new object[] { 2.71828183f, 1.0f, 2.89638673f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) + yield return new object[] { 2.71828183f, 1.12837917f, 2.94317781f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (2 / sqrt(pi)) + yield return new object[] { 2.71828183f, 1.41421356f, 3.06415667f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (sqrt(2)) + yield return new object[] { 2.71828183f, 1.44269504f, 3.07740558f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (log2(e)) + yield return new object[] { 2.71828183f, 1.57079633f, 3.13949951f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (pi / 2) + yield return new object[] { 2.71828183f, 2.30258509f, 3.56243656f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (ln(10)) + yield return new object[] { 2.71828183f, 2.71828183f, 3.84423103f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (e) + yield return new object[] { 2.71828183f, 3.14159265f, 4.15435440f, SingleCrossPlatformMachineEpsilon * 10 }; // x: (e) y: (pi) + yield return new object[] { 10.0f, 0.318309886f, 10.0050648f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (1 / pi) + yield return new object[] { 10.0f, 0.434294482f, 10.0094261f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (log10(e)) + yield return new object[] { 10.0f, 0.636619772f, 10.0202437f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (2 / pi) + yield return new object[] { 10.0f, 0.693147181f, 10.0239939f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (ln(2)) + yield return new object[] { 10.0f, 0.707106781f, 10.0249688f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (1 / sqrt(2)) + yield return new object[] { 10.0f, 0.785398163f, 10.0307951f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (pi / 4) + yield return new object[] { 10.0f, 1.0f, 10.0498756f, SingleCrossPlatformMachineEpsilon * 100 }; // + yield return new object[] { 10.0f, 1.12837917f, 10.0634606f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (2 / sqrt(pi)) + yield return new object[] { 10.0f, 1.41421356f, 10.0995049f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (sqrt(2)) + yield return new object[] { 10.0f, 1.44269504f, 10.1035325f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (log2(e)) + yield return new object[] { 10.0f, 1.57079633f, 10.1226183f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (pi / 2) + yield return new object[] { 10.0f, 2.30258509f, 10.2616713f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (ln(10)) + yield return new object[] { 10.0f, 2.71828183f, 10.3628691f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (e) + yield return new object[] { 10.0f, 3.14159265f, 10.4818703f, SingleCrossPlatformMachineEpsilon * 100 }; // y: (pi) + yield return new object[] { float.PositiveInfinity, float.NaN, float.PositiveInfinity, 0.0f }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { float.PositiveInfinity, 1.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { float.PositiveInfinity, 2.71828183f, float.PositiveInfinity, 0.0f }; + yield return new object[] { float.PositiveInfinity, 10.0f, float.PositiveInfinity, 0.0f }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 0.0f }; + } + } + + public static IEnumerable IsNaNDouble + { + get + { + yield return new object[] { double.NegativeInfinity, false }; + yield return new object[] { double.MinValue, false }; + yield return new object[] { -MinNormalDouble, false }; + yield return new object[] { -MaxSubnormalDouble, false }; + yield return new object[] { -double.Epsilon, false }; + yield return new object[] { -0.0, false }; + yield return new object[] { double.NaN, true }; + yield return new object[] { 0.0, false }; + yield return new object[] { double.Epsilon, false }; + yield return new object[] { MaxSubnormalDouble, false }; + yield return new object[] { MinNormalDouble, false }; + yield return new object[] { double.MaxValue, false }; + yield return new object[] { double.PositiveInfinity, false }; + } + } + + public static IEnumerable IsNaNSingle + { + get + { + yield return new object[] { float.NegativeInfinity, false }; + yield return new object[] { float.MinValue, false }; + yield return new object[] { -MinNormalSingle, false }; + yield return new object[] { -MaxSubnormalSingle, false }; + yield return new object[] { -float.Epsilon, false }; + yield return new object[] { -0.0f, false }; + yield return new object[] { float.NaN, true }; + yield return new object[] { 0.0f, false }; + yield return new object[] { float.Epsilon, false }; + yield return new object[] { MaxSubnormalSingle, false }; + yield return new object[] { MinNormalSingle, false }; + yield return new object[] { float.MaxValue, false }; + yield return new object[] { float.PositiveInfinity, false }; + } + } + + public static IEnumerable IsNegativeDouble + { + get + { + yield return new object[] { double.NegativeInfinity, true }; + yield return new object[] { double.MinValue, true }; + yield return new object[] { -MinNormalDouble, true }; + yield return new object[] { -MaxSubnormalDouble, true }; + yield return new object[] { -0.0, true }; + yield return new object[] { double.NaN, true }; + yield return new object[] { 0.0, false }; + yield return new object[] { MaxSubnormalDouble, false }; + yield return new object[] { MinNormalDouble, false }; + yield return new object[] { double.MaxValue, false }; + yield return new object[] { double.PositiveInfinity, false }; + } + } + + public static IEnumerable IsNegativeSingle + { + get + { + yield return new object[] { float.NegativeInfinity, true }; + yield return new object[] { float.MinValue, true }; + yield return new object[] { -MinNormalSingle, true }; + yield return new object[] { -MaxSubnormalSingle, true }; + yield return new object[] { -0.0f, true }; + yield return new object[] { float.NaN, true }; + yield return new object[] { 0.0f, false }; + yield return new object[] { MaxSubnormalSingle, false }; + yield return new object[] { MinNormalSingle, false }; + yield return new object[] { float.MaxValue, false }; + yield return new object[] { float.PositiveInfinity, false }; + } + } + + public static IEnumerable IsPositiveDouble + { + get + { + yield return new object[] { double.NegativeInfinity, false }; + yield return new object[] { double.MinValue, false }; + yield return new object[] { -MinNormalDouble, false }; + yield return new object[] { -MaxSubnormalDouble, false }; + yield return new object[] { -0.0, false }; + yield return new object[] { double.NaN, false }; + yield return new object[] { 0.0, true }; + yield return new object[] { MaxSubnormalDouble, true }; + yield return new object[] { MinNormalDouble, true }; + yield return new object[] { double.MaxValue, true }; + yield return new object[] { double.PositiveInfinity, true }; + } + } + + public static IEnumerable IsPositiveSingle + { + get + { + yield return new object[] { float.NegativeInfinity, false }; + yield return new object[] { float.MinValue, false }; + yield return new object[] { -MinNormalSingle, false }; + yield return new object[] { -MaxSubnormalSingle, false }; + yield return new object[] { -0.0f, false }; + yield return new object[] { float.NaN, false }; + yield return new object[] { 0.0f, true }; + yield return new object[] { MaxSubnormalSingle, true }; + yield return new object[] { MinNormalSingle, true }; + yield return new object[] { float.MaxValue, true }; + yield return new object[] { float.PositiveInfinity, true }; + } + } + + public static IEnumerable IsPositiveInfinityDouble + { + get + { + yield return new object[] { double.NegativeInfinity, false }; + yield return new object[] { double.MinValue, false }; + yield return new object[] { -MinNormalDouble, false }; + yield return new object[] { -MaxSubnormalDouble, false }; + yield return new object[] { -double.Epsilon, false }; + yield return new object[] { -0.0, false }; + yield return new object[] { double.NaN, false }; + yield return new object[] { 0.0, false }; + yield return new object[] { double.Epsilon, false }; + yield return new object[] { MaxSubnormalDouble, false }; + yield return new object[] { MinNormalDouble, false }; + yield return new object[] { double.MaxValue, false }; + yield return new object[] { double.PositiveInfinity, true }; + } + } + + public static IEnumerable IsPositiveInfinitySingle + { + get + { + yield return new object[] { float.NegativeInfinity, false }; + yield return new object[] { float.MinValue, false }; + yield return new object[] { -MinNormalSingle, false }; + yield return new object[] { -MaxSubnormalSingle, false }; + yield return new object[] { -float.Epsilon, false }; + yield return new object[] { -0.0f, false }; + yield return new object[] { float.NaN, false }; + yield return new object[] { 0.0f, false }; + yield return new object[] { float.Epsilon, false }; + yield return new object[] { MaxSubnormalSingle, false }; + yield return new object[] { MinNormalSingle, false }; + yield return new object[] { float.MaxValue, false }; + yield return new object[] { float.PositiveInfinity, true }; + } + } + + public static IEnumerable IsZeroDouble + { + get + { + yield return new object[] { double.NegativeInfinity, false }; + yield return new object[] { double.MinValue, false }; + yield return new object[] { -MinNormalDouble, false }; + yield return new object[] { -MaxSubnormalDouble, false }; + yield return new object[] { -double.Epsilon, false }; + yield return new object[] { -0.0, true }; + yield return new object[] { double.NaN, false }; + yield return new object[] { 0.0, true }; + yield return new object[] { double.Epsilon, false }; + yield return new object[] { MaxSubnormalDouble, false }; + yield return new object[] { MinNormalDouble, false }; + yield return new object[] { double.MaxValue, false }; + yield return new object[] { double.PositiveInfinity, false }; + } + } + + public static IEnumerable IsZeroSingle + { + get + { + yield return new object[] { float.NegativeInfinity, false }; + yield return new object[] { float.MinValue, false }; + yield return new object[] { -MinNormalSingle, false }; + yield return new object[] { -MaxSubnormalSingle, false }; + yield return new object[] { -float.Epsilon, false }; + yield return new object[] { -0.0f, true }; + yield return new object[] { float.NaN, false }; + yield return new object[] { 0.0f, true }; + yield return new object[] { float.Epsilon, false }; + yield return new object[] { MaxSubnormalSingle, false }; + yield return new object[] { MinNormalSingle, false }; + yield return new object[] { float.MaxValue, false }; + yield return new object[] { float.PositiveInfinity, false }; + } + } + + public static IEnumerable LerpDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NegativeInfinity, 0.5, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, double.NaN, 0.5, double.NaN }; + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, 0.5, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, 0.5, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, 1.0, 0.5, double.NegativeInfinity }; + yield return new object[] { double.NaN, double.NegativeInfinity, 0.5, double.NaN }; + yield return new object[] { double.NaN, double.NaN, 0.5, double.NaN }; + yield return new object[] { double.NaN, double.PositiveInfinity, 0.5, double.NaN }; + yield return new object[] { double.NaN, 0.0, 0.5, double.NaN }; + yield return new object[] { double.NaN, 1.0, 0.5, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, 0.5, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.NaN, 0.5, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.5, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, 0.0, 0.5, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, 1.0, 0.5, double.PositiveInfinity }; + yield return new object[] { 1.0, 3.0, 0.0, 1.0 }; + yield return new object[] { 1.0, 3.0, 0.5, 2.0 }; + yield return new object[] { 1.0, 3.0, 1.0, 3.0 }; + yield return new object[] { 1.0, 3.0, 2.0, 5.0 }; + yield return new object[] { 2.0, 4.0, 0.0, 2.0 }; + yield return new object[] { 2.0, 4.0, 0.5, 3.0 }; + yield return new object[] { 2.0, 4.0, 1.0, 4.0 }; + yield return new object[] { 2.0, 4.0, 2.0, 6.0 }; + yield return new object[] { 3.0, 1.0, 0.0, 3.0 }; + yield return new object[] { 3.0, 1.0, 0.5, 2.0 }; + yield return new object[] { 3.0, 1.0, 1.0, 1.0 }; + yield return new object[] { 3.0, 1.0, 2.0, -1.0 }; + yield return new object[] { 4.0, 2.0, 0.0, 4.0 }; + yield return new object[] { 4.0, 2.0, 0.5, 3.0 }; + yield return new object[] { 4.0, 2.0, 1.0, 2.0 }; + yield return new object[] { 4.0, 2.0, 2.0, 0.0 }; + } + } + + public static IEnumerable LerpSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, 0.5f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, float.NaN, 0.5f, float.NaN }; + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, 0.5f, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, 0.5f, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, 1.0f, 0.5f, float.NegativeInfinity }; + yield return new object[] { float.NaN, float.NegativeInfinity, 0.5f, float.NaN }; + yield return new object[] { float.NaN, float.NaN, 0.5f, float.NaN }; + yield return new object[] { float.NaN, float.PositiveInfinity, 0.5f, float.NaN }; + yield return new object[] { float.NaN, 0.0f, 0.5f, float.NaN }; + yield return new object[] { float.NaN, 1.0f, 0.5f, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, 0.5f, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.NaN, 0.5f, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.5f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, 0.0f, 0.5f, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, 1.0f, 0.5f, float.PositiveInfinity }; + yield return new object[] { 1.0f, 3.0f, 0.0f, 1.0f }; + yield return new object[] { 1.0f, 3.0f, 0.5f, 2.0f }; + yield return new object[] { 1.0f, 3.0f, 1.0f, 3.0f }; + yield return new object[] { 1.0f, 3.0f, 2.0f, 5.0f }; + yield return new object[] { 2.0f, 4.0f, 0.0f, 2.0f }; + yield return new object[] { 2.0f, 4.0f, 0.5f, 3.0f }; + yield return new object[] { 2.0f, 4.0f, 1.0f, 4.0f }; + yield return new object[] { 2.0f, 4.0f, 2.0f, 6.0f }; + yield return new object[] { 3.0f, 1.0f, 0.0f, 3.0f }; + yield return new object[] { 3.0f, 1.0f, 0.5f, 2.0f }; + yield return new object[] { 3.0f, 1.0f, 1.0f, 1.0f }; + yield return new object[] { 3.0f, 1.0f, 2.0f, -1.0f }; + yield return new object[] { 4.0f, 2.0f, 0.0f, 4.0f }; + yield return new object[] { 4.0f, 2.0f, 0.5f, 3.0f }; + yield return new object[] { 4.0f, 2.0f, 1.0f, 2.0f }; + yield return new object[] { 4.0f, 2.0f, 2.0f, 0.0f }; + } + } + + public static IEnumerable LogDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.NaN, 0.0 }; + yield return new object[] { -3.1415926535897932, double.NaN, 0.0 }; // value: -(pi) + yield return new object[] { -2.7182818284590452, double.NaN, 0.0 }; // value: -(e) + yield return new object[] { -1.4142135623730950, double.NaN, 0.0 }; // value: -(sqrt(2)) + yield return new object[] { -1.0, double.NaN, 0.0 }; + yield return new object[] { -0.69314718055994531, double.NaN, 0.0 }; // value: -(ln(2)) + yield return new object[] { -0.43429448190325183, double.NaN, 0.0 }; // value: -(log10(e)) + yield return new object[] { -0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] { double.NaN, double.NaN, 0.0 }; + yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] { 0.043213918263772250, -3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) + yield return new object[] { 0.065988035845312537, -2.7182818284590452, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) + yield return new object[] { 0.1, -2.3025850929940457, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) + yield return new object[] { 0.20787957635076191, -1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) + yield return new object[] { 0.23629008834452270, -1.4426950408889634, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) + yield return new object[] { 0.24311673443421421, -1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) + yield return new object[] { 0.32355726390307110, -1.1283791670955126, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { 0.36787944117144232, -1.0, 0.0f }; + yield return new object[] { 0.45593812776599624, -0.78539816339744831, DoubleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { 0.49306869139523979, -0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { 0.5, -0.69314718055994531, DoubleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { 0.52907780826773535, -0.63661977236758134, DoubleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { 0.64772148514180065, -0.43429448190325183, DoubleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { 0.72737734929521647, -0.31830988618379067, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { 1.0, 0.0, 0.0 }; + yield return new object[] { 1.3748022274393586, 0.31830988618379067, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { 1.5438734439711811, 0.43429448190325183, DoubleCrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { 1.8900811645722220, 0.63661977236758134, DoubleCrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { 2.0, 0.69314718055994531, DoubleCrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { 2.0281149816474725, 0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { 2.1932800507380155, 0.78539816339744831, DoubleCrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { 2.7182818284590452, 1.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (e) + yield return new object[] { 3.0906430223107976, 1.1283791670955126, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { 4.1132503787829275, 1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) + yield return new object[] { 4.2320861065570819, 1.4426950408889634, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) + yield return new object[] { 4.8104773809653517, 1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) + yield return new object[] { 10.0, 2.3025850929940457, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) + yield return new object[] { 15.154262241479264, 2.7182818284590452, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (e) + yield return new object[] { 23.140692632779269, 3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; + } + } + + public static IEnumerable LogSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.NaN, 0.0f }; + yield return new object[] { -3.14159265f, float.NaN, 0.0f }; // value: -(pi) + yield return new object[] { -2.71828183f, float.NaN, 0.0f }; // value: -(e) + yield return new object[] { -1.41421356f, float.NaN, 0.0f }; // value: -(sqrt(2)) + yield return new object[] { -1.0f, float.NaN, 0.0f }; + yield return new object[] { -0.693147181f, float.NaN, 0.0f }; // value: -(ln(2)) + yield return new object[] { -0.434294482f, float.NaN, 0.0f }; // value: -(log10(e)) + yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { float.NaN, float.NaN, 0.0f }; + yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { 0.0432139183f, -3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) + yield return new object[] { 0.0659880358f, -2.71828183f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) + yield return new object[] { 0.1f, -2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) + yield return new object[] { 0.207879576f, -1.57079633f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) + yield return new object[] { 0.236290088f, -1.44269504f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) + yield return new object[] { 0.243116734f, -1.41421356f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) + yield return new object[] { 0.323557264f, -1.12837917f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { 0.367879441f, -1.0f, 0.0f }; + yield return new object[] { 0.455938128f, -0.785398163f, SingleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { 0.493068691f, -0.707106781f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { 0.5f, -0.693147181f, SingleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { 0.529077808f, -0.636619772f, SingleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { 0.647721485f, -0.434294482f, SingleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { 0.727377349f, -0.318309886f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { 1.0f, 0.0f, 0.0f }; + yield return new object[] { 1.37480223f, 0.318309886f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { 1.54387344f, 0.434294482f, SingleCrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { 1.89008116f, 0.636619772f, SingleCrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { 2.0f, 0.693147181f, SingleCrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { 2.02811498f, 0.707106781f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { 2.19328005f, 0.785398163f, SingleCrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { 2.71828183f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (e) + yield return new object[] { 3.09064302f, 1.12837917f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { 4.11325038f, 1.41421356f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) + yield return new object[] { 4.23208611f, 1.44269504f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) + yield return new object[] { 4.81047738f, 1.57079633f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) + yield return new object[] { 10.0f, 2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) + yield return new object[] { 15.1542622f, 2.71828183f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (e) + yield return new object[] { 23.1406926f, 3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; + } + } + + public static IEnumerable Log2Double + { + get + { + yield return new object[] { double.NegativeInfinity, double.NaN, 0.0 }; + yield return new object[] {-0.11331473229676087, double.NaN, 0.0 }; + yield return new object[] {-0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] { double.NaN, double.NaN, 0.0 }; + yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; + yield return new object[] { 0.11331473229676087, -3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) + yield return new object[] { 0.15195522325791297, -2.7182818284590453, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) + yield return new object[] { 0.20269956628651730, -2.3025850929940460, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) + yield return new object[] { 0.33662253682241906, -1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) + yield return new object[] { 0.36787944117144232, -1.4426950408889634, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) + yield return new object[] { 0.37521422724648177, -1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) + yield return new object[] { 0.45742934732229695, -1.1283791670955126, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { 0.5, -1.0, 0.0f }; + yield return new object[] { 0.58019181037172444, -0.78539816339744840, DoubleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { 0.61254732653606592, -0.70710678118654750, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { 0.61850313780157598, -0.69314718055994537, DoubleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { 0.64321824193300488, -0.63661977236758126, DoubleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { 0.74005557395545179, -0.43429448190325190, DoubleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { 0.80200887896145195, -0.31830988618379073, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { 1, 0.0, 0.0 }; + yield return new object[] { 1.2468689889006383, 0.31830988618379073, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { 1.3512498725672678, 0.43429448190325226, DoubleCrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { 1.5546822754821001, 0.63661977236758126, DoubleCrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { 1.6168066722416747, 0.69314718055994537, DoubleCrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { 1.6325269194381528, 0.70710678118654750, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { 1.7235679341273495, 0.78539816339744830, DoubleCrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { 2, 1.0, 0.0 }; // value: (e) + yield return new object[] { 2.1861299583286618, 1.1283791670955128, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { 2.6651441426902252, 1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) + yield return new object[] { 2.7182818284590452, 1.4426950408889632, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) + yield return new object[] { 2.9706864235520193, 1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) + yield return new object[] { 4.9334096679145963, 2.3025850929940460, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) + yield return new object[] { 6.5808859910179210, 2.7182818284590455, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (e) + yield return new object[] { 8.8249778270762876, 3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; + } + } + + public static IEnumerable Log2Single + { + get + { + yield return new object[] { float.NegativeInfinity, float.NaN, 0.0f }; + yield return new object[] { -0.113314732f, float.NaN, 0.0f }; + yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { float.NaN, float.NaN, 0.0f }; + yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; + yield return new object[] { 0.113314732f, -3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) + yield return new object[] { 0.151955223f, -2.71828200f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) + yield return new object[] { 0.202699566f, -2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) + yield return new object[] { 0.336622537f, -1.57079630f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) + yield return new object[] { 0.367879441f, -1.44269500f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) + yield return new object[] { 0.375214227f, -1.41421360f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) + yield return new object[] { 0.457429347f, -1.12837910f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) + yield return new object[] { 0.5f, -1.0f, 0.0f }; + yield return new object[] { 0.580191810f, -0.785398211f, SingleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) + yield return new object[] { 0.612547327f, -0.707106700f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) + yield return new object[] { 0.618503138f, -0.693147144f, SingleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) + yield return new object[] { 0.643218242f, -0.636619823f, SingleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) + yield return new object[] { 0.740055574f, -0.434294550f, SingleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) + yield return new object[] { 0.802008879f, -0.318309900f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) + yield return new object[] { 1, 0.0f, 0.0f }; + yield return new object[] { 1.24686899f, 0.318309870f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { 1.35124987f, 0.434294340f, SingleCrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { 1.55468228f, 0.636619823f, SingleCrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { 1.61680667f, 0.693147144f, SingleCrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { 1.63252692f, 0.707106700f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { 1.72356793f, 0.785398211f, SingleCrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { 2, 1.0f, 0.0f }; // value: (e) + yield return new object[] { 2.18612996f, 1.12837920f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) + yield return new object[] { 2.66514414f, 1.41421360f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) + yield return new object[] { 2.71828183f, 1.44269490f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) + yield return new object[] { 2.97068642f, 1.57079630f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) + yield return new object[] { 4.93340967f, 2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) + yield return new object[] { 6.58088599f, 2.71828170f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (e) + yield return new object[] { 8.82497783f, 3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; + } + } + + public static IEnumerable MaxDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MaxValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MaxValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, double.NaN }; + yield return new object[] { 1.0f, double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NaN }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MaxSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MaxValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MaxValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, float.NaN }; + yield return new object[] { 1.0f, float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MaxMagnitudeDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MaxValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MaxValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, double.NaN }; + yield return new object[] { 1.0f, double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NaN }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MaxMagnitudeSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MaxValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MaxValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, float.NaN }; + yield return new object[] { 1.0f, float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MaxMagnitudeNumberDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MaxValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MaxValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, double.NaN, 1.0f }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NegativeInfinity }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MaxMagnitudeNumberSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MaxValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MaxValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, float.NaN, 1.0f }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NegativeInfinity }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MaxNumberDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MaxValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MaxValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, double.NaN, 1.0f }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NegativeInfinity }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MaxNumberSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MaxValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MaxValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, float.NaN, 1.0f }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NegativeInfinity }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, 0.0f }; + yield return new object[] { 0.0f, -0.0f, 0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, 3.0f }; + yield return new object[] { -2.0f, 3.0f, 3.0f }; + } + } + + public static IEnumerable MinDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MinValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MinValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, double.NaN }; + yield return new object[] { 1.0f, double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NaN }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable MinSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MinValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MinValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, float.NaN }; + yield return new object[] { 1.0f, float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable MinMagnitudeDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MinValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MinValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, double.NaN }; + yield return new object[] { 1.0f, double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NaN }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NaN }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable MinMagnitudeSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MinValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MinValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, float.NaN }; + yield return new object[] { 1.0f, float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NaN }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable MinMagnitudeNumberDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MinValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MinValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, double.NaN, 1.0f }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NegativeInfinity }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable MinMagnitudeNumberSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MinValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MinValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, float.NaN, 1.0f }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NegativeInfinity }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, 2.0f }; + yield return new object[] { -3.0f, 2.0f, 2.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable MinNumberDouble + { + get + { + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.MinValue, double.MaxValue, double.MinValue }; + yield return new object[] { double.MaxValue, double.MinValue, double.MinValue }; + yield return new object[] { double.NaN, double.NaN, double.NaN }; + yield return new object[] { double.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, double.NaN, 1.0f }; + yield return new object[] { double.PositiveInfinity, double.NaN, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.NaN, double.NegativeInfinity }; + yield return new object[] { double.NaN, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.NaN, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable MinNumberSingle + { + get + { + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.MinValue, float.MaxValue, float.MinValue }; + yield return new object[] { float.MaxValue, float.MinValue, float.MinValue }; + yield return new object[] { float.NaN, float.NaN, float.NaN }; + yield return new object[] { float.NaN, 1.0f, 1.0f }; + yield return new object[] { 1.0f, float.NaN, 1.0f }; + yield return new object[] { float.PositiveInfinity, float.NaN, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NaN, float.NegativeInfinity }; + yield return new object[] { float.NaN, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NaN, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { -0.0f, 0.0f, -0.0f }; + yield return new object[] { 0.0f, -0.0f, -0.0f }; + yield return new object[] { 2.0f, -3.0f, -3.0f }; + yield return new object[] { -3.0f, 2.0f, -3.0f }; + yield return new object[] { 3.0f, -2.0f, -2.0f }; + yield return new object[] { -2.0f, 3.0f, -2.0f }; + } + } + + public static IEnumerable RadiansToDegreesDouble + { + get + { + yield return new object[] { double.NaN, double.NaN, 0.0 }; + yield return new object[] { 0.0, 0.0, 0.0 }; + yield return new object[] { 0.0055555555555555567, 0.3183098861837906, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { 0.0075798686324546743, 0.4342944819032518, DoubleCrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { 0.008726646259971648, 0.5, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.0111111111111111124, 0.6366197723675813, DoubleCrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { 0.0120977005016866801, 0.6931471805599453, DoubleCrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { 0.0123413414948843512, 0.7071067811865475, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { 0.0137077838904018851, 0.7853981633974483, DoubleCrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { 0.017453292519943295, 1.0, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.019693931676727953, 1.1283791670955126, DoubleCrossPlatformMachineEpsilon }; // expected: (2 / sqrt(pi)) + yield return new object[] { 0.024682682989768702, 1.4142135623730950, DoubleCrossPlatformMachineEpsilon }; // expected: (sqrt(2)) + yield return new object[] { 0.025179778565706630, 1.4426950408889634, DoubleCrossPlatformMachineEpsilon }; // expected: (log2(e)) + yield return new object[] { 0.026179938779914940, 1.5, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.027415567780803770, 1.5707963267948966, DoubleCrossPlatformMachineEpsilon }; // expected: (pi / 2) + yield return new object[] { 0.034906585039886590, 2.0, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.040187691180085916, 2.3025850929940457, DoubleCrossPlatformMachineEpsilon }; // expected: (ln(10)) + yield return new object[] { 0.043633231299858240, 2.5, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.047442967903742035, 2.7182818284590452, DoubleCrossPlatformMachineEpsilon }; // expected: (e) + yield return new object[] { 0.052359877559829880, 3.0, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.054831135561607540, 3.1415926535897932, DoubleCrossPlatformMachineEpsilon }; // expected: (pi) + yield return new object[] { 0.061086523819801536, 3.5, DoubleCrossPlatformMachineEpsilon }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; + } + } + + public static IEnumerable RadiansToDegreesSingle + { + get + { + yield return new object[] { float.NaN, float.NaN, 0.0 }; + yield return new object[] { 0.0f, 0.0f, 0.0 }; + yield return new object[] { 0.0055555557f, 0.318309886f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / pi) + yield return new object[] { 0.007579869f, 0.434294482f, SingleCrossPlatformMachineEpsilon }; // expected: (log10(e)) + yield return new object[] { 0.008726646f, 0.5f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.011111111f, 0.636619772f, SingleCrossPlatformMachineEpsilon }; // expected: (2 / pi) + yield return new object[] { 0.0120977005f, 0.693147181f, SingleCrossPlatformMachineEpsilon }; // expected: (ln(2)) + yield return new object[] { 0.012341342f, 0.707106781f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) + yield return new object[] { 0.013707785f, 0.785398163f, SingleCrossPlatformMachineEpsilon }; // expected: (pi / 4) + yield return new object[] { 0.017453292f, 1.0f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.019693933f, 1.12837917f, SingleCrossPlatformMachineEpsilon }; // expected: (2 / sqrt(pi)) + yield return new object[] { 0.024682684f, 1.41421356f, SingleCrossPlatformMachineEpsilon }; // expected: (sqrt(2)) + yield return new object[] { 0.025179777f, 1.44269504f, SingleCrossPlatformMachineEpsilon }; // expected: (log2(e)) + yield return new object[] { 0.02617994f, 1.5f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.02741557f, 1.57079633f, SingleCrossPlatformMachineEpsilon }; // expected: (pi / 2) + yield return new object[] { 0.034906585f, 2.0f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.040187694f, 2.30258509f, SingleCrossPlatformMachineEpsilon }; // expected: (ln(10)) + yield return new object[] { 0.043633234f, 2.5f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.047442965f, 2.71828183f, SingleCrossPlatformMachineEpsilon }; // expected: (e) + yield return new object[] { 0.05235988f, 3.0f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { 0.05483114f, 3.14159265f, SingleCrossPlatformMachineEpsilon }; // expected: (pi) + yield return new object[] { 0.061086528f, 3.5f, SingleCrossPlatformMachineEpsilon }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0 }; + } + } + + public static IEnumerable RoundDouble + { + get + { + yield return new object[] { 0.0, 0.0 }; + yield return new object[] { 1.4, 1.0 }; + yield return new object[] { 1.5, 2.0 }; + yield return new object[] { 2e7, 2e7 }; + yield return new object[] { -0.0, 0.0 }; + yield return new object[] { -1.4, -1.0 }; + yield return new object[] { -1.5, -2.0 }; + yield return new object[] { -2e7, -2e7 }; + } + } + + public static IEnumerable RoundSingle + { + get + { + yield return new object[] { 0.0f, 0.0f }; + yield return new object[] { 1.4f, 1.0f }; + yield return new object[] { 1.5f, 2.0f }; + yield return new object[] { 2e7f, 2e7f }; + yield return new object[] { -0.0f, 0.0f }; + yield return new object[] { -1.4f, -1.0f }; + yield return new object[] { -1.5f, -2.0f }; + yield return new object[] { -2e7f, -2e7f }; + } + } + + public static IEnumerable RoundAwayFromZeroDouble + { + get + { + yield return new object[] { 1, 1 }; + yield return new object[] { 0.5, 1 }; + yield return new object[] { 1.5, 2 }; + yield return new object[] { 2.5, 3 }; + yield return new object[] { 3.5, 4 }; + yield return new object[] { 0.49999999999999994, 0 }; + yield return new object[] { 1.5, 2 }; + yield return new object[] { 2.5, 3 }; + yield return new object[] { 3.5, 4 }; + yield return new object[] { 4.5, 5 }; + yield return new object[] { 3.141592653589793, 3 }; + yield return new object[] { 2.718281828459045, 3 }; + yield return new object[] { 1385.4557313670111, 1385 }; + yield return new object[] { 3423423.43432, 3423423 }; + yield return new object[] { 535345.5, 535346 }; + yield return new object[] { 535345.50001, 535346 }; + yield return new object[] { 535345.5, 535346 }; + yield return new object[] { 535345.4, 535345 }; + yield return new object[] { 535345.6, 535346 }; + yield return new object[] { -2.718281828459045, -3 }; + yield return new object[] { 10, 10 }; + yield return new object[] { -10, -10 }; + yield return new object[] { -0, -0 }; + yield return new object[] { 0, 0 }; + yield return new object[] { double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { 1.7976931348623157E+308, 1.7976931348623157E+308 }; + yield return new object[] { -1.7976931348623157E+308, -1.7976931348623157E+308 }; + } + } + + public static IEnumerable RoundAwayFromZeroSingle + { + get + { + yield return new object[] { 1f, 1f }; + yield return new object[] { 0.5f, 1f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 3f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 0.49999997f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 3f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 4.5f, 5f }; + yield return new object[] { 3.1415927f, 3f }; + yield return new object[] { 2.7182817f, 3f }; + yield return new object[] { 1385.4557f, 1385f }; + yield return new object[] { 3423.4343f, 3423f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.4f, 535345f }; + yield return new object[] { 535345.6f, 535346f }; + yield return new object[] { -2.7182817f, -3f }; + yield return new object[] { 10f, 10f }; + yield return new object[] { -10f, -10f }; + yield return new object[] { -0f, -0f }; + yield return new object[] { 0f, 0f }; + yield return new object[] { float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; + yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; + } + } + + public static IEnumerable RoundToEvenDouble + { + get + { + yield return new object[] { 1, 1 }; + yield return new object[] { 0.5, 0 }; + yield return new object[] { 1.5, 2 }; + yield return new object[] { 2.5, 2 }; + yield return new object[] { 3.5, 4 }; + + // Math.Round(var = 0.49999999999999994) returns 1 on ARM32 + if (!PlatformDetection.IsArmProcess) + yield return new object[] { 0.49999999999999994, 0 }; + + yield return new object[] { 1.5, 2 }; + yield return new object[] { 2.5, 2 }; + yield return new object[] { 3.5, 4 }; + yield return new object[] { 4.5, 4 }; + yield return new object[] { 3.141592653589793, 3 }; + yield return new object[] { 2.718281828459045, 3 }; + yield return new object[] { 1385.4557313670111, 1385 }; + yield return new object[] { 3423423.43432, 3423423 }; + yield return new object[] { 535345.5, 535346 }; + yield return new object[] { 535345.50001, 535346 }; + yield return new object[] { 535345.5, 535346 }; + yield return new object[] { 535345.4, 535345 }; + yield return new object[] { 535345.6, 535346 }; + yield return new object[] { -2.718281828459045, -3 }; + yield return new object[] { 10, 10 }; + yield return new object[] { -10, -10 }; + yield return new object[] { -0, -0 }; + yield return new object[] { 0, 0 }; + yield return new object[] { double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { 1.7976931348623157E+308, 1.7976931348623157E+308 }; + yield return new object[] { -1.7976931348623157E+308, -1.7976931348623157E+308 }; + } + } + + public static IEnumerable RoundToEvenSingle + { + get + { + yield return new object[] { 1f, 1f }; + yield return new object[] { 0.5f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 2f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 0.49999997f, 0f }; + yield return new object[] { 1.5f, 2f }; + yield return new object[] { 2.5f, 2f }; + yield return new object[] { 3.5f, 4f }; + yield return new object[] { 4.5f, 4f }; + yield return new object[] { 3.1415927f, 3f }; + yield return new object[] { 2.7182817f, 3f }; + yield return new object[] { 1385.4557f, 1385f }; + yield return new object[] { 3423.4343f, 3423f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.5f, 535346f }; + yield return new object[] { 535345.4f, 535345f }; + yield return new object[] { 535345.6f, 535346f }; + yield return new object[] { -2.7182817f, -3f }; + yield return new object[] { 10f, 10f }; + yield return new object[] { -10f, -10f }; + yield return new object[] { -0f, -0f }; + yield return new object[] { 0f, 0f }; + yield return new object[] { float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; + yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; + } + } + + public static IEnumerable TruncateDouble + { + get + { + yield return new object[] { 0.12345, 0.0f }; + yield return new object[] { 3.14159, 3.0f }; + yield return new object[] { -3.14159, -3.0f }; + } + } + + public static IEnumerable TruncateSingle + { + get + { + yield return new object[] { 0.12345f, 0.0f }; + yield return new object[] { 3.14159f, 3.0f }; + yield return new object[] { -3.14159f, -3.0f }; + } + } + } +} diff --git a/src/libraries/Common/tests/System/Runtime/Intrinsics/VectorTestMemberData.cs b/src/libraries/Common/tests/System/Runtime/Intrinsics/VectorTestMemberData.cs deleted file mode 100644 index ab2381a97967e6..00000000000000 --- a/src/libraries/Common/tests/System/Runtime/Intrinsics/VectorTestMemberData.cs +++ /dev/null @@ -1,442 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -using System.Collections.Generic; - -namespace System.Runtime.Intrinsics.Tests.Vectors -{ - internal static class VectorTestMemberData - { - // binary64 (double) has a machine epsilon of 2^-52 (approx. 2.22e-16). However, this - // is slightly too accurate when writing tests meant to run against libm implementations - // for various platforms. 2^-50 (approx. 8.88e-16) seems to be as accurate as we can get. - // - // The tests themselves will take CrossPlatformMachineEpsilon and adjust it according to the expected result - // so that the delta used for comparison will compare the most significant digits and ignore - // any digits that are outside the double precision range (15-17 digits). - // - // For example, a test with an expect result in the format of 0.xxxxxxxxxxxxxxxxx will use - // CrossPlatformMachineEpsilon for the variance, while an expected result in the format of 0.0xxxxxxxxxxxxxxxxx - // will use CrossPlatformMachineEpsilon / 10 and expected result in the format of x.xxxxxxxxxxxxxxxx will - // use CrossPlatformMachineEpsilon * 10. - internal const double DoubleCrossPlatformMachineEpsilon = 8.8817841970012523e-16; - - // binary32 (float) has a machine epsilon of 2^-23 (approx. 1.19e-07). However, this - // is slightly too accurate when writing tests meant to run against libm implementations - // for various platforms. 2^-21 (approx. 4.76e-07) seems to be as accurate as we can get. - // - // The tests themselves will take CrossPlatformMachineEpsilon and adjust it according to the expected result - // so that the delta used for comparison will compare the most significant digits and ignore - // any digits that are outside the single precision range (6-9 digits). - // - // For example, a test with an expect result in the format of 0.xxxxxxxxx will use - // CrossPlatformMachineEpsilon for the variance, while an expected result in the format of 0.0xxxxxxxxx - // will use CrossPlatformMachineEpsilon / 10 and expected result in the format of x.xxxxxx will - // use CrossPlatformMachineEpsilon * 10. - private const float SingleCrossPlatformMachineEpsilon = 4.76837158e-07f; - - public static IEnumerable ExpDouble - { - get - { - yield return new object[] { double.NegativeInfinity, 0.0, 0.0 }; - yield return new object[] { -3.1415926535897932, 0.043213918263772250, DoubleCrossPlatformMachineEpsilon / 10 }; // value: -(pi) - yield return new object[] { -2.7182818284590452, 0.065988035845312537, DoubleCrossPlatformMachineEpsilon / 10 }; // value: -(e) - yield return new object[] { -2.3025850929940457, 0.1, DoubleCrossPlatformMachineEpsilon }; // value: -(ln(10)) - yield return new object[] { -1.5707963267948966, 0.20787957635076191, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 2) - yield return new object[] { -1.4426950408889634, 0.23629008834452270, DoubleCrossPlatformMachineEpsilon }; // value: -(log2(e)) - yield return new object[] { -1.4142135623730950, 0.24311673443421421, DoubleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) - yield return new object[] { -1.1283791670955126, 0.32355726390307110, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) - yield return new object[] { -1.0, 0.36787944117144232, DoubleCrossPlatformMachineEpsilon }; - yield return new object[] { -0.78539816339744831, 0.45593812776599624, DoubleCrossPlatformMachineEpsilon }; // value: -(pi / 4) - yield return new object[] { -0.70710678118654752, 0.49306869139523979, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) - yield return new object[] { -0.69314718055994531, 0.5, 0.0 }; // value: -(ln(2)) - yield return new object[] { -0.63661977236758134, 0.52907780826773535, DoubleCrossPlatformMachineEpsilon }; // value: -(2 / pi) - yield return new object[] { -0.43429448190325183, 0.64772148514180065, DoubleCrossPlatformMachineEpsilon }; // value: -(log10(e)) - yield return new object[] { -0.31830988618379067, 0.72737734929521647, DoubleCrossPlatformMachineEpsilon }; // value: -(1 / pi) - yield return new object[] { -0.0, 1.0, 0.0 }; - yield return new object[] { double.NaN, double.NaN, 0.0 }; - yield return new object[] { 0.0, 1.0, 0.0 }; - yield return new object[] { 0.31830988618379067, 1.3748022274393586, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (1 / pi) - yield return new object[] { 0.43429448190325183, 1.5438734439711811, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (log10(e)) - yield return new object[] { 0.63661977236758134, 1.8900811645722220, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (2 / pi) - yield return new object[] { 0.69314718055994531, 2.0, 0.0 }; // value: (ln(2)) - yield return new object[] { 0.70710678118654752, 2.0281149816474725, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (1 / sqrt(2)) - yield return new object[] { 0.78539816339744831, 2.1932800507380155, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 4) - yield return new object[] { 1.0, 2.7182818284590452, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (e) - yield return new object[] { 1.1283791670955126, 3.0906430223107976, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (2 / sqrt(pi)) - yield return new object[] { 1.4142135623730950, 4.1132503787829275, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (sqrt(2)) - yield return new object[] { 1.4426950408889634, 4.2320861065570819, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (log2(e)) - yield return new object[] { 1.5707963267948966, 4.8104773809653517, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 2) - yield return new object[] { 2.3025850929940457, 10.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (ln(10)) - yield return new object[] { 2.7182818284590452, 15.154262241479264, DoubleCrossPlatformMachineEpsilon * 100 }; // value: (e) - yield return new object[] { 3.1415926535897932, 23.140692632779269, DoubleCrossPlatformMachineEpsilon * 100 }; // value: (pi) - yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; - } - } - - public static IEnumerable ExpSingle - { - get - { - yield return new object[] { float.NegativeInfinity, 0.0f, 0.0f }; - yield return new object[] { -3.14159265f, 0.0432139183f, SingleCrossPlatformMachineEpsilon / 10 }; // value: -(pi) - yield return new object[] { -2.71828183f, 0.0659880358f, SingleCrossPlatformMachineEpsilon / 10 }; // value: -(e) - yield return new object[] { -2.30258509f, 0.1f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(10)) - yield return new object[] { -1.57079633f, 0.207879576f, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 2) - yield return new object[] { -1.44269504f, 0.236290088f, SingleCrossPlatformMachineEpsilon }; // value: -(log2(e)) - yield return new object[] { -1.41421356f, 0.243116734f, SingleCrossPlatformMachineEpsilon }; // value: -(sqrt(2)) - yield return new object[] { -1.12837917f, 0.323557264f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / sqrt(pi)) - yield return new object[] { -1.0f, 0.367879441f, SingleCrossPlatformMachineEpsilon }; - yield return new object[] { -0.785398163f, 0.455938128f, SingleCrossPlatformMachineEpsilon }; // value: -(pi / 4) - yield return new object[] { -0.707106781f, 0.493068691f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / sqrt(2)) - yield return new object[] { -0.693147181f, 0.5f, SingleCrossPlatformMachineEpsilon }; // value: -(ln(2)) - yield return new object[] { -0.636619772f, 0.529077808f, SingleCrossPlatformMachineEpsilon }; // value: -(2 / pi) - yield return new object[] { -0.434294482f, 0.647721485f, SingleCrossPlatformMachineEpsilon }; // value: -(log10(e)) - yield return new object[] { -0.318309886f, 0.727377349f, SingleCrossPlatformMachineEpsilon }; // value: -(1 / pi) - yield return new object[] { -0.0f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; - yield return new object[] { float.NaN, float.NaN, 0.0f }; - yield return new object[] { 0.0f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; - yield return new object[] { 0.318309886f, 1.37480223f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (1 / pi) - yield return new object[] { 0.434294482f, 1.54387344f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (log10(e)) - yield return new object[] { 0.636619772f, 1.89008116f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (2 / pi) - yield return new object[] { 0.693147181f, 2.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (ln(2)) - yield return new object[] { 0.707106781f, 2.02811498f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (1 / sqrt(2)) - yield return new object[] { 0.785398163f, 2.19328005f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 4) - yield return new object[] { 1.0f, 2.71828183f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (e) - yield return new object[] { 1.12837917f, 3.09064302f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (2 / sqrt(pi)) - yield return new object[] { 1.41421356f, 4.11325038f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (sqrt(2)) - yield return new object[] { 1.44269504f, 4.23208611f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (log2(e)) - yield return new object[] { 1.57079633f, 4.81047738f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (pi / 2) - yield return new object[] { 2.30258509f, 10.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (ln(10)) - yield return new object[] { 2.71828183f, 15.1542622f, SingleCrossPlatformMachineEpsilon * 100 }; // value: (e) - yield return new object[] { 3.14159265f, 23.1406926f, SingleCrossPlatformMachineEpsilon * 100 }; // value: (pi) - yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; - } - } - - public static IEnumerable LogDouble - { - get - { - yield return new object[] { double.NegativeInfinity, double.NaN, 0.0 }; - yield return new object[] { -3.1415926535897932, double.NaN, 0.0 }; // value: -(pi) - yield return new object[] { -2.7182818284590452, double.NaN, 0.0 }; // value: -(e) - yield return new object[] { -1.4142135623730950, double.NaN, 0.0 }; // value: -(sqrt(2)) - yield return new object[] { -1.0, double.NaN, 0.0 }; - yield return new object[] { -0.69314718055994531, double.NaN, 0.0 }; // value: -(ln(2)) - yield return new object[] { -0.43429448190325183, double.NaN, 0.0 }; // value: -(log10(e)) - yield return new object[] { -0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] { double.NaN, double.NaN, 0.0 }; - yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] { 0.043213918263772250, -3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) - yield return new object[] { 0.065988035845312537, -2.7182818284590452, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) - yield return new object[] { 0.1, -2.3025850929940457, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) - yield return new object[] { 0.20787957635076191, -1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) - yield return new object[] { 0.23629008834452270, -1.4426950408889634, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) - yield return new object[] { 0.24311673443421421, -1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) - yield return new object[] { 0.32355726390307110, -1.1283791670955126, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) - yield return new object[] { 0.36787944117144232, -1.0, 0.0f }; - yield return new object[] { 0.45593812776599624, -0.78539816339744831, DoubleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) - yield return new object[] { 0.49306869139523979, -0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) - yield return new object[] { 0.5, -0.69314718055994531, DoubleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) - yield return new object[] { 0.52907780826773535, -0.63661977236758134, DoubleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) - yield return new object[] { 0.64772148514180065, -0.43429448190325183, DoubleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) - yield return new object[] { 0.72737734929521647, -0.31830988618379067, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) - yield return new object[] { 1.0, 0.0, 0.0 }; - yield return new object[] { 1.3748022274393586, 0.31830988618379067, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / pi) - yield return new object[] { 1.5438734439711811, 0.43429448190325183, DoubleCrossPlatformMachineEpsilon }; // expected: (log10(e)) - yield return new object[] { 1.8900811645722220, 0.63661977236758134, DoubleCrossPlatformMachineEpsilon }; // expected: (2 / pi) - yield return new object[] { 2.0, 0.69314718055994531, DoubleCrossPlatformMachineEpsilon }; // expected: (ln(2)) - yield return new object[] { 2.0281149816474725, 0.70710678118654752, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) - yield return new object[] { 2.1932800507380155, 0.78539816339744831, DoubleCrossPlatformMachineEpsilon }; // expected: (pi / 4) - yield return new object[] { 2.7182818284590452, 1.0, DoubleCrossPlatformMachineEpsilon * 10 }; // value: (e) - yield return new object[] { 3.0906430223107976, 1.1283791670955126, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) - yield return new object[] { 4.1132503787829275, 1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) - yield return new object[] { 4.2320861065570819, 1.4426950408889634, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) - yield return new object[] { 4.8104773809653517, 1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) - yield return new object[] { 10.0, 2.3025850929940457, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) - yield return new object[] { 15.154262241479264, 2.7182818284590452, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (e) - yield return new object[] { 23.140692632779269, 3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) - yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; - } - } - - public static IEnumerable LogSingle - { - get - { - yield return new object[] { float.NegativeInfinity, float.NaN, 0.0f }; - yield return new object[] { -3.14159265f, float.NaN, 0.0f }; // value: -(pi) - yield return new object[] { -2.71828183f, float.NaN, 0.0f }; // value: -(e) - yield return new object[] { -1.41421356f, float.NaN, 0.0f }; // value: -(sqrt(2)) - yield return new object[] { -1.0f, float.NaN, 0.0f }; - yield return new object[] { -0.693147181f, float.NaN, 0.0f }; // value: -(ln(2)) - yield return new object[] { -0.434294482f, float.NaN, 0.0f }; // value: -(log10(e)) - yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { float.NaN, float.NaN, 0.0f }; - yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { 0.0432139183f, -3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) - yield return new object[] { 0.0659880358f, -2.71828183f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) - yield return new object[] { 0.1f, -2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) - yield return new object[] { 0.207879576f, -1.57079633f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) - yield return new object[] { 0.236290088f, -1.44269504f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) - yield return new object[] { 0.243116734f, -1.41421356f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) - yield return new object[] { 0.323557264f, -1.12837917f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) - yield return new object[] { 0.367879441f, -1.0f, 0.0f }; - yield return new object[] { 0.455938128f, -0.785398163f, SingleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) - yield return new object[] { 0.493068691f, -0.707106781f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) - yield return new object[] { 0.5f, -0.693147181f, SingleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) - yield return new object[] { 0.529077808f, -0.636619772f, SingleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) - yield return new object[] { 0.647721485f, -0.434294482f, SingleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) - yield return new object[] { 0.727377349f, -0.318309886f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) - yield return new object[] { 1.0f, 0.0f, 0.0f }; - yield return new object[] { 1.37480223f, 0.318309886f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / pi) - yield return new object[] { 1.54387344f, 0.434294482f, SingleCrossPlatformMachineEpsilon }; // expected: (log10(e)) - yield return new object[] { 1.89008116f, 0.636619772f, SingleCrossPlatformMachineEpsilon }; // expected: (2 / pi) - yield return new object[] { 2.0f, 0.693147181f, SingleCrossPlatformMachineEpsilon }; // expected: (ln(2)) - yield return new object[] { 2.02811498f, 0.707106781f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) - yield return new object[] { 2.19328005f, 0.785398163f, SingleCrossPlatformMachineEpsilon }; // expected: (pi / 4) - yield return new object[] { 2.71828183f, 1.0f, SingleCrossPlatformMachineEpsilon * 10 }; // value: (e) - yield return new object[] { 3.09064302f, 1.12837917f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) - yield return new object[] { 4.11325038f, 1.41421356f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) - yield return new object[] { 4.23208611f, 1.44269504f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) - yield return new object[] { 4.81047738f, 1.57079633f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) - yield return new object[] { 10.0f, 2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) - yield return new object[] { 15.1542622f, 2.71828183f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (e) - yield return new object[] { 23.1406926f, 3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) - yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; - } - } - - public static IEnumerable Log2Double - { - get - { - yield return new object[] { double.NegativeInfinity, double.NaN, 0.0 }; - yield return new object[] {-0.11331473229676087, double.NaN, 0.0 }; - yield return new object[] {-0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] { double.NaN, double.NaN, 0.0 }; - yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] { 0.11331473229676087, -3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) - yield return new object[] { 0.15195522325791297, -2.7182818284590453, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) - yield return new object[] { 0.20269956628651730, -2.3025850929940460, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) - yield return new object[] { 0.33662253682241906, -1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) - yield return new object[] { 0.36787944117144232, -1.4426950408889634, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) - yield return new object[] { 0.37521422724648177, -1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) - yield return new object[] { 0.45742934732229695, -1.1283791670955126, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) - yield return new object[] { 0.5, -1.0, 0.0f }; - yield return new object[] { 0.58019181037172444, -0.78539816339744840, DoubleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) - yield return new object[] { 0.61254732653606592, -0.70710678118654750, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) - yield return new object[] { 0.61850313780157598, -0.69314718055994537, DoubleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) - yield return new object[] { 0.64321824193300488, -0.63661977236758126, DoubleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) - yield return new object[] { 0.74005557395545179, -0.43429448190325190, DoubleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) - yield return new object[] { 0.80200887896145195, -0.31830988618379073, DoubleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) - yield return new object[] { 1, 0.0, 0.0 }; - yield return new object[] { 1.2468689889006383, 0.31830988618379073, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / pi) - yield return new object[] { 1.3512498725672678, 0.43429448190325226, DoubleCrossPlatformMachineEpsilon }; // expected: (log10(e)) - yield return new object[] { 1.5546822754821001, 0.63661977236758126, DoubleCrossPlatformMachineEpsilon }; // expected: (2 / pi) - yield return new object[] { 1.6168066722416747, 0.69314718055994537, DoubleCrossPlatformMachineEpsilon }; // expected: (ln(2)) - yield return new object[] { 1.6325269194381528, 0.70710678118654750, DoubleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) - yield return new object[] { 1.7235679341273495, 0.78539816339744830, DoubleCrossPlatformMachineEpsilon }; // expected: (pi / 4) - yield return new object[] { 2, 1.0, 0.0 }; // value: (e) - yield return new object[] { 2.1861299583286618, 1.1283791670955128, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) - yield return new object[] { 2.6651441426902252, 1.4142135623730950, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) - yield return new object[] { 2.7182818284590452, 1.4426950408889632, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) - yield return new object[] { 2.9706864235520193, 1.5707963267948966, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) - yield return new object[] { 4.9334096679145963, 2.3025850929940460, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) - yield return new object[] { 6.5808859910179210, 2.7182818284590455, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (e) - yield return new object[] { 8.8249778270762876, 3.1415926535897932, DoubleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) - yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, 0.0 }; - } - } - - public static IEnumerable Log2Single - { - get - { - yield return new object[] { float.NegativeInfinity, float.NaN, 0.0f }; - yield return new object[] { -0.113314732f, float.NaN, 0.0f }; - yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { float.NaN, float.NaN, 0.0f }; - yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { 0.113314732f, -3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi) - yield return new object[] { 0.151955223f, -2.71828200f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(e) - yield return new object[] { 0.202699566f, -2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(ln(10)) - yield return new object[] { 0.336622537f, -1.57079630f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(pi / 2) - yield return new object[] { 0.367879441f, -1.44269500f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(log2(e)) - yield return new object[] { 0.375214227f, -1.41421360f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(sqrt(2)) - yield return new object[] { 0.457429347f, -1.12837910f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: -(2 / sqrt(pi)) - yield return new object[] { 0.5f, -1.0f, 0.0f }; - yield return new object[] { 0.580191810f, -0.785398211f, SingleCrossPlatformMachineEpsilon }; // expected: -(pi / 4) - yield return new object[] { 0.612547327f, -0.707106700f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / sqrt(2)) - yield return new object[] { 0.618503138f, -0.693147144f, SingleCrossPlatformMachineEpsilon }; // expected: -(ln(2)) - yield return new object[] { 0.643218242f, -0.636619823f, SingleCrossPlatformMachineEpsilon }; // expected: -(2 / pi) - yield return new object[] { 0.740055574f, -0.434294550f, SingleCrossPlatformMachineEpsilon }; // expected: -(log10(e)) - yield return new object[] { 0.802008879f, -0.318309900f, SingleCrossPlatformMachineEpsilon }; // expected: -(1 / pi) - yield return new object[] { 1, 0.0f, 0.0f }; - yield return new object[] { 1.24686899f, 0.318309870f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / pi) - yield return new object[] { 1.35124987f, 0.434294340f, SingleCrossPlatformMachineEpsilon }; // expected: (log10(e)) - yield return new object[] { 1.55468228f, 0.636619823f, SingleCrossPlatformMachineEpsilon }; // expected: (2 / pi) - yield return new object[] { 1.61680667f, 0.693147144f, SingleCrossPlatformMachineEpsilon }; // expected: (ln(2)) - yield return new object[] { 1.63252692f, 0.707106700f, SingleCrossPlatformMachineEpsilon }; // expected: (1 / sqrt(2)) - yield return new object[] { 1.72356793f, 0.785398211f, SingleCrossPlatformMachineEpsilon }; // expected: (pi / 4) - yield return new object[] { 2, 1.0f, 0.0f }; // value: (e) - yield return new object[] { 2.18612996f, 1.12837920f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (2 / sqrt(pi)) - yield return new object[] { 2.66514414f, 1.41421360f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (sqrt(2)) - yield return new object[] { 2.71828183f, 1.44269490f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (log2(e)) - yield return new object[] { 2.97068642f, 1.57079630f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi / 2) - yield return new object[] { 4.93340967f, 2.30258509f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (ln(10)) - yield return new object[] { 6.58088599f, 2.71828170f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (e) - yield return new object[] { 8.82497783f, 3.14159265f, SingleCrossPlatformMachineEpsilon * 10 }; // expected: (pi) - yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, 0.0f }; - } - } - - public static IEnumerable MultiplyAddDouble - { - get - { - yield return new object[] { double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] { double.NegativeInfinity, -0.0, double.NegativeInfinity }; - yield return new object[] { double.NegativeInfinity, -0.0, -3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, -0.0, -0.0 }; - yield return new object[] { double.NegativeInfinity, -0.0, double.NaN }; - yield return new object[] { double.NegativeInfinity, -0.0, 0.0 }; - yield return new object[] { double.NegativeInfinity, -0.0, 3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, -0.0, double.PositiveInfinity }; - yield return new object[] { double.NegativeInfinity, 0.0, double.NegativeInfinity }; - yield return new object[] { double.NegativeInfinity, 0.0, -3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, 0.0, -0.0 }; - yield return new object[] { double.NegativeInfinity, 0.0, double.NaN }; - yield return new object[] { double.NegativeInfinity, 0.0, 0.0 }; - yield return new object[] { double.NegativeInfinity, 0.0, 3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, 0.0, double.PositiveInfinity }; - yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] {-1e308, 2.0, 1e308 }; - yield return new object[] {-1e308, 2.0, double.PositiveInfinity }; - yield return new object[] {-5, 4, -3 }; - yield return new object[] {-0.0, double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] {-0.0, double.NegativeInfinity, -3.1415926535897932 }; - yield return new object[] {-0.0, double.NegativeInfinity, -0.0 }; - yield return new object[] {-0.0, double.NegativeInfinity, double.NaN }; - yield return new object[] {-0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] {-0.0, double.NegativeInfinity, 3.1415926535897932 }; - yield return new object[] {-0.0, double.NegativeInfinity, double.PositiveInfinity }; - yield return new object[] {-0.0, double.PositiveInfinity, double.NegativeInfinity }; - yield return new object[] {-0.0, double.PositiveInfinity, -3.1415926535897932 }; - yield return new object[] {-0.0, double.PositiveInfinity, -0.0 }; - yield return new object[] {-0.0, double.PositiveInfinity, double.NaN }; - yield return new object[] {-0.0, double.PositiveInfinity, 0.0 }; - yield return new object[] {-0.0, double.PositiveInfinity, 3.1415926535897932 }; - yield return new object[] {-0.0, double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] { 0.0, double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] { 0.0, double.NegativeInfinity, -3.1415926535897932 }; - yield return new object[] { 0.0, double.NegativeInfinity, -0.0 }; - yield return new object[] { 0.0, double.NegativeInfinity, double.NaN }; - yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] { 0.0, double.NegativeInfinity, 3.1415926535897932 }; - yield return new object[] { 0.0, double.NegativeInfinity, double.PositiveInfinity }; - yield return new object[] { 0.0, double.PositiveInfinity, double.NegativeInfinity }; - yield return new object[] { 0.0, double.PositiveInfinity, -3.1415926535897932 }; - yield return new object[] { 0.0, double.PositiveInfinity, -0.0 }; - yield return new object[] { 0.0, double.PositiveInfinity, double.NaN }; - yield return new object[] { 0.0, double.PositiveInfinity, 0.0 }; - yield return new object[] { 0.0, double.PositiveInfinity, 3.1415926535897932 }; - yield return new object[] { 0.0, double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] { 5, 4, 3 }; - yield return new object[] { 1e308, 2.0, -1e308 }; - yield return new object[] { 1e308, 2.0, double.NegativeInfinity }; - yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; - yield return new object[] { double.PositiveInfinity, -0.0, double.NegativeInfinity }; - yield return new object[] { double.PositiveInfinity, -0.0, -3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, -0.0, -0.0 }; - yield return new object[] { double.PositiveInfinity, -0.0, double.NaN }; - yield return new object[] { double.PositiveInfinity, -0.0, 0.0 }; - yield return new object[] { double.PositiveInfinity, -0.0, 3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, -0.0, double.PositiveInfinity }; - yield return new object[] { double.PositiveInfinity, 0.0, double.NegativeInfinity }; - yield return new object[] { double.PositiveInfinity, 0.0, -3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, 0.0, -0.0 }; - yield return new object[] { double.PositiveInfinity, 0.0, double.NaN }; - yield return new object[] { double.PositiveInfinity, 0.0, 0.0 }; - yield return new object[] { double.PositiveInfinity, 0.0, 3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, 0.0, double.PositiveInfinity }; - yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, double.NegativeInfinity }; - } - } - - public static IEnumerable MultiplyAddSingle - { - get - { - yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { float.NegativeInfinity, -0.0f, float.NegativeInfinity }; - yield return new object[] { float.NegativeInfinity, -0.0f, -3.14159265f }; - yield return new object[] { float.NegativeInfinity, -0.0f, -0.0f }; - yield return new object[] { float.NegativeInfinity, -0.0f, float.NaN }; - yield return new object[] { float.NegativeInfinity, -0.0f, 0.0f }; - yield return new object[] { float.NegativeInfinity, -0.0f, 3.14159265f }; - yield return new object[] { float.NegativeInfinity, -0.0f, float.PositiveInfinity }; - yield return new object[] { float.NegativeInfinity, 0.0f, float.NegativeInfinity }; - yield return new object[] { float.NegativeInfinity, 0.0f, -3.14159265f }; - yield return new object[] { float.NegativeInfinity, 0.0f, -0.0f }; - yield return new object[] { float.NegativeInfinity, 0.0f, float.NaN }; - yield return new object[] { float.NegativeInfinity, 0.0f, 0.0f }; - yield return new object[] { float.NegativeInfinity, 0.0f, 3.14159265f }; - yield return new object[] { float.NegativeInfinity, 0.0f, float.PositiveInfinity }; - yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { -1e38f, 2.0f, 1e38f }; - yield return new object[] { -1e38f, 2.0f, float.PositiveInfinity }; - yield return new object[] { -5, 4, -3 }; - yield return new object[] { -0.0f, float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { -0.0f, float.NegativeInfinity, -3.14159265f }; - yield return new object[] { -0.0f, float.NegativeInfinity, -0.0f }; - yield return new object[] { -0.0f, float.NegativeInfinity, float.NaN }; - yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { -0.0f, float.NegativeInfinity, 3.14159265f }; - yield return new object[] { -0.0f, float.NegativeInfinity, float.PositiveInfinity }; - yield return new object[] { -0.0f, float.PositiveInfinity, float.NegativeInfinity }; - yield return new object[] { -0.0f, float.PositiveInfinity, -3.14159265f }; - yield return new object[] { -0.0f, float.PositiveInfinity, -0.0f }; - yield return new object[] { -0.0f, float.PositiveInfinity, float.NaN }; - yield return new object[] { -0.0f, float.PositiveInfinity, 0.0f }; - yield return new object[] { -0.0f, float.PositiveInfinity, 3.14159265f }; - yield return new object[] { -0.0f, float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { 0.0f, float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { 0.0f, float.NegativeInfinity, -3.14159265f }; - yield return new object[] { 0.0f, float.NegativeInfinity, -0.0f }; - yield return new object[] { 0.0f, float.NegativeInfinity, float.NaN }; - yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { 0.0f, float.NegativeInfinity, 3.14159265f }; - yield return new object[] { 0.0f, float.NegativeInfinity, float.PositiveInfinity }; - yield return new object[] { 0.0f, float.PositiveInfinity, float.NegativeInfinity }; - yield return new object[] { 0.0f, float.PositiveInfinity, -3.14159265f }; - yield return new object[] { 0.0f, float.PositiveInfinity, -0.0f }; - yield return new object[] { 0.0f, float.PositiveInfinity, float.NaN }; - yield return new object[] { 0.0f, float.PositiveInfinity, 0.0f }; - yield return new object[] { 0.0f, float.PositiveInfinity, 3.14159265f }; - yield return new object[] { 0.0f, float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { 5, 4, 3 }; - yield return new object[] { 1e38f, 2.0f, -1e38f }; - yield return new object[] { 1e38f, 2.0f, float.NegativeInfinity }; - yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; - yield return new object[] { float.PositiveInfinity, -0.0f, float.NegativeInfinity }; - yield return new object[] { float.PositiveInfinity, -0.0f, -3.14159265f }; - yield return new object[] { float.PositiveInfinity, -0.0f, -0.0f }; - yield return new object[] { float.PositiveInfinity, -0.0f, float.NaN }; - yield return new object[] { float.PositiveInfinity, -0.0f, 0.0f }; - yield return new object[] { float.PositiveInfinity, -0.0f, 3.14159265f }; - yield return new object[] { float.PositiveInfinity, -0.0f, float.PositiveInfinity }; - yield return new object[] { float.PositiveInfinity, 0.0f, float.NegativeInfinity }; - yield return new object[] { float.PositiveInfinity, 0.0f, -3.14159265f }; - yield return new object[] { float.PositiveInfinity, 0.0f, -0.0f }; - yield return new object[] { float.PositiveInfinity, 0.0f, float.NaN }; - yield return new object[] { float.PositiveInfinity, 0.0f, 0.0f }; - yield return new object[] { float.PositiveInfinity, 0.0f, 3.14159265f }; - yield return new object[] { float.PositiveInfinity, 0.0f, float.PositiveInfinity }; - yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity }; - } - } - } -} diff --git a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs index 02c7d3fa8a878a..eb99ed2b90122e 100644 --- a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs @@ -8,7 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; -using System.Runtime.Intrinsics.Tests.Vectors; +using System.Tests; using Xunit; using Xunit.Sdk; @@ -4537,35 +4537,458 @@ private static void TestCreateSequence(T start, T step) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] + public void ExpDoubleTest(double value, double expectedResult, double variance) + { + Vector actualResult = Vector.Exp(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ExpSingleTest(float value, float expectedResult, float variance) + { + Vector actualResult = Vector.Exp(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LogDouble), MemberType = typeof(GenericMathTestMemberData))] + public void LogDoubleTest(double value, double expectedResult, double variance) + { + Vector actualResult = Vector.Log(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LogSingleTest(float value, float expectedResult, float variance) + { + Vector actualResult = Vector.Log(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] + public void Log2DoubleTest(double value, double expectedResult, double variance) + { + Vector actualResult = Vector.Log2(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] + public void Log2SingleTest(float value, float expectedResult, float variance) + { + Vector actualResult = Vector.Log2(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddDoubleTest(double left, double right, double addend) { Vector actualResult = Vector.FusedMultiplyAdd(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(new Vector(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); + AssertEqual(Vector.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { Vector actualResult = Vector.FusedMultiplyAdd(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(new Vector(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); + AssertEqual(Vector.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) { Vector actualResult = Vector.MultiplyAddEstimate(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(new Vector(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); + AssertEqual(Vector.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { Vector actualResult = Vector.MultiplyAddEstimate(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(new Vector(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); + AssertEqual(Vector.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampDouble), MemberType = typeof(GenericMathTestMemberData))] + public void ClampDoubleTest(double x, double min, double max, double expectedResult) + { + Vector actualResult = Vector.Clamp(Vector.Create(x), Vector.Create(min), Vector.Create(max)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector actualResult = Vector.Clamp(Vector.Create(x), Vector.Create(min), Vector.Create(max)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.CopySign(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.CopySign(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansDouble), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansDoubleTest(double value, double expectedResult, double variance) + { + Vector actualResult1 = Vector.DegreesToRadians(Vector.Create(-value)); + AssertEqual(Vector.Create(-expectedResult), actualResult1, Vector.Create(variance)); + + Vector actualResult2 = Vector.DegreesToRadians(Vector.Create(+value)); + AssertEqual(Vector.Create(+expectedResult), actualResult2, Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector.Create(-expectedResult), Vector.DegreesToRadians(Vector.Create(-value)), Vector.Create(variance)); + AssertEqual(Vector.Create(+expectedResult), Vector.DegreesToRadians(Vector.Create(+value)), Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotDouble), MemberType = typeof(GenericMathTestMemberData))] + public void HypotDoubleTest(double x, double y, double expectedResult, double variance) + { + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-x), Vector.Create(-y)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-x), Vector.Create(+y)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+x), Vector.Create(-y)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+x), Vector.Create(+y)), Vector.Create(variance)); + + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-y), Vector.Create(-x)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-y), Vector.Create(+x)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+y), Vector.Create(-x)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+y), Vector.Create(+x)), Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-x), Vector.Create(-y)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-x), Vector.Create(+y)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+x), Vector.Create(-y)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+x), Vector.Create(+y)), Vector.Create(variance)); + + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-y), Vector.Create(-x)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(-y), Vector.Create(+x)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+y), Vector.Create(-x)), Vector.Create(variance)); + AssertEqual(Vector.Create(expectedResult), Vector.Hypot(Vector.Create(+y), Vector.Create(+x)), Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsNaN(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsNaN(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsNegative(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsNegative(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsPositive(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsPositive(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinityDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinityDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsPositiveInfinity(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinitySingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinitySingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsPositiveInfinity(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsZero(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector.AllBitsSet : Vector.Zero, Vector.IsZero(Vector.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpDouble), MemberType = typeof(GenericMathTestMemberData))] + public void LerpDoubleTest(double x, double y, double amount, double expectedResult) + { + AssertEqual(Vector.Create(+expectedResult), Vector.Lerp(Vector.Create(+x), Vector.Create(+y), Vector.Create(amount)), Vector.Zero); + AssertEqual(Vector.Create((expectedResult == 0.0) ? expectedResult : -expectedResult), Vector.Lerp(Vector.Create(-x), Vector.Create(-y), Vector.Create(amount)), Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector.Create(+expectedResult), Vector.Lerp(Vector.Create(+x), Vector.Create(+y), Vector.Create(amount)), Vector.Zero); + AssertEqual(Vector.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector.Lerp(Vector.Create(-x), Vector.Create(-y), Vector.Create(amount)), Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.Max(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.Max(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.MaxMagnitude(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.MaxMagnitude(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.MaxMagnitudeNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.MaxMagnitudeNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.MaxNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.MaxNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.Min(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.Min(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.MinMagnitude(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.MinMagnitude(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.MinMagnitudeNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.MinMagnitudeNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberDoubleTest(double x, double y, double expectedResult) + { + Vector actualResult = Vector.MinNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector actualResult = Vector.MinNumber(Vector.Create(x), Vector.Create(y)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesDoubleTest(double value, double expectedResult, double variance) + { + AssertEqual(Vector.Create(-expectedResult), Vector.RadiansToDegrees(Vector.Create(-value)), Vector.Create(variance)); + AssertEqual(Vector.Create(+expectedResult), Vector.RadiansToDegrees(Vector.Create(+value)), Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector.Create(-expectedResult), Vector.RadiansToDegrees(Vector.Create(-value)), Vector.Create(variance)); + AssertEqual(Vector.Create(+expectedResult), Vector.RadiansToDegrees(Vector.Create(+value)), Vector.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundDoubleTest(double value, double expectedResult) + { + Vector actualResult = Vector.Round(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector actualResult = Vector.Round(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroDoubleTest(double value, double expectedResult) + { + Vector actualResult = Vector.Round(Vector.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector actualResult = Vector.Round(Vector.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenDoubleTest(double value, double expectedResult) + { + Vector actualResult = Vector.Round(Vector.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector actualResult = Vector.Round(Vector.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateDoubleTest(double value, double expectedResult) + { + Vector actualResult = Vector.Truncate(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector actualResult = Vector.Truncate(Vector.Create(value)); + AssertEqual(Vector.Create(expectedResult), actualResult, Vector.Zero); } } } diff --git a/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj b/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj index 243d1490ced0e5..d6b26bdac8e45d 100644 --- a/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj +++ b/src/libraries/System.Numerics.Vectors/tests/System.Numerics.Vectors.Tests.csproj @@ -18,6 +18,6 @@ - + diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs index 0472832009f4d2..65ab6ab4f0cf4a 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs @@ -3,7 +3,7 @@ using System.Globalization; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.Tests.Vectors; +using System.Tests; using Xunit; namespace System.Numerics.Tests @@ -1300,19 +1300,194 @@ private class EmbeddedVectorObject } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ExpSingleTest(float value, float expectedResult, float variance) + { + Vector2 actualResult = Vector2.Exp(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LogSingleTest(float value, float expectedResult, float variance) + { + Vector2 actualResult = Vector2.Log(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] + public void Log2SingleTest(float value, float expectedResult, float variance) + { + Vector2 actualResult = Vector2.Log2(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { - Vector2 actualResult = Vector2.FusedMultiplyAdd(new Vector2(left), new Vector2(right), new Vector2(addend)); - AssertEqual(new Vector2(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector2.Zero); + Vector2 actualResult = Vector2.FusedMultiplyAdd(Vector2.Create(left), Vector2.Create(right), Vector2.Create(addend)); + AssertEqual(Vector2.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector2.Zero); } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { - Vector2 actualResult = Vector2.MultiplyAddEstimate(new Vector2(left), new Vector2(right), new Vector2(addend)); - AssertEqual(new Vector2(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector2.Zero); + Vector2 actualResult = Vector2.MultiplyAddEstimate(Vector2.Create(left), Vector2.Create(right), Vector2.Create(addend)); + AssertEqual(Vector2.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector2 actualResult = Vector2.Clamp(Vector2.Create(x), Vector2.Create(min), Vector2.Create(max)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.CopySign(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector2.Create(-expectedResult), Vector2.DegreesToRadians(Vector2.Create(-value)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(+expectedResult), Vector2.DegreesToRadians(Vector2.Create(+value)), Vector2.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(-x), Vector2.Create(-y)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(-x), Vector2.Create(+y)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(+x), Vector2.Create(-y)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(+x), Vector2.Create(+y)), Vector2.Create(variance)); + + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(-y), Vector2.Create(-x)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(-y), Vector2.Create(+x)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(+y), Vector2.Create(-x)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(expectedResult), Vector2.Hypot(Vector2.Create(+y), Vector2.Create(+x)), Vector2.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector2.Create(+expectedResult), Vector2.Lerp(Vector2.Create(+x), Vector2.Create(+y), Vector2.Create(amount)), Vector2.Zero); + AssertEqual(Vector2.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector2.Lerp(Vector2.Create(-x), Vector2.Create(-y), Vector2.Create(amount)), Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.Max(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.MaxMagnitude(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.MaxMagnitudeNumber(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.MaxNumber(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.Min(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.MinMagnitude(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.MinMagnitudeNumber(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector2 actualResult = Vector2.MinNumber(Vector2.Create(x), Vector2.Create(y)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector2.Create(-expectedResult), Vector2.RadiansToDegrees(Vector2.Create(-value)), Vector2.Create(variance)); + AssertEqual(Vector2.Create(+expectedResult), Vector2.RadiansToDegrees(Vector2.Create(+value)), Vector2.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector2 actualResult = Vector2.Round(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector2 actualResult = Vector2.Round(Vector2.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector2 actualResult = Vector2.Round(Vector2.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector2 actualResult = Vector2.Truncate(Vector2.Create(value)); + AssertEqual(Vector2.Create(expectedResult), actualResult, Vector2.Zero); } } } diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs index 4d0e97526a918a..a5d0195d83c0c0 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs @@ -3,7 +3,7 @@ using System.Globalization; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.Tests.Vectors; +using System.Tests; using Xunit; namespace System.Numerics.Tests @@ -1350,19 +1350,194 @@ private class EmbeddedVectorObject } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ExpSingleTest(float value, float expectedResult, float variance) + { + Vector3 actualResult = Vector3.Exp(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LogSingleTest(float value, float expectedResult, float variance) + { + Vector3 actualResult = Vector3.Log(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] + public void Log2SingleTest(float value, float expectedResult, float variance) + { + Vector3 actualResult = Vector3.Log2(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { - Vector3 actualResult = Vector3.FusedMultiplyAdd(new Vector3(left), new Vector3(right), new Vector3(addend)); - AssertEqual(new Vector3(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector3.Zero); + Vector3 actualResult = Vector3.FusedMultiplyAdd(Vector3.Create(left), Vector3.Create(right), Vector3.Create(addend)); + AssertEqual(Vector3.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector3.Zero); } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { - Vector3 actualResult = Vector3.MultiplyAddEstimate(new Vector3(left), new Vector3(right), new Vector3(addend)); - AssertEqual(new Vector3(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector3.Zero); + Vector3 actualResult = Vector3.MultiplyAddEstimate(Vector3.Create(left), Vector3.Create(right), Vector3.Create(addend)); + AssertEqual(Vector3.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector3 actualResult = Vector3.Clamp(Vector3.Create(x), Vector3.Create(min), Vector3.Create(max)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.CopySign(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector3.Create(-expectedResult), Vector3.DegreesToRadians(Vector3.Create(-value)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(+expectedResult), Vector3.DegreesToRadians(Vector3.Create(+value)), Vector3.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(-x), Vector3.Create(-y)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(-x), Vector3.Create(+y)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(+x), Vector3.Create(-y)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(+x), Vector3.Create(+y)), Vector3.Create(variance)); + + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(-y), Vector3.Create(-x)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(-y), Vector3.Create(+x)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(+y), Vector3.Create(-x)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(expectedResult), Vector3.Hypot(Vector3.Create(+y), Vector3.Create(+x)), Vector3.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector3.Create(+expectedResult), Vector3.Lerp(Vector3.Create(+x), Vector3.Create(+y), Vector3.Create(amount)), Vector3.Zero); + AssertEqual(Vector3.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector3.Lerp(Vector3.Create(-x), Vector3.Create(-y), Vector3.Create(amount)), Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.Max(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.MaxMagnitude(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.MaxMagnitudeNumber(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.MaxNumber(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.Min(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.MinMagnitude(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.MinMagnitudeNumber(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector3 actualResult = Vector3.MinNumber(Vector3.Create(x), Vector3.Create(y)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector3.Create(-expectedResult), Vector3.RadiansToDegrees(Vector3.Create(-value)), Vector3.Create(variance)); + AssertEqual(Vector3.Create(+expectedResult), Vector3.RadiansToDegrees(Vector3.Create(+value)), Vector3.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector3 actualResult = Vector3.Round(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector3 actualResult = Vector3.Round(Vector3.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector3 actualResult = Vector3.Round(Vector3.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector3 actualResult = Vector3.Truncate(Vector3.Create(value)); + AssertEqual(Vector3.Create(expectedResult), actualResult, Vector3.Zero); } } } diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs index b3759a716a028b..cdfa700126e463 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs @@ -3,7 +3,7 @@ using System.Globalization; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.Tests.Vectors; +using System.Tests; using Xunit; namespace System.Numerics.Tests @@ -1725,19 +1725,194 @@ public struct Level7 #pragma warning restore 0169 [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ExpSingleTest(float value, float expectedResult, float variance) + { + Vector4 actualResult = Vector4.Exp(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LogSingleTest(float value, float expectedResult, float variance) + { + Vector4 actualResult = Vector4.Log(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] + public void Log2SingleTest(float value, float expectedResult, float variance) + { + Vector4 actualResult = Vector4.Log2(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { - Vector4 actualResult = Vector4.FusedMultiplyAdd(new Vector4(left), new Vector4(right), new Vector4(addend)); - AssertEqual(new Vector4(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector4.Zero); + Vector4 actualResult = Vector4.FusedMultiplyAdd(Vector4.Create(left), Vector4.Create(right), Vector4.Create(addend)); + AssertEqual(Vector4.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector4.Zero); } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { - Vector4 actualResult = Vector4.MultiplyAddEstimate(new Vector4(left), new Vector4(right), new Vector4(addend)); - AssertEqual(new Vector4(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector4.Zero); + Vector4 actualResult = Vector4.MultiplyAddEstimate(Vector4.Create(left), Vector4.Create(right), Vector4.Create(addend)); + AssertEqual(Vector4.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector4 actualResult = Vector4.Clamp(Vector4.Create(x), Vector4.Create(min), Vector4.Create(max)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.CopySign(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector4.Create(-expectedResult), Vector4.DegreesToRadians(Vector4.Create(-value)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(+expectedResult), Vector4.DegreesToRadians(Vector4.Create(+value)), Vector4.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(-x), Vector4.Create(-y)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(-x), Vector4.Create(+y)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(+x), Vector4.Create(-y)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(+x), Vector4.Create(+y)), Vector4.Create(variance)); + + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(-y), Vector4.Create(-x)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(-y), Vector4.Create(+x)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(+y), Vector4.Create(-x)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(expectedResult), Vector4.Hypot(Vector4.Create(+y), Vector4.Create(+x)), Vector4.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector4.Create(+expectedResult), Vector4.Lerp(Vector4.Create(+x), Vector4.Create(+y), Vector4.Create(amount)), Vector4.Zero); + AssertEqual(Vector4.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector4.Lerp(Vector4.Create(-x), Vector4.Create(-y), Vector4.Create(amount)), Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.Max(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.MaxMagnitude(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.MaxMagnitudeNumber(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.MaxNumber(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.Min(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.MinMagnitude(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.MinMagnitudeNumber(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector4 actualResult = Vector4.MinNumber(Vector4.Create(x), Vector4.Create(y)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector4.Create(-expectedResult), Vector4.RadiansToDegrees(Vector4.Create(-value)), Vector4.Create(variance)); + AssertEqual(Vector4.Create(+expectedResult), Vector4.RadiansToDegrees(Vector4.Create(+value)), Vector4.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector4 actualResult = Vector4.Round(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector4 actualResult = Vector4.Round(Vector4.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector4 actualResult = Vector4.Round(Vector4.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector4 actualResult = Vector4.Truncate(Vector4.Create(value)); + AssertEqual(Vector4.Create(expectedResult), actualResult, Vector4.Zero); } } } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj b/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj index b8fc0641259d47..e956491c0a63b1 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj +++ b/src/libraries/System.Runtime.Intrinsics/tests/System.Runtime.Intrinsics.Tests.csproj @@ -13,7 +13,7 @@ - + diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs index ce4f1d8fcf3e65..27d63954ebcdd0 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs @@ -5,7 +5,7 @@ using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.X86; +using System.Tests; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -4825,7 +4825,7 @@ private static void TestCreateSequence(T start, T step) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] [SkipOnMono("https://github.com/dotnet/runtime/issues/97176")] public void ExpDoubleTest(double value, double expectedResult, double variance) { @@ -4834,7 +4834,7 @@ public void ExpDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] [SkipOnMono("https://github.com/dotnet/runtime/issues/97176")] public void ExpSingleTest(float value, float expectedResult, float variance) { @@ -4843,7 +4843,7 @@ public void ExpSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogDouble), MemberType = typeof(GenericMathTestMemberData))] public void LogDoubleTest(double value, double expectedResult, double variance) { Vector128 actualResult = Vector128.Log(Vector128.Create(value)); @@ -4851,7 +4851,7 @@ public void LogDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] public void LogSingleTest(float value, float expectedResult, float variance) { Vector128 actualResult = Vector128.Log(Vector128.Create(value)); @@ -4859,7 +4859,7 @@ public void LogSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Double), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] public void Log2DoubleTest(double value, double expectedResult, double variance) { Vector128 actualResult = Vector128.Log2(Vector128.Create(value)); @@ -4867,7 +4867,7 @@ public void Log2DoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Single), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] public void Log2SingleTest(float value, float expectedResult, float variance) { Vector128 actualResult = Vector128.Log2(Vector128.Create(value)); @@ -4875,7 +4875,7 @@ public void Log2SingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddDoubleTest(double left, double right, double addend) { Vector128 actualResult = Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); @@ -4883,7 +4883,7 @@ public void FusedMultiplyAddDoubleTest(double left, double right, double addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { Vector128 actualResult = Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); @@ -4891,7 +4891,7 @@ public void FusedMultiplyAddSingleTest(float left, float right, float addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) { Vector128 actualResult = Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); @@ -4899,7 +4899,7 @@ public void MultiplyAddEstimateDoubleTest(double left, double right, double adde } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { Vector128 actualResult = Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); @@ -4987,5 +4987,380 @@ public void ConvertToUInt64NativeTest() Assert.Equal(Vector128.Create(double.ConvertToIntegerNative(2.6)), Vector128.ConvertToUInt64Native(Vector128.Create(2.6))); Assert.Equal(Vector128.Create(double.ConvertToIntegerNative(double.MaxValue)), Vector128.ConvertToUInt64Native(Vector128.Create(double.MaxValue))); } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampDouble), MemberType = typeof(GenericMathTestMemberData))] + public void ClampDoubleTest(double x, double min, double max, double expectedResult) + { + Vector128 actualResult = Vector128.Clamp(Vector128.Create(x), Vector128.Create(min), Vector128.Create(max)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector128 actualResult = Vector128.Clamp(Vector128.Create(x), Vector128.Create(min), Vector128.Create(max)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.CopySign(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.CopySign(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansDouble), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansDoubleTest(double value, double expectedResult, double variance) + { + Vector128 actualResult1 = Vector128.DegreesToRadians(Vector128.Create(-value)); + AssertEqual(Vector128.Create(-expectedResult), actualResult1, Vector128.Create(variance)); + + Vector128 actualResult2 = Vector128.DegreesToRadians(Vector128.Create(+value)); + AssertEqual(Vector128.Create(+expectedResult), actualResult2, Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector128.Create(-expectedResult), Vector128.DegreesToRadians(Vector128.Create(-value)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(+expectedResult), Vector128.DegreesToRadians(Vector128.Create(+value)), Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotDouble), MemberType = typeof(GenericMathTestMemberData))] + public void HypotDoubleTest(double x, double y, double expectedResult, double variance) + { + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-x), Vector128.Create(-y)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-x), Vector128.Create(+y)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+x), Vector128.Create(-y)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+x), Vector128.Create(+y)), Vector128.Create(variance)); + + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-y), Vector128.Create(-x)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-y), Vector128.Create(+x)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+y), Vector128.Create(-x)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+y), Vector128.Create(+x)), Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-x), Vector128.Create(-y)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-x), Vector128.Create(+y)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+x), Vector128.Create(-y)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+x), Vector128.Create(+y)), Vector128.Create(variance)); + + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-y), Vector128.Create(-x)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(-y), Vector128.Create(+x)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+y), Vector128.Create(-x)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(expectedResult), Vector128.Hypot(Vector128.Create(+y), Vector128.Create(+x)), Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsNaN(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsNaN(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsNegative(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsNegative(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsPositive(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsPositive(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinityDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinityDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsPositiveInfinity(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinitySingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinitySingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsPositiveInfinity(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsZero(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector128.AllBitsSet : Vector128.Zero, Vector128.IsZero(Vector128.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpDouble), MemberType = typeof(GenericMathTestMemberData))] + public void LerpDoubleTest(double x, double y, double amount, double expectedResult) + { + AssertEqual(Vector128.Create(+expectedResult), Vector128.Lerp(Vector128.Create(+x), Vector128.Create(+y), Vector128.Create(amount)), Vector128.Zero); + AssertEqual(Vector128.Create((expectedResult == 0.0) ? expectedResult : -expectedResult), Vector128.Lerp(Vector128.Create(-x), Vector128.Create(-y), Vector128.Create(amount)), Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector128.Create(+expectedResult), Vector128.Lerp(Vector128.Create(+x), Vector128.Create(+y), Vector128.Create(amount)), Vector128.Zero); + AssertEqual(Vector128.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector128.Lerp(Vector128.Create(-x), Vector128.Create(-y), Vector128.Create(amount)), Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.Max(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.Max(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.MaxMagnitude(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.MaxMagnitude(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.MaxMagnitudeNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.MaxMagnitudeNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.MaxNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.MaxNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.Min(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.Min(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.MinMagnitude(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.MinMagnitude(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.MinMagnitudeNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.MinMagnitudeNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberDoubleTest(double x, double y, double expectedResult) + { + Vector128 actualResult = Vector128.MinNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector128 actualResult = Vector128.MinNumber(Vector128.Create(x), Vector128.Create(y)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesDoubleTest(double value, double expectedResult, double variance) + { + AssertEqual(Vector128.Create(-expectedResult), Vector128.RadiansToDegrees(Vector128.Create(-value)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(+expectedResult), Vector128.RadiansToDegrees(Vector128.Create(+value)), Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector128.Create(-expectedResult), Vector128.RadiansToDegrees(Vector128.Create(-value)), Vector128.Create(variance)); + AssertEqual(Vector128.Create(+expectedResult), Vector128.RadiansToDegrees(Vector128.Create(+value)), Vector128.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundDoubleTest(double value, double expectedResult) + { + Vector128 actualResult = Vector128.Round(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector128 actualResult = Vector128.Round(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroDoubleTest(double value, double expectedResult) + { + Vector128 actualResult = Vector128.Round(Vector128.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector128 actualResult = Vector128.Round(Vector128.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenDoubleTest(double value, double expectedResult) + { + Vector128 actualResult = Vector128.Round(Vector128.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector128 actualResult = Vector128.Round(Vector128.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateDoubleTest(double value, double expectedResult) + { + Vector128 actualResult = Vector128.Truncate(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector128 actualResult = Vector128.Truncate(Vector128.Create(value)); + AssertEqual(Vector128.Create(expectedResult), actualResult, Vector128.Zero); + } } } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs index d264cd47771208..cdc0ff2740d3c0 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; +using System.Tests; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -5840,7 +5841,7 @@ private static void TestCreateSequence(T start, T step) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] [SkipOnMono("https://github.com/dotnet/runtime/issues/97176")] public void ExpDoubleTest(double value, double expectedResult, double variance) { @@ -5849,7 +5850,7 @@ public void ExpDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] [SkipOnMono("https://github.com/dotnet/runtime/issues/97176")] public void ExpSingleTest(float value, float expectedResult, float variance) { @@ -5858,7 +5859,7 @@ public void ExpSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogDouble), MemberType = typeof(GenericMathTestMemberData))] public void LogDoubleTest(double value, double expectedResult, double variance) { Vector256 actualResult = Vector256.Log(Vector256.Create(value)); @@ -5866,7 +5867,7 @@ public void LogDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] public void LogSingleTest(float value, float expectedResult, float variance) { Vector256 actualResult = Vector256.Log(Vector256.Create(value)); @@ -5874,7 +5875,7 @@ public void LogSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Double), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] public void Log2DoubleTest(double value, double expectedResult, double variance) { Vector256 actualResult = Vector256.Log2(Vector256.Create(value)); @@ -5882,7 +5883,7 @@ public void Log2DoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Single), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] public void Log2SingleTest(float value, float expectedResult, float variance) { Vector256 actualResult = Vector256.Log2(Vector256.Create(value)); @@ -5890,7 +5891,7 @@ public void Log2SingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddDoubleTest(double left, double right, double addend) { Vector256 actualResult = Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); @@ -5898,7 +5899,7 @@ public void FusedMultiplyAddDoubleTest(double left, double right, double addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { Vector256 actualResult = Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); @@ -5906,7 +5907,7 @@ public void FusedMultiplyAddSingleTest(float left, float right, float addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) { Vector256 actualResult = Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); @@ -5914,7 +5915,7 @@ public void MultiplyAddEstimateDoubleTest(double left, double right, double adde } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { Vector256 actualResult = Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); @@ -6002,5 +6003,380 @@ public void ConvertToUInt64NativeTest() Assert.Equal(Vector256.Create(double.ConvertToIntegerNative(2.6)), Vector256.ConvertToUInt64Native(Vector256.Create(2.6))); Assert.Equal(Vector256.Create(double.ConvertToIntegerNative(double.MaxValue)), Vector256.ConvertToUInt64Native(Vector256.Create(double.MaxValue))); } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampDouble), MemberType = typeof(GenericMathTestMemberData))] + public void ClampDoubleTest(double x, double min, double max, double expectedResult) + { + Vector256 actualResult = Vector256.Clamp(Vector256.Create(x), Vector256.Create(min), Vector256.Create(max)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector256 actualResult = Vector256.Clamp(Vector256.Create(x), Vector256.Create(min), Vector256.Create(max)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.CopySign(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.CopySign(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansDouble), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansDoubleTest(double value, double expectedResult, double variance) + { + Vector256 actualResult1 = Vector256.DegreesToRadians(Vector256.Create(-value)); + AssertEqual(Vector256.Create(-expectedResult), actualResult1, Vector256.Create(variance)); + + Vector256 actualResult2 = Vector256.DegreesToRadians(Vector256.Create(+value)); + AssertEqual(Vector256.Create(+expectedResult), actualResult2, Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector256.Create(-expectedResult), Vector256.DegreesToRadians(Vector256.Create(-value)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(+expectedResult), Vector256.DegreesToRadians(Vector256.Create(+value)), Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotDouble), MemberType = typeof(GenericMathTestMemberData))] + public void HypotDoubleTest(double x, double y, double expectedResult, double variance) + { + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-x), Vector256.Create(-y)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-x), Vector256.Create(+y)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+x), Vector256.Create(-y)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+x), Vector256.Create(+y)), Vector256.Create(variance)); + + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-y), Vector256.Create(-x)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-y), Vector256.Create(+x)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+y), Vector256.Create(-x)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+y), Vector256.Create(+x)), Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-x), Vector256.Create(-y)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-x), Vector256.Create(+y)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+x), Vector256.Create(-y)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+x), Vector256.Create(+y)), Vector256.Create(variance)); + + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-y), Vector256.Create(-x)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(-y), Vector256.Create(+x)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+y), Vector256.Create(-x)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(expectedResult), Vector256.Hypot(Vector256.Create(+y), Vector256.Create(+x)), Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsNaN(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsNaN(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsNegative(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsNegative(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsPositive(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsPositive(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinityDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinityDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsPositiveInfinity(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinitySingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinitySingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsPositiveInfinity(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsZero(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector256.AllBitsSet : Vector256.Zero, Vector256.IsZero(Vector256.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpDouble), MemberType = typeof(GenericMathTestMemberData))] + public void LerpDoubleTest(double x, double y, double amount, double expectedResult) + { + AssertEqual(Vector256.Create(+expectedResult), Vector256.Lerp(Vector256.Create(+x), Vector256.Create(+y), Vector256.Create(amount)), Vector256.Zero); + AssertEqual(Vector256.Create((expectedResult == 0.0) ? expectedResult : -expectedResult), Vector256.Lerp(Vector256.Create(-x), Vector256.Create(-y), Vector256.Create(amount)), Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector256.Create(+expectedResult), Vector256.Lerp(Vector256.Create(+x), Vector256.Create(+y), Vector256.Create(amount)), Vector256.Zero); + AssertEqual(Vector256.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector256.Lerp(Vector256.Create(-x), Vector256.Create(-y), Vector256.Create(amount)), Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.Max(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.Max(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.MaxMagnitude(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.MaxMagnitude(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.MaxMagnitudeNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.MaxMagnitudeNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.MaxNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.MaxNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.Min(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.Min(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.MinMagnitude(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.MinMagnitude(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.MinMagnitudeNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.MinMagnitudeNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberDoubleTest(double x, double y, double expectedResult) + { + Vector256 actualResult = Vector256.MinNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector256 actualResult = Vector256.MinNumber(Vector256.Create(x), Vector256.Create(y)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesDoubleTest(double value, double expectedResult, double variance) + { + AssertEqual(Vector256.Create(-expectedResult), Vector256.RadiansToDegrees(Vector256.Create(-value)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(+expectedResult), Vector256.RadiansToDegrees(Vector256.Create(+value)), Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector256.Create(-expectedResult), Vector256.RadiansToDegrees(Vector256.Create(-value)), Vector256.Create(variance)); + AssertEqual(Vector256.Create(+expectedResult), Vector256.RadiansToDegrees(Vector256.Create(+value)), Vector256.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundDoubleTest(double value, double expectedResult) + { + Vector256 actualResult = Vector256.Round(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector256 actualResult = Vector256.Round(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroDoubleTest(double value, double expectedResult) + { + Vector256 actualResult = Vector256.Round(Vector256.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector256 actualResult = Vector256.Round(Vector256.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenDoubleTest(double value, double expectedResult) + { + Vector256 actualResult = Vector256.Round(Vector256.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector256 actualResult = Vector256.Round(Vector256.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateDoubleTest(double value, double expectedResult) + { + Vector256 actualResult = Vector256.Truncate(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector256 actualResult = Vector256.Truncate(Vector256.Create(value)); + AssertEqual(Vector256.Create(expectedResult), actualResult, Vector256.Zero); + } } } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs index 93ecf183070ecb..b88bb78ec93c4b 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs @@ -5,6 +5,7 @@ using System.Reflection; using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; +using System.Tests; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -5273,7 +5274,7 @@ private static void TestCreateSequence(T start, T step) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] [SkipOnMono("https://github.com/dotnet/runtime/issues/97176")] public void ExpDoubleTest(double value, double expectedResult, double variance) { @@ -5282,7 +5283,7 @@ public void ExpDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] [SkipOnMono("https://github.com/dotnet/runtime/issues/97176")] public void ExpSingleTest(float value, float expectedResult, float variance) { @@ -5291,7 +5292,7 @@ public void ExpSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogDouble), MemberType = typeof(GenericMathTestMemberData))] public void LogDoubleTest(double value, double expectedResult, double variance) { Vector512 actualResult = Vector512.Log(Vector512.Create(value)); @@ -5299,7 +5300,7 @@ public void LogDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] public void LogSingleTest(float value, float expectedResult, float variance) { Vector512 actualResult = Vector512.Log(Vector512.Create(value)); @@ -5307,7 +5308,7 @@ public void LogSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Double), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] public void Log2DoubleTest(double value, double expectedResult, double variance) { Vector512 actualResult = Vector512.Log2(Vector512.Create(value)); @@ -5315,7 +5316,7 @@ public void Log2DoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Single), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] public void Log2SingleTest(float value, float expectedResult, float variance) { Vector512 actualResult = Vector512.Log2(Vector512.Create(value)); @@ -5323,7 +5324,7 @@ public void Log2SingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddDoubleTest(double left, double right, double addend) { Vector512 actualResult = Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); @@ -5331,7 +5332,7 @@ public void FusedMultiplyAddDoubleTest(double left, double right, double addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { Vector512 actualResult = Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); @@ -5339,7 +5340,7 @@ public void FusedMultiplyAddSingleTest(float left, float right, float addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) { Vector512 actualResult = Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); @@ -5347,7 +5348,7 @@ public void MultiplyAddEstimateDoubleTest(double left, double right, double adde } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { Vector512 actualResult = Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); @@ -5435,5 +5436,380 @@ public void ConvertToUInt64NativeTest() Assert.Equal(Vector512.Create(double.ConvertToIntegerNative(2.6)), Vector512.ConvertToUInt64Native(Vector512.Create(2.6))); Assert.Equal(Vector512.Create(double.ConvertToIntegerNative(double.MaxValue)), Vector512.ConvertToUInt64Native(Vector512.Create(double.MaxValue))); } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampDouble), MemberType = typeof(GenericMathTestMemberData))] + public void ClampDoubleTest(double x, double min, double max, double expectedResult) + { + Vector512 actualResult = Vector512.Clamp(Vector512.Create(x), Vector512.Create(min), Vector512.Create(max)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector512 actualResult = Vector512.Clamp(Vector512.Create(x), Vector512.Create(min), Vector512.Create(max)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.CopySign(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.CopySign(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansDouble), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansDoubleTest(double value, double expectedResult, double variance) + { + Vector512 actualResult1 = Vector512.DegreesToRadians(Vector512.Create(-value)); + AssertEqual(Vector512.Create(-expectedResult), actualResult1, Vector512.Create(variance)); + + Vector512 actualResult2 = Vector512.DegreesToRadians(Vector512.Create(+value)); + AssertEqual(Vector512.Create(+expectedResult), actualResult2, Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector512.Create(-expectedResult), Vector512.DegreesToRadians(Vector512.Create(-value)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(+expectedResult), Vector512.DegreesToRadians(Vector512.Create(+value)), Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotDouble), MemberType = typeof(GenericMathTestMemberData))] + public void HypotDoubleTest(double x, double y, double expectedResult, double variance) + { + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-x), Vector512.Create(-y)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-x), Vector512.Create(+y)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+x), Vector512.Create(-y)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+x), Vector512.Create(+y)), Vector512.Create(variance)); + + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-y), Vector512.Create(-x)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-y), Vector512.Create(+x)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+y), Vector512.Create(-x)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+y), Vector512.Create(+x)), Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-x), Vector512.Create(-y)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-x), Vector512.Create(+y)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+x), Vector512.Create(-y)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+x), Vector512.Create(+y)), Vector512.Create(variance)); + + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-y), Vector512.Create(-x)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(-y), Vector512.Create(+x)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+y), Vector512.Create(-x)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(expectedResult), Vector512.Hypot(Vector512.Create(+y), Vector512.Create(+x)), Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsNaN(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsNaN(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsNegative(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsNegative(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsPositive(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsPositive(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinityDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinityDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsPositiveInfinity(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinitySingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinitySingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsPositiveInfinity(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsZero(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector512.AllBitsSet : Vector512.Zero, Vector512.IsZero(Vector512.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpDouble), MemberType = typeof(GenericMathTestMemberData))] + public void LerpDoubleTest(double x, double y, double amount, double expectedResult) + { + AssertEqual(Vector512.Create(+expectedResult), Vector512.Lerp(Vector512.Create(+x), Vector512.Create(+y), Vector512.Create(amount)), Vector512.Zero); + AssertEqual(Vector512.Create((expectedResult == 0.0) ? expectedResult : -expectedResult), Vector512.Lerp(Vector512.Create(-x), Vector512.Create(-y), Vector512.Create(amount)), Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector512.Create(+expectedResult), Vector512.Lerp(Vector512.Create(+x), Vector512.Create(+y), Vector512.Create(amount)), Vector512.Zero); + AssertEqual(Vector512.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector512.Lerp(Vector512.Create(-x), Vector512.Create(-y), Vector512.Create(amount)), Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.Max(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.Max(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.MaxMagnitude(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.MaxMagnitude(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.MaxMagnitudeNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.MaxMagnitudeNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.MaxNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.MaxNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.Min(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.Min(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.MinMagnitude(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.MinMagnitude(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.MinMagnitudeNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.MinMagnitudeNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberDoubleTest(double x, double y, double expectedResult) + { + Vector512 actualResult = Vector512.MinNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector512 actualResult = Vector512.MinNumber(Vector512.Create(x), Vector512.Create(y)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesDoubleTest(double value, double expectedResult, double variance) + { + AssertEqual(Vector512.Create(-expectedResult), Vector512.RadiansToDegrees(Vector512.Create(-value)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(+expectedResult), Vector512.RadiansToDegrees(Vector512.Create(+value)), Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector512.Create(-expectedResult), Vector512.RadiansToDegrees(Vector512.Create(-value)), Vector512.Create(variance)); + AssertEqual(Vector512.Create(+expectedResult), Vector512.RadiansToDegrees(Vector512.Create(+value)), Vector512.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundDoubleTest(double value, double expectedResult) + { + Vector512 actualResult = Vector512.Round(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector512 actualResult = Vector512.Round(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroDoubleTest(double value, double expectedResult) + { + Vector512 actualResult = Vector512.Round(Vector512.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector512 actualResult = Vector512.Round(Vector512.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenDoubleTest(double value, double expectedResult) + { + Vector512 actualResult = Vector512.Round(Vector512.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector512 actualResult = Vector512.Round(Vector512.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateDoubleTest(double value, double expectedResult) + { + Vector512 actualResult = Vector512.Truncate(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector512 actualResult = Vector512.Truncate(Vector512.Create(value)); + AssertEqual(Vector512.Create(expectedResult), actualResult, Vector512.Zero); + } } } diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs index c42580263a038f..ddedcfc02d3a7d 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs @@ -4,7 +4,7 @@ using System.Numerics; using System.Reflection; using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.X86; +using System.Tests; using Xunit; namespace System.Runtime.Intrinsics.Tests.Vectors @@ -4242,7 +4242,7 @@ private static void TestCreateSequence(T start, T step) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpDouble), MemberType = typeof(GenericMathTestMemberData))] public void ExpDoubleTest(double value, double expectedResult, double variance) { Vector64 actualResult = Vector64.Exp(Vector64.Create(value)); @@ -4250,7 +4250,7 @@ public void ExpDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.ExpSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] public void ExpSingleTest(float value, float expectedResult, float variance) { Vector64 actualResult = Vector64.Exp(Vector64.Create(value)); @@ -4258,7 +4258,7 @@ public void ExpSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogDouble), MemberType = typeof(GenericMathTestMemberData))] public void LogDoubleTest(double value, double expectedResult, double variance) { Vector64 actualResult = Vector64.Log(Vector64.Create(value)); @@ -4266,7 +4266,7 @@ public void LogDoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.LogSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] public void LogSingleTest(float value, float expectedResult, float variance) { Vector64 actualResult = Vector64.Log(Vector64.Create(value)); @@ -4274,7 +4274,7 @@ public void LogSingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Double), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] public void Log2DoubleTest(double value, double expectedResult, double variance) { Vector64 actualResult = Vector64.Log2(Vector64.Create(value)); @@ -4282,7 +4282,7 @@ public void Log2DoubleTest(double value, double expectedResult, double variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.Log2Single), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] public void Log2SingleTest(float value, float expectedResult, float variance) { Vector64 actualResult = Vector64.Log2(Vector64.Create(value)); @@ -4290,7 +4290,7 @@ public void Log2SingleTest(float value, float expectedResult, float variance) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddDoubleTest(double left, double right, double addend) { Vector64 actualResult = Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); @@ -4298,7 +4298,7 @@ public void FusedMultiplyAddDoubleTest(double left, double right, double addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void FusedMultiplyAddSingleTest(float left, float right, float addend) { Vector64 actualResult = Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); @@ -4306,7 +4306,7 @@ public void FusedMultiplyAddSingleTest(float left, float right, float addend) } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddDouble), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) { Vector64 actualResult = Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); @@ -4314,7 +4314,7 @@ public void MultiplyAddEstimateDoubleTest(double left, double right, double adde } [Theory] - [MemberData(nameof(VectorTestMemberData.MultiplyAddSingle), MemberType = typeof(VectorTestMemberData))] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public void MultiplyAddEstimateSingleTest(float left, float right, float addend) { Vector64 actualResult = Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); @@ -4392,5 +4392,380 @@ public void ConvertToUInt64NativeTest() Assert.Equal(Vector64.Create(double.ConvertToIntegerNative(2.6)), Vector64.ConvertToUInt64Native(Vector64.Create(2.6))); Assert.Equal(Vector64.Create(double.ConvertToIntegerNative(double.MaxValue)), Vector64.ConvertToUInt64Native(Vector64.Create(double.MaxValue))); } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampDouble), MemberType = typeof(GenericMathTestMemberData))] + public void ClampDoubleTest(double x, double min, double max, double expectedResult) + { + Vector64 actualResult = Vector64.Clamp(Vector64.Create(x), Vector64.Create(min), Vector64.Create(max)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public void ClampSingleTest(float x, float min, float max, float expectedResult) + { + Vector64 actualResult = Vector64.Clamp(Vector64.Create(x), Vector64.Create(min), Vector64.Create(max)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignDouble), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.CopySign(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] + public void CopySignSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.CopySign(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansDouble), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansDoubleTest(double value, double expectedResult, double variance) + { + Vector64 actualResult1 = Vector64.DegreesToRadians(Vector64.Create(-value)); + AssertEqual(Vector64.Create(-expectedResult), actualResult1, Vector64.Create(variance)); + + Vector64 actualResult2 = Vector64.DegreesToRadians(Vector64.Create(+value)); + AssertEqual(Vector64.Create(+expectedResult), actualResult2, Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] + public void DegreesToRadiansSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector64.Create(-expectedResult), Vector64.DegreesToRadians(Vector64.Create(-value)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(+expectedResult), Vector64.DegreesToRadians(Vector64.Create(+value)), Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotDouble), MemberType = typeof(GenericMathTestMemberData))] + public void HypotDoubleTest(double x, double y, double expectedResult, double variance) + { + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-x), Vector64.Create(-y)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-x), Vector64.Create(+y)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+x), Vector64.Create(-y)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+x), Vector64.Create(+y)), Vector64.Create(variance)); + + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-y), Vector64.Create(-x)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-y), Vector64.Create(+x)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+y), Vector64.Create(-x)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+y), Vector64.Create(+x)), Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] + public void HypotSingleTest(float x, float y, float expectedResult, float variance) + { + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-x), Vector64.Create(-y)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-x), Vector64.Create(+y)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+x), Vector64.Create(-y)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+x), Vector64.Create(+y)), Vector64.Create(variance)); + + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-y), Vector64.Create(-x)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(-y), Vector64.Create(+x)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+y), Vector64.Create(-x)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(expectedResult), Vector64.Hypot(Vector64.Create(+y), Vector64.Create(+x)), Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsNaN(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNaNSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsNaN(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsNegative(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsNegativeSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsNegative(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsPositive(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsPositive(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinityDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinityDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsPositiveInfinity(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinitySingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsPositiveInfinitySingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsPositiveInfinity(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroDoubleTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsZero(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void IsZeroSingleTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult ? Vector64.AllBitsSet : Vector64.Zero, Vector64.IsZero(Vector64.Create(value))); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpDouble), MemberType = typeof(GenericMathTestMemberData))] + public void LerpDoubleTest(double x, double y, double amount, double expectedResult) + { + AssertEqual(Vector64.Create(+expectedResult), Vector64.Lerp(Vector64.Create(+x), Vector64.Create(+y), Vector64.Create(amount)), Vector64.Zero); + AssertEqual(Vector64.Create((expectedResult == 0.0) ? expectedResult : -expectedResult), Vector64.Lerp(Vector64.Create(-x), Vector64.Create(-y), Vector64.Create(amount)), Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] + public void LerpSingleTest(float x, float y, float amount, float expectedResult) + { + AssertEqual(Vector64.Create(+expectedResult), Vector64.Lerp(Vector64.Create(+x), Vector64.Create(+y), Vector64.Create(amount)), Vector64.Zero); + AssertEqual(Vector64.Create((expectedResult == 0.0f) ? expectedResult : -expectedResult), Vector64.Lerp(Vector64.Create(-x), Vector64.Create(-y), Vector64.Create(amount)), Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.Max(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.Max(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.MaxMagnitude(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.MaxMagnitude(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.MaxMagnitudeNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.MaxMagnitudeNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.MaxNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MaxNumberSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.MaxNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.Min(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.Min(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.MinMagnitude(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.MinMagnitude(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.MinMagnitudeNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinMagnitudeNumberSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.MinMagnitudeNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberDoubleTest(double x, double y, double expectedResult) + { + Vector64 actualResult = Vector64.MinNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public void MinNumberSingleTest(float x, float y, float expectedResult) + { + Vector64 actualResult = Vector64.MinNumber(Vector64.Create(x), Vector64.Create(y)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesDoubleTest(double value, double expectedResult, double variance) + { + AssertEqual(Vector64.Create(-expectedResult), Vector64.RadiansToDegrees(Vector64.Create(-value)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(+expectedResult), Vector64.RadiansToDegrees(Vector64.Create(+value)), Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RadiansToDegreesSingleTest(float value, float expectedResult, float variance) + { + AssertEqual(Vector64.Create(-expectedResult), Vector64.RadiansToDegrees(Vector64.Create(-value)), Vector64.Create(variance)); + AssertEqual(Vector64.Create(+expectedResult), Vector64.RadiansToDegrees(Vector64.Create(+value)), Vector64.Create(variance)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundDoubleTest(double value, double expectedResult) + { + Vector64 actualResult = Vector64.Round(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundSingleTest(float value, float expectedResult) + { + Vector64 actualResult = Vector64.Round(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroDoubleTest(double value, double expectedResult) + { + Vector64 actualResult = Vector64.Round(Vector64.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundAwayFromZeroSingleTest(float value, float expectedResult) + { + Vector64 actualResult = Vector64.Round(Vector64.Create(value), MidpointRounding.AwayFromZero); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenDouble), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenDoubleTest(double value, double expectedResult) + { + Vector64 actualResult = Vector64.Round(Vector64.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] + public void RoundToEvenSingleTest(float value, float expectedResult) + { + Vector64 actualResult = Vector64.Round(Vector64.Create(value), MidpointRounding.ToEven); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateDoubleTest(double value, double expectedResult) + { + Vector64 actualResult = Vector64.Truncate(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public void TruncateSingleTest(float value, float expectedResult) + { + Vector64 actualResult = Vector64.Truncate(Vector64.Create(value)); + AssertEqual(Vector64.Create(expectedResult), actualResult, Vector64.Zero); + } } } diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System.Runtime.Extensions.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System.Runtime.Extensions.Tests.csproj index bf090364567c53..6efe773b447f87 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System.Runtime.Extensions.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System.Runtime.Extensions.Tests.csproj @@ -1,4 +1,4 @@ - + true true @@ -86,6 +86,7 @@ + diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs index 7d8606b799d649..136e4acf1d3735 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/Math.cs @@ -658,46 +658,7 @@ public static void IEEERemainder() } [Theory] - [InlineData( double.NegativeInfinity, double.NaN, 0.0)] - [InlineData(-3.1415926535897932, double.NaN, 0.0)] // value: -(pi) - [InlineData(-2.7182818284590452, double.NaN, 0.0)] // value: -(e) - [InlineData(-1.4142135623730950, double.NaN, 0.0)] // value: -(sqrt(2)) - [InlineData(-1.0, double.NaN, 0.0)] - [InlineData(-0.69314718055994531, double.NaN, 0.0)] // value: -(ln(2)) - [InlineData(-0.43429448190325183, double.NaN, 0.0)] // value: -(log10(e)) - [InlineData(-0.0, double.NegativeInfinity, 0.0)] - [InlineData( double.NaN, double.NaN, 0.0)] - [InlineData( 0.0, double.NegativeInfinity, 0.0)] - [InlineData( 0.043213918263772250, -3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) - [InlineData( 0.065988035845312537, -2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: -(e) - [InlineData( 0.1, -2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) - [InlineData( 0.20787957635076191, -1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) - [InlineData( 0.23629008834452270, -1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) - [InlineData( 0.24311673443421421, -1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) - [InlineData( 0.32355726390307110, -1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) - [InlineData( 0.36787944117144232, -1.0, CrossPlatformMachineEpsilon * 10)] - [InlineData( 0.45593812776599624, -0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) - [InlineData( 0.49306869139523979, -0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) - [InlineData( 0.5, -0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) - [InlineData( 0.52907780826773535, -0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) - [InlineData( 0.64772148514180065, -0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) - [InlineData( 0.72737734929521647, -0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) - [InlineData( 1.0, 0.0, 0.0)] - [InlineData( 1.3748022274393586, 0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: (1 / pi) - [InlineData( 1.5438734439711811, 0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: (log10(e)) - [InlineData( 1.8900811645722220, 0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: (2 / pi) - [InlineData( 2.0, 0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: (ln(2)) - [InlineData( 2.0281149816474725, 0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) - [InlineData( 2.1932800507380155, 0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: (pi / 4) - [InlineData( 2.7182818284590452, 1.0, CrossPlatformMachineEpsilon * 10)] // value: (e) - [InlineData( 3.0906430223107976, 1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) - [InlineData( 4.1132503787829275, 1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) - [InlineData( 4.2320861065570819, 1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) - [InlineData( 4.8104773809653517, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) - [InlineData( 10.0, 2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) - [InlineData( 15.154262241479264, 2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: (e) - [InlineData( 23.140692632779269, 3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: (pi) - [InlineData( double.PositiveInfinity, double.PositiveInfinity, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.LogDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Log(double value, double expectedResult, double allowedVariance) { AssertExtensions.Equal(expectedResult, Math.Log(value), allowedVariance); @@ -776,23 +737,7 @@ public static void Max_Decimal() } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MaxValue)] - [InlineData(double.MaxValue, double.MinValue, double.MaxValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, double.NaN)] - [InlineData(1.0, double.NaN, double.NaN)] - [InlineData(double.PositiveInfinity, double.NaN, double.NaN)] - [InlineData(double.NegativeInfinity, double.NaN, double.NaN)] - [InlineData(double.NaN, double.PositiveInfinity, double.NaN)] - [InlineData(double.NaN, double.NegativeInfinity, double.NaN)] - [InlineData(-0.0, 0.0, 0.0)] - [InlineData( 0.0, -0.0, 0.0)] - [InlineData( 2.0, -3.0, 2.0)] - [InlineData(-3.0, 2.0, 2.0)] - [InlineData( 3.0, -2.0, 3.0)] - [InlineData(-2.0, 3.0, 3.0)] + [MemberData(nameof(GenericMathTestMemberData.MaxDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Max_Double_NotNetFramework(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, Math.Max(x, y), 0.0); @@ -857,23 +802,7 @@ public static void Max_SByte() } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] - [InlineData(float.MaxValue, float.MinValue, float.MaxValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0, float.NaN)] - [InlineData(1.0, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] - [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0, 0.0, 0.0)] - [InlineData( 0.0, -0.0, 0.0)] - [InlineData( 2.0, -3.0, 2.0)] - [InlineData(-3.0, 2.0, 2.0)] - [InlineData( 3.0, -2.0, 3.0)] - [InlineData(-2.0, 3.0, 3.0)] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Max_Single_NotNetFramework(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, Math.Max(x, y), 0.0f); @@ -945,23 +874,7 @@ public static void Min_Decimal() } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MinValue)] - [InlineData(double.MaxValue, double.MinValue, double.MinValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, double.NaN)] - [InlineData(1.0, double.NaN, double.NaN)] - [InlineData(double.PositiveInfinity, double.NaN, double.NaN)] - [InlineData(double.NegativeInfinity, double.NaN, double.NaN)] - [InlineData(double.NaN, double.PositiveInfinity, double.NaN)] - [InlineData(double.NaN, double.NegativeInfinity, double.NaN)] - [InlineData(-0.0, 0.0, -0.0)] - [InlineData( 0.0, -0.0, -0.0)] - [InlineData( 2.0, -3.0, -3.0)] - [InlineData(-3.0, 2.0, -3.0)] - [InlineData( 3.0, -2.0, -2.0)] - [InlineData(-2.0, 3.0, -2.0)] + [MemberData(nameof(GenericMathTestMemberData.MinDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Min_Double_NotNetFramework(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, Math.Min(x, y), 0.0); @@ -1026,23 +939,7 @@ public static void Min_SByte() } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MinValue)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0, float.NaN)] - [InlineData(1.0, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] - [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0, 0.0, -0.0)] - [InlineData( 0.0, -0.0, -0.0)] - [InlineData( 2.0, -3.0, -3.0)] - [InlineData(-3.0, 2.0, -3.0)] - [InlineData( 3.0, -2.0, -2.0)] - [InlineData(-2.0, 3.0, -2.0)] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Min_Single_NotNetFramework(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, Math.Min(x, y), 0.0f); @@ -1708,12 +1605,11 @@ public static void Truncate_Decimal() Assert.Equal(-3.0m, Math.Truncate(-3.14159m)); } - [Fact] - public static void Truncate_Double() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void Truncate_Double(double value, double expectedResult) { - Assert.Equal(0.0, Math.Truncate(0.12345)); - Assert.Equal(3.0, Math.Truncate(3.14159)); - Assert.Equal(-3.0, Math.Truncate(-3.14159)); + AssertExtensions.Equal(expectedResult, Math.Truncate(value)); } [Theory] @@ -2378,7 +2274,6 @@ public static void Clamp_ULong(ulong value, ulong min, ulong max, ulong expected Assert.Equal(expected, Math.Clamp(value, min, max)); } - [Theory] [MemberData(nameof(Clamp_SignedInt_TestData))] public static void Clamp_NInt(int value, int min, int max, int expected) @@ -2394,38 +2289,14 @@ public static void Clamp_NUInt(uint value, uint min, uint max, uint expected) } [Theory] - [MemberData(nameof(Clamp_SignedInt_TestData))] - [InlineData(double.NegativeInfinity, double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)] - [InlineData(1, double.NegativeInfinity, double.PositiveInfinity, 1)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(1, double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(1, double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(double.NaN, double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, double.NaN, 1, double.NaN)] - [InlineData(double.NaN, 1, double.NaN, double.NaN)] - [InlineData(double.NaN, 1, 1, double.NaN)] - [InlineData(1, double.NaN, double.NaN, 1)] - [InlineData(1, double.NaN, 1, 1)] - [InlineData(1, 1, double.NaN, 1)] + [MemberData(nameof(GenericMathTestMemberData.ClampDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Clamp_Double(double value, double min, double max, double expected) { Assert.Equal(expected, Math.Clamp(value, min, max)); } [Theory] - [MemberData(nameof(Clamp_SignedInt_TestData))] - [InlineData(float.NegativeInfinity, float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] - [InlineData(1, float.NegativeInfinity, float.PositiveInfinity, 1)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(1, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(1, float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.NaN, float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, float.NaN, 1, float.NaN)] - [InlineData(float.NaN, 1, float.NaN, float.NaN)] - [InlineData(float.NaN, 1, 1, float.NaN)] - [InlineData(1, float.NaN, float.NaN, 1)] - [InlineData(1, float.NaN, 1, 1)] - [InlineData(1, 1, float.NaN, 1)] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Clamp_Float(float value, float min, float max, float expected) { Assert.Equal(expected, Math.Clamp(value, min, max)); @@ -2456,127 +2327,14 @@ public static void Clamp_MinGreaterThanMax_ThrowsArgumentException() } [Theory] - [InlineData( double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData( double.NegativeInfinity, -3.1415926535897932, double.NegativeInfinity)] - [InlineData( double.NegativeInfinity, -0.0, double.NegativeInfinity)] - [InlineData( double.NegativeInfinity, double.NaN, double.NegativeInfinity)] - [InlineData( double.NegativeInfinity, 0.0, double.PositiveInfinity)] - [InlineData( double.NegativeInfinity, 3.1415926535897932, double.PositiveInfinity)] - [InlineData( double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(-3.1415926535897932, double.NegativeInfinity, -3.1415926535897932)] - [InlineData(-3.1415926535897932, -3.1415926535897932, -3.1415926535897932)] - [InlineData(-3.1415926535897932, -0.0, -3.1415926535897932)] - [InlineData(-3.1415926535897932, double.NaN, -3.1415926535897932)] - [InlineData(-3.1415926535897932, 0.0, 3.1415926535897932)] - [InlineData(-3.1415926535897932, 3.1415926535897932, 3.1415926535897932)] - [InlineData(-3.1415926535897932, double.PositiveInfinity, 3.1415926535897932)] - [InlineData(-0.0, double.NegativeInfinity, -0.0)] - [InlineData(-0.0, -3.1415926535897932, -0.0)] - [InlineData(-0.0, -0.0, -0.0)] - [InlineData(-0.0, double.NaN, -0.0)] - [InlineData(-0.0, 0.0, 0.0)] - [InlineData(-0.0, 3.1415926535897932, 0.0)] - [InlineData(-0.0, double.PositiveInfinity, 0.0)] - [InlineData( double.NaN, double.NegativeInfinity, double.NaN)] - [InlineData( double.NaN, -3.1415926535897932, double.NaN)] - [InlineData( double.NaN, -0.0, double.NaN)] - [InlineData( double.NaN, double.NaN, double.NaN)] - [InlineData( double.NaN, 0.0, double.NaN)] - [InlineData( double.NaN, 3.1415926535897932, double.NaN)] - [InlineData( double.NaN, double.PositiveInfinity, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, -0.0)] - [InlineData( 0.0, -3.1415926535897932, -0.0)] - [InlineData( 0.0, -0.0, -0.0)] - [InlineData( 0.0, double.NaN, -0.0)] - [InlineData( 0.0, 0.0, 0.0)] - [InlineData( 0.0, 3.1415926535897932, 0.0)] - [InlineData( 0.0, double.PositiveInfinity, 0.0)] - [InlineData( 3.1415926535897932, double.NegativeInfinity, -3.1415926535897932)] - [InlineData( 3.1415926535897932, -3.1415926535897932, -3.1415926535897932)] - [InlineData( 3.1415926535897932, -0.0, -3.1415926535897932)] - [InlineData( 3.1415926535897932, double.NaN, -3.1415926535897932)] - [InlineData( 3.1415926535897932, 0.0, 3.1415926535897932)] - [InlineData( 3.1415926535897932, 3.1415926535897932, 3.1415926535897932)] - [InlineData( 3.1415926535897932, double.PositiveInfinity, 3.1415926535897932)] - [InlineData( double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData( double.PositiveInfinity, -3.1415926535897932, double.NegativeInfinity)] - [InlineData( double.PositiveInfinity, -0.0, double.NegativeInfinity)] - [InlineData( double.PositiveInfinity, double.NaN, double.NegativeInfinity)] - [InlineData( double.PositiveInfinity, 0.0, double.PositiveInfinity)] - [InlineData( double.PositiveInfinity, 3.1415926535897932, double.PositiveInfinity)] - [InlineData( double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity)] + [MemberData(nameof(GenericMathTestMemberData.CopySignDouble), MemberType = typeof(GenericMathTestMemberData))] public static void CopySign(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, Math.CopySign(x, y), 0.0); } [Theory] - [InlineData( double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity, double.NaN)] - [InlineData( double.NegativeInfinity, -0.0, double.NegativeInfinity, double.NaN)] - [InlineData( double.NegativeInfinity, -0.0, -3.1415926535897932, double.NaN)] - [InlineData( double.NegativeInfinity, -0.0, -0.0, double.NaN)] - [InlineData( double.NegativeInfinity, -0.0, double.NaN, double.NaN)] - [InlineData( double.NegativeInfinity, -0.0, 0.0, double.NaN)] - [InlineData( double.NegativeInfinity, -0.0, 3.1415926535897932, double.NaN)] - [InlineData( double.NegativeInfinity, -0.0, double.PositiveInfinity, double.NaN)] - [InlineData( double.NegativeInfinity, 0.0, double.NegativeInfinity, double.NaN)] - [InlineData( double.NegativeInfinity, 0.0, -3.1415926535897932, double.NaN)] - [InlineData( double.NegativeInfinity, 0.0, -0.0, double.NaN)] - [InlineData( double.NegativeInfinity, 0.0, double.NaN, double.NaN)] - [InlineData( double.NegativeInfinity, 0.0, 0.0, double.NaN)] - [InlineData( double.NegativeInfinity, 0.0, 3.1415926535897932, double.NaN)] - [InlineData( double.NegativeInfinity, 0.0, double.PositiveInfinity, double.NaN)] - [InlineData( double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity, double.NaN)] - [InlineData(-1e308, 2.0, 1e308, -1e308)] - [InlineData(-1e308, 2.0, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(-5, 4, -3, -23)] - [InlineData(-0.0, double.NegativeInfinity, double.NegativeInfinity, double.NaN)] - [InlineData(-0.0, double.NegativeInfinity, -3.1415926535897932, double.NaN)] - [InlineData(-0.0, double.NegativeInfinity, -0.0, double.NaN)] - [InlineData(-0.0, double.NegativeInfinity, double.NaN, double.NaN)] - [InlineData(-0.0, double.NegativeInfinity, 0.0, double.NaN)] - [InlineData(-0.0, double.NegativeInfinity, 3.1415926535897932, double.NaN)] - [InlineData(-0.0, double.NegativeInfinity, double.PositiveInfinity, double.NaN)] - [InlineData(-0.0, double.PositiveInfinity, double.NegativeInfinity, double.NaN)] - [InlineData(-0.0, double.PositiveInfinity, -3.1415926535897932, double.NaN)] - [InlineData(-0.0, double.PositiveInfinity, -0.0, double.NaN)] - [InlineData(-0.0, double.PositiveInfinity, double.NaN, double.NaN)] - [InlineData(-0.0, double.PositiveInfinity, 0.0, double.NaN)] - [InlineData(-0.0, double.PositiveInfinity, 3.1415926535897932, double.NaN)] - [InlineData(-0.0, double.PositiveInfinity, double.PositiveInfinity, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, double.NegativeInfinity, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, -3.1415926535897932, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, -0.0, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, double.NaN, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, 0.0, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, 3.1415926535897932, double.NaN)] - [InlineData( 0.0, double.NegativeInfinity, double.PositiveInfinity, double.NaN)] - [InlineData( 0.0, double.PositiveInfinity, double.NegativeInfinity, double.NaN)] - [InlineData( 0.0, double.PositiveInfinity, -3.1415926535897932, double.NaN)] - [InlineData( 0.0, double.PositiveInfinity, -0.0, double.NaN)] - [InlineData( 0.0, double.PositiveInfinity, double.NaN, double.NaN)] - [InlineData( 0.0, double.PositiveInfinity, 0.0, double.NaN)] - [InlineData( 0.0, double.PositiveInfinity, 3.1415926535897932, double.NaN)] - [InlineData( 0.0, double.PositiveInfinity, double.PositiveInfinity, double.NaN)] - [InlineData( 5, 4, 3, 23)] - [InlineData( 1e308, 2.0, -1e308, 1e308)] - [InlineData( 1e308, 2.0, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData( double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity, double.NaN)] - [InlineData( double.PositiveInfinity, -0.0, double.NegativeInfinity, double.NaN)] - [InlineData( double.PositiveInfinity, -0.0, -3.1415926535897932, double.NaN)] - [InlineData( double.PositiveInfinity, -0.0, -0.0, double.NaN)] - [InlineData( double.PositiveInfinity, -0.0, double.NaN, double.NaN)] - [InlineData( double.PositiveInfinity, -0.0, 0.0, double.NaN)] - [InlineData( double.PositiveInfinity, -0.0, 3.1415926535897932, double.NaN)] - [InlineData( double.PositiveInfinity, -0.0, double.PositiveInfinity, double.NaN)] - [InlineData( double.PositiveInfinity, 0.0, double.NegativeInfinity, double.NaN)] - [InlineData( double.PositiveInfinity, 0.0, -3.1415926535897932, double.NaN)] - [InlineData( double.PositiveInfinity, 0.0, -0.0, double.NaN)] - [InlineData( double.PositiveInfinity, 0.0, double.NaN, double.NaN)] - [InlineData( double.PositiveInfinity, 0.0, 0.0, double.NaN)] - [InlineData( double.PositiveInfinity, 0.0, 3.1415926535897932, double.NaN)] - [InlineData( double.PositiveInfinity, 0.0, double.PositiveInfinity, double.NaN)] - [InlineData( double.PositiveInfinity, double.PositiveInfinity, double.NegativeInfinity, double.NaN)] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] public static void FusedMultiplyAdd(double x, double y, double z, double expectedResult) { AssertExtensions.Equal(expectedResult, Math.FusedMultiplyAdd(x, y, z), 0.0); @@ -2633,64 +2391,14 @@ public static void ILogB(double value, int expectedResult) } [Theory] - [InlineData( double.NegativeInfinity, double.NaN, 0.0)] - [InlineData(-0.11331473229676087, double.NaN, 0.0)] - [InlineData(-0.0, double.NegativeInfinity, 0.0)] - [InlineData( double.NaN, double.NaN, 0.0)] - [InlineData( 0.0, double.NegativeInfinity, 0.0)] - [InlineData( 0.11331473229676087, -3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) - [InlineData( 0.15195522325791297, -2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: -(e) - [InlineData( 0.20269956628651730, -2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) - [InlineData( 0.33662253682241906, -1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) - [InlineData( 0.36787944117144232, -1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) - [InlineData( 0.37521422724648177, -1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) - [InlineData( 0.45742934732229695, -1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) - [InlineData( 0.5, -1.0, CrossPlatformMachineEpsilon * 10)] - [InlineData( 0.58019181037172444, -0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) - [InlineData( 0.61254732653606592, -0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) - [InlineData( 0.61850313780157598, -0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) - [InlineData( 0.64321824193300488, -0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) - [InlineData( 0.74005557395545179, -0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) - [InlineData( 0.80200887896145195, -0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) - [InlineData( 1, 0.0, 0.0)] - [InlineData( 1.2468689889006383, 0.31830988618379067, CrossPlatformMachineEpsilon)] // expected: (1 / pi) - [InlineData( 1.3512498725672678, 0.43429448190325183, CrossPlatformMachineEpsilon)] // expected: (log10(e)) - [InlineData( 1.5546822754821001, 0.63661977236758134, CrossPlatformMachineEpsilon)] // expected: (2 / pi) - [InlineData( 1.6168066722416747, 0.69314718055994531, CrossPlatformMachineEpsilon)] // expected: (ln(2)) - [InlineData( 1.6325269194381528, 0.70710678118654752, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) - [InlineData( 1.7235679341273495, 0.78539816339744831, CrossPlatformMachineEpsilon)] // expected: (pi / 4) - [InlineData( 2, 1.0, CrossPlatformMachineEpsilon * 10)] // value: (e) - [InlineData( 2.1861299583286618, 1.1283791670955126, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) - [InlineData( 2.6651441426902252, 1.4142135623730950, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) - [InlineData( 2.7182818284590452, 1.4426950408889634, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) - [InlineData( 2.9706864235520193, 1.5707963267948966, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) - [InlineData( 4.9334096679145963, 2.3025850929940457, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) - [InlineData( 6.5808859910179210, 2.7182818284590452, CrossPlatformMachineEpsilon * 10)] // expected: (e) - [InlineData( 8.8249778270762876, 3.1415926535897932, CrossPlatformMachineEpsilon * 10)] // expected: (pi) - [InlineData( double.PositiveInfinity, double.PositiveInfinity, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] public static void Log2(double value, double expectedResult, double allowedVariance) { AssertExtensions.Equal(expectedResult, Math.Log2(value), allowedVariance); } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MaxValue)] - [InlineData(double.MaxValue, double.MinValue, double.MaxValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, double.NaN)] - [InlineData(1.0, double.NaN, double.NaN)] - [InlineData(double.PositiveInfinity, double.NaN, double.NaN)] - [InlineData(double.NegativeInfinity, double.NaN, double.NaN)] - [InlineData(double.NaN, double.PositiveInfinity, double.NaN)] - [InlineData(double.NaN, double.NegativeInfinity, double.NaN)] - [InlineData(-0.0, 0.0, 0.0)] - [InlineData(0.0, -0.0, 0.0)] - [InlineData(2.0, -3.0, -3.0)] - [InlineData(-3.0, 2.0, -3.0)] - [InlineData(3.0, -2.0, 3.0)] - [InlineData(-2.0, 3.0, 3.0)] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] public static void MaxMagnitude(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, Math.MaxMagnitude(x, y), 0.0); @@ -2720,23 +2428,7 @@ public static void MaxMagnitude(double x, double y, double expectedResult) } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MinValue)] - [InlineData(double.MaxValue, double.MinValue, double.MinValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, double.NaN)] - [InlineData(1.0, double.NaN, double.NaN)] - [InlineData(double.PositiveInfinity, double.NaN, double.NaN)] - [InlineData(double.NegativeInfinity, double.NaN, double.NaN)] - [InlineData(double.NaN, double.PositiveInfinity, double.NaN)] - [InlineData(double.NaN, double.NegativeInfinity, double.NaN)] - [InlineData(-0.0, 0.0, -0.0)] - [InlineData(0.0, -0.0, -0.0)] - [InlineData(2.0, -3.0, 2.0)] - [InlineData(-3.0, 2.0, 2.0)] - [InlineData(3.0, -2.0, -2.0)] - [InlineData(-2.0, 3.0, -2.0)] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] public static void MinMagnitude(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, Math.MinMagnitude(x, y), 0.0); @@ -3074,45 +2766,8 @@ public static void Round_Float_Constant_Arg() Assert.Equal(-4, MathF.Round(-3.5f, MidpointRounding.AwayFromZero)); } - public static IEnumerable Round_ToEven_TestData() - { - yield return new object[] { 1, 1 }; - yield return new object[] { 0.5, 0 }; - yield return new object[] { 1.5, 2 }; - yield return new object[] { 2.5, 2 }; - yield return new object[] { 3.5, 4 }; - - // Math.Round(var = 0.49999999999999994) returns 1 on ARM32 - if (!PlatformDetection.IsArmProcess) - yield return new object[] { 0.49999999999999994, 0 }; - - yield return new object[] { 1.5, 2 }; - yield return new object[] { 2.5, 2 }; - yield return new object[] { 3.5, 4 }; - yield return new object[] { 4.5, 4 }; - yield return new object[] { 3.141592653589793, 3 }; - yield return new object[] { 2.718281828459045, 3 }; - yield return new object[] { 1385.4557313670111, 1385 }; - yield return new object[] { 3423423.43432, 3423423 }; - yield return new object[] { 535345.5, 535346 }; - yield return new object[] { 535345.50001, 535346 }; - yield return new object[] { 535345.5, 535346 }; - yield return new object[] { 535345.4, 535345 }; - yield return new object[] { 535345.6, 535346 }; - yield return new object[] { -2.718281828459045, -3 }; - yield return new object[] { 10, 10 }; - yield return new object[] { -10, -10 }; - yield return new object[] { -0, -0 }; - yield return new object[] { 0, 0 }; - yield return new object[] { double.NaN, double.NaN }; - yield return new object[] { double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] { double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] { 1.7976931348623157E+308, 1.7976931348623157E+308 }; - yield return new object[] { -1.7976931348623157E+308, -1.7976931348623157E+308 }; - } - - [Theory] - [MemberData(nameof(Round_ToEven_TestData))] + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Round_ToEven_0(double value, double expected) { // Math.Round has special fast paths when MidpointRounding is a const @@ -3121,41 +2776,8 @@ public static void Round_ToEven_0(double value, double expected) Assert.Equal(expected, Math.Round(value, 0, MidpointRounding.ToEven)); } - public static IEnumerable Round_AwayFromZero_TestData() - { - yield return new object[] { 1, 1 }; - yield return new object[] { 0.5, 1 }; - yield return new object[] { 1.5, 2 }; - yield return new object[] { 2.5, 3 }; - yield return new object[] { 3.5, 4 }; - yield return new object[] { 0.49999999999999994, 0 }; - yield return new object[] { 1.5, 2 }; - yield return new object[] { 2.5, 3 }; - yield return new object[] { 3.5, 4 }; - yield return new object[] { 4.5, 5 }; - yield return new object[] { 3.141592653589793, 3 }; - yield return new object[] { 2.718281828459045, 3 }; - yield return new object[] { 1385.4557313670111, 1385 }; - yield return new object[] { 3423423.43432, 3423423 }; - yield return new object[] { 535345.5, 535346 }; - yield return new object[] { 535345.50001, 535346 }; - yield return new object[] { 535345.5, 535346 }; - yield return new object[] { 535345.4, 535345 }; - yield return new object[] { 535345.6, 535346 }; - yield return new object[] { -2.718281828459045, -3 }; - yield return new object[] { 10, 10 }; - yield return new object[] { -10, -10 }; - yield return new object[] { -0, -0 }; - yield return new object[] { 0, 0 }; - yield return new object[] { double.NaN, double.NaN }; - yield return new object[] { double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] { double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] { 1.7976931348623157E+308, 1.7976931348623157E+308 }; - yield return new object[] { -1.7976931348623157E+308, -1.7976931348623157E+308 }; - } - - [Theory] - [MemberData(nameof(Round_AwayFromZero_TestData))] + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Round_AwayFromZero_0(double value, double expected) { // Math.Round has special fast paths when MidpointRounding is a const diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs index 59040cd799c47a..565c00a986b294 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Extensions.Tests/System/MathF.cs @@ -577,55 +577,7 @@ public static void Ceiling(float value, float expectedResult, float allowedVaria } [Theory] - [InlineData(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.NegativeInfinity, -3.14159265f, float.NegativeInfinity)] - [InlineData(float.NegativeInfinity, -0.0f, float.NegativeInfinity)] - [InlineData(float.NegativeInfinity, float.NaN, float.NegativeInfinity)] - [InlineData(float.NegativeInfinity, 0.0f, float.PositiveInfinity)] - [InlineData(float.NegativeInfinity, 3.14159265f, float.PositiveInfinity)] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(-3.14159265f, float.NegativeInfinity, -3.14159265f)] - [InlineData(-3.14159265f, -3.14159265f, -3.14159265f)] - [InlineData(-3.14159265f, -0.0f, -3.14159265f)] - [InlineData(-3.14159265f, float.NaN, -3.14159265f)] - [InlineData(-3.14159265f, 0.0f, 3.14159265f)] - [InlineData(-3.14159265f, 3.14159265f, 3.14159265f)] - [InlineData(-3.14159265f, float.PositiveInfinity, 3.14159265f)] - [InlineData(-0.0f, float.NegativeInfinity, -0.0f)] - [InlineData(-0.0f, -3.14159265f, -0.0f)] - [InlineData(-0.0f, -0.0f, -0.0f)] - [InlineData(-0.0f, float.NaN, -0.0f)] - [InlineData(-0.0f, 0.0f, 0.0f)] - [InlineData(-0.0f, 3.14159265f, 0.0f)] - [InlineData(-0.0f, float.PositiveInfinity, 0.0f)] - [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] - [InlineData(float.NaN, -3.14159265f, float.NaN)] - [InlineData(float.NaN, -0.0f, float.NaN)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 0.0f, float.NaN)] - [InlineData(float.NaN, 3.14159265f, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, -0.0f)] - [InlineData(0.0f, -3.14159265f, -0.0f)] - [InlineData(0.0f, -0.0f, -0.0f)] - [InlineData(0.0f, float.NaN, -0.0f)] - [InlineData(0.0f, 0.0f, 0.0f)] - [InlineData(0.0f, 3.14159265f, 0.0f)] - [InlineData(0.0f, float.PositiveInfinity, 0.0f)] - [InlineData(3.14159265f, float.NegativeInfinity, -3.14159265f)] - [InlineData(3.14159265f, -3.14159265f, -3.14159265f)] - [InlineData(3.14159265f, -0.0f, -3.14159265f)] - [InlineData(3.14159265f, float.NaN, -3.14159265f)] - [InlineData(3.14159265f, 0.0f, 3.14159265f)] - [InlineData(3.14159265f, 3.14159265f, 3.14159265f)] - [InlineData(3.14159265f, float.PositiveInfinity, 3.14159265f)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, -3.14159265f, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, -0.0f, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, float.NaN, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, 0.0f, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, 3.14159265f, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity)] + [MemberData(nameof(GenericMathTestMemberData.CopySignSingle), MemberType = typeof(GenericMathTestMemberData))] public static void CopySign(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, MathF.CopySign(x, y), 0.0f); @@ -710,39 +662,7 @@ public static void Cosh(float value, float expectedResult, float allowedVariance } [Theory] - [InlineData(float.NegativeInfinity, 0.0f, CrossPlatformMachineEpsilon)] - [InlineData(-3.14159265f, 0.0432139183f, CrossPlatformMachineEpsilon / 10)] // value: -(pi) - [InlineData(-2.71828183f, 0.0659880358f, CrossPlatformMachineEpsilon / 10)] // value: -(e) - [InlineData(-2.30258509f, 0.1f, CrossPlatformMachineEpsilon)] // value: -(ln(10)) - [InlineData(-1.57079633f, 0.207879576f, CrossPlatformMachineEpsilon)] // value: -(pi / 2) - [InlineData(-1.44269504f, 0.236290088f, CrossPlatformMachineEpsilon)] // value: -(log2(e)) - [InlineData(-1.41421356f, 0.243116734f, CrossPlatformMachineEpsilon)] // value: -(sqrt(2)) - [InlineData(-1.12837917f, 0.323557264f, CrossPlatformMachineEpsilon)] // value: -(2 / sqrt(pi)) - [InlineData(-1.0f, 0.367879441f, CrossPlatformMachineEpsilon)] - [InlineData(-0.785398163f, 0.455938128f, CrossPlatformMachineEpsilon)] // value: -(pi / 4) - [InlineData(-0.707106781f, 0.493068691f, CrossPlatformMachineEpsilon)] // value: -(1 / sqrt(2)) - [InlineData(-0.693147181f, 0.5f, CrossPlatformMachineEpsilon)] // value: -(ln(2)) - [InlineData(-0.636619772f, 0.529077808f, CrossPlatformMachineEpsilon)] // value: -(2 / pi) - [InlineData(-0.434294482f, 0.647721485f, CrossPlatformMachineEpsilon)] // value: -(log10(e)) - [InlineData(-0.318309886f, 0.727377349f, CrossPlatformMachineEpsilon)] // value: -(1 / pi) - [InlineData(-0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData(float.NaN, float.NaN, 0.0f)] - [InlineData(0.0f, 1.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData(0.318309886f, 1.37480223f, CrossPlatformMachineEpsilon * 10)] // value: (1 / pi) - [InlineData(0.434294482f, 1.54387344f, CrossPlatformMachineEpsilon * 10)] // value: (log10(e)) - [InlineData(0.636619772f, 1.89008116f, CrossPlatformMachineEpsilon * 10)] // value: (2 / pi) - [InlineData(0.693147181f, 2.0f, CrossPlatformMachineEpsilon * 10)] // value: (ln(2)) - [InlineData(0.707106781f, 2.02811498f, CrossPlatformMachineEpsilon * 10)] // value: (1 / sqrt(2)) - [InlineData(0.785398163f, 2.19328005f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 4) - [InlineData(1.0f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) - [InlineData(1.12837917f, 3.09064302f, CrossPlatformMachineEpsilon * 10)] // value: (2 / sqrt(pi)) - [InlineData(1.41421356f, 4.11325038f, CrossPlatformMachineEpsilon * 10)] // value: (sqrt(2)) - [InlineData(1.44269504f, 4.23208611f, CrossPlatformMachineEpsilon * 10)] // value: (log2(e)) - [InlineData(1.57079633f, 4.81047738f, CrossPlatformMachineEpsilon * 10)] // value: (pi / 2) - [InlineData(2.30258509f, 10.0f, CrossPlatformMachineEpsilon * 100)] // value: (ln(10)) - [InlineData(2.71828183f, 15.1542622f, CrossPlatformMachineEpsilon * 100)] // value: (e) - [InlineData(3.14159265f, 23.1406926f, CrossPlatformMachineEpsilon * 100)] // value: (pi) - [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.ExpSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Exp(float value, float expectedResult, float allowedVariance) { AssertExtensions.Equal(expectedResult, MathF.Exp(value), allowedVariance); @@ -788,72 +708,7 @@ public static void Floor(float value, float expectedResult, float allowedVarianc } [Theory] - [InlineData(float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity, float.NaN)] - [InlineData(float.NegativeInfinity, -0.0f, float.NegativeInfinity, float.NaN)] - [InlineData(float.NegativeInfinity, -0.0f, -3.14159265f, float.NaN)] - [InlineData(float.NegativeInfinity, -0.0f, -0.0f, float.NaN)] - [InlineData(float.NegativeInfinity, -0.0f, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, -0.0f, 0.0f, float.NaN)] - [InlineData(float.NegativeInfinity, -0.0f, 3.14159265f, float.NaN)] - [InlineData(float.NegativeInfinity, -0.0f, float.PositiveInfinity, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, float.NegativeInfinity, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, -3.14159265f, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, -0.0f, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, 0.0f, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, 3.14159265f, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, float.PositiveInfinity, float.NaN)] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity, float.NaN)] - [InlineData(-1e38f, 2.0f, 1e38f, -1e38f)] - [InlineData(-1e38f, 2.0f, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(-5, 4, -3, -23)] - [InlineData(-0.0f, float.NegativeInfinity, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0f, float.NegativeInfinity, -3.14159265f, float.NaN)] - [InlineData(-0.0f, float.NegativeInfinity, -0.0f, float.NaN)] - [InlineData(-0.0f, float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(-0.0f, float.NegativeInfinity, 0.0f, float.NaN)] - [InlineData(-0.0f, float.NegativeInfinity, 3.14159265f, float.NaN)] - [InlineData(-0.0f, float.NegativeInfinity, float.PositiveInfinity, float.NaN)] - [InlineData(-0.0f, float.PositiveInfinity, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0f, float.PositiveInfinity, -3.14159265f, float.NaN)] - [InlineData(-0.0f, float.PositiveInfinity, -0.0f, float.NaN)] - [InlineData(-0.0f, float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(-0.0f, float.PositiveInfinity, 0.0f, float.NaN)] - [InlineData(-0.0f, float.PositiveInfinity, 3.14159265f, float.NaN)] - [InlineData(-0.0f, float.PositiveInfinity, float.PositiveInfinity, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, float.NegativeInfinity, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, -3.14159265f, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, -0.0f, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, 0.0f, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, 3.14159265f, float.NaN)] - [InlineData(0.0f, float.NegativeInfinity, float.PositiveInfinity, float.NaN)] - [InlineData(0.0f, float.PositiveInfinity, float.NegativeInfinity, float.NaN)] - [InlineData(0.0f, float.PositiveInfinity, -3.14159265f, float.NaN)] - [InlineData(0.0f, float.PositiveInfinity, -0.0f, float.NaN)] - [InlineData(0.0f, float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(0.0f, float.PositiveInfinity, 0.0f, float.NaN)] - [InlineData(0.0f, float.PositiveInfinity, 3.14159265f, float.NaN)] - [InlineData(0.0f, float.PositiveInfinity, float.PositiveInfinity, float.NaN)] - [InlineData(5, 4, 3, 23)] - [InlineData(1e38f, 2.0f, -1e38f, 1e38f)] - [InlineData(1e38f, 2.0f, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity, float.NaN)] - [InlineData(float.PositiveInfinity, -0.0f, float.NegativeInfinity, float.NaN)] - [InlineData(float.PositiveInfinity, -0.0f, -3.14159265f, float.NaN)] - [InlineData(float.PositiveInfinity, -0.0f, -0.0f, float.NaN)] - [InlineData(float.PositiveInfinity, -0.0f, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, -0.0f, 0.0f, float.NaN)] - [InlineData(float.PositiveInfinity, -0.0f, 3.14159265f, float.NaN)] - [InlineData(float.PositiveInfinity, -0.0f, float.PositiveInfinity, float.NaN)] - [InlineData(float.PositiveInfinity, 0.0f, float.NegativeInfinity, float.NaN)] - [InlineData(float.PositiveInfinity, 0.0f, -3.14159265f, float.NaN)] - [InlineData(float.PositiveInfinity, 0.0f, -0.0f, float.NaN)] - [InlineData(float.PositiveInfinity, 0.0f, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, 0.0f, 0.0f, float.NaN)] - [InlineData(float.PositiveInfinity, 0.0f, 3.14159265f, float.NaN)] - [InlineData(float.PositiveInfinity, 0.0f, float.PositiveInfinity, float.NaN)] - [InlineData(float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NaN)] + [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] public static void FusedMultiplyAdd(float x, float y, float z, float expectedResult) { AssertExtensions.Equal(expectedResult, MathF.FusedMultiplyAdd(x, y, z), 0.0f); @@ -925,46 +780,7 @@ public static void ILogB(float value, int expectedResult) } [Theory] - [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] - [InlineData(-3.14159265f, float.NaN, 0.0f)] // value: -(pi) - [InlineData(-2.71828183f, float.NaN, 0.0f)] // value: -(e) - [InlineData(-1.41421356f, float.NaN, 0.0f)] // value: -(sqrt(2)) - [InlineData(-1.0f, float.NaN, 0.0f)] - [InlineData(-0.693147181f, float.NaN, 0.0f)] // value: -(ln(2)) - [InlineData(-0.434294482f, float.NaN, 0.0f)] // value: -(log10(e)) - [InlineData(-0.0f, float.NegativeInfinity, 0.0f)] - [InlineData(float.NaN, float.NaN, 0.0f)] - [InlineData(0.0f, float.NegativeInfinity, 0.0f)] - [InlineData(0.0432139183f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) - [InlineData(0.0659880358f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) - [InlineData(0.1f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) - [InlineData(0.207879576f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) - [InlineData(0.236290088f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) - [InlineData(0.243116734f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) - [InlineData(0.323557264f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) - [InlineData(0.367879441f, -1.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData(0.455938128f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) - [InlineData(0.493068691f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) - [InlineData(0.5f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) - [InlineData(0.529077808f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) - [InlineData(0.647721485f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) - [InlineData(0.727377349f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) - [InlineData(1.0f, 0.0f, 0.0f)] - [InlineData(1.37480223f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) - [InlineData(1.54387344f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) - [InlineData(1.89008116f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) - [InlineData(2.0f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) - [InlineData(2.02811498f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) - [InlineData(2.19328005f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) - [InlineData(2.71828183f, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (e) - [InlineData(3.09064302f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) - [InlineData(4.11325038f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) - [InlineData(4.23208611f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) - [InlineData(4.81047738f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) - [InlineData(10.0f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) - [InlineData(15.1542622f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) - [InlineData(23.1406926f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) - [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.LogSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Log(float value, float expectedResult, float allowedVariance) { AssertExtensions.Equal(expectedResult, MathF.Log(value), allowedVariance); @@ -983,41 +799,7 @@ public static void LogWithBase() } [Theory] - [InlineData(float.NegativeInfinity, float.NaN, 0.0f)] - [InlineData(-0.113314732f, float.NaN, 0.0f)] - [InlineData(-0.0f, float.NegativeInfinity, 0.0f)] - [InlineData(float.NaN, float.NaN, 0.0f)] - [InlineData(0.0f, float.NegativeInfinity, 0.0f)] - [InlineData(0.113314732f, -3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi) - [InlineData(0.151955223f, -2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: -(e) - [InlineData(0.202699566f, -2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: -(ln(10)) - [InlineData(0.336622537f, -1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: -(pi / 2) - [InlineData(0.367879441f, -1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: -(log2(e)) - [InlineData(0.375214227f, -1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: -(sqrt(2)) - [InlineData(0.457429347f, -1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: -(2 / sqrt(pi)) - [InlineData(0.5f, -1.0f, CrossPlatformMachineEpsilon * 10)] - [InlineData(0.580191810f, -0.785398163f, CrossPlatformMachineEpsilon)] // expected: -(pi / 4) - [InlineData(0.612547327f, -0.707106781f, CrossPlatformMachineEpsilon)] // expected: -(1 / sqrt(2)) - [InlineData(0.618503138f, -0.693147181f, CrossPlatformMachineEpsilon)] // expected: -(ln(2)) - [InlineData(0.643218242f, -0.636619772f, CrossPlatformMachineEpsilon)] // expected: -(2 / pi) - [InlineData(0.740055574f, -0.434294482f, CrossPlatformMachineEpsilon)] // expected: -(log10(e)) - [InlineData(0.802008879f, -0.318309886f, CrossPlatformMachineEpsilon)] // expected: -(1 / pi) - [InlineData(1, 0.0f, 0.0f)] - [InlineData(1.24686899f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) - [InlineData(1.35124987f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) - [InlineData(1.55468228f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) - [InlineData(1.61680667f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) - [InlineData(1.63252692f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) - [InlineData(1.72356793f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) - [InlineData(2, 1.0f, CrossPlatformMachineEpsilon * 10)] // value: (e) - [InlineData(2.18612996f, 1.12837917f, CrossPlatformMachineEpsilon * 10)] // expected: (2 / sqrt(pi)) - [InlineData(2.66514414f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] // expected: (sqrt(2)) - [InlineData(2.71828183f, 1.44269504f, CrossPlatformMachineEpsilon * 10)] // expected: (log2(e)) - [InlineData(2.97068642f, 1.57079633f, CrossPlatformMachineEpsilon * 10)] // expected: (pi / 2) - [InlineData(4.93340967f, 2.30258509f, CrossPlatformMachineEpsilon * 10)] // expected: (ln(10)) - [InlineData(6.58088599f, 2.71828183f, CrossPlatformMachineEpsilon * 10)] // expected: (e) - [InlineData(8.82497783f, 3.14159265f, CrossPlatformMachineEpsilon * 10)] // expected: (pi) - [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] public static void Log2(float value, float expectedResult, float allowedVariance) { AssertExtensions.Equal(expectedResult, MathF.Log2(value), allowedVariance); @@ -1070,23 +852,7 @@ public static void Log10(float value, float expectedResult, float allowedVarianc } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] - [InlineData(float.MaxValue, float.MinValue, float.MaxValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, float.NaN)] - [InlineData(1.0f, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] - [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0f, 0.0f, 0.0f)] - [InlineData(0.0f, -0.0f, 0.0f)] - [InlineData(2.0f, -3.0f, 2.0f)] - [InlineData(-3.0f, 2.0f, 2.0f)] - [InlineData(3.0f, -2.0f, 3.0f)] - [InlineData(-2.0f, 3.0f, 3.0f)] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Max(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, MathF.Max(x, y), 0.0f); @@ -1116,23 +882,7 @@ public static void Max(float x, float y, float expectedResult) } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] - [InlineData(float.MaxValue, float.MinValue, float.MaxValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, float.NaN)] - [InlineData(1.0f, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] - [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0f, 0.0f, 0.0f)] - [InlineData(0.0f, -0.0f, 0.0f)] - [InlineData(2.0f, -3.0f, -3.0f)] - [InlineData(-3.0f, 2.0f, -3.0f)] - [InlineData(3.0f, -2.0f, 3.0f)] - [InlineData(-2.0f, 3.0f, 3.0f)] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] public static void MaxMagnitude(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, MathF.MaxMagnitude(x, y), 0.0f); @@ -1162,23 +912,7 @@ public static void MaxMagnitude(float x, float y, float expectedResult) } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MinValue)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, float.NaN)] - [InlineData(1.0f, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] - [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0f, 0.0f, -0.0f)] - [InlineData(0.0f, -0.0f, -0.0f)] - [InlineData(2.0f, -3.0f, -3.0f)] - [InlineData(-3.0f, 2.0f, -3.0f)] - [InlineData(3.0f, -2.0f, -2.0f)] - [InlineData(-2.0f, 3.0f, -2.0f)] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Min(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, MathF.Min(x, y), 0.0f); @@ -1203,23 +937,7 @@ public static void Min(float x, float y, float expectedResult) } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MinValue)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, float.NaN)] - [InlineData(1.0f, float.NaN, float.NaN)] - [InlineData(float.PositiveInfinity, float.NaN, float.NaN)] - [InlineData(float.NegativeInfinity, float.NaN, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, float.NaN)] - [InlineData(float.NaN, float.NegativeInfinity, float.NaN)] - [InlineData(-0.0f, 0.0f, -0.0f)] - [InlineData(0.0f, -0.0f, -0.0f)] - [InlineData(2.0f, -3.0f, 2.0f)] - [InlineData(-3.0f, 2.0f, 2.0f)] - [InlineData(3.0f, -2.0f, -2.0f)] - [InlineData(-2.0f, 3.0f, -2.0f)] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] public static void MinMagnitude(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, MathF.MinMagnitude(x, y), 0.0f); @@ -1523,17 +1241,11 @@ public static IEnumerable Round_Digits_TestData } } - [Fact] - public static void Round() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.RoundSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void Round(float value, float expectedResult) { - Assert.Equal(0.0f, MathF.Round(0.0f)); - Assert.Equal(1.0f, MathF.Round(1.4f)); - Assert.Equal(2.0f, MathF.Round(1.5f)); - Assert.Equal(2e7f, MathF.Round(2e7f)); - Assert.Equal(0.0f, MathF.Round(-0.0f)); - Assert.Equal(-1.0f, MathF.Round(-1.4f)); - Assert.Equal(-2.0f, MathF.Round(-1.5f)); - Assert.Equal(-2e7f, MathF.Round(-2e7f)); + AssertExtensions.Equal(expectedResult, MathF.Round(value), 0.0f); } [Theory] @@ -1874,49 +1586,15 @@ public static void Tanh(float value, float expectedResult, float allowedVariance AssertExtensions.Equal(expectedResult, MathF.Tanh(value), allowedVariance); } - [Fact] - public static void Truncate() - { - Assert.Equal(0.0f, MathF.Truncate(0.12345f)); - Assert.Equal(3.0f, MathF.Truncate(3.14159f)); - Assert.Equal(-3.0f, MathF.Truncate(-3.14159f)); - } - - public static IEnumerable Round_ToEven_TestData() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.TruncateSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void Truncate(float value, float expectedResult) { - yield return new object[] { 1f, 1f }; - yield return new object[] { 0.5f, 0f }; - yield return new object[] { 1.5f, 2f }; - yield return new object[] { 2.5f, 2f }; - yield return new object[] { 3.5f, 4f }; - yield return new object[] { 0.49999997f, 0f }; - yield return new object[] { 1.5f, 2f }; - yield return new object[] { 2.5f, 2f }; - yield return new object[] { 3.5f, 4f }; - yield return new object[] { 4.5f, 4f }; - yield return new object[] { 3.1415927f, 3f }; - yield return new object[] { 2.7182817f, 3f }; - yield return new object[] { 1385.4557f, 1385f }; - yield return new object[] { 3423.4343f, 3423f }; - yield return new object[] { 535345.5f, 535346f }; - yield return new object[] { 535345.5f, 535346f }; - yield return new object[] { 535345.5f, 535346f }; - yield return new object[] { 535345.4f, 535345f }; - yield return new object[] { 535345.6f, 535346f }; - yield return new object[] { -2.7182817f, -3f }; - yield return new object[] { 10f, 10f }; - yield return new object[] { -10f, -10f }; - yield return new object[] { -0f, -0f }; - yield return new object[] { 0f, 0f }; - yield return new object[] { float.NaN, float.NaN }; - yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; - yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; + AssertExtensions.Equal(expectedResult, MathF.Truncate(value), 0.0f); } [Theory] - [MemberData(nameof(Round_ToEven_TestData))] + [MemberData(nameof(GenericMathTestMemberData.RoundToEvenSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Round_ToEven_0(float value, float expected) { // Math.Round has special fast paths when MidpointRounding is a const @@ -1925,41 +1603,8 @@ public static void Round_ToEven_0(float value, float expected) Assert.Equal(expected, MathF.Round(value, 0, MidpointRounding.ToEven)); } - public static IEnumerable Round_AwayFromZero_TestData() - { - yield return new object[] { 1f, 1f }; - yield return new object[] { 0.5f, 1f }; - yield return new object[] { 1.5f, 2f }; - yield return new object[] { 2.5f, 3f }; - yield return new object[] { 3.5f, 4f }; - yield return new object[] { 0.49999997f, 0f }; - yield return new object[] { 1.5f, 2f }; - yield return new object[] { 2.5f, 3f }; - yield return new object[] { 3.5f, 4f }; - yield return new object[] { 4.5f, 5f }; - yield return new object[] { 3.1415927f, 3f }; - yield return new object[] { 2.7182817f, 3f }; - yield return new object[] { 1385.4557f, 1385f }; - yield return new object[] { 3423.4343f, 3423f }; - yield return new object[] { 535345.5f, 535346f }; - yield return new object[] { 535345.5f, 535346f }; - yield return new object[] { 535345.5f, 535346f }; - yield return new object[] { 535345.4f, 535345f }; - yield return new object[] { 535345.6f, 535346f }; - yield return new object[] { -2.7182817f, -3f }; - yield return new object[] { 10f, 10f }; - yield return new object[] { -10f, -10f }; - yield return new object[] { -0f, -0f }; - yield return new object[] { 0f, 0f }; - yield return new object[] { float.NaN, float.NaN }; - yield return new object[] { float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { 3.4028235E+38f, 3.4028235E+38f }; - yield return new object[] { -3.4028235E+38f, -3.4028235E+38f }; - } - [Theory] - [MemberData(nameof(Round_AwayFromZero_TestData))] + [MemberData(nameof(GenericMathTestMemberData.RoundAwayFromZeroSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Round_AwayFromZero_0(float value, float expected) { // Math.Round has special fast paths when MidpointRounding is a const diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj index 1c9fa97e35c6da..92bc0929991912 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System.Runtime.Tests.csproj @@ -43,6 +43,7 @@ + diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs index d829eb1199d4d7..a565d4b0c96e7c 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs @@ -117,24 +117,11 @@ public static void IsPow2Test() Assert.False(BinaryNumberHelper.IsPow2(double.PositiveInfinity)); } - [Fact] - public static void Log2Test() - { - AssertBitwiseEqual(double.NaN, BinaryNumberHelper.Log2(double.NegativeInfinity)); - AssertBitwiseEqual(double.NaN, BinaryNumberHelper.Log2(double.MinValue)); - AssertBitwiseEqual(double.NaN, BinaryNumberHelper.Log2(-1.0)); - AssertBitwiseEqual(double.NaN, BinaryNumberHelper.Log2(-MinNormal)); - AssertBitwiseEqual(double.NaN, BinaryNumberHelper.Log2(-MaxSubnormal)); - AssertBitwiseEqual(double.NaN, BinaryNumberHelper.Log2(-double.Epsilon)); - AssertBitwiseEqual(double.NegativeInfinity, BinaryNumberHelper.Log2(-0.0)); - AssertBitwiseEqual(double.NaN, BinaryNumberHelper.Log2(double.NaN)); - AssertBitwiseEqual(double.NegativeInfinity, BinaryNumberHelper.Log2(0.0)); - AssertBitwiseEqual(-1074.0, BinaryNumberHelper.Log2(double.Epsilon)); - AssertBitwiseEqual(-1022.0, BinaryNumberHelper.Log2(MaxSubnormal)); - AssertBitwiseEqual(-1022.0, BinaryNumberHelper.Log2(MinNormal)); - AssertBitwiseEqual(0.0, BinaryNumberHelper.Log2(1.0)); - AssertBitwiseEqual(1024.0, BinaryNumberHelper.Log2(double.MaxValue)); - AssertBitwiseEqual(double.PositiveInfinity, BinaryNumberHelper.Log2(double.PositiveInfinity)); + [Theory] + [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] + public static void Log2Test(double value, double expectedResult) + { + AssertExtensions.Equal(expectedResult, BinaryNumberHelper.Log2(value)); } // @@ -1029,104 +1016,39 @@ public static void op_CheckedMultiplyTest() // INumber // - [Fact] - public static void ClampTest() - { - AssertBitwiseEqual(1.0, NumberHelper.Clamp(double.NegativeInfinity, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(double.MinValue, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(-1.0, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(-MinNormal, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(-MaxSubnormal, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(-double.Epsilon, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(-0.0, 1.0, 63.0)); - AssertBitwiseEqual(double.NaN, NumberHelper.Clamp(double.NaN, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(0.0, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(double.Epsilon, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(MaxSubnormal, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(MinNormal, 1.0, 63.0)); - AssertBitwiseEqual(1.0, NumberHelper.Clamp(1.0, 1.0, 63.0)); - AssertBitwiseEqual(63.0, NumberHelper.Clamp(double.MaxValue, 1.0, 63.0)); - AssertBitwiseEqual(63.0, NumberHelper.Clamp(double.PositiveInfinity, 1.0, 63.0)); - } - - [Fact] - public static void MaxTest() - { - AssertBitwiseEqual(1.0, NumberHelper.Max(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(double.MinValue, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(-1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(-MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(-double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(-0.0, 1.0)); - AssertBitwiseEqual(double.NaN, NumberHelper.Max(double.NaN, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Max(1.0, 1.0)); - AssertBitwiseEqual(double.MaxValue, NumberHelper.Max(double.MaxValue, 1.0)); - AssertBitwiseEqual(double.PositiveInfinity, NumberHelper.Max(double.PositiveInfinity, 1.0)); - } - - [Fact] - public static void MaxNumberTest() - { - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(double.MinValue, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(-1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(-MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(-double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(-0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(double.NaN, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MaxNumber(1.0, 1.0)); - AssertBitwiseEqual(double.MaxValue, NumberHelper.MaxNumber(double.MaxValue, 1.0)); - AssertBitwiseEqual(double.PositiveInfinity, NumberHelper.MaxNumber(double.PositiveInfinity, 1.0)); - } - - [Fact] - public static void MinTest() - { - AssertBitwiseEqual(double.NegativeInfinity, NumberHelper.Min(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(double.MinValue, NumberHelper.Min(double.MinValue, 1.0)); - AssertBitwiseEqual(-1.0, NumberHelper.Min(-1.0, 1.0)); - AssertBitwiseEqual(-MinNormal, NumberHelper.Min(-MinNormal, 1.0)); - AssertBitwiseEqual(-MaxSubnormal, NumberHelper.Min(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(-double.Epsilon, NumberHelper.Min(-double.Epsilon, 1.0)); - AssertBitwiseEqual(-0.0, NumberHelper.Min(-0.0, 1.0)); - AssertBitwiseEqual(double.NaN, NumberHelper.Min(double.NaN, 1.0)); - AssertBitwiseEqual(0.0, NumberHelper.Min(0.0, 1.0)); - AssertBitwiseEqual(double.Epsilon, NumberHelper.Min(double.Epsilon, 1.0)); - AssertBitwiseEqual(MaxSubnormal, NumberHelper.Min(MaxSubnormal, 1.0)); - AssertBitwiseEqual(MinNormal, NumberHelper.Min(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Min(1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Min(double.MaxValue, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.Min(double.PositiveInfinity, 1.0)); - } - - [Fact] - public static void MinNumberTest() - { - AssertBitwiseEqual(double.NegativeInfinity, NumberHelper.MinNumber(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(double.MinValue, NumberHelper.MinNumber(double.MinValue, 1.0)); - AssertBitwiseEqual(-1.0, NumberHelper.MinNumber(-1.0, 1.0)); - AssertBitwiseEqual(-MinNormal, NumberHelper.MinNumber(-MinNormal, 1.0)); - AssertBitwiseEqual(-MaxSubnormal, NumberHelper.MinNumber(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(-double.Epsilon, NumberHelper.MinNumber(-double.Epsilon, 1.0)); - AssertBitwiseEqual(-0.0, NumberHelper.MinNumber(-0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MinNumber(double.NaN, 1.0)); - AssertBitwiseEqual(0.0, NumberHelper.MinNumber(0.0, 1.0)); - AssertBitwiseEqual(double.Epsilon, NumberHelper.MinNumber(double.Epsilon, 1.0)); - AssertBitwiseEqual(MaxSubnormal, NumberHelper.MinNumber(MaxSubnormal, 1.0)); - AssertBitwiseEqual(MinNormal, NumberHelper.MinNumber(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MinNumber(1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MinNumber(double.MaxValue, 1.0)); - AssertBitwiseEqual(1.0, NumberHelper.MinNumber(double.PositiveInfinity, 1.0)); + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void ClampTest(double value, double min, double max, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberHelper.Clamp(value, min, max)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberHelper.Max(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxNumberTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberHelper.MaxNumber(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MinTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberHelper.Min(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MinNumberTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberHelper.MinNumber(x, y)); } [Fact] @@ -2198,44 +2120,18 @@ public static void IsIntegerTest() Assert.False(NumberBaseHelper.IsInteger(double.PositiveInfinity)); } - [Fact] - public static void IsNaNTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void IsNaNTest(double value, bool expectedResult) { - Assert.False(NumberBaseHelper.IsNaN(double.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsNaN(double.MinValue)); - Assert.False(NumberBaseHelper.IsNaN(-1.0)); - Assert.False(NumberBaseHelper.IsNaN(-MinNormal)); - Assert.False(NumberBaseHelper.IsNaN(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsNaN(-double.Epsilon)); - Assert.False(NumberBaseHelper.IsNaN(-0.0)); - Assert.True(NumberBaseHelper.IsNaN(double.NaN)); - Assert.False(NumberBaseHelper.IsNaN(0.0)); - Assert.False(NumberBaseHelper.IsNaN(double.Epsilon)); - Assert.False(NumberBaseHelper.IsNaN(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsNaN(MinNormal)); - Assert.False(NumberBaseHelper.IsNaN(1.0)); - Assert.False(NumberBaseHelper.IsNaN(double.MaxValue)); - Assert.False(NumberBaseHelper.IsNaN(double.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsNaN(value)); } - [Fact] - public static void IsNegativeTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void IsNegativeTest(double value, bool expectedResult) { - Assert.True(NumberBaseHelper.IsNegative(double.NegativeInfinity)); - Assert.True(NumberBaseHelper.IsNegative(double.MinValue)); - Assert.True(NumberBaseHelper.IsNegative(-1.0)); - Assert.True(NumberBaseHelper.IsNegative(-MinNormal)); - Assert.True(NumberBaseHelper.IsNegative(-MaxSubnormal)); - Assert.True(NumberBaseHelper.IsNegative(-double.Epsilon)); - Assert.True(NumberBaseHelper.IsNegative(-0.0)); - Assert.True(NumberBaseHelper.IsNegative(double.NaN)); - Assert.False(NumberBaseHelper.IsNegative(0.0)); - Assert.False(NumberBaseHelper.IsNegative(double.Epsilon)); - Assert.False(NumberBaseHelper.IsNegative(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsNegative(MinNormal)); - Assert.False(NumberBaseHelper.IsNegative(1.0)); - Assert.False(NumberBaseHelper.IsNegative(double.MaxValue)); - Assert.False(NumberBaseHelper.IsNegative(double.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsNegative(value)); } [Fact] @@ -2298,44 +2194,18 @@ public static void IsOddIntegerTest() Assert.False(NumberBaseHelper.IsOddInteger(double.PositiveInfinity)); } - [Fact] - public static void IsPositiveTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void IsPositiveTest(double value, bool expectedResult) { - Assert.False(NumberBaseHelper.IsPositive(double.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsPositive(double.MinValue)); - Assert.False(NumberBaseHelper.IsPositive(-1.0)); - Assert.False(NumberBaseHelper.IsPositive(-MinNormal)); - Assert.False(NumberBaseHelper.IsPositive(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsPositive(-double.Epsilon)); - Assert.False(NumberBaseHelper.IsPositive(-0.0)); - Assert.False(NumberBaseHelper.IsPositive(double.NaN)); - Assert.True(NumberBaseHelper.IsPositive(0.0)); - Assert.True(NumberBaseHelper.IsPositive(double.Epsilon)); - Assert.True(NumberBaseHelper.IsPositive(MaxSubnormal)); - Assert.True(NumberBaseHelper.IsPositive(MinNormal)); - Assert.True(NumberBaseHelper.IsPositive(1.0)); - Assert.True(NumberBaseHelper.IsPositive(double.MaxValue)); - Assert.True(NumberBaseHelper.IsPositive(double.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsPositive(value)); } - [Fact] - public static void IsPositiveInfinityTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinityDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void IsPositiveInfinityTest(double value, bool expectedResult) { - Assert.False(NumberBaseHelper.IsPositiveInfinity(double.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(double.MinValue)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-1.0)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-MinNormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-double.Epsilon)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-0.0)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(double.NaN)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(0.0)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(double.Epsilon)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(MinNormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(1.0)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(double.MaxValue)); - Assert.True(NumberBaseHelper.IsPositiveInfinity(double.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsPositiveInfinity(value)); } [Fact] @@ -2378,104 +2248,39 @@ public static void IsSubnormalTest() Assert.False(NumberBaseHelper.IsSubnormal(double.PositiveInfinity)); } - [Fact] - public static void IsZeroTest() - { - Assert.False(NumberBaseHelper.IsZero(double.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsZero(double.MinValue)); - Assert.False(NumberBaseHelper.IsZero(-1.0)); - Assert.False(NumberBaseHelper.IsZero(-MinNormal)); - Assert.False(NumberBaseHelper.IsZero(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsZero(-double.Epsilon)); - Assert.True(NumberBaseHelper.IsZero(-0.0)); - Assert.False(NumberBaseHelper.IsZero(double.NaN)); - Assert.True(NumberBaseHelper.IsZero(0.0)); - Assert.False(NumberBaseHelper.IsZero(double.Epsilon)); - Assert.False(NumberBaseHelper.IsZero(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsZero(MinNormal)); - Assert.False(NumberBaseHelper.IsZero(1.0)); - Assert.False(NumberBaseHelper.IsZero(double.MaxValue)); - Assert.False(NumberBaseHelper.IsZero(double.PositiveInfinity)); - } - - [Fact] - public static void MaxMagnitudeTest() - { - AssertBitwiseEqual(double.NegativeInfinity, NumberBaseHelper.MaxMagnitude(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(double.MinValue, NumberBaseHelper.MaxMagnitude(double.MinValue, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(-1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(-MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(-double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(-0.0, 1.0)); - AssertBitwiseEqual(double.NaN, NumberBaseHelper.MaxMagnitude(double.NaN, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitude(1.0, 1.0)); - AssertBitwiseEqual(double.MaxValue, NumberBaseHelper.MaxMagnitude(double.MaxValue, 1.0)); - AssertBitwiseEqual(double.PositiveInfinity, NumberBaseHelper.MaxMagnitude(double.PositiveInfinity, 1.0)); - } - - [Fact] - public static void MaxMagnitudeNumberTest() - { - AssertBitwiseEqual(double.NegativeInfinity, NumberBaseHelper.MaxMagnitudeNumber(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(double.MinValue, NumberBaseHelper.MaxMagnitudeNumber(double.MinValue, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(-1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(-MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(-double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(-0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(double.NaN, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(double.Epsilon, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(MaxSubnormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MaxMagnitudeNumber(1.0, 1.0)); - AssertBitwiseEqual(double.MaxValue, NumberBaseHelper.MaxMagnitudeNumber(double.MaxValue, 1.0)); - AssertBitwiseEqual(double.PositiveInfinity, NumberBaseHelper.MaxMagnitudeNumber(double.PositiveInfinity, 1.0)); - } - - [Fact] - public static void MinMagnitudeTest() - { - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitude(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitude(double.MinValue, 1.0)); - AssertBitwiseEqual(-1.0, NumberBaseHelper.MinMagnitude(-1.0, 1.0)); - AssertBitwiseEqual(-MinNormal, NumberBaseHelper.MinMagnitude(-MinNormal, 1.0)); - AssertBitwiseEqual(-MaxSubnormal, NumberBaseHelper.MinMagnitude(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(-double.Epsilon, NumberBaseHelper.MinMagnitude(-double.Epsilon, 1.0)); - AssertBitwiseEqual(-0.0, NumberBaseHelper.MinMagnitude(-0.0, 1.0)); - AssertBitwiseEqual(double.NaN, NumberBaseHelper.MinMagnitude(double.NaN, 1.0)); - AssertBitwiseEqual(0.0, NumberBaseHelper.MinMagnitude(0.0, 1.0)); - AssertBitwiseEqual(double.Epsilon, NumberBaseHelper.MinMagnitude(double.Epsilon, 1.0)); - AssertBitwiseEqual(MaxSubnormal, NumberBaseHelper.MinMagnitude(MaxSubnormal, 1.0)); - AssertBitwiseEqual(MinNormal, NumberBaseHelper.MinMagnitude(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitude(1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitude(double.MaxValue, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitude(double.PositiveInfinity, 1.0)); - } - - [Fact] - public static void MinMagnitudeNumberTest() - { - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitudeNumber(double.NegativeInfinity, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitudeNumber(double.MinValue, 1.0)); - AssertBitwiseEqual(-1.0, NumberBaseHelper.MinMagnitudeNumber(-1.0, 1.0)); - AssertBitwiseEqual(-MinNormal, NumberBaseHelper.MinMagnitudeNumber(-MinNormal, 1.0)); - AssertBitwiseEqual(-MaxSubnormal, NumberBaseHelper.MinMagnitudeNumber(-MaxSubnormal, 1.0)); - AssertBitwiseEqual(-double.Epsilon, NumberBaseHelper.MinMagnitudeNumber(-double.Epsilon, 1.0)); - AssertBitwiseEqual(-0.0, NumberBaseHelper.MinMagnitudeNumber(-0.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitudeNumber(double.NaN, 1.0)); - AssertBitwiseEqual(0.0, NumberBaseHelper.MinMagnitudeNumber(0.0, 1.0)); - AssertBitwiseEqual(double.Epsilon, NumberBaseHelper.MinMagnitudeNumber(double.Epsilon, 1.0)); - AssertBitwiseEqual(MaxSubnormal, NumberBaseHelper.MinMagnitudeNumber(MaxSubnormal, 1.0)); - AssertBitwiseEqual(MinNormal, NumberBaseHelper.MinMagnitudeNumber(MinNormal, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitudeNumber(1.0, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitudeNumber(double.MaxValue, 1.0)); - AssertBitwiseEqual(1.0, NumberBaseHelper.MinMagnitudeNumber(double.PositiveInfinity, 1.0)); + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void IsZeroTest(double value, bool expectedResult) + { + Assert.Equal(expectedResult, NumberBaseHelper.IsZero(value)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxMagnitudeTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MaxMagnitude(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxMagnitudeNumberTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MaxMagnitudeNumber(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MinMagnitudeTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MinMagnitude(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] + public static void MinMagnitudeNumberTest(double x, double y, double expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MinMagnitudeNumber(x, y)); } // diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs index bf5e2261995ee0..a236858cff20d1 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.cs @@ -159,55 +159,7 @@ public static void GetTypeCode_Invoke_ReturnsDouble() } [Theory] - [InlineData(double.NaN, double.NaN, double.NaN, 0.0)] - [InlineData(double.NaN, 0.0f, double.NaN, 0.0)] - [InlineData(double.NaN, 1.0f, double.NaN, 0.0)] - [InlineData(double.NaN, 2.7182818284590452, double.NaN, 0.0)] - [InlineData(double.NaN, 10.0, double.NaN, 0.0)] - [InlineData(0.0, 0.0, 0.0, 0.0)] - [InlineData(0.0, 1.0, 1.0, 0.0)] - [InlineData(0.0, 1.5707963267948966, 1.5707963267948966, 0.0)] - [InlineData(0.0, 2.0, 2.0, 0.0)] - [InlineData(0.0, 2.7182818284590452, 2.7182818284590452, 0.0)] - [InlineData(0.0, 3.0, 3.0, 0.0)] - [InlineData(0.0, 10.0, 10.0, 0.0)] - [InlineData(1.0, 1.0, 1.4142135623730950, CrossPlatformMachineEpsilon * 10)] - [InlineData(1.0, 1e+10, 1e+10, 0.0)] // dotnet/runtime#75651 - [InlineData(1.0, 1e+20, 1e+20, 0.0)] // dotnet/runtime#75651 - [InlineData(2.7182818284590452, 0.31830988618379067, 2.7368553638387594, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / pi) - [InlineData(2.7182818284590452, 0.43429448190325183, 2.7527563996732919, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log10(e)) - [InlineData(2.7182818284590452, 0.63661977236758134, 2.7918346715914253, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / pi) - [InlineData(2.7182818284590452, 0.69314718055994531, 2.8052645352709344, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (ln(2)) - [InlineData(2.7182818284590452, 0.70710678118654752, 2.8087463571726533, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / sqrt(2)) - [InlineData(2.7182818284590452, 0.78539816339744831, 2.8294710413783590, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 4) - [InlineData(2.7182818284590452, 1.0, 2.8963867315900082, CrossPlatformMachineEpsilon * 10)] // x: (e) - [InlineData(2.7182818284590452, 1.1283791670955126, 2.9431778138036127, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / sqrt(pi)) - [InlineData(2.7182818284590452, 1.4142135623730950, 3.0641566701020120, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (sqrt(2)) - [InlineData(2.7182818284590452, 1.4426950408889634, 3.0774055761202907, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log2(e)) - [InlineData(2.7182818284590452, 1.5707963267948966, 3.1394995141268918, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 2) - [InlineData(2.7182818284590452, 2.3025850929940457, 3.5624365551415857, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (ln(10)) - [InlineData(2.7182818284590452, 2.7182818284590452, 3.8442310281591168, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (e) - [InlineData(2.7182818284590452, 3.1415926535897932, 4.1543544023133136, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi) - [InlineData(10.0, 0.31830988618379067, 10.005064776584025, CrossPlatformMachineEpsilon * 100)] // y: (1 / pi) - [InlineData(10.0, 0.43429448190325183, 10.009426142242702, CrossPlatformMachineEpsilon * 100)] // y: (log10(e)) - [InlineData(10.0, 0.63661977236758134, 10.020243746265325, CrossPlatformMachineEpsilon * 100)] // y: (2 / pi) - [InlineData(10.0, 0.69314718055994531, 10.023993865417028, CrossPlatformMachineEpsilon * 100)] // y: (ln(2)) - [InlineData(10.0, 0.70710678118654752, 10.024968827881711, CrossPlatformMachineEpsilon * 100)] // y: (1 / sqrt(2)) - [InlineData(10.0, 0.78539816339744831, 10.030795096853892, CrossPlatformMachineEpsilon * 100)] // y: (pi / 4) - [InlineData(10.0, 1.0, 10.049875621120890, CrossPlatformMachineEpsilon * 100)] // - [InlineData(10.0, 1.1283791670955126, 10.063460614755501, CrossPlatformMachineEpsilon * 100)] // y: (2 / sqrt(pi)) - [InlineData(10.0, 1.4142135623730950, 10.099504938362078, CrossPlatformMachineEpsilon * 100)] // y: (sqrt(2)) - [InlineData(10.0, 1.4426950408889634, 10.103532500121213, CrossPlatformMachineEpsilon * 100)] // y: (log2(e)) - [InlineData(10.0, 1.5707963267948966, 10.122618292728040, CrossPlatformMachineEpsilon * 100)] // y: (pi / 2) - [InlineData(10.0, 2.3025850929940457, 10.261671311754163, CrossPlatformMachineEpsilon * 100)] // y: (ln(10)) - [InlineData(10.0, 2.7182818284590452, 10.362869105558106, CrossPlatformMachineEpsilon * 100)] // y: (e) - [InlineData(10.0, 3.1415926535897932, 10.481870272097884, CrossPlatformMachineEpsilon * 100)] // y: (pi) - [InlineData(double.PositiveInfinity, double.NaN, double.PositiveInfinity, 0.0)] - [InlineData(double.PositiveInfinity, 0.0, double.PositiveInfinity, 0.0)] - [InlineData(double.PositiveInfinity, 1.0, double.PositiveInfinity, 0.0)] - [InlineData(double.PositiveInfinity, 2.7182818284590452, double.PositiveInfinity, 0.0)] - [InlineData(double.PositiveInfinity, 10.0, double.PositiveInfinity, 0.0)] - [InlineData(double.PositiveInfinity, double.PositiveInfinity, double.PositiveInfinity, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.HypotDouble), MemberType = typeof(GenericMathTestMemberData))] public static void Hypot(double x, double y, double expectedResult, double allowedVariance) { AssertExtensions.Equal(expectedResult, double.Hypot(-x, -y), allowedVariance); @@ -241,19 +193,7 @@ public static void IsInfinity(double d, bool expected) } [Theory] - [InlineData(double.NegativeInfinity, false)] // Negative Infinity - [InlineData(double.MinValue, false)] // Min Negative Normal - [InlineData(-2.2250738585072014E-308, false)] // Max Negative Normal - [InlineData(-2.2250738585072009E-308, false)] // Min Negative Subnormal - [InlineData(-double.Epsilon, false)] // Max Negative Subnormal (Negative Epsilon) - [InlineData(-0.0, false)] // Negative Zero - [InlineData(double.NaN, true)] // NaN - [InlineData(0.0, false)] // Positive Zero - [InlineData(double.Epsilon, false)] // Min Positive Subnormal (Positive Epsilon) - [InlineData(2.2250738585072009E-308, false)] // Max Positive Subnormal - [InlineData(2.2250738585072014E-308, false)] // Min Positive Normal - [InlineData(double.MaxValue, false)] // Max Positive Normal - [InlineData(double.PositiveInfinity, false)] // Positive Infinity + [MemberData(nameof(GenericMathTestMemberData.IsNaNDouble), MemberType = typeof(GenericMathTestMemberData))] public static void IsNaN(double d, bool expected) { Assert.Equal(expected, double.IsNaN(d)); @@ -279,19 +219,7 @@ public static void IsNegativeInfinity(double d, bool expected) } [Theory] - [InlineData(double.NegativeInfinity, false)] // Negative Infinity - [InlineData(double.MinValue, false)] // Min Negative Normal - [InlineData(-2.2250738585072014E-308, false)] // Max Negative Normal - [InlineData(-2.2250738585072009E-308, false)] // Min Negative Subnormal - [InlineData(-double.Epsilon, false)] // Max Negative Subnormal (Negative Epsilon) - [InlineData(-0.0, false)] // Negative Zero - [InlineData(double.NaN, false)] // NaN - [InlineData(0.0, false)] // Positive Zero - [InlineData(double.Epsilon, false)] // Min Positive Subnormal (Positive Epsilon) - [InlineData(2.2250738585072009E-308, false)] // Max Positive Subnormal - [InlineData(2.2250738585072014E-308, false)] // Min Positive Normal - [InlineData(double.MaxValue, false)] // Max Positive Normal - [InlineData(double.PositiveInfinity, true)] // Positive Infinity + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinityDouble), MemberType = typeof(GenericMathTestMemberData))] public static void IsPositiveInfinity(double d, bool expected) { Assert.Equal(expected, double.IsPositiveInfinity(d)); @@ -935,19 +863,7 @@ public static void IsFinite(double d, bool expected) } [Theory] - [InlineData(double.NegativeInfinity, true)] // Negative Infinity - [InlineData(double.MinValue, true)] // Min Negative Normal - [InlineData(-2.2250738585072014E-308, true)] // Max Negative Normal - [InlineData(-2.2250738585072009E-308, true)] // Min Negative Subnormal - [InlineData(-4.94065645841247E-324, true)] // Max Negative Subnormal - [InlineData(-0.0, true)] // Negative Zero - [InlineData(double.NaN, true)] // NaN - [InlineData(0.0, false)] // Positive Zero - [InlineData(4.94065645841247E-324, false)] // Min Positive Subnormal - [InlineData(2.2250738585072009E-308, false)] // Max Positive Subnormal - [InlineData(2.2250738585072014E-308, false)] // Min Positive Normal - [InlineData(double.MaxValue, false)] // Max Positive Normal - [InlineData(double.PositiveInfinity, false)] // Positive Infinity + [MemberData(nameof(GenericMathTestMemberData.IsNegativeDouble), MemberType = typeof(GenericMathTestMemberData))] public static void IsNegative(double d, bool expected) { Assert.Equal(expected, double.IsNegative(d)); @@ -1060,92 +976,28 @@ public static void TestNegativeNumberParsingWithHyphen() } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MaxValue)] - [InlineData(double.MaxValue, double.MinValue, double.MaxValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, 1.0)] - [InlineData(1.0, double.NaN, 1.0)] - [InlineData(double.PositiveInfinity, double.NaN, double.PositiveInfinity)] - [InlineData(double.NegativeInfinity, double.NaN, double.NegativeInfinity)] - [InlineData(double.NaN, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.NaN, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(-0.0, 0.0, 0.0)] - [InlineData(0.0, -0.0, 0.0)] - [InlineData(2.0, -3.0, -3.0)] - [InlineData(-3.0, 2.0, -3.0)] - [InlineData(3.0, -2.0, 3.0)] - [InlineData(-2.0, 3.0, 3.0)] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] public static void MaxMagnitudeNumberTest(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, double.MaxMagnitudeNumber(x, y), 0.0); } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MaxValue)] - [InlineData(double.MaxValue, double.MinValue, double.MaxValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, 1.0)] - [InlineData(1.0, double.NaN, 1.0)] - [InlineData(double.PositiveInfinity, double.NaN, double.PositiveInfinity)] - [InlineData(double.NegativeInfinity, double.NaN, double.NegativeInfinity)] - [InlineData(double.NaN, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.NaN, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(-0.0, 0.0, 0.0)] - [InlineData(0.0, -0.0, 0.0)] - [InlineData(2.0, -3.0, 2.0)] - [InlineData(-3.0, 2.0, 2.0)] - [InlineData(3.0, -2.0, 3.0)] - [InlineData(-2.0, 3.0, 3.0)] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberDouble), MemberType = typeof(GenericMathTestMemberData))] public static void MaxNumberTest(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, double.MaxNumber(x, y), 0.0); } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MinValue)] - [InlineData(double.MaxValue, double.MinValue, double.MinValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, 1.0)] - [InlineData(1.0, double.NaN, 1.0)] - [InlineData(double.PositiveInfinity, double.NaN, double.PositiveInfinity)] - [InlineData(double.NegativeInfinity, double.NaN, double.NegativeInfinity)] - [InlineData(double.NaN, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.NaN, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(-0.0, 0.0, -0.0)] - [InlineData(0.0, -0.0, -0.0)] - [InlineData(2.0, -3.0, 2.0)] - [InlineData(-3.0, 2.0, 2.0)] - [InlineData(3.0, -2.0, -2.0)] - [InlineData(-2.0, 3.0, -2.0)] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberDouble), MemberType = typeof(GenericMathTestMemberData))] public static void MinMagnitudeNumberTest(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, double.MinMagnitudeNumber(x, y), 0.0); } [Theory] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, double.NegativeInfinity)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(double.MinValue, double.MaxValue, double.MinValue)] - [InlineData(double.MaxValue, double.MinValue, double.MinValue)] - [InlineData(double.NaN, double.NaN, double.NaN)] - [InlineData(double.NaN, 1.0, 1.0)] - [InlineData(1.0, double.NaN, 1.0)] - [InlineData(double.PositiveInfinity, double.NaN, double.PositiveInfinity)] - [InlineData(double.NegativeInfinity, double.NaN, double.NegativeInfinity)] - [InlineData(double.NaN, double.PositiveInfinity, double.PositiveInfinity)] - [InlineData(double.NaN, double.NegativeInfinity, double.NegativeInfinity)] - [InlineData(-0.0, 0.0, -0.0)] - [InlineData(0.0, -0.0, -0.0)] - [InlineData(2.0, -3.0, -3.0)] - [InlineData(-3.0, 2.0, -3.0)] - [InlineData(3.0, -2.0, -2.0)] - [InlineData(-2.0, 3.0, -2.0)] + [MemberData(nameof(GenericMathTestMemberData.MinNumberDouble), MemberType = typeof(GenericMathTestMemberData))] public static void MinNumberTest(double x, double y, double expectedResult) { AssertExtensions.Equal(expectedResult, double.MinNumber(x, y), 0.0); @@ -1662,37 +1514,7 @@ public static void TanPiTest(double value, double expectedResult, double allowed } [Theory] - [InlineData(double.NegativeInfinity, double.NegativeInfinity, 0.5, double.NegativeInfinity)] - [InlineData(double.NegativeInfinity, double.NaN, 0.5, double.NaN)] - [InlineData(double.NegativeInfinity, double.PositiveInfinity, 0.5, double.NaN)] - [InlineData(double.NegativeInfinity, 0.0, 0.5, double.NegativeInfinity)] - [InlineData(double.NegativeInfinity, 1.0, 0.5, double.NegativeInfinity)] - [InlineData(double.NaN, double.NegativeInfinity, 0.5, double.NaN)] - [InlineData(double.NaN, double.NaN, 0.5, double.NaN)] - [InlineData(double.NaN, double.PositiveInfinity, 0.5, double.NaN)] - [InlineData(double.NaN, 0.0, 0.5, double.NaN)] - [InlineData(double.NaN, 1.0, 0.5, double.NaN)] - [InlineData(double.PositiveInfinity, double.NegativeInfinity, 0.5, double.NaN)] - [InlineData(double.PositiveInfinity, double.NaN, 0.5, double.NaN)] - [InlineData(double.PositiveInfinity, double.PositiveInfinity, 0.5, double.PositiveInfinity)] - [InlineData(double.PositiveInfinity, 0.0, 0.5, double.PositiveInfinity)] - [InlineData(double.PositiveInfinity, 1.0, 0.5, double.PositiveInfinity)] - [InlineData(1.0, 3.0, 0.0, 1.0)] - [InlineData(1.0, 3.0, 0.5, 2.0)] - [InlineData(1.0, 3.0, 1.0, 3.0)] - [InlineData(1.0, 3.0, 2.0, 5.0)] - [InlineData(2.0, 4.0, 0.0, 2.0)] - [InlineData(2.0, 4.0, 0.5, 3.0)] - [InlineData(2.0, 4.0, 1.0, 4.0)] - [InlineData(2.0, 4.0, 2.0, 6.0)] - [InlineData(3.0, 1.0, 0.0, 3.0)] - [InlineData(3.0, 1.0, 0.5, 2.0)] - [InlineData(3.0, 1.0, 1.0, 1.0)] - [InlineData(3.0, 1.0, 2.0, -1.0)] - [InlineData(4.0, 2.0, 0.0, 4.0)] - [InlineData(4.0, 2.0, 0.5, 3.0)] - [InlineData(4.0, 2.0, 1.0, 2.0)] - [InlineData(4.0, 2.0, 2.0, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.LerpDouble), MemberType = typeof(GenericMathTestMemberData))] public static void LerpTest(double value1, double value2, double amount, double expectedResult) { AssertExtensions.Equal(+expectedResult, double.Lerp(+value1, +value2, amount), 0); @@ -1700,29 +1522,7 @@ public static void LerpTest(double value1, double value2, double amount, double } [Theory] - [InlineData(double.NaN, double.NaN, 0.0)] - [InlineData(0.0, 0.0, 0.0)] - [InlineData(0.31830988618379067, 0.005555555555555556, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData(0.43429448190325183, 0.007579868632454674, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData(0.5, 0.008726646259971648, CrossPlatformMachineEpsilon)] - [InlineData(0.63661977236758134, 0.011111111111111112, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData(0.69314718055994531, 0.01209770050168668, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData(0.70710678118654752, 0.012341341494884351, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData(0.78539816339744831, 0.013707783890401885, CrossPlatformMachineEpsilon)] // value: (pi / 4) - [InlineData(1.0, 0.017453292519943295, CrossPlatformMachineEpsilon)] - [InlineData(1.1283791670955126, 0.019693931676727953, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData(1.4142135623730950, 0.024682682989768702, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData(1.4426950408889634, 0.02517977856570663, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData(1.5, 0.02617993877991494, CrossPlatformMachineEpsilon)] - [InlineData(1.5707963267948966, 0.02741556778080377, CrossPlatformMachineEpsilon)] // value: (pi / 2) - [InlineData(2.0, 0.03490658503988659, CrossPlatformMachineEpsilon)] - [InlineData(2.3025850929940457, 0.040187691180085916, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData(2.5, 0.04363323129985824, CrossPlatformMachineEpsilon)] - [InlineData(2.7182818284590452, 0.047442967903742035, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData(3.0, 0.05235987755982988, CrossPlatformMachineEpsilon)] - [InlineData(3.1415926535897932, 0.05483113556160754, CrossPlatformMachineEpsilon)] // value: (pi) - [InlineData(3.5, 0.061086523819801536, CrossPlatformMachineEpsilon)] - [InlineData(double.PositiveInfinity, double.PositiveInfinity, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansDouble), MemberType = typeof(GenericMathTestMemberData))] public static void DegreesToRadiansTest(double value, double expectedResult, double allowedVariance) { AssertExtensions.Equal(-expectedResult, double.DegreesToRadians(-value), allowedVariance); @@ -1730,29 +1530,7 @@ public static void DegreesToRadiansTest(double value, double expectedResult, dou } [Theory] - [InlineData(double.NaN, double.NaN, 0.0)] - [InlineData(0.0, 0.0, 0.0)] - [InlineData(0.0055555555555555567, 0.3183098861837906, CrossPlatformMachineEpsilon)] // expected: (1 / pi) - [InlineData(0.0075798686324546743, 0.4342944819032518, CrossPlatformMachineEpsilon)] // expected: (log10(e)) - [InlineData(0.008726646259971648, 0.5, CrossPlatformMachineEpsilon)] - [InlineData(0.0111111111111111124, 0.6366197723675813, CrossPlatformMachineEpsilon)] // expected: (2 / pi) - [InlineData(0.0120977005016866801, 0.6931471805599453, CrossPlatformMachineEpsilon)] // expected: (ln(2)) - [InlineData(0.0123413414948843512, 0.7071067811865475, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) - [InlineData(0.0137077838904018851, 0.7853981633974483, CrossPlatformMachineEpsilon)] // expected: (pi / 4) - [InlineData(0.017453292519943295, 1.0, CrossPlatformMachineEpsilon)] - [InlineData(0.019693931676727953, 1.1283791670955126, CrossPlatformMachineEpsilon)] // expected: (2 / sqrt(pi)) - [InlineData(0.024682682989768702, 1.4142135623730950, CrossPlatformMachineEpsilon)] // expected: (sqrt(2)) - [InlineData(0.025179778565706630, 1.4426950408889634, CrossPlatformMachineEpsilon)] // expected: (log2(e)) - [InlineData(0.026179938779914940, 1.5, CrossPlatformMachineEpsilon)] - [InlineData(0.027415567780803770, 1.5707963267948966, CrossPlatformMachineEpsilon)] // expected: (pi / 2) - [InlineData(0.034906585039886590, 2.0, CrossPlatformMachineEpsilon)] - [InlineData(0.040187691180085916, 2.3025850929940457, CrossPlatformMachineEpsilon)] // expected: (ln(10)) - [InlineData(0.043633231299858240, 2.5, CrossPlatformMachineEpsilon)] - [InlineData(0.047442967903742035, 2.7182818284590452, CrossPlatformMachineEpsilon)] // expected: (e) - [InlineData(0.052359877559829880, 3.0, CrossPlatformMachineEpsilon)] - [InlineData(0.054831135561607540, 3.1415926535897932, CrossPlatformMachineEpsilon)] // expected: (pi) - [InlineData(0.061086523819801536, 3.5, CrossPlatformMachineEpsilon)] - [InlineData(double.PositiveInfinity, double.PositiveInfinity, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesDouble), MemberType = typeof(GenericMathTestMemberData))] public static void RadiansToDegreesTest(double value, double expectedResult, double allowedVariance) { AssertExtensions.Equal(-expectedResult, double.RadiansToDegrees(-value), allowedVariance); diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs index 21a4ba2cd77a11..063ad2d9cfe242 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.GenericMath.cs @@ -117,24 +117,11 @@ public static void IsPow2Test() Assert.False(BinaryNumberHelper.IsPow2(float.PositiveInfinity)); } - [Fact] - public static void Log2Test() - { - AssertBitwiseEqual(float.NaN, BinaryNumberHelper.Log2(float.NegativeInfinity)); - AssertBitwiseEqual(float.NaN, BinaryNumberHelper.Log2(float.MinValue)); - AssertBitwiseEqual(float.NaN, BinaryNumberHelper.Log2(-1.0f)); - AssertBitwiseEqual(float.NaN, BinaryNumberHelper.Log2(-MinNormal)); - AssertBitwiseEqual(float.NaN, BinaryNumberHelper.Log2(-MaxSubnormal)); - AssertBitwiseEqual(float.NaN, BinaryNumberHelper.Log2(-float.Epsilon)); - AssertBitwiseEqual(float.NegativeInfinity, BinaryNumberHelper.Log2(-0.0f)); - AssertBitwiseEqual(float.NaN, BinaryNumberHelper.Log2(float.NaN)); - AssertBitwiseEqual(float.NegativeInfinity, BinaryNumberHelper.Log2(0.0f)); - AssertBitwiseEqual(-149.0f, BinaryNumberHelper.Log2(float.Epsilon)); - AssertBitwiseEqual(-126.0f, BinaryNumberHelper.Log2(MaxSubnormal)); - AssertBitwiseEqual(-126.0f, BinaryNumberHelper.Log2(MinNormal)); - AssertBitwiseEqual(0.0f, BinaryNumberHelper.Log2(1.0f)); - AssertBitwiseEqual(128.0f, BinaryNumberHelper.Log2(float.MaxValue)); - AssertBitwiseEqual(float.PositiveInfinity, BinaryNumberHelper.Log2(float.PositiveInfinity)); + [Theory] + [MemberData(nameof(GenericMathTestMemberData.Log2Single), MemberType = typeof(GenericMathTestMemberData))] + public static void Log2Test(float value, float expectedResult, float allowedVariance) + { + AssertExtensions.Equal(expectedResult, BinaryNumberHelper.Log2(value), allowedVariance); } // @@ -1029,104 +1016,39 @@ public static void op_CheckedMultiplyTest() // INumber // - [Fact] - public static void ClampTest() - { - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(float.NegativeInfinity, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(float.MinValue, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(-1.0f, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(-MinNormal, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(-MaxSubnormal, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(-float.Epsilon, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(-0.0f, 1.0f, 63.0f)); - AssertBitwiseEqual(float.NaN, NumberHelper.Clamp(float.NaN, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(0.0f, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(float.Epsilon, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(MaxSubnormal, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(MinNormal, 1.0f, 63.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Clamp(1.0f, 1.0f, 63.0f)); - AssertBitwiseEqual(63.0f, NumberHelper.Clamp(float.MaxValue, 1.0f, 63.0f)); - AssertBitwiseEqual(63.0f, NumberHelper.Clamp(float.PositiveInfinity, 1.0f, 63.0f)); - } - - [Fact] - public static void MaxTest() - { - AssertBitwiseEqual(1.0f, NumberHelper.Max(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(float.MinValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(-1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(-MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(-0.0f, 1.0f)); - AssertBitwiseEqual(float.NaN, NumberHelper.Max(float.NaN, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Max(1.0f, 1.0f)); - AssertBitwiseEqual(float.MaxValue, NumberHelper.Max(float.MaxValue, 1.0f)); - AssertBitwiseEqual(float.PositiveInfinity, NumberHelper.Max(float.PositiveInfinity, 1.0f)); - } - - [Fact] - public static void MaxNumberTest() - { - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(float.MinValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(-1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(-MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(-0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(float.NaN, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MaxNumber(1.0f, 1.0f)); - AssertBitwiseEqual(float.MaxValue, NumberHelper.MaxNumber(float.MaxValue, 1.0f)); - AssertBitwiseEqual(float.PositiveInfinity, NumberHelper.MaxNumber(float.PositiveInfinity, 1.0f)); - } - - [Fact] - public static void MinTest() - { - AssertBitwiseEqual(float.NegativeInfinity, NumberHelper.Min(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(float.MinValue, NumberHelper.Min(float.MinValue, 1.0f)); - AssertBitwiseEqual(-1.0f, NumberHelper.Min(-1.0f, 1.0f)); - AssertBitwiseEqual(-MinNormal, NumberHelper.Min(-MinNormal, 1.0f)); - AssertBitwiseEqual(-MaxSubnormal, NumberHelper.Min(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(-float.Epsilon, NumberHelper.Min(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(-0.0f, NumberHelper.Min(-0.0f, 1.0f)); - AssertBitwiseEqual(float.NaN, NumberHelper.Min(float.NaN, 1.0f)); - AssertBitwiseEqual(0.0f, NumberHelper.Min(0.0f, 1.0f)); - AssertBitwiseEqual(float.Epsilon, NumberHelper.Min(float.Epsilon, 1.0f)); - AssertBitwiseEqual(MaxSubnormal, NumberHelper.Min(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(MinNormal, NumberHelper.Min(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Min(1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Min(float.MaxValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.Min(float.PositiveInfinity, 1.0f)); - } - - [Fact] - public static void MinNumberTest() - { - AssertBitwiseEqual(float.NegativeInfinity, NumberHelper.MinNumber(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(float.MinValue, NumberHelper.MinNumber(float.MinValue, 1.0f)); - AssertBitwiseEqual(-1.0f, NumberHelper.MinNumber(-1.0f, 1.0f)); - AssertBitwiseEqual(-MinNormal, NumberHelper.MinNumber(-MinNormal, 1.0f)); - AssertBitwiseEqual(-MaxSubnormal, NumberHelper.MinNumber(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(-float.Epsilon, NumberHelper.MinNumber(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(-0.0f, NumberHelper.MinNumber(-0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MinNumber(float.NaN, 1.0f)); - AssertBitwiseEqual(0.0f, NumberHelper.MinNumber(0.0f, 1.0f)); - AssertBitwiseEqual(float.Epsilon, NumberHelper.MinNumber(float.Epsilon, 1.0f)); - AssertBitwiseEqual(MaxSubnormal, NumberHelper.MinNumber(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(MinNormal, NumberHelper.MinNumber(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MinNumber(1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MinNumber(float.MaxValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberHelper.MinNumber(float.PositiveInfinity, 1.0f)); + [Theory] + [MemberData(nameof(GenericMathTestMemberData.ClampSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void ClampTest(float x, float min, float max, float expectedResult) + { + AssertBitwiseEqual(expectedResult, NumberHelper.Clamp(x, min, max)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxTest(float x, float y, float expectedResult) + { + AssertBitwiseEqual(expectedResult, NumberHelper.Max(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxNumberTest(float x, float y, float expectedResult) + { + AssertBitwiseEqual(expectedResult, NumberHelper.MaxNumber(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MinTest(float x, float y, float expectedResult) + { + AssertBitwiseEqual(expectedResult, NumberHelper.Min(x, y)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MinNumberTest(float x, float y, float expectedResult) + { + AssertBitwiseEqual(expectedResult, NumberHelper.MinNumber(x, y)); } [Fact] @@ -2204,44 +2126,18 @@ public static void IsIntegerTest() Assert.False(NumberBaseHelper.IsInteger(float.PositiveInfinity)); } - [Fact] - public static void IsNaNTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNaNSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void IsNaNTest(float value, bool expectedResult) { - Assert.False(NumberBaseHelper.IsNaN(float.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsNaN(float.MinValue)); - Assert.False(NumberBaseHelper.IsNaN(-1.0f)); - Assert.False(NumberBaseHelper.IsNaN(-MinNormal)); - Assert.False(NumberBaseHelper.IsNaN(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsNaN(-float.Epsilon)); - Assert.False(NumberBaseHelper.IsNaN(-0.0f)); - Assert.True(NumberBaseHelper.IsNaN(float.NaN)); - Assert.False(NumberBaseHelper.IsNaN(0.0f)); - Assert.False(NumberBaseHelper.IsNaN(float.Epsilon)); - Assert.False(NumberBaseHelper.IsNaN(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsNaN(MinNormal)); - Assert.False(NumberBaseHelper.IsNaN(1.0f)); - Assert.False(NumberBaseHelper.IsNaN(float.MaxValue)); - Assert.False(NumberBaseHelper.IsNaN(float.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsNaN(value)); } - [Fact] - public static void IsNegativeTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsNegativeSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void IsNegativeTest(float value, bool expectedResult) { - Assert.True(NumberBaseHelper.IsNegative(float.NegativeInfinity)); - Assert.True(NumberBaseHelper.IsNegative(float.MinValue)); - Assert.True(NumberBaseHelper.IsNegative(-1.0f)); - Assert.True(NumberBaseHelper.IsNegative(-MinNormal)); - Assert.True(NumberBaseHelper.IsNegative(-MaxSubnormal)); - Assert.True(NumberBaseHelper.IsNegative(-float.Epsilon)); - Assert.True(NumberBaseHelper.IsNegative(-0.0f)); - Assert.True(NumberBaseHelper.IsNegative(float.NaN)); - Assert.False(NumberBaseHelper.IsNegative(0.0f)); - Assert.False(NumberBaseHelper.IsNegative(float.Epsilon)); - Assert.False(NumberBaseHelper.IsNegative(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsNegative(MinNormal)); - Assert.False(NumberBaseHelper.IsNegative(1.0f)); - Assert.False(NumberBaseHelper.IsNegative(float.MaxValue)); - Assert.False(NumberBaseHelper.IsNegative(float.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsNegative(value)); } [Fact] @@ -2304,44 +2200,18 @@ public static void IsOddIntegerTest() Assert.False(NumberBaseHelper.IsOddInteger(float.PositiveInfinity)); } - [Fact] - public static void IsPositiveTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void IsPositiveTest(float value, bool expectedResult) { - Assert.False(NumberBaseHelper.IsPositive(float.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsPositive(float.MinValue)); - Assert.False(NumberBaseHelper.IsPositive(-1.0f)); - Assert.False(NumberBaseHelper.IsPositive(-MinNormal)); - Assert.False(NumberBaseHelper.IsPositive(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsPositive(-float.Epsilon)); - Assert.False(NumberBaseHelper.IsPositive(-0.0f)); - Assert.False(NumberBaseHelper.IsPositive(float.NaN)); - Assert.True(NumberBaseHelper.IsPositive(0.0f)); - Assert.True(NumberBaseHelper.IsPositive(float.Epsilon)); - Assert.True(NumberBaseHelper.IsPositive(MaxSubnormal)); - Assert.True(NumberBaseHelper.IsPositive(MinNormal)); - Assert.True(NumberBaseHelper.IsPositive(1.0f)); - Assert.True(NumberBaseHelper.IsPositive(float.MaxValue)); - Assert.True(NumberBaseHelper.IsPositive(float.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsPositive(value)); } - [Fact] - public static void IsPositiveInfinityTest() + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinitySingle), MemberType = typeof(GenericMathTestMemberData))] + public static void IsPositiveInfinityTest(float value, bool expectedResult) { - Assert.False(NumberBaseHelper.IsPositiveInfinity(float.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(float.MinValue)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-1.0f)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-MinNormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-float.Epsilon)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(-0.0f)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(float.NaN)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(0.0f)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(float.Epsilon)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(MinNormal)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(1.0f)); - Assert.False(NumberBaseHelper.IsPositiveInfinity(float.MaxValue)); - Assert.True(NumberBaseHelper.IsPositiveInfinity(float.PositiveInfinity)); + Assert.Equal(expectedResult, NumberBaseHelper.IsPositiveInfinity(value)); } [Fact] @@ -2384,104 +2254,39 @@ public static void IsSubnormalTest() Assert.False(NumberBaseHelper.IsSubnormal(float.PositiveInfinity)); } - [Fact] - public static void IsZeroTest() - { - Assert.False(NumberBaseHelper.IsZero(float.NegativeInfinity)); - Assert.False(NumberBaseHelper.IsZero(float.MinValue)); - Assert.False(NumberBaseHelper.IsZero(-1.0f)); - Assert.False(NumberBaseHelper.IsZero(-MinNormal)); - Assert.False(NumberBaseHelper.IsZero(-MaxSubnormal)); - Assert.False(NumberBaseHelper.IsZero(-float.Epsilon)); - Assert.True(NumberBaseHelper.IsZero(-0.0f)); - Assert.False(NumberBaseHelper.IsZero(float.NaN)); - Assert.True(NumberBaseHelper.IsZero(0.0f)); - Assert.False(NumberBaseHelper.IsZero(float.Epsilon)); - Assert.False(NumberBaseHelper.IsZero(MaxSubnormal)); - Assert.False(NumberBaseHelper.IsZero(MinNormal)); - Assert.False(NumberBaseHelper.IsZero(1.0f)); - Assert.False(NumberBaseHelper.IsZero(float.MaxValue)); - Assert.False(NumberBaseHelper.IsZero(float.PositiveInfinity)); - } - - [Fact] - public static void MaxMagnitudeTest() - { - AssertBitwiseEqual(float.NegativeInfinity, NumberBaseHelper.MaxMagnitude(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(float.MinValue, NumberBaseHelper.MaxMagnitude(float.MinValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(-1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(-MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(-0.0f, 1.0f)); - AssertBitwiseEqual(float.NaN, NumberBaseHelper.MaxMagnitude(float.NaN, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitude(1.0f, 1.0f)); - AssertBitwiseEqual(float.MaxValue, NumberBaseHelper.MaxMagnitude(float.MaxValue, 1.0f)); - AssertBitwiseEqual(float.PositiveInfinity, NumberBaseHelper.MaxMagnitude(float.PositiveInfinity, 1.0f)); - } - - [Fact] - public static void MaxMagnitudeNumberTest() - { - AssertBitwiseEqual(float.NegativeInfinity, NumberBaseHelper.MaxMagnitudeNumber(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(float.MinValue, NumberBaseHelper.MaxMagnitudeNumber(float.MinValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(-1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(-MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(-0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(float.NaN, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(float.Epsilon, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MaxMagnitudeNumber(1.0f, 1.0f)); - AssertBitwiseEqual(float.MaxValue, NumberBaseHelper.MaxMagnitudeNumber(float.MaxValue, 1.0f)); - AssertBitwiseEqual(float.PositiveInfinity, NumberBaseHelper.MaxMagnitudeNumber(float.PositiveInfinity, 1.0f)); - } - - [Fact] - public static void MinMagnitudeTest() - { - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitude(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitude(float.MinValue, 1.0f)); - AssertBitwiseEqual(-1.0f, NumberBaseHelper.MinMagnitude(-1.0f, 1.0f)); - AssertBitwiseEqual(-MinNormal, NumberBaseHelper.MinMagnitude(-MinNormal, 1.0f)); - AssertBitwiseEqual(-MaxSubnormal, NumberBaseHelper.MinMagnitude(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(-float.Epsilon, NumberBaseHelper.MinMagnitude(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(-0.0f, NumberBaseHelper.MinMagnitude(-0.0f, 1.0f)); - AssertBitwiseEqual(float.NaN, NumberBaseHelper.MinMagnitude(float.NaN, 1.0f)); - AssertBitwiseEqual(0.0f, NumberBaseHelper.MinMagnitude(0.0f, 1.0f)); - AssertBitwiseEqual(float.Epsilon, NumberBaseHelper.MinMagnitude(float.Epsilon, 1.0f)); - AssertBitwiseEqual(MaxSubnormal, NumberBaseHelper.MinMagnitude(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(MinNormal, NumberBaseHelper.MinMagnitude(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitude(1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitude(float.MaxValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitude(float.PositiveInfinity, 1.0f)); - } - - [Fact] - public static void MinMagnitudeNumberTest() - { - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitudeNumber(float.NegativeInfinity, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitudeNumber(float.MinValue, 1.0f)); - AssertBitwiseEqual(-1.0f, NumberBaseHelper.MinMagnitudeNumber(-1.0f, 1.0f)); - AssertBitwiseEqual(-MinNormal, NumberBaseHelper.MinMagnitudeNumber(-MinNormal, 1.0f)); - AssertBitwiseEqual(-MaxSubnormal, NumberBaseHelper.MinMagnitudeNumber(-MaxSubnormal, 1.0f)); - AssertBitwiseEqual(-float.Epsilon, NumberBaseHelper.MinMagnitudeNumber(-float.Epsilon, 1.0f)); - AssertBitwiseEqual(-0.0f, NumberBaseHelper.MinMagnitudeNumber(-0.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitudeNumber(float.NaN, 1.0f)); - AssertBitwiseEqual(0.0f, NumberBaseHelper.MinMagnitudeNumber(0.0f, 1.0f)); - AssertBitwiseEqual(float.Epsilon, NumberBaseHelper.MinMagnitudeNumber(float.Epsilon, 1.0f)); - AssertBitwiseEqual(MaxSubnormal, NumberBaseHelper.MinMagnitudeNumber(MaxSubnormal, 1.0f)); - AssertBitwiseEqual(MinNormal, NumberBaseHelper.MinMagnitudeNumber(MinNormal, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitudeNumber(1.0f, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitudeNumber(float.MaxValue, 1.0f)); - AssertBitwiseEqual(1.0f, NumberBaseHelper.MinMagnitudeNumber(float.PositiveInfinity, 1.0f)); + [Theory] + [MemberData(nameof(GenericMathTestMemberData.IsZeroSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void IsZeroTest(float value, bool expectedResult) + { + Assert.Equal(expectedResult, NumberBaseHelper.IsZero(value)); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxMagnitudeTest(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MaxMagnitude(x, y), 0.0f); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MaxMagnitudeNumberTest(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MaxMagnitudeNumber(x, y), 0.0f); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MinMagnitudeTest(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MinMagnitude(x, y), 0.0f); + } + + [Theory] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] + public static void MinMagnitudeNumberTest(float x, float y, float expectedResult) + { + AssertExtensions.Equal(expectedResult, NumberBaseHelper.MinMagnitudeNumber(x, y), 0.0f); } // diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs index 25f8d230c80c03..a7152e5ab00efb 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/SingleTests.cs @@ -156,55 +156,7 @@ public static void GetTypeCode_Invoke_ReturnsSingle() } [Theory] - [InlineData(float.NaN, float.NaN, float.NaN, 0.0f)] - [InlineData(float.NaN, 0.0f, float.NaN, 0.0f)] - [InlineData(float.NaN, 1.0f, float.NaN, 0.0f)] - [InlineData(float.NaN, 2.71828183f, float.NaN, 0.0f)] - [InlineData(float.NaN, 10.0f, float.NaN, 0.0f)] - [InlineData(0.0f, 0.0f, 0.0f, 0.0f)] - [InlineData(0.0f, 1.0f, 1.0f, 0.0f)] - [InlineData(0.0f, 1.57079633f, 1.57079633f, 0.0f)] - [InlineData(0.0f, 2.0f, 2.0f, 0.0f)] - [InlineData(0.0f, 2.71828183f, 2.71828183f, 0.0f)] - [InlineData(0.0f, 3.0f, 3.0f, 0.0f)] - [InlineData(0.0f, 10.0f, 10.0f, 0.0f)] - [InlineData(1.0f, 1.0f, 1.41421356f, CrossPlatformMachineEpsilon * 10)] - [InlineData(1.0f, 1e+10f, 1e+10f, 0.0)] // dotnet/runtime#75651 - [InlineData(1.0f, 1e+20f, 1e+20f, 0.0)] // dotnet/runtime#75651 - [InlineData(2.71828183f, 0.318309886f, 2.73685536f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / pi) - [InlineData(2.71828183f, 0.434294482f, 2.75275640f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log10(e)) - [InlineData(2.71828183f, 0.636619772f, 2.79183467f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / pi) - [InlineData(2.71828183f, 0.693147181f, 2.80526454f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (ln(2)) - [InlineData(2.71828183f, 0.707106781f, 2.80874636f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (1 / sqrt(2)) - [InlineData(2.71828183f, 0.785398163f, 2.82947104f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 4) - [InlineData(2.71828183f, 1.0f, 2.89638673f, CrossPlatformMachineEpsilon * 10)] // x: (e) - [InlineData(2.71828183f, 1.12837917f, 2.94317781f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (2 / sqrt(pi)) - [InlineData(2.71828183f, 1.41421356f, 3.06415667f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (sqrt(2)) - [InlineData(2.71828183f, 1.44269504f, 3.07740558f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (log2(e)) - [InlineData(2.71828183f, 1.57079633f, 3.13949951f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi / 2) - [InlineData(2.71828183f, 2.30258509f, 3.56243656f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (ln(10)) - [InlineData(2.71828183f, 2.71828183f, 3.84423103f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (e) - [InlineData(2.71828183f, 3.14159265f, 4.15435440f, CrossPlatformMachineEpsilon * 10)] // x: (e) y: (pi) - [InlineData(10.0f, 0.318309886f, 10.0050648f, CrossPlatformMachineEpsilon * 100)] // y: (1 / pi) - [InlineData(10.0f, 0.434294482f, 10.0094261f, CrossPlatformMachineEpsilon * 100)] // y: (log10(e)) - [InlineData(10.0f, 0.636619772f, 10.0202437f, CrossPlatformMachineEpsilon * 100)] // y: (2 / pi) - [InlineData(10.0f, 0.693147181f, 10.0239939f, CrossPlatformMachineEpsilon * 100)] // y: (ln(2)) - [InlineData(10.0f, 0.707106781f, 10.0249688f, CrossPlatformMachineEpsilon * 100)] // y: (1 / sqrt(2)) - [InlineData(10.0f, 0.785398163f, 10.0307951f, CrossPlatformMachineEpsilon * 100)] // y: (pi / 4) - [InlineData(10.0f, 1.0f, 10.0498756f, CrossPlatformMachineEpsilon * 100)] // - [InlineData(10.0f, 1.12837917f, 10.0634606f, CrossPlatformMachineEpsilon * 100)] // y: (2 / sqrt(pi)) - [InlineData(10.0f, 1.41421356f, 10.0995049f, CrossPlatformMachineEpsilon * 100)] // y: (sqrt(2)) - [InlineData(10.0f, 1.44269504f, 10.1035325f, CrossPlatformMachineEpsilon * 100)] // y: (log2(e)) - [InlineData(10.0f, 1.57079633f, 10.1226183f, CrossPlatformMachineEpsilon * 100)] // y: (pi / 2) - [InlineData(10.0f, 2.30258509f, 10.2616713f, CrossPlatformMachineEpsilon * 100)] // y: (ln(10)) - [InlineData(10.0f, 2.71828183f, 10.3628691f, CrossPlatformMachineEpsilon * 100)] // y: (e) - [InlineData(10.0f, 3.14159265f, 10.4818703f, CrossPlatformMachineEpsilon * 100)] // y: (pi) - [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity, 0.0f)] - [InlineData(float.PositiveInfinity, 0.0f, float.PositiveInfinity, 0.0f)] - [InlineData(float.PositiveInfinity, 1.0f, float.PositiveInfinity, 0.0f)] - [InlineData(float.PositiveInfinity, 2.71828183f, float.PositiveInfinity, 0.0f)] - [InlineData(float.PositiveInfinity, 10.0f, float.PositiveInfinity, 0.0f)] - [InlineData(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.HypotSingle), MemberType = typeof(GenericMathTestMemberData))] public static void Hypot(float x, float y, float expectedResult, float allowedVariance) { AssertExtensions.Equal(expectedResult, float.Hypot(-x, -y), allowedVariance); @@ -238,19 +190,7 @@ public static void IsInfinity(float d, bool expected) } [Theory] - [InlineData(float.NegativeInfinity, false)] // Negative Infinity - [InlineData(float.MinValue, false)] // Min Negative Normal - [InlineData(-1.17549435E-38f, false)] // Max Negative Normal - [InlineData(-1.17549421E-38f, false)] // Min Negative Subnormal - [InlineData(-float.Epsilon, false)] // Max Negative Subnormal (Negative Epsilon) - [InlineData(-0.0f, false)] // Negative Zero - [InlineData(float.NaN, true)] // NaN - [InlineData(0.0f, false)] // Positive Zero - [InlineData(float.Epsilon, false)] // Min Positive Subnormal (Positive Epsilon) - [InlineData(1.17549421E-38f, false)] // Max Positive Subnormal - [InlineData(1.17549435E-38f, false)] // Min Positive Normal - [InlineData(float.MaxValue, false)] // Max Positive Normal - [InlineData(float.PositiveInfinity, false)] // Positive Infinity + [MemberData(nameof(GenericMathTestMemberData.IsNaNSingle), MemberType = typeof(GenericMathTestMemberData))] public static void IsNaN(float d, bool expected) { Assert.Equal(expected, float.IsNaN(d)); @@ -276,19 +216,7 @@ public static void IsNegativeInfinity(float d, bool expected) } [Theory] - [InlineData(float.NegativeInfinity, false)] // Negative Infinity - [InlineData(float.MinValue, false)] // Min Negative Normal - [InlineData(-1.17549435E-38f, false)] // Max Negative Normal - [InlineData(-1.17549421E-38f, false)] // Min Negative Subnormal - [InlineData(-float.Epsilon, false)] // Max Negative Subnormal (Negative Epsilon) - [InlineData(-0.0f, false)] // Negative Zero - [InlineData(float.NaN, false)] // NaN - [InlineData(0.0f, false)] // Positive Zero - [InlineData(float.Epsilon, false)] // Min Positive Subnormal (Positive Epsilon) - [InlineData(1.17549421E-38f, false)] // Max Positive Subnormal - [InlineData(1.17549435E-38f, false)] // Min Positive Normal - [InlineData(float.MaxValue, false)] // Max Positive Normal - [InlineData(float.PositiveInfinity, true)] // Positive Infinity + [MemberData(nameof(GenericMathTestMemberData.IsPositiveInfinitySingle), MemberType = typeof(GenericMathTestMemberData))] public static void IsPositiveInfinity(float d, bool expected) { Assert.Equal(expected, float.IsPositiveInfinity(d)); @@ -856,19 +784,7 @@ public static void IsFinite(float d, bool expected) } [Theory] - [InlineData(float.NegativeInfinity, true)] // Negative Infinity - [InlineData(float.MinValue, true)] // Min Negative Normal - [InlineData(-1.17549435E-38f, true)] // Max Negative Normal - [InlineData(-1.17549421E-38f, true)] // Min Negative Subnormal - [InlineData(-1.401298E-45, true)] // Max Negative Subnormal - [InlineData(-0.0f, true)] // Negative Zero - [InlineData(float.NaN, true)] // NaN - [InlineData(0.0f, false)] // Positive Zero - [InlineData(1.401298E-45, false)] // Min Positive Subnormal - [InlineData(1.17549421E-38f, false)] // Max Positive Subnormal - [InlineData(1.17549435E-38f, false)] // Min Positive Normal - [InlineData(float.MaxValue, false)] // Max Positive Normal - [InlineData(float.PositiveInfinity, false)] // Positive Infinity + [MemberData(nameof(GenericMathTestMemberData.IsNegativeSingle), MemberType = typeof(GenericMathTestMemberData))] public static void IsNegative(float d, bool expected) { Assert.Equal(expected, float.IsNegative(d)); @@ -972,92 +888,28 @@ public static void ToStringRoundtrip_R(float value) } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] - [InlineData(float.MaxValue, float.MinValue, float.MaxValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, 1.0f)] - [InlineData(1.0f, float.NaN, 1.0f)] - [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] - [InlineData(float.NegativeInfinity, float.NaN, float.NegativeInfinity)] - [InlineData(float.NaN, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.NaN, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(-0.0f, 0.0f, 0.0f)] - [InlineData(0.0f, -0.0f, 0.0f)] - [InlineData(2.0f, -3.0f, -3.0f)] - [InlineData(-3.0f, 2.0f, -3.0f)] - [InlineData(3.0f, -2.0f, 3.0f)] - [InlineData(-2.0f, 3.0f, 3.0f)] + [MemberData(nameof(GenericMathTestMemberData.MaxMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] public static void MaxMagnitudeNumberTest(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, float.MaxMagnitudeNumber(x, y), 0.0f); } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MaxValue)] - [InlineData(float.MaxValue, float.MinValue, float.MaxValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, 1.0f)] - [InlineData(1.0f, float.NaN, 1.0f)] - [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] - [InlineData(float.NegativeInfinity, float.NaN, float.NegativeInfinity)] - [InlineData(float.NaN, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.NaN, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(-0.0f, 0.0f, 0.0f)] - [InlineData(0.0f, -0.0f, 0.0f)] - [InlineData(2.0f, -3.0f, 2.0f)] - [InlineData(-3.0f, 2.0f, 2.0f)] - [InlineData(3.0f, -2.0f, 3.0f)] - [InlineData(-2.0f, 3.0f, 3.0f)] + [MemberData(nameof(GenericMathTestMemberData.MaxNumberSingle), MemberType = typeof(GenericMathTestMemberData))] public static void MaxNumberTest(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, float.MaxNumber(x, y), 0.0f); } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MinValue)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, 1.0f)] - [InlineData(1.0f, float.NaN, 1.0f)] - [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] - [InlineData(float.NegativeInfinity, float.NaN, float.NegativeInfinity)] - [InlineData(float.NaN, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.NaN, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(-0.0f, 0.0f, -0.0f)] - [InlineData(0.0f, -0.0f, -0.0f)] - [InlineData(2.0f, -3.0f, 2.0f)] - [InlineData(-3.0f, 2.0f, 2.0f)] - [InlineData(3.0f, -2.0f, -2.0f)] - [InlineData(-2.0f, 3.0f, -2.0f)] + [MemberData(nameof(GenericMathTestMemberData.MinMagnitudeNumberSingle), MemberType = typeof(GenericMathTestMemberData))] public static void MinMagnitudeNumberTest(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, float.MinMagnitudeNumber(x, y), 0.0f); } [Theory] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, float.NegativeInfinity)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(float.MinValue, float.MaxValue, float.MinValue)] - [InlineData(float.MaxValue, float.MinValue, float.MinValue)] - [InlineData(float.NaN, float.NaN, float.NaN)] - [InlineData(float.NaN, 1.0f, 1.0f)] - [InlineData(1.0f, float.NaN, 1.0f)] - [InlineData(float.PositiveInfinity, float.NaN, float.PositiveInfinity)] - [InlineData(float.NegativeInfinity, float.NaN, float.NegativeInfinity)] - [InlineData(float.NaN, float.PositiveInfinity, float.PositiveInfinity)] - [InlineData(float.NaN, float.NegativeInfinity, float.NegativeInfinity)] - [InlineData(-0.0f, 0.0f, -0.0f)] - [InlineData(0.0f, -0.0f, -0.0f)] - [InlineData(2.0f, -3.0f, -3.0f)] - [InlineData(-3.0f, 2.0f, -3.0f)] - [InlineData(3.0f, -2.0f, -2.0f)] - [InlineData(-2.0f, 3.0f, -2.0f)] + [MemberData(nameof(GenericMathTestMemberData.MinNumberSingle), MemberType = typeof(GenericMathTestMemberData))] public static void MinNumberTest(float x, float y, float expectedResult) { AssertExtensions.Equal(expectedResult, float.MinNumber(x, y), 0.0f); @@ -1574,37 +1426,7 @@ public static void TanPiTest(float value, float expectedResult, float allowedVar } [Theory] - [InlineData(float.NegativeInfinity, float.NegativeInfinity, 0.5f, float.NegativeInfinity)] - [InlineData(float.NegativeInfinity, float.NaN, 0.5f, float.NaN)] - [InlineData(float.NegativeInfinity, float.PositiveInfinity, 0.5f, float.NaN)] - [InlineData(float.NegativeInfinity, 0.0f, 0.5f, float.NegativeInfinity)] - [InlineData(float.NegativeInfinity, 1.0f, 0.5f, float.NegativeInfinity)] - [InlineData(float.NaN, float.NegativeInfinity, 0.5f, float.NaN)] - [InlineData(float.NaN, float.NaN, 0.5f, float.NaN)] - [InlineData(float.NaN, float.PositiveInfinity, 0.5f, float.NaN)] - [InlineData(float.NaN, 0.0f, 0.5f, float.NaN)] - [InlineData(float.NaN, 1.0f, 0.5f, float.NaN)] - [InlineData(float.PositiveInfinity, float.NegativeInfinity, 0.5f, float.NaN)] - [InlineData(float.PositiveInfinity, float.NaN, 0.5f, float.NaN)] - [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.5f, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, 0.0f, 0.5f, float.PositiveInfinity)] - [InlineData(float.PositiveInfinity, 1.0f, 0.5f, float.PositiveInfinity)] - [InlineData(1.0f, 3.0f, 0.0f, 1.0f)] - [InlineData(1.0f, 3.0f, 0.5f, 2.0f)] - [InlineData(1.0f, 3.0f, 1.0f, 3.0f)] - [InlineData(1.0f, 3.0f, 2.0f, 5.0f)] - [InlineData(2.0f, 4.0f, 0.0f, 2.0f)] - [InlineData(2.0f, 4.0f, 0.5f, 3.0f)] - [InlineData(2.0f, 4.0f, 1.0f, 4.0f)] - [InlineData(2.0f, 4.0f, 2.0f, 6.0f)] - [InlineData(3.0f, 1.0f, 0.0f, 3.0f)] - [InlineData(3.0f, 1.0f, 0.5f, 2.0f)] - [InlineData(3.0f, 1.0f, 1.0f, 1.0f)] - [InlineData(3.0f, 1.0f, 2.0f, -1.0f)] - [InlineData(4.0f, 2.0f, 0.0f, 4.0f)] - [InlineData(4.0f, 2.0f, 0.5f, 3.0f)] - [InlineData(4.0f, 2.0f, 1.0f, 2.0f)] - [InlineData(4.0f, 2.0f, 2.0f, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.LerpSingle), MemberType = typeof(GenericMathTestMemberData))] public static void LerpTest(float value1, float value2, float amount, float expectedResult) { AssertExtensions.Equal(+expectedResult, float.Lerp(+value1, +value2, amount), 0); @@ -1612,29 +1434,7 @@ public static void LerpTest(float value1, float value2, float amount, float expe } [Theory] - [InlineData(float.NaN, float.NaN, 0.0f)] - [InlineData(0.0f, 0.0f, 0.0f)] - [InlineData(0.318309886f, 0.0055555557f, CrossPlatformMachineEpsilon)] // value: (1 / pi) - [InlineData(0.434294482f, 0.007579869f, CrossPlatformMachineEpsilon)] // value: (log10(e)) - [InlineData(0.5f, 0.008726646f, CrossPlatformMachineEpsilon)] - [InlineData(0.636619772f, 0.011111111f, CrossPlatformMachineEpsilon)] // value: (2 / pi) - [InlineData(0.693147181f, 0.0120977005f, CrossPlatformMachineEpsilon)] // value: (ln(2)) - [InlineData(0.707106781f, 0.012341342f, CrossPlatformMachineEpsilon)] // value: (1 / sqrt(2)) - [InlineData(0.785398163f, 0.013707785f, CrossPlatformMachineEpsilon)] // value: (pi / 4) - [InlineData(1.0f, 0.017453292f, CrossPlatformMachineEpsilon)] - [InlineData(1.12837917f, 0.019693933f, CrossPlatformMachineEpsilon)] // value: (2 / sqrt(pi)) - [InlineData(1.41421356f, 0.024682684f, CrossPlatformMachineEpsilon)] // value: (sqrt(2)) - [InlineData(1.44269504f, 0.025179777f, CrossPlatformMachineEpsilon)] // value: (log2(e)) - [InlineData(1.5f, 0.02617994f, CrossPlatformMachineEpsilon)] - [InlineData(1.57079633f, 0.02741557f, CrossPlatformMachineEpsilon)] // value: (pi / 2) - [InlineData(2.0f, 0.034906585f, CrossPlatformMachineEpsilon)] - [InlineData(2.30258509f, 0.040187694f, CrossPlatformMachineEpsilon)] // value: (ln(10)) - [InlineData(2.5f, 0.043633234f, CrossPlatformMachineEpsilon)] - [InlineData(2.71828183f, 0.047442965f, CrossPlatformMachineEpsilon)] // value: (e) - [InlineData(3.0f, 0.05235988f, CrossPlatformMachineEpsilon)] - [InlineData(3.14159265f, 0.05483114f, CrossPlatformMachineEpsilon)] // value: (pi) - [InlineData(3.5f, 0.061086528f, CrossPlatformMachineEpsilon)] - [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0f)] + [MemberData(nameof(GenericMathTestMemberData.DegreesToRadiansSingle), MemberType = typeof(GenericMathTestMemberData))] public static void DegreesToRadiansTest(float value, float expectedResult, float allowedVariance) { AssertExtensions.Equal(-expectedResult, float.DegreesToRadians(-value), allowedVariance); @@ -1642,29 +1442,7 @@ public static void DegreesToRadiansTest(float value, float expectedResult, float } [Theory] - [InlineData(float.NaN, float.NaN, 0.0)] - [InlineData(0.0f, 0.0f, 0.0)] - [InlineData(0.0055555557f, 0.318309886f, CrossPlatformMachineEpsilon)] // expected: (1 / pi) - [InlineData(0.007579869f, 0.434294482f, CrossPlatformMachineEpsilon)] // expected: (log10(e)) - [InlineData(0.008726646f, 0.5f, CrossPlatformMachineEpsilon)] - [InlineData(0.011111111f, 0.636619772f, CrossPlatformMachineEpsilon)] // expected: (2 / pi) - [InlineData(0.0120977005f, 0.693147181f, CrossPlatformMachineEpsilon)] // expected: (ln(2)) - [InlineData(0.012341342f, 0.707106781f, CrossPlatformMachineEpsilon)] // expected: (1 / sqrt(2)) - [InlineData(0.013707785f, 0.785398163f, CrossPlatformMachineEpsilon)] // expected: (pi / 4) - [InlineData(0.017453292f, 1.0f, CrossPlatformMachineEpsilon)] - [InlineData(0.019693933f, 1.12837917f, CrossPlatformMachineEpsilon)] // expected: (2 / sqrt(pi)) - [InlineData(0.024682684f, 1.41421356f, CrossPlatformMachineEpsilon)] // expected: (sqrt(2)) - [InlineData(0.025179777f, 1.44269504f, CrossPlatformMachineEpsilon)] // expected: (log2(e)) - [InlineData(0.02617994f, 1.5f, CrossPlatformMachineEpsilon)] - [InlineData(0.02741557f, 1.57079633f, CrossPlatformMachineEpsilon)] // expected: (pi / 2) - [InlineData(0.034906585f, 2.0f, CrossPlatformMachineEpsilon)] - [InlineData(0.040187694f, 2.30258509f, CrossPlatformMachineEpsilon)] // expected: (ln(10)) - [InlineData(0.043633234f, 2.5f, CrossPlatformMachineEpsilon)] - [InlineData(0.047442965f, 2.71828183f, CrossPlatformMachineEpsilon)] // expected: (e) - [InlineData(0.05235988f, 3.0f, CrossPlatformMachineEpsilon)] - [InlineData(0.05483114f, 3.14159265f, CrossPlatformMachineEpsilon)] // expected: (pi) - [InlineData(0.061086528f, 3.5f, CrossPlatformMachineEpsilon)] - [InlineData(float.PositiveInfinity, float.PositiveInfinity, 0.0)] + [MemberData(nameof(GenericMathTestMemberData.RadiansToDegreesSingle), MemberType = typeof(GenericMathTestMemberData))] public static void RadiansToDegreesTest(float value, float expectedResult, float allowedVariance) { AssertExtensions.Equal(-expectedResult, float.RadiansToDegrees(-value), allowedVariance); From dcffeb84f7fa88c9d41374d4597d6cd7fd16494d Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 13:23:51 -0700 Subject: [PATCH 21/39] Fix the mono handling for IsNaN, IsNegative, and IsPositive --- src/mono/mono/mini/simd-intrinsics.c | 26 ++++++++++++++++++-------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 51794d5c8c47d3..a8ba97b06bad28 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2145,28 +2145,39 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; if (!type_enum_is_float(arg0_type)) return emit_xzero (cfg, klass); - args [0] = emit_xcompare (cfg, klass, arg0_type, args [0], args [0]); - return emit_simd_ins_for_unary_op (cfg, klass, fsig, args, arg0_type, SN_op_OnesComplement); + MonoInst *xcmp = emit_xcompare (cfg, klass, arg0_type, args [0], args [0]); + MonoInst *xnot = emit_simd_ins (cfg, klass, OP_ONES_COMPLEMENT, xcmp->dreg, -1); + xnot->inst_c1 = arg0_type; + return xnot; } case SN_IsNegative: { if (!is_element_type_primitive (fsig->params [0])) return NULL; - if (type_enum_is_unsigned(arg0_type)) + if (type_enum_is_unsigned(arg0_type)) { return emit_xzero (cfg, klass); + } else if (arg0_type == MONO_TYPE_R4) { + arg0_type = MONO_TYPE_I4; + } else if (arg0_type == MONO_TYPE_R8) { + arg0_type = MONO_TYPE_I8; + } return emit_xcompare_for_intrinsic (cfg, klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, klass)); } case SN_IsPositive: { if (!is_element_type_primitive (fsig->params [0])) return NULL; - if (type_enum_is_unsigned(arg0_type)) + if (type_enum_is_unsigned(arg0_type)) { return emit_xones (cfg, klass); + } else if (arg0_type == MONO_TYPE_R4) { + arg0_type = MONO_TYPE_I4; + } else if (arg0_type == MONO_TYPE_R8) { + arg0_type = MONO_TYPE_I8; + } return emit_xcompare_for_intrinsic (cfg, klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, klass)); } case SN_IsPositiveInfinity: { if (!is_element_type_primitive (fsig->params [0])) return NULL; - MonoType *etype = get_vector_t_elem_type(fsig->params [0]); - if (etype->type == MONO_TYPE_R4) { + if (arg0_type == MONO_TYPE_R4) { guint32 value[4]; value [0] = 0x7F800000; @@ -2176,8 +2187,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi MonoInst* arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); return emit_xcompare (cfg, klass, arg0_type, args [0], arg1); - } - if (etype->type == MONO_TYPE_R8) { + } else if (arg0_type == MONO_TYPE_R8) { guint64 value[2]; value [0] = 0x7FF0000000000000; From 68044569da0d8f9d91adbaf39ce0f9f614b7bc12 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 14:02:27 -0700 Subject: [PATCH 22/39] Use the right op for WASM --- src/mono/mono/mini/simd-intrinsics.c | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index a8ba97b06bad28..1303797186ffc6 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2145,8 +2145,16 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; if (!type_enum_is_float(arg0_type)) return emit_xzero (cfg, klass); + int op = -1; +#if defined(TARGET_ARM64) || defined(TARGET_AMD64) + op = OP_ONES_COMPLEMENT; +#elif defined(TARGET_WASM) + op = OP_WASM_ONESCOMPLEMENT; +#endif + if (op == -1) + return NULL; MonoInst *xcmp = emit_xcompare (cfg, klass, arg0_type, args [0], args [0]); - MonoInst *xnot = emit_simd_ins (cfg, klass, OP_ONES_COMPLEMENT, xcmp->dreg, -1); + MonoInst *xnot = emit_simd_ins (cfg, klass, op, xcmp->dreg, -1); xnot->inst_c1 = arg0_type; return xnot; } @@ -2185,7 +2193,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi value [2] = 0x7F800000; value [3] = 0x7F800000; - MonoInst* arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); + MonoInst *arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); return emit_xcompare (cfg, klass, arg0_type, args [0], arg1); } else if (arg0_type == MONO_TYPE_R8) { guint64 value[2]; @@ -2193,7 +2201,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi value [0] = 0x7FF0000000000000; value [1] = 0x7FF0000000000000; - MonoInst* arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); + MonoInst *arg1 = emit_xconst_v128 (cfg, klass, (guint8*)value); return emit_xcompare (cfg, klass, arg0_type, args [0], arg1); } return emit_xzero (cfg, klass); From 72d2dd634cf8dfe13ea7867d034c3adf9d344d15 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 14:51:56 -0700 Subject: [PATCH 23/39] Fix a round test to correctly expect -0 --- .../Common/tests/System/GenericMathTestMemberData.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/Common/tests/System/GenericMathTestMemberData.cs b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs index 0ff24e428fb5f7..b2818922d89496 100644 --- a/src/libraries/Common/tests/System/GenericMathTestMemberData.cs +++ b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs @@ -1494,7 +1494,7 @@ public static IEnumerable RoundDouble yield return new object[] { 1.4, 1.0 }; yield return new object[] { 1.5, 2.0 }; yield return new object[] { 2e7, 2e7 }; - yield return new object[] { -0.0, 0.0 }; + yield return new object[] { -0.0, -0.0 }; yield return new object[] { -1.4, -1.0 }; yield return new object[] { -1.5, -2.0 }; yield return new object[] { -2e7, -2e7 }; @@ -1509,7 +1509,7 @@ public static IEnumerable RoundSingle yield return new object[] { 1.4f, 1.0f }; yield return new object[] { 1.5f, 2.0f }; yield return new object[] { 2e7f, 2e7f }; - yield return new object[] { -0.0f, 0.0f }; + yield return new object[] { -0.0f, -0.0f }; yield return new object[] { -1.4f, -1.0f }; yield return new object[] { -1.5f, -2.0f }; yield return new object[] { -2e7f, -2e7f }; From aaa71b257b5bdd93eb3e985e56875b08a99a4d09 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 18:53:02 -0700 Subject: [PATCH 24/39] Fix some tests where the wrong parameter counts were being passed --- .../tests/System/GenericMathTestMemberData.cs | 264 +++++++++--------- .../tests/GenericVectorTests.cs | 28 +- .../tests/Vector2Tests.cs | 14 +- .../tests/Vector3Tests.cs | 14 +- .../tests/Vector4Tests.cs | 14 +- .../tests/Vectors/Vector128Tests.cs | 28 +- .../tests/Vectors/Vector256Tests.cs | 28 +- .../tests/Vectors/Vector512Tests.cs | 28 +- .../tests/Vectors/Vector64Tests.cs | 28 +- .../System/DoubleTests.GenericMath.cs | 4 +- 10 files changed, 173 insertions(+), 277 deletions(-) diff --git a/src/libraries/Common/tests/System/GenericMathTestMemberData.cs b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs index b2818922d89496..2e40a0940fc5a0 100644 --- a/src/libraries/Common/tests/System/GenericMathTestMemberData.cs +++ b/src/libraries/Common/tests/System/GenericMathTestMemberData.cs @@ -342,72 +342,72 @@ public static IEnumerable FusedMultiplyAddDouble { get { - yield return new object[] { double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] { double.NegativeInfinity, -0.0, double.NegativeInfinity }; - yield return new object[] { double.NegativeInfinity, -0.0, -3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, -0.0, -0.0 }; - yield return new object[] { double.NegativeInfinity, -0.0, double.NaN }; - yield return new object[] { double.NegativeInfinity, -0.0, 0.0 }; - yield return new object[] { double.NegativeInfinity, -0.0, 3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, -0.0, double.PositiveInfinity }; - yield return new object[] { double.NegativeInfinity, 0.0, double.NegativeInfinity }; - yield return new object[] { double.NegativeInfinity, 0.0, -3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, 0.0, -0.0 }; - yield return new object[] { double.NegativeInfinity, 0.0, double.NaN }; - yield return new object[] { double.NegativeInfinity, 0.0, 0.0 }; - yield return new object[] { double.NegativeInfinity, 0.0, 3.1415926535897932 }; - yield return new object[] { double.NegativeInfinity, 0.0, double.PositiveInfinity }; - yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] {-1e308, 2.0, 1e308 }; - yield return new object[] {-1e308, 2.0, double.PositiveInfinity }; - yield return new object[] {-5, 4, -3 }; - yield return new object[] {-0.0, double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] {-0.0, double.NegativeInfinity, -3.1415926535897932 }; - yield return new object[] {-0.0, double.NegativeInfinity, -0.0 }; - yield return new object[] {-0.0, double.NegativeInfinity, double.NaN }; - yield return new object[] {-0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] {-0.0, double.NegativeInfinity, 3.1415926535897932 }; - yield return new object[] {-0.0, double.NegativeInfinity, double.PositiveInfinity }; - yield return new object[] {-0.0, double.PositiveInfinity, double.NegativeInfinity }; - yield return new object[] {-0.0, double.PositiveInfinity, -3.1415926535897932 }; - yield return new object[] {-0.0, double.PositiveInfinity, -0.0 }; - yield return new object[] {-0.0, double.PositiveInfinity, double.NaN }; - yield return new object[] {-0.0, double.PositiveInfinity, 0.0 }; - yield return new object[] {-0.0, double.PositiveInfinity, 3.1415926535897932 }; - yield return new object[] {-0.0, double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] { 0.0, double.NegativeInfinity, double.NegativeInfinity }; - yield return new object[] { 0.0, double.NegativeInfinity, -3.1415926535897932 }; - yield return new object[] { 0.0, double.NegativeInfinity, -0.0 }; - yield return new object[] { 0.0, double.NegativeInfinity, double.NaN }; - yield return new object[] { 0.0, double.NegativeInfinity, 0.0 }; - yield return new object[] { 0.0, double.NegativeInfinity, 3.1415926535897932 }; - yield return new object[] { 0.0, double.NegativeInfinity, double.PositiveInfinity }; - yield return new object[] { 0.0, double.PositiveInfinity, double.NegativeInfinity }; - yield return new object[] { 0.0, double.PositiveInfinity, -3.1415926535897932 }; - yield return new object[] { 0.0, double.PositiveInfinity, -0.0 }; - yield return new object[] { 0.0, double.PositiveInfinity, double.NaN }; - yield return new object[] { 0.0, double.PositiveInfinity, 0.0 }; - yield return new object[] { 0.0, double.PositiveInfinity, 3.1415926535897932 }; - yield return new object[] { 0.0, double.PositiveInfinity, double.PositiveInfinity }; - yield return new object[] { 5, 4, 3 }; - yield return new object[] { 1e308, 2.0, -1e308 }; - yield return new object[] { 1e308, 2.0, double.NegativeInfinity }; - yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity }; - yield return new object[] { double.PositiveInfinity, -0.0, double.NegativeInfinity }; - yield return new object[] { double.PositiveInfinity, -0.0, -3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, -0.0, -0.0 }; - yield return new object[] { double.PositiveInfinity, -0.0, double.NaN }; - yield return new object[] { double.PositiveInfinity, -0.0, 0.0 }; - yield return new object[] { double.PositiveInfinity, -0.0, 3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, -0.0, double.PositiveInfinity }; - yield return new object[] { double.PositiveInfinity, 0.0, double.NegativeInfinity }; - yield return new object[] { double.PositiveInfinity, 0.0, -3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, 0.0, -0.0 }; - yield return new object[] { double.PositiveInfinity, 0.0, double.NaN }; - yield return new object[] { double.PositiveInfinity, 0.0, 0.0 }; - yield return new object[] { double.PositiveInfinity, 0.0, 3.1415926535897932 }; - yield return new object[] { double.PositiveInfinity, 0.0, double.PositiveInfinity }; - yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, double.NegativeInfinity }; + yield return new object[] { double.NegativeInfinity, double.NegativeInfinity, double.NegativeInfinity, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, -3.1415926535897932, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, -0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, double.NaN, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, 0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, 3.1415926535897932, double.NaN }; + yield return new object[] { double.NegativeInfinity, -0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, -3.1415926535897932, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, -0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, double.NaN, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, 0.0, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, 3.1415926535897932, double.NaN }; + yield return new object[] { double.NegativeInfinity, 0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.NegativeInfinity, double.PositiveInfinity, double.PositiveInfinity, double.NaN }; + yield return new object[] { -1e308, 2.0, 1e308, -1e308 }; + yield return new object[] { -1e308, 2.0, double.PositiveInfinity, double.PositiveInfinity }; + yield return new object[] { -5, 4, -3, -23 }; + yield return new object[] { -0.0, double.NegativeInfinity, double.NegativeInfinity, double.NaN }; + yield return new object[] { -0.0, double.NegativeInfinity, -3.1415926535897932, double.NaN }; + yield return new object[] { -0.0, double.NegativeInfinity, -0.0, double.NaN }; + yield return new object[] { -0.0, double.NegativeInfinity, double.NaN, double.NaN }; + yield return new object[] { -0.0, double.NegativeInfinity, 0.0, double.NaN }; + yield return new object[] { -0.0, double.NegativeInfinity, 3.1415926535897932, double.NaN }; + yield return new object[] { -0.0, double.NegativeInfinity, double.PositiveInfinity, double.NaN }; + yield return new object[] { -0.0, double.PositiveInfinity, double.NegativeInfinity, double.NaN }; + yield return new object[] { -0.0, double.PositiveInfinity, -3.1415926535897932, double.NaN }; + yield return new object[] { -0.0, double.PositiveInfinity, -0.0, double.NaN }; + yield return new object[] { -0.0, double.PositiveInfinity, double.NaN, double.NaN }; + yield return new object[] { -0.0, double.PositiveInfinity, 0.0, double.NaN }; + yield return new object[] { -0.0, double.PositiveInfinity, 3.1415926535897932, double.NaN }; + yield return new object[] { -0.0, double.PositiveInfinity, double.PositiveInfinity, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, double.NegativeInfinity, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, -3.1415926535897932, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, -0.0, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, double.NaN, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, 0.0, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, 3.1415926535897932, double.NaN }; + yield return new object[] { 0.0, double.NegativeInfinity, double.PositiveInfinity, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, double.NegativeInfinity, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, -3.1415926535897932, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, -0.0, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, double.NaN, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, 0.0, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, 3.1415926535897932, double.NaN }; + yield return new object[] { 0.0, double.PositiveInfinity, double.PositiveInfinity, double.NaN }; + yield return new object[] { 5, 4, 3, 23 }; + yield return new object[] { 1e308, 2.0, -1e308, 1e308 }; + yield return new object[] { 1e308, 2.0, double.NegativeInfinity, double.NegativeInfinity }; + yield return new object[] { double.PositiveInfinity, double.NegativeInfinity, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, -3.1415926535897932, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, -0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, 0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, 3.1415926535897932, double.NaN }; + yield return new object[] { double.PositiveInfinity, -0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, double.NegativeInfinity, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, -3.1415926535897932, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, -0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, double.NaN, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, 0.0, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, 3.1415926535897932, double.NaN }; + yield return new object[] { double.PositiveInfinity, 0.0, double.PositiveInfinity, double.NaN }; + yield return new object[] { double.PositiveInfinity, double.PositiveInfinity, double.NegativeInfinity, double.NaN }; } } @@ -415,72 +415,72 @@ public static IEnumerable FusedMultiplyAddSingle { get { - yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { float.NegativeInfinity, -0.0f, float.NegativeInfinity }; - yield return new object[] { float.NegativeInfinity, -0.0f, -3.14159265f }; - yield return new object[] { float.NegativeInfinity, -0.0f, -0.0f }; - yield return new object[] { float.NegativeInfinity, -0.0f, float.NaN }; - yield return new object[] { float.NegativeInfinity, -0.0f, 0.0f }; - yield return new object[] { float.NegativeInfinity, -0.0f, 3.14159265f }; - yield return new object[] { float.NegativeInfinity, -0.0f, float.PositiveInfinity }; - yield return new object[] { float.NegativeInfinity, 0.0f, float.NegativeInfinity }; - yield return new object[] { float.NegativeInfinity, 0.0f, -3.14159265f }; - yield return new object[] { float.NegativeInfinity, 0.0f, -0.0f }; - yield return new object[] { float.NegativeInfinity, 0.0f, float.NaN }; - yield return new object[] { float.NegativeInfinity, 0.0f, 0.0f }; - yield return new object[] { float.NegativeInfinity, 0.0f, 3.14159265f }; - yield return new object[] { float.NegativeInfinity, 0.0f, float.PositiveInfinity }; - yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { -1e38f, 2.0f, 1e38f }; - yield return new object[] { -1e38f, 2.0f, float.PositiveInfinity }; - yield return new object[] { -5, 4, -3 }; - yield return new object[] { -0.0f, float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { -0.0f, float.NegativeInfinity, -3.14159265f }; - yield return new object[] { -0.0f, float.NegativeInfinity, -0.0f }; - yield return new object[] { -0.0f, float.NegativeInfinity, float.NaN }; - yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { -0.0f, float.NegativeInfinity, 3.14159265f }; - yield return new object[] { -0.0f, float.NegativeInfinity, float.PositiveInfinity }; - yield return new object[] { -0.0f, float.PositiveInfinity, float.NegativeInfinity }; - yield return new object[] { -0.0f, float.PositiveInfinity, -3.14159265f }; - yield return new object[] { -0.0f, float.PositiveInfinity, -0.0f }; - yield return new object[] { -0.0f, float.PositiveInfinity, float.NaN }; - yield return new object[] { -0.0f, float.PositiveInfinity, 0.0f }; - yield return new object[] { -0.0f, float.PositiveInfinity, 3.14159265f }; - yield return new object[] { -0.0f, float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { 0.0f, float.NegativeInfinity, float.NegativeInfinity }; - yield return new object[] { 0.0f, float.NegativeInfinity, -3.14159265f }; - yield return new object[] { 0.0f, float.NegativeInfinity, -0.0f }; - yield return new object[] { 0.0f, float.NegativeInfinity, float.NaN }; - yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f }; - yield return new object[] { 0.0f, float.NegativeInfinity, 3.14159265f }; - yield return new object[] { 0.0f, float.NegativeInfinity, float.PositiveInfinity }; - yield return new object[] { 0.0f, float.PositiveInfinity, float.NegativeInfinity }; - yield return new object[] { 0.0f, float.PositiveInfinity, -3.14159265f }; - yield return new object[] { 0.0f, float.PositiveInfinity, -0.0f }; - yield return new object[] { 0.0f, float.PositiveInfinity, float.NaN }; - yield return new object[] { 0.0f, float.PositiveInfinity, 0.0f }; - yield return new object[] { 0.0f, float.PositiveInfinity, 3.14159265f }; - yield return new object[] { 0.0f, float.PositiveInfinity, float.PositiveInfinity }; - yield return new object[] { 5, 4, 3 }; - yield return new object[] { 1e38f, 2.0f, -1e38f }; - yield return new object[] { 1e38f, 2.0f, float.NegativeInfinity }; - yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity }; - yield return new object[] { float.PositiveInfinity, -0.0f, float.NegativeInfinity }; - yield return new object[] { float.PositiveInfinity, -0.0f, -3.14159265f }; - yield return new object[] { float.PositiveInfinity, -0.0f, -0.0f }; - yield return new object[] { float.PositiveInfinity, -0.0f, float.NaN }; - yield return new object[] { float.PositiveInfinity, -0.0f, 0.0f }; - yield return new object[] { float.PositiveInfinity, -0.0f, 3.14159265f }; - yield return new object[] { float.PositiveInfinity, -0.0f, float.PositiveInfinity }; - yield return new object[] { float.PositiveInfinity, 0.0f, float.NegativeInfinity }; - yield return new object[] { float.PositiveInfinity, 0.0f, -3.14159265f }; - yield return new object[] { float.PositiveInfinity, 0.0f, -0.0f }; - yield return new object[] { float.PositiveInfinity, 0.0f, float.NaN }; - yield return new object[] { float.PositiveInfinity, 0.0f, 0.0f }; - yield return new object[] { float.PositiveInfinity, 0.0f, 3.14159265f }; - yield return new object[] { float.PositiveInfinity, 0.0f, float.PositiveInfinity }; - yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity }; + yield return new object[] { float.NegativeInfinity, float.NegativeInfinity, float.NegativeInfinity, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, -3.14159265f, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, -0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.NaN, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, 0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, 3.14159265f, float.NaN }; + yield return new object[] { float.NegativeInfinity, -0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, -3.14159265f, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, -0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.NaN, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, 0.0f, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, 3.14159265f, float.NaN }; + yield return new object[] { float.NegativeInfinity, 0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.NegativeInfinity, float.PositiveInfinity, float.PositiveInfinity, float.NaN }; + yield return new object[] { -1e38f, 2.0f, 1e38f, -1e38f }; + yield return new object[] { -1e38f, 2.0f, float.PositiveInfinity, float.PositiveInfinity }; + yield return new object[] { -5, 4, -3, -23 }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, -3.14159265f, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, -0.0f, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.NaN, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, 0.0f, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, 3.14159265f, float.NaN }; + yield return new object[] { -0.0f, float.NegativeInfinity, float.PositiveInfinity, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.NegativeInfinity, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, -3.14159265f, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, -0.0f, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.NaN, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, 0.0f, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, 3.14159265f, float.NaN }; + yield return new object[] { -0.0f, float.PositiveInfinity, float.PositiveInfinity, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.NegativeInfinity, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, -3.14159265f, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, -0.0f, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.NaN, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, 0.0f, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, 3.14159265f, float.NaN }; + yield return new object[] { 0.0f, float.NegativeInfinity, float.PositiveInfinity, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.NegativeInfinity, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, -3.14159265f, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, -0.0f, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.NaN, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, 0.0f, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, 3.14159265f, float.NaN }; + yield return new object[] { 0.0f, float.PositiveInfinity, float.PositiveInfinity, float.NaN }; + yield return new object[] { 5, 4, 3, 23 }; + yield return new object[] { 1e38f, 2.0f, -1e38f, 1e38f }; + yield return new object[] { 1e38f, 2.0f, float.NegativeInfinity, float.NegativeInfinity }; + yield return new object[] { float.PositiveInfinity, float.NegativeInfinity, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, -3.14159265f, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, -0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, 0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, 3.14159265f, float.NaN }; + yield return new object[] { float.PositiveInfinity, -0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.NegativeInfinity, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, -3.14159265f, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, -0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.NaN, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, 0.0f, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, 3.14159265f, float.NaN }; + yield return new object[] { float.PositiveInfinity, 0.0f, float.PositiveInfinity, float.NaN }; + yield return new object[] { float.PositiveInfinity, float.PositiveInfinity, float.NegativeInfinity, float.NaN }; } } diff --git a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs index eb99ed2b90122e..8caf901a258bef 100644 --- a/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/GenericVectorTests.cs @@ -4586,34 +4586,18 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + public void FusedMultiplyAddDoubleTest(double left, double right, double addend, double expectedResult) { - Vector actualResult = Vector.FusedMultiplyAdd(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(Vector.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); + AssertEqual(Vector.Create(expectedResult), Vector.FusedMultiplyAdd(Vector.Create(left), Vector.Create(right), Vector.Create(addend)), Vector.Zero); + AssertEqual(Vector.Create(double.MultiplyAddEstimate(left, right, addend)), Vector.MultiplyAddEstimate(Vector.Create(left), Vector.Create(right), Vector.Create(addend)), Vector.Zero); } [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector actualResult = Vector.FusedMultiplyAdd(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(Vector.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) - { - Vector actualResult = Vector.MultiplyAddEstimate(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(Vector.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector actualResult = Vector.MultiplyAddEstimate(new Vector(left), new Vector(right), new Vector(addend)); - AssertEqual(Vector.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector.Zero); + AssertEqual(Vector.Create(expectedResult), Vector.FusedMultiplyAdd(Vector.Create(left), Vector.Create(right), Vector.Create(addend)), Vector.Zero); + AssertEqual(Vector.Create(float.MultiplyAddEstimate(left, right, addend)), Vector.MultiplyAddEstimate(Vector.Create(left), Vector.Create(right), Vector.Create(addend)), Vector.Zero); } [Theory] diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs index 65ab6ab4f0cf4a..3d130d26556092 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector2Tests.cs @@ -1325,18 +1325,10 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector2 actualResult = Vector2.FusedMultiplyAdd(Vector2.Create(left), Vector2.Create(right), Vector2.Create(addend)); - AssertEqual(Vector2.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector2.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector2 actualResult = Vector2.MultiplyAddEstimate(Vector2.Create(left), Vector2.Create(right), Vector2.Create(addend)); - AssertEqual(Vector2.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector2.Zero); + AssertEqual(Vector2.Create(expectedResult), Vector2.FusedMultiplyAdd(Vector2.Create(left), Vector2.Create(right), Vector2.Create(addend)), Vector2.Zero); + AssertEqual(Vector2.Create(float.MultiplyAddEstimate(left, right, addend)), Vector2.MultiplyAddEstimate(Vector2.Create(left), Vector2.Create(right), Vector2.Create(addend)), Vector2.Zero); } [Theory] diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs index a5d0195d83c0c0..9ec5e504239387 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector3Tests.cs @@ -1375,18 +1375,10 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector3 actualResult = Vector3.FusedMultiplyAdd(Vector3.Create(left), Vector3.Create(right), Vector3.Create(addend)); - AssertEqual(Vector3.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector3.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector3 actualResult = Vector3.MultiplyAddEstimate(Vector3.Create(left), Vector3.Create(right), Vector3.Create(addend)); - AssertEqual(Vector3.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector3.Zero); + AssertEqual(Vector3.Create(expectedResult), Vector3.FusedMultiplyAdd(Vector3.Create(left), Vector3.Create(right), Vector3.Create(addend)), Vector3.Zero); + AssertEqual(Vector3.Create(float.MultiplyAddEstimate(left, right, addend)), Vector3.MultiplyAddEstimate(Vector3.Create(left), Vector3.Create(right), Vector3.Create(addend)), Vector3.Zero); } [Theory] diff --git a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs index cdfa700126e463..d1144cdf3e5cd2 100644 --- a/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs +++ b/src/libraries/System.Numerics.Vectors/tests/Vector4Tests.cs @@ -1750,18 +1750,10 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector4 actualResult = Vector4.FusedMultiplyAdd(Vector4.Create(left), Vector4.Create(right), Vector4.Create(addend)); - AssertEqual(Vector4.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector4.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector4 actualResult = Vector4.MultiplyAddEstimate(Vector4.Create(left), Vector4.Create(right), Vector4.Create(addend)); - AssertEqual(Vector4.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector4.Zero); + AssertEqual(Vector4.Create(expectedResult), Vector4.FusedMultiplyAdd(Vector4.Create(left), Vector4.Create(right), Vector4.Create(addend)), Vector4.Zero); + AssertEqual(Vector4.Create(float.MultiplyAddEstimate(left, right, addend)), Vector4.MultiplyAddEstimate(Vector4.Create(left), Vector4.Create(right), Vector4.Create(addend)), Vector4.Zero); } [Theory] diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs index 27d63954ebcdd0..afa6e6aa99c4ae 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector128Tests.cs @@ -4876,34 +4876,18 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + public void FusedMultiplyAddDoubleTest(double left, double right, double addend, double expectedResult) { - Vector128 actualResult = Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); - AssertEqual(Vector128.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector128.Zero); + AssertEqual(Vector128.Create(expectedResult), Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)), Vector128.Zero); + AssertEqual(Vector128.Create(double.MultiplyAddEstimate(left, right, addend)), Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)), Vector128.Zero); } [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector128 actualResult = Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); - AssertEqual(Vector128.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector128.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) - { - Vector128 actualResult = Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); - AssertEqual(Vector128.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector128.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector128 actualResult = Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)); - AssertEqual(Vector128.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector128.Zero); + AssertEqual(Vector128.Create(expectedResult), Vector128.FusedMultiplyAdd(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)), Vector128.Zero); + AssertEqual(Vector128.Create(float.MultiplyAddEstimate(left, right, addend)), Vector128.MultiplyAddEstimate(Vector128.Create(left), Vector128.Create(right), Vector128.Create(addend)), Vector128.Zero); } [Fact] diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs index cdc0ff2740d3c0..46c2e190217dd2 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector256Tests.cs @@ -5892,34 +5892,18 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + public void FusedMultiplyAddDoubleTest(double left, double right, double addend, double expectedResult) { - Vector256 actualResult = Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); - AssertEqual(Vector256.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector256.Zero); + AssertEqual(Vector256.Create(expectedResult), Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)), Vector256.Zero); + AssertEqual(Vector256.Create(double.MultiplyAddEstimate(left, right, addend)), Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)), Vector256.Zero); } [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector256 actualResult = Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); - AssertEqual(Vector256.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector256.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) - { - Vector256 actualResult = Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); - AssertEqual(Vector256.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector256.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector256 actualResult = Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)); - AssertEqual(Vector256.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector256.Zero); + AssertEqual(Vector256.Create(expectedResult), Vector256.FusedMultiplyAdd(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)), Vector256.Zero); + AssertEqual(Vector256.Create(float.MultiplyAddEstimate(left, right, addend)), Vector256.MultiplyAddEstimate(Vector256.Create(left), Vector256.Create(right), Vector256.Create(addend)), Vector256.Zero); } [Fact] diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs index b88bb78ec93c4b..c7a700852095d3 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector512Tests.cs @@ -5325,34 +5325,18 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + public void FusedMultiplyAddDoubleTest(double left, double right, double addend, double expectedResult) { - Vector512 actualResult = Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); - AssertEqual(Vector512.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector512.Zero); + AssertEqual(Vector512.Create(expectedResult), Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)), Vector512.Zero); + AssertEqual(Vector512.Create(double.MultiplyAddEstimate(left, right, addend)), Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)), Vector512.Zero); } [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector512 actualResult = Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); - AssertEqual(Vector512.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector512.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) - { - Vector512 actualResult = Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); - AssertEqual(Vector512.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector512.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector512 actualResult = Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)); - AssertEqual(Vector512.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector512.Zero); + AssertEqual(Vector512.Create(expectedResult), Vector512.FusedMultiplyAdd(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)), Vector512.Zero); + AssertEqual(Vector512.Create(float.MultiplyAddEstimate(left, right, addend)), Vector512.MultiplyAddEstimate(Vector512.Create(left), Vector512.Create(right), Vector512.Create(addend)), Vector512.Zero); } [Fact] diff --git a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs index ddedcfc02d3a7d..ba7ee7c8917874 100644 --- a/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs +++ b/src/libraries/System.Runtime.Intrinsics/tests/Vectors/Vector64Tests.cs @@ -4291,34 +4291,18 @@ public void Log2SingleTest(float value, float expectedResult, float variance) [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddDoubleTest(double left, double right, double addend) + public void FusedMultiplyAddDoubleTest(double left, double right, double addend, double expectedResult) { - Vector64 actualResult = Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); - AssertEqual(Vector64.Create(double.FusedMultiplyAdd(left, right, addend)), actualResult, Vector64.Zero); + AssertEqual(Vector64.Create(expectedResult), Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)), Vector64.Zero); + AssertEqual(Vector64.Create(double.MultiplyAddEstimate(left, right, addend)), Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)), Vector64.Zero); } [Theory] [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void FusedMultiplyAddSingleTest(float left, float right, float addend) + public void FusedMultiplyAddSingleTest(float left, float right, float addend, float expectedResult) { - Vector64 actualResult = Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); - AssertEqual(Vector64.Create(float.FusedMultiplyAdd(left, right, addend)), actualResult, Vector64.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddDouble), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateDoubleTest(double left, double right, double addend) - { - Vector64 actualResult = Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); - AssertEqual(Vector64.Create(double.MultiplyAddEstimate(left, right, addend)), actualResult, Vector64.Zero); - } - - [Theory] - [MemberData(nameof(GenericMathTestMemberData.FusedMultiplyAddSingle), MemberType = typeof(GenericMathTestMemberData))] - public void MultiplyAddEstimateSingleTest(float left, float right, float addend) - { - Vector64 actualResult = Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)); - AssertEqual(Vector64.Create(float.MultiplyAddEstimate(left, right, addend)), actualResult, Vector64.Zero); + AssertEqual(Vector64.Create(expectedResult), Vector64.FusedMultiplyAdd(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)), Vector64.Zero); + AssertEqual(Vector64.Create(float.MultiplyAddEstimate(left, right, addend)), Vector64.MultiplyAddEstimate(Vector64.Create(left), Vector64.Create(right), Vector64.Create(addend)), Vector64.Zero); } [Fact] diff --git a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs index a565d4b0c96e7c..3402e419b36178 100644 --- a/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs +++ b/src/libraries/System.Runtime/tests/System.Runtime.Tests/System/DoubleTests.GenericMath.cs @@ -119,9 +119,9 @@ public static void IsPow2Test() [Theory] [MemberData(nameof(GenericMathTestMemberData.Log2Double), MemberType = typeof(GenericMathTestMemberData))] - public static void Log2Test(double value, double expectedResult) + public static void Log2Test(double value, double expectedResult, double allowedVariance) { - AssertExtensions.Equal(expectedResult, BinaryNumberHelper.Log2(value)); + AssertExtensions.Equal(expectedResult, BinaryNumberHelper.Log2(value), allowedVariance); } // From 304324dcb7c0fe5ae45a0ecf8f23d88071077c17 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 21:58:35 -0700 Subject: [PATCH 25/39] Ensure APIs are correctly handled for Vector --- src/coreclr/jit/simdashwintrinsic.cpp | 25 ++++++++++++++++++++ src/coreclr/jit/simdashwintrinsiclistarm64.h | 5 ++++ src/coreclr/jit/simdashwintrinsiclistxarch.h | 7 +++++- 3 files changed, 36 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/simdashwintrinsic.cpp b/src/coreclr/jit/simdashwintrinsic.cpp index d11bdb3f78c8a1..7c36076fa90c84 100644 --- a/src/coreclr/jit/simdashwintrinsic.cpp +++ b/src/coreclr/jit/simdashwintrinsic.cpp @@ -910,6 +910,31 @@ GenTree* Compiler::impSimdAsHWIntrinsicSpecial(NamedIntrinsic intrinsic, return gtNewSimdFloorNode(retType, op1, simdBaseJitType, simdSize); } + case NI_VectorT_IsNaN: + { + return gtNewSimdIsNaNNode(retType, op1, simdBaseJitType, simdSize); + } + + case NI_VectorT_IsNegative: + { + return gtNewSimdIsNegativeNode(retType, op1, simdBaseJitType, simdSize); + } + + case NI_VectorT_IsPositive: + { + return gtNewSimdIsPositiveNode(retType, op1, simdBaseJitType, simdSize); + } + + case NI_VectorT_IsPositiveInfinity: + { + return gtNewSimdIsPositiveInfinityNode(retType, op1, simdBaseJitType, simdSize); + } + + case NI_VectorT_IsZero: + { + return gtNewSimdIsZeroNode(retType, op1, simdBaseJitType, simdSize); + } + case NI_VectorT_LoadUnsafe: { if (op1->OperIs(GT_CAST) && op1->gtGetOp1()->TypeIs(TYP_BYREF)) diff --git a/src/coreclr/jit/simdashwintrinsiclistarm64.h b/src/coreclr/jit/simdashwintrinsiclistarm64.h index 14cb7f68f957c7..6bbea32494f315 100644 --- a/src/coreclr/jit/simdashwintrinsiclistarm64.h +++ b/src/coreclr/jit/simdashwintrinsiclistarm64.h @@ -82,6 +82,11 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanAny, SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanOrEqual, 2, {NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanOrEqualAll, 2, {NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanOrEqualAny, 2, {NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsNaN, 1, {NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsNegative, 1, {NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsPositive, 1, {NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsPositiveInfinity, 1, {NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsZero, 1, {NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, LessThan, 2, {NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, LessThanAll, 2, {NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, LessThanAny, 2, {NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny}, SimdAsHWIntrinsicFlag::None) diff --git a/src/coreclr/jit/simdashwintrinsiclistxarch.h b/src/coreclr/jit/simdashwintrinsiclistxarch.h index a5689429e240a6..1d769f27e4f97d 100644 --- a/src/coreclr/jit/simdashwintrinsiclistxarch.h +++ b/src/coreclr/jit/simdashwintrinsiclistxarch.h @@ -82,6 +82,11 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanAny, SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanOrEqual, 2, {NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual, NI_VectorT_GreaterThanOrEqual}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanOrEqualAll, 2, {NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll, NI_VectorT_GreaterThanOrEqualAll}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, GreaterThanOrEqualAny, 2, {NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny, NI_VectorT_GreaterThanOrEqualAny}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsNaN, 1, {NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN, NI_VectorT_IsNaN}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsNegative, 1, {NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative, NI_VectorT_IsNegative}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsPositive, 1, {NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive, NI_VectorT_IsPositive}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsPositiveInfinity, 1, {NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity, NI_VectorT_IsPositiveInfinity}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, IsZero, 1, {NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero, NI_VectorT_IsZero}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, LessThan, 2, {NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan, NI_VectorT_LessThan}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, LessThanAll, 2, {NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll, NI_VectorT_LessThanAll}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, LessThanAny, 2, {NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny, NI_VectorT_LessThanAny}, SimdAsHWIntrinsicFlag::None) @@ -108,7 +113,7 @@ SIMD_AS_HWINTRINSIC_ID(VectorT, op_Explicit, SIMD_AS_HWINTRINSIC_ID(VectorT, op_Inequality, 2, {NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality, NI_VectorT_op_Inequality}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, op_LeftShift, 2, {NI_Illegal, NI_Illegal, NI_VectorT_op_LeftShift, NI_VectorT_op_LeftShift, NI_VectorT_op_LeftShift, NI_VectorT_op_LeftShift, NI_VectorT_op_LeftShift, NI_VectorT_op_LeftShift, NI_VectorT_op_LeftShift, NI_VectorT_op_LeftShift}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, op_Multiply, 2, {NI_Illegal, NI_Illegal, NI_VectorT_op_Multiply, NI_VectorT_op_Multiply, NI_VectorT_op_Multiply, NI_VectorT_op_Multiply, NI_Illegal, NI_Illegal, NI_VectorT_op_Multiply, NI_VectorT_op_Multiply}, SimdAsHWIntrinsicFlag::None) -SIMD_AS_HWINTRINSIC_ID(VectorT, op_OnesComplement, 2, {NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement}, SimdAsHWIntrinsicFlag::None) +SIMD_AS_HWINTRINSIC_ID(VectorT, op_OnesComplement, 1, {NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement, NI_VectorT_op_OnesComplement}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, op_RightShift, 2, {NI_Illegal, NI_Illegal, NI_VectorT_op_RightShift, NI_VectorT_op_RightShift, NI_VectorT_op_RightShift, NI_VectorT_op_RightShift, NI_VectorT_op_RightShift, NI_VectorT_op_RightShift, NI_VectorT_op_RightShift, NI_VectorT_op_RightShift}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, op_Subtraction, 2, {NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction, NI_VectorT_op_Subtraction}, SimdAsHWIntrinsicFlag::None) SIMD_AS_HWINTRINSIC_ID(VectorT, op_UnaryNegation, 1, {NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation, NI_VectorT_op_UnaryNegation}, SimdAsHWIntrinsicFlag::None) From c722402bd3e0f63b50f4f2ba9021e1318b1d99f2 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 22:11:46 -0700 Subject: [PATCH 26/39] Fix the mono handling for OP_XCOMPARE_FP --- src/mono/mono/mini/mini-amd64.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/mini-amd64.c b/src/mono/mono/mini/mini-amd64.c index 76b42da79296fe..29cdaab1c9a97e 100644 --- a/src/mono/mono/mini/mini-amd64.c +++ b/src/mono/mono/mini/mini-amd64.c @@ -4072,8 +4072,26 @@ mono_arch_lowering_pass (MonoCompile *cfg, MonoBasicBlock *bb) case CMP_NE: ins->inst_c0 = 4; break; case CMP_LT: ins->inst_c0 = 1; break; case CMP_LE: ins->inst_c0 = 2; break; - case CMP_GT: ins->inst_c0 = 6; break; - case CMP_GE: ins->inst_c0 = 5; break; + case CMP_GT: { + // CMPNLT (5) is not the same as CMPGT due to NaN + // as such, we want to emit CMPLT (1) with swapped + // operands instead, ensuring we get correct handling + int tmp = ins->sreg1; + ins->sreg1 = ins->sreg2; + ins->sreg2 = tmp; + ins->inst_c0 = 1; + break; + } + case CMP_GE: { + // CMPNLE (6) is not the same as CMPGE due to NaN + // as such, we want to emit CMPLE (2) with swapped + // operands instead, ensuring we get correct handling + int tmp = ins->sreg1; + ins->sreg1 = ins->sreg2; + ins->sreg2 = tmp; + ins->inst_c0 = 2; + break; + } default: g_assert_not_reached(); break; From f5f7a317497c87d2c1d562f4759572b06e7d350b Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 29 Jun 2024 23:10:26 -0700 Subject: [PATCH 27/39] Have Mono use the proper klass for IsPositive/IsNegative since we're reinterpreting --- src/mono/mono/mini/simd-intrinsics.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 1303797186ffc6..71b5802cae3c50 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2163,10 +2163,16 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; if (type_enum_is_unsigned(arg0_type)) { return emit_xzero (cfg, klass); - } else if (arg0_type == MONO_TYPE_R4) { - arg0_type = MONO_TYPE_I4; - } else if (arg0_type == MONO_TYPE_R8) { - arg0_type = MONO_TYPE_I8; + } else if (type_enum_is_float (arg0_type)) { + MonoClass* cast_klass; + if (arg0_type == MONO_TYPE_R4) { + arg0_type = MONO_TYPE_I4; + cast_klass = mono_defaults.int32_class; + } else { + arg0_type = MONO_TYPE_I8; + cast_klass = mono_defaults.int64_class; + } + klass = create_class_instance ("System.Runtime.Intrinsics", m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); } return emit_xcompare_for_intrinsic (cfg, klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, klass)); } @@ -2175,10 +2181,16 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; if (type_enum_is_unsigned(arg0_type)) { return emit_xones (cfg, klass); - } else if (arg0_type == MONO_TYPE_R4) { - arg0_type = MONO_TYPE_I4; - } else if (arg0_type == MONO_TYPE_R8) { - arg0_type = MONO_TYPE_I8; + } else if (type_enum_is_float (arg0_type)) { + MonoClass* cast_klass; + if (arg0_type == MONO_TYPE_R4) { + arg0_type = MONO_TYPE_I4; + cast_klass = mono_defaults.int32_class; + } else { + arg0_type = MONO_TYPE_I8; + cast_klass = mono_defaults.int64_class; + } + klass = create_class_instance ("System.Runtime.Intrinsics", m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); } return emit_xcompare_for_intrinsic (cfg, klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, klass)); } From b34be17d7c12e7bb2b1de4cb90ab361c4469a3de Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sun, 30 Jun 2024 10:27:32 -0700 Subject: [PATCH 28/39] Ensure Mono looks up the class namespace --- src/mono/mono/mini/simd-intrinsics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 71b5802cae3c50..884859a6e3b3bc 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2172,7 +2172,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi arg0_type = MONO_TYPE_I8; cast_klass = mono_defaults.int64_class; } - klass = create_class_instance ("System.Runtime.Intrinsics", m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); + klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); } return emit_xcompare_for_intrinsic (cfg, klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, klass)); } @@ -2190,7 +2190,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi arg0_type = MONO_TYPE_I8; cast_klass = mono_defaults.int64_class; } - klass = create_class_instance ("System.Runtime.Intrinsics", m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); + klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); } return emit_xcompare_for_intrinsic (cfg, klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, klass)); } From 10b1513219f9b8e3b5499f231e273b64f0b3bbbe Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 1 Jul 2024 08:28:39 -0700 Subject: [PATCH 29/39] Ensure mono inserts xcast where required and handles MultiplyAddEstimate --- src/mono/mono/mini/simd-intrinsics.c | 72 ++++++++++++++++++++++++---- src/mono/mono/mini/simd-methods.h | 1 + 2 files changed, 65 insertions(+), 8 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 884859a6e3b3bc..1a65054ffea640 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1243,6 +1243,7 @@ static guint16 sri_vector_methods [] = { SN_Min, SN_MinNative, SN_Multiply, + SN_MultiplyAddEstimate, SN_Narrow, SN_Negate, SN_OnesComplement, @@ -1633,6 +1634,39 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; #endif } + case SN_MultiplyAddEstimate: { + + int mul_op; + int add_op; + + if (type_enum_is_float (arg0_type)) + { + mul_op = OP_FMUL; + add_op = OP_FADD; + } else { + mul_op = OP_IMUL; + add_op = OP_IADD; + +#ifdef TARGET_ARM64 + if (!COMPILE_LLVM (cfg) && (arg0_type == MONO_TYPE_I8 || arg0_type == MONO_TYPE_U8 || arg0_type == MONO_TYPE_I || arg0_type == MONO_TYPE_U)) + return NULL; +#endif +#ifdef TARGET_AMD64 + if (!COMPILE_LLVM (cfg)) + return NULL; +#endif + } + + MonoInst *mul_ins = emit_simd_ins (cfg, klass, OP_XBINOP, args [0]->dreg, args [1]->dreg); + mul_ins->instc0 = mul_op; + mul_ins->instc1 = arg0_type; + + MonoInst *add_ins = emit_simd_ins (cfg, klass, OP_XBINOP, mul_ins->dreg, args [2]->dreg); + mul_ins->instc0 = add_op; + mul_ins->instc1 = arg0_type; + + return add_ins; + } case SN_As: case SN_AsByte: case SN_AsDouble: @@ -2163,8 +2197,12 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi return NULL; if (type_enum_is_unsigned(arg0_type)) { return emit_xzero (cfg, klass); - } else if (type_enum_is_float (arg0_type)) { - MonoClass* cast_klass; + } + + MonoInst *arg0 = args [0]; + MonoClass *cast_klass = NULL; + + if (type_enum_is_float (arg0_type)) { if (arg0_type == MONO_TYPE_R4) { arg0_type = MONO_TYPE_I4; cast_klass = mono_defaults.int32_class; @@ -2172,17 +2210,28 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi arg0_type = MONO_TYPE_I8; cast_klass = mono_defaults.int64_class; } - klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); + cast_klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); + arg0 = emit_simd_ins (cfg, cast_klass, OP_XCAST, arg0->dreg, -1); } - return emit_xcompare_for_intrinsic (cfg, klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, klass)); + + MonoInst *ins = emit_xcompare_for_intrinsic (cfg, klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, klass)); + + if (cast_klass != NULL) { + ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); + } + return ins; } case SN_IsPositive: { if (!is_element_type_primitive (fsig->params [0])) return NULL; if (type_enum_is_unsigned(arg0_type)) { return emit_xones (cfg, klass); - } else if (type_enum_is_float (arg0_type)) { - MonoClass* cast_klass; + } + + MonoInst *arg0 = args [0]; + MonoClass *cast_klass = NULL; + + if (type_enum_is_float (arg0_type)) { if (arg0_type == MONO_TYPE_R4) { arg0_type = MONO_TYPE_I4; cast_klass = mono_defaults.int32_class; @@ -2190,9 +2239,16 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi arg0_type = MONO_TYPE_I8; cast_klass = mono_defaults.int64_class; } - klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); + cast_klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); + arg0 = emit_simd_ins (cfg, cast_klass, OP_XCAST, arg0->dreg, -1); } - return emit_xcompare_for_intrinsic (cfg, klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, klass)); + + MonoInst *ins = emit_xcompare_for_intrinsic (cfg, klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, klass)); + + if (cast_klass != NULL) { + ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); + } + return ins; } case SN_IsPositiveInfinity: { if (!is_element_type_primitive (fsig->params [0])) diff --git a/src/mono/mono/mini/simd-methods.h b/src/mono/mono/mini/simd-methods.h index c137ddd441a1c6..933385e45d0857 100644 --- a/src/mono/mono/mini/simd-methods.h +++ b/src/mono/mono/mini/simd-methods.h @@ -32,6 +32,7 @@ METHOD(MaxScalar) METHOD(Min) METHOD(MinNative) METHOD(MinScalar) +METHOD(MultiplyAddEstimate) METHOD(Normalize) METHOD(PopCount) METHOD(LeadingZeroCount) From bf3bc42d0de7d264c9a7c9da0fa3f4c4602b0d67 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 1 Jul 2024 10:26:45 -0700 Subject: [PATCH 30/39] Add missing underscores to fix the mono build --- src/mono/mono/mini/simd-intrinsics.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 1a65054ffea640..10498f685813bd 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1658,12 +1658,12 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi } MonoInst *mul_ins = emit_simd_ins (cfg, klass, OP_XBINOP, args [0]->dreg, args [1]->dreg); - mul_ins->instc0 = mul_op; - mul_ins->instc1 = arg0_type; + mul_ins->inst_c0 = mul_op; + mul_ins->inst_c1 = arg0_type; MonoInst *add_ins = emit_simd_ins (cfg, klass, OP_XBINOP, mul_ins->dreg, args [2]->dreg); - mul_ins->instc0 = add_op; - mul_ins->instc1 = arg0_type; + mul_ins->inst_c0 = add_op; + mul_ins->inst_c1 = arg0_type; return add_ins; } From f114721b43e1baff18628bdf1c52801d5c319ffb Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 1 Jul 2024 11:29:59 -0700 Subject: [PATCH 31/39] Add the if is_element_type_primitive check to MultiplyAddEstimate for mono --- src/mono/mono/mini/simd-intrinsics.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 10498f685813bd..9c5af94f17222f 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1635,7 +1635,9 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi #endif } case SN_MultiplyAddEstimate: { - + if (!is_element_type_primitive (fsig->params [0])) + return NULL; + int mul_op; int add_op; From cbafcb50ff965d7dde1e6fe475d4b4d33f0390fb Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 1 Jul 2024 12:30:30 -0700 Subject: [PATCH 32/39] Pass the right klass on Mono --- src/mono/mono/mini/simd-intrinsics.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 9c5af94f17222f..bc31db1fbe4c5f 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2202,23 +2202,23 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi } MonoInst *arg0 = args [0]; - MonoClass *cast_klass = NULL; + MonoClass *op_klass = klass; if (type_enum_is_float (arg0_type)) { if (arg0_type == MONO_TYPE_R4) { arg0_type = MONO_TYPE_I4; - cast_klass = mono_defaults.int32_class; + op_klass = mono_defaults.int32_class; } else { arg0_type = MONO_TYPE_I8; - cast_klass = mono_defaults.int64_class; + op_klass = mono_defaults.int64_class; } - cast_klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); - arg0 = emit_simd_ins (cfg, cast_klass, OP_XCAST, arg0->dreg, -1); + op_klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (op_klass)); + arg0 = emit_simd_ins (cfg, op_klass, OP_XCAST, arg0->dreg, -1); } - MonoInst *ins = emit_xcompare_for_intrinsic (cfg, klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, klass)); + MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, op_klass)); - if (cast_klass != NULL) { + if (op_klass != NULL) { ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); } return ins; @@ -2231,23 +2231,23 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi } MonoInst *arg0 = args [0]; - MonoClass *cast_klass = NULL; + MonoClass *op_klass = klass; if (type_enum_is_float (arg0_type)) { if (arg0_type == MONO_TYPE_R4) { arg0_type = MONO_TYPE_I4; - cast_klass = mono_defaults.int32_class; + op_klass = mono_defaults.int32_class; } else { arg0_type = MONO_TYPE_I8; - cast_klass = mono_defaults.int64_class; + op_klass = mono_defaults.int64_class; } - cast_klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (cast_klass)); - arg0 = emit_simd_ins (cfg, cast_klass, OP_XCAST, arg0->dreg, -1); + op_klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (op_klass)); + arg0 = emit_simd_ins (cfg, op_klass, OP_XCAST, arg0->dreg, -1); } - MonoInst *ins = emit_xcompare_for_intrinsic (cfg, klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, klass)); + MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, op_klass)); - if (cast_klass != NULL) { + if (op_klass != NULL) { ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); } return ins; From 6ea941c3bc4a8c1baa2b4d35110d2bbcdbafce15 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 1 Jul 2024 13:29:59 -0700 Subject: [PATCH 33/39] Ensure mono sets the metadata for add_ins --- src/mono/mono/mini/simd-intrinsics.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index bc31db1fbe4c5f..172a97a7a8c5b9 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -1641,8 +1641,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi int mul_op; int add_op; - if (type_enum_is_float (arg0_type)) - { + if (type_enum_is_float (arg0_type)) { mul_op = OP_FMUL; add_op = OP_FADD; } else { @@ -1664,8 +1663,8 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi mul_ins->inst_c1 = arg0_type; MonoInst *add_ins = emit_simd_ins (cfg, klass, OP_XBINOP, mul_ins->dreg, args [2]->dreg); - mul_ins->inst_c0 = add_op; - mul_ins->inst_c1 = arg0_type; + add_ins->inst_c0 = add_op; + add_ins->inst_c1 = arg0_type; return add_ins; } From 5728b80f7a73868270349493ce1d0868843a4d52 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 1 Jul 2024 14:07:29 -0700 Subject: [PATCH 34/39] Ensure mono passes down the cast arg0 --- src/mono/mono/mini/simd-intrinsics.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 172a97a7a8c5b9..e5c835d6d2110c 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2215,7 +2215,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi arg0 = emit_simd_ins (cfg, op_klass, OP_XCAST, arg0->dreg, -1); } - MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_LessThan, arg0_type, args [0], emit_xzero (cfg, op_klass)); + MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_LessThan, arg0_type, arg0, emit_xzero (cfg, op_klass)); if (op_klass != NULL) { ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); @@ -2244,7 +2244,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi arg0 = emit_simd_ins (cfg, op_klass, OP_XCAST, arg0->dreg, -1); } - MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_GreaterThanOrEqual, arg0_type, args [0], emit_xzero (cfg, op_klass)); + MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_GreaterThanOrEqual, arg0_type, arg0, emit_xzero (cfg, op_klass)); if (op_klass != NULL) { ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); From a47ea2aab4754c8332dac7c7c5e83d84481cb9d1 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 1 Jul 2024 19:25:15 -0700 Subject: [PATCH 35/39] Fix the lerp for Mono to match the managed impl --- src/mono/mono/mini/simd-intrinsics.c | 48 ++++++++++++++++++---------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index e5c835d6d2110c..58aae36124d661 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -3080,10 +3080,8 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f float value[4]; value [0] = 1.0f; value [1] = 1.0f; - value [2] = 1.0f; - value [3] = 1.0f; - if (len == 3) - value [3] = 0.0f; + value [2] = (len > 2) ? 1.0f : 0.0f; + value [3] = (len > 3) ? 1.0f : 0.0f; return emit_xconst_v128 (cfg, klass, (guint8*)value); } case SN_set_Item: { @@ -3299,26 +3297,44 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f #endif } case SN_Lerp: { -#if defined (TARGET_ARM64) - MonoInst* v1 = args [1]; if (!strcmp ("Quaternion", m_class_get_name (klass))) return NULL; - - MonoInst *diffs = emit_simd_ins (cfg, klass, OP_XBINOP, v1->dreg, args [0]->dreg); - diffs->inst_c0 = OP_FSUB; - diffs->inst_c1 = MONO_TYPE_R4; + float value[4]; + value [0] = 1.0f; + value [1] = 1.0f; + value [2] = (len > 2) ? 1.0f : 0.0f; + value [3] = (len > 3) ? 1.0f : 0.0f; + MonoInst *ins_one = emit_xconst_v128 (cfg, klass, (guint8*)value); + + MonoInst *ins_amount = args [2]; - MonoInst *scaled_diffs = handle_mul_div_by_scalar (cfg, klass, MONO_TYPE_R4, args [2]->dreg, diffs->dreg, OP_FMUL); - - MonoInst *result = emit_simd_ins (cfg, klass, OP_XBINOP, args [0]->dreg, scaled_diffs->dreg); + if (!type_is_simd_vector (fsig->params [2])) { + ins_amount = emit_simd_ins (cfg, klass, type_to_expand_op (etype->type), ins_amount->dreg, -1); + ins_amount->inst_c1 = MONO_TYPE_R4; + } + + // diff = 1.0 - amount + MonoInst *ins_diff = emit_simd_ins (cfg, klass, OP_XBINOP, ins_one->dreg, ins_amount->dreg); + ins_diff->inst_c0 = OP_FSUB; + ins_diff->inst_c1 = MONO_TYPE_R4; + + // prodx = x * diff + MonoInst *ins_prodx = emit_simd_ins (cfg, klass, OP_XBINOP, args [0]->dreg, ins_diff->dreg); + ins_prodx->inst_c0 = OP_FMUL; + ins_prodx->inst_c1 = MONO_TYPE_R4; + + // prody = y * amount + MonoInst *ins_prody = emit_simd_ins (cfg, klass, OP_XBINOP, args [1]->dreg, ins_diff->dreg); + ins_prody->inst_c0 = OP_FMUL; + ins_prody->inst_c1 = MONO_TYPE_R4; + + // result = prodx + prody + MonoInst *result = emit_simd_ins (cfg, klass, OP_XBINOP, ins_prodx->dreg, ins_prody->dreg); result->inst_c0 = OP_FADD; result->inst_c1 = MONO_TYPE_R4; return result; -#else - return NULL; -#endif } case SN_Normalize: { #if defined (TARGET_ARM64) From 414b00a6af7d54d8c21768710c994bc8e4122324 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 2 Jul 2024 09:24:14 -0700 Subject: [PATCH 36/39] Ensure mono lerp uses ins_amount for scaling y --- src/mono/mono/mini/simd-intrinsics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 58aae36124d661..b18c3495ddd52e 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -3325,7 +3325,7 @@ emit_vector_2_3_4 (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *f ins_prodx->inst_c1 = MONO_TYPE_R4; // prody = y * amount - MonoInst *ins_prody = emit_simd_ins (cfg, klass, OP_XBINOP, args [1]->dreg, ins_diff->dreg); + MonoInst *ins_prody = emit_simd_ins (cfg, klass, OP_XBINOP, args [1]->dreg, ins_amount->dreg); ins_prody->inst_c0 = OP_FMUL; ins_prody->inst_c1 = MONO_TYPE_R4; From 3c3ef36f37f21faf3de18c9902a292054f845e1e Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 3 Jul 2024 17:41:48 -0700 Subject: [PATCH 37/39] Use gtCloneExpr after the first fgMakeMultiUse if we need another copy --- src/coreclr/jit/gentree.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index d3ac8da661df79..a7e0c000c681aa 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -20769,7 +20769,7 @@ GenTree* Compiler::gtNewSimdAbsNode(var_types type, GenTree* op1, CorInfoType si { GenTree* tmp; GenTree* op1Dup1 = fgMakeMultiUse(&op1); - GenTree* op1Dup2 = fgMakeMultiUse(&op1Dup1); + GenTree* op1Dup2 = gtCloneExpr(op1Dup1); // op1 = IsNegative(op1) op1 = gtNewSimdIsNegativeNode(type, op1, simdBaseJitType, simdSize); @@ -22844,10 +22844,10 @@ GenTree* Compiler::gtNewSimdCmpOpNode( // result = BitwiseOr(op1, op2) GenTree* op1Dup1 = fgMakeMultiUse(&op1); - GenTree* op1Dup2 = fgMakeMultiUse(&op1Dup1); + GenTree* op1Dup2 = gtCloneExpr(op1Dup1); GenTree* op2Dup1 = fgMakeMultiUse(&op2); - GenTree* op2Dup2 = fgMakeMultiUse(&op2Dup1); + GenTree* op2Dup2 = gtCloneExpr(op2Dup1); GenTree* t = gtNewSimdCmpOpNode(op, type, op1, op2, CORINFO_TYPE_INT, simdSize); GenTree* u = gtNewSimdCmpOpNode(GT_EQ, type, op1Dup1, op2Dup1, CORINFO_TYPE_INT, simdSize); @@ -23099,10 +23099,10 @@ GenTree* Compiler::gtNewSimdCmpOpNode( // result = BitwiseOr(op1, op2) GenTree* op1Dup1 = fgMakeMultiUse(&op1); - GenTree* op1Dup2 = fgMakeMultiUse(&op1Dup1); + GenTree* op1Dup2 = gtCloneExpr(op1Dup1); GenTree* op2Dup1 = fgMakeMultiUse(&op2); - GenTree* op2Dup2 = fgMakeMultiUse(&op2Dup1); + GenTree* op2Dup2 = gtCloneExpr(op2Dup1); GenTree* t = gtNewSimdCmpOpNode(op, type, op1, op2, CORINFO_TYPE_INT, simdSize); GenTree* u = gtNewSimdCmpOpNode(GT_EQ, type, op1Dup1, op2Dup1, CORINFO_TYPE_INT, simdSize); @@ -24936,12 +24936,12 @@ GenTree* Compiler::gtNewSimdMaxNode( if (varTypeIsFloating(simdBaseType)) { GenTree* op1Dup1 = fgMakeMultiUse(&op1); - GenTree* op1Dup2 = fgMakeMultiUse(&op1); - GenTree* op1Dup3 = fgMakeMultiUse(&op1); + GenTree* op1Dup2 = gtCloneExpr(op1Dup1); + GenTree* op1Dup3 = gtCloneExpr(op1Dup2); GenTree* op2Dup1 = fgMakeMultiUse(&op2); - GenTree* op2Dup2 = fgMakeMultiUse(&op2); - GenTree* op2Dup3 = fgMakeMultiUse(&op2); + GenTree* op2Dup2 = gtCloneExpr(op2Dup1); + GenTree* op2Dup3 = gtCloneExpr(op2Dup2); GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); GenTree* isNegativeMask = gtNewSimdIsNegativeNode(type, op2Dup1, simdBaseJitType, simdSize); @@ -25195,12 +25195,12 @@ GenTree* Compiler::gtNewSimdMinNode( if (varTypeIsFloating(simdBaseType)) { GenTree* op1Dup1 = fgMakeMultiUse(&op1); - GenTree* op1Dup2 = fgMakeMultiUse(&op1); - GenTree* op1Dup3 = fgMakeMultiUse(&op1); - GenTree* op1Dup4 = fgMakeMultiUse(&op1); + GenTree* op1Dup2 = gtCloneExpr(op1Dup1); + GenTree* op1Dup3 = gtCloneExpr(op1Dup2); + GenTree* op1Dup4 = gtCloneExpr(op1Dup3); GenTree* op2Dup1 = fgMakeMultiUse(&op2); - GenTree* op2Dup2 = fgMakeMultiUse(&op2); + GenTree* op2Dup2 = gtCloneExpr(op2Dup1); GenTree* equalsMask = gtNewSimdCmpOpNode(GT_EQ, type, op1, op2, simdBaseJitType, simdSize); GenTree* isNegativeMask = gtNewSimdIsNegativeNode(type, op1Dup1, simdBaseJitType, simdSize); @@ -25333,7 +25333,7 @@ GenTree* Compiler::gtNewSimdMinNativeNode( GenTree* constVector = gtNewSimdCreateBroadcastNode(type, constVal, CORINFO_TYPE_INT, simdSize); GenTree* constVectorDup1 = fgMakeMultiUse(&constVector); - GenTree* constVectorDup2 = fgMakeMultiUse(&constVectorDup1); + GenTree* constVectorDup2 = gtCloneExpr(constVectorDup1); // op1 = op1 - constVector // -or- From 4eabf81ad0728b9ffb90ef5ca1f9a34187fe00f9 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 8 Jul 2024 14:18:11 -0700 Subject: [PATCH 38/39] Combine the SN_IsNegative and SN_IsPositive logic --- src/mono/mono/mini/simd-intrinsics.c | 37 ++++++---------------------- 1 file changed, 7 insertions(+), 30 deletions(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index 207d80c94347fe..a541fa49e24677 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2221,40 +2221,16 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi xnot->inst_c1 = arg0_type; return xnot; } - case SN_IsNegative: { + case SN_IsNegative: + case SN_IsPositive: { if (!is_element_type_primitive (fsig->params [0])) return NULL; if (type_enum_is_unsigned(arg0_type)) { - return emit_xzero (cfg, klass); - } - - MonoInst *arg0 = args [0]; - MonoClass *op_klass = klass; - - if (type_enum_is_float (arg0_type)) { - if (arg0_type == MONO_TYPE_R4) { - arg0_type = MONO_TYPE_I4; - op_klass = mono_defaults.int32_class; + if (id == SN_IsNegative) { + return emit_xzero (cfg, klass); } else { - arg0_type = MONO_TYPE_I8; - op_klass = mono_defaults.int64_class; + return emit_xones (cfg, klass); } - op_klass = create_class_instance (m_class_get_name_space (klass), m_class_get_name (klass), m_class_get_byval_arg (op_klass)); - arg0 = emit_simd_ins (cfg, op_klass, OP_XCAST, arg0->dreg, -1); - } - - MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_LessThan, arg0_type, arg0, emit_xzero (cfg, op_klass)); - - if (op_klass != NULL) { - ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); - } - return ins; - } - case SN_IsPositive: { - if (!is_element_type_primitive (fsig->params [0])) - return NULL; - if (type_enum_is_unsigned(arg0_type)) { - return emit_xones (cfg, klass); } MonoInst *arg0 = args [0]; @@ -2272,7 +2248,8 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi arg0 = emit_simd_ins (cfg, op_klass, OP_XCAST, arg0->dreg, -1); } - MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, SN_GreaterThanOrEqual, arg0_type, arg0, emit_xzero (cfg, op_klass)); + int cmpId = (id == SN_IsNegative) ? SN_LessThan : SN_GreaterThanOrEqual; + MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, cmpId, arg0_type, arg0, emit_xzero (cfg, op_klass)); if (op_klass != NULL) { ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); From 73fda9a4dcd217c8ec5dc900e7a50e6c47f459fa Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Tue, 9 Jul 2024 08:25:41 -0700 Subject: [PATCH 39/39] Update src/mono/mono/mini/simd-intrinsics.c --- src/mono/mono/mini/simd-intrinsics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/simd-intrinsics.c b/src/mono/mono/mini/simd-intrinsics.c index a541fa49e24677..44fc12ac0a232f 100644 --- a/src/mono/mono/mini/simd-intrinsics.c +++ b/src/mono/mono/mini/simd-intrinsics.c @@ -2251,7 +2251,7 @@ emit_sri_vector (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSignature *fsi int cmpId = (id == SN_IsNegative) ? SN_LessThan : SN_GreaterThanOrEqual; MonoInst *ins = emit_xcompare_for_intrinsic (cfg, op_klass, cmpId, arg0_type, arg0, emit_xzero (cfg, op_klass)); - if (op_klass != NULL) { + if (op_klass != klass) { ins = emit_simd_ins (cfg, klass, OP_XCAST, ins->dreg, -1); } return ins;