diff --git a/src/Maths/Silk.NET.Maths/PublicAPI.Unshipped.txt b/src/Maths/Silk.NET.Maths/PublicAPI.Unshipped.txt index 815c92006a..5d7ec3d70e 100644 --- a/src/Maths/Silk.NET.Maths/PublicAPI.Unshipped.txt +++ b/src/Maths/Silk.NET.Maths/PublicAPI.Unshipped.txt @@ -1 +1,105 @@ -#nullable enable \ No newline at end of file +#nullable enable +Silk.NET.Maths.Simd128 +Silk.NET.Maths.Simd128 +Silk.NET.Maths.Simd256 +Silk.NET.Maths.Simd256 +Silk.NET.Maths.Simd64 +Silk.NET.Maths.Simd64 +static readonly Silk.NET.Maths.Simd128.AllBitsSet -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.E -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.Epsilon -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.MaxValue -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.MinusOne -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.MinusTwo -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.MinValue -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.NaN -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.NegativeInfinity -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.One -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.Pi -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.PiOver2 -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.PositiveInfinity -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.Tau -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.Two -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd128.Zero -> System.Runtime.Intrinsics.Vector128 +static readonly Silk.NET.Maths.Simd256.AllBitsSet -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.E -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.Epsilon -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.MaxValue -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.MinusOne -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.MinusTwo -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.MinValue -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.NaN -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.NegativeInfinity -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.One -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.Pi -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.PiOver2 -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.PositiveInfinity -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.Tau -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.Two -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd256.Zero -> System.Runtime.Intrinsics.Vector256 +static readonly Silk.NET.Maths.Simd64.AllBitsSet -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.E -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.Epsilon -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.MaxValue -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.MinusOne -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.MinusTwo -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.MinValue -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.NaN -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.NegativeInfinity -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.One -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.Pi -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.PiOver2 -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.PositiveInfinity -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.Tau -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.Two -> System.Runtime.Intrinsics.Vector64 +static readonly Silk.NET.Maths.Simd64.Zero -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Scalar.And(T left, T right) -> T +static Silk.NET.Maths.Scalar.Not(T value) -> T +static Silk.NET.Maths.Scalar.Or(T left, T right) -> T +static Silk.NET.Maths.Scalar.RotateLeft(T value, int offset) -> T +static Silk.NET.Maths.Scalar.RotateRight(T value, int offset) -> T +static Silk.NET.Maths.Scalar.ShiftLeft(T value, int offset) -> T +static Silk.NET.Maths.Scalar.ShiftRight(T value, int offset) -> T +static Silk.NET.Maths.Scalar.Xor(T left, T right) -> T +static Silk.NET.Maths.Simd128.Abs(System.Runtime.Intrinsics.Vector128 vector) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Add(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.And(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Create(T value) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Divide(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Load(T* ptr) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Multiply(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Not(System.Runtime.Intrinsics.Vector128 vector) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Or(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Store(T* destination, System.Runtime.Intrinsics.Vector128 source) -> void +static Silk.NET.Maths.Simd128.Subtract(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.Xor(System.Runtime.Intrinsics.Vector128 left, System.Runtime.Intrinsics.Vector128 right) -> System.Runtime.Intrinsics.Vector128 +static Silk.NET.Maths.Simd128.IsHardwareAccelerated.get -> bool +static Silk.NET.Maths.Simd128.IsSupported.get -> bool +static Silk.NET.Maths.Simd256.Abs(System.Runtime.Intrinsics.Vector256 vector) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Add(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.And(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Create(T value) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Divide(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Load(T* ptr) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Multiply(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Not(System.Runtime.Intrinsics.Vector256 vector) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Or(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Store(T* destination, System.Runtime.Intrinsics.Vector256 source) -> void +static Silk.NET.Maths.Simd256.Subtract(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.Xor(System.Runtime.Intrinsics.Vector256 left, System.Runtime.Intrinsics.Vector256 right) -> System.Runtime.Intrinsics.Vector256 +static Silk.NET.Maths.Simd256.IsHardwareAccelerated.get -> bool +static Silk.NET.Maths.Simd256.IsSupported.get -> bool +static Silk.NET.Maths.Simd64.Abs(System.Runtime.Intrinsics.Vector64 vector) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Add(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.And(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Create(T value) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Divide(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Load(T* ptr) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Multiply(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Not(System.Runtime.Intrinsics.Vector64 vector) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Or(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Store(T* destination, System.Runtime.Intrinsics.Vector64 source) -> void +static Silk.NET.Maths.Simd64.Subtract(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.Xor(System.Runtime.Intrinsics.Vector64 left, System.Runtime.Intrinsics.Vector64 right) -> System.Runtime.Intrinsics.Vector64 +static Silk.NET.Maths.Simd64.IsHardwareAccelerated.get -> bool +static Silk.NET.Maths.Simd64.IsSupported.get -> bool \ No newline at end of file diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.And.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.And.cs index 5e2250aad4..4a60877d0d 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.And.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.And.cs @@ -2,6 +2,11 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 + namespace Silk.NET.Maths { @@ -10,7 +15,7 @@ static partial class Scalar /// /// Performs And on supported types /// - public static T And(T left, T right) where T : unmanaged + public static T And(T left, T right) { return Byte(left, right); diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Not.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Not.cs index 4db3748511..bc87957ea2 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Not.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Not.cs @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 namespace Silk.NET.Maths { @@ -10,7 +14,7 @@ static partial class Scalar /// /// Performs Not on supported types /// - public static T Not(T value) where T : unmanaged + public static T Not(T value) { return Byte(value); diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Or.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Or.cs index 1f893116c0..ce5559f809 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Or.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Or.cs @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 namespace Silk.NET.Maths { @@ -10,7 +14,7 @@ static partial class Scalar /// /// Performs Or on supported types /// - public static T Or(T left, T right) where T : unmanaged + public static T Or(T left, T right) { return Byte(left, right); diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateLeft.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateLeft.cs index 979340447b..5b49a1b5d8 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateLeft.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateLeft.cs @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 namespace Silk.NET.Maths { @@ -11,7 +15,7 @@ static partial class Scalar /// Rotates a given value bitwise. /// Shifting float and double obeys unsigned integers' behaviour. /// - public static T RotateLeft(T value, int offset) where T : unmanaged + public static T RotateLeft(T value, int offset) { return Byte(value, offset); diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateRight.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateRight.cs index 3324597f08..652782d871 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateRight.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.RotateRight.cs @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 namespace Silk.NET.Maths { @@ -11,7 +15,7 @@ static partial class Scalar /// Rotates a given value bitwise. /// Shifting float and double obeys unsigned integers' behaviour. /// - public static T RotateRight(T value, int offset) where T : unmanaged + public static T RotateRight(T value, int offset) { return Byte(value, offset); diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftLeft.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftLeft.cs index 52f2b07f21..6f5da05724 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftLeft.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftLeft.cs @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 namespace Silk.NET.Maths { @@ -10,7 +14,7 @@ static partial class Scalar /// /// Performs ShiftLeft on supported types /// - public static T ShiftLeft(T value, int offset) where T : unmanaged + public static T ShiftLeft(T value, int offset) { return Byte(value, offset); diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftRight.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftRight.cs index 29f844c792..f0726e028e 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftRight.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.ShiftRight.cs @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 namespace Silk.NET.Maths { @@ -10,7 +14,7 @@ static partial class Scalar /// /// Performs ShiftRight on supported types /// - public static T ShiftRight(T value, int offset) where T : unmanaged + public static T ShiftRight(T value, int offset) { return Byte(value, offset); diff --git a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Xor.cs b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Xor.cs index 797e946281..118c53129b 100644 --- a/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Xor.cs +++ b/src/Maths/Silk.NET.Maths/Scalar.Bitwise/Scalar.Xor.cs @@ -2,6 +2,10 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Runtime.CompilerServices; +// nullability-related things +#pragma warning disable 8603 +#pragma warning disable 8605 +#pragma warning disable 8600 namespace Silk.NET.Maths { @@ -10,7 +14,7 @@ static partial class Scalar /// /// Performs Xor on supported types /// - public static T Xor(T left, T right) where T : unmanaged + public static T Xor(T left, T right) { return Byte(left, right); diff --git a/src/Maths/Silk.NET.Maths/Silk.NET.Maths.csproj b/src/Maths/Silk.NET.Maths/Silk.NET.Maths.csproj index 769925a3ff..49de10e2d9 100644 --- a/src/Maths/Silk.NET.Maths/Silk.NET.Maths.csproj +++ b/src/Maths/Silk.NET.Maths/Silk.NET.Maths.csproj @@ -8,7 +8,7 @@ true 9.0 - $(DefineConstants);SSE + $(DefineConstants);SSE;AVX;INTRINSICS $(DefineConstants);BTEC_INTRINSICS;MATHF $(DefineConstants);POH;AdvSIMD true diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Abs.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Abs.cs new file mode 100644 index 0000000000..a6a8155db6 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Abs.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Abs on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Abs(Vector128 vector) where T : unmanaged + { + return Byte(vector); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(Vector128 vector) + { + if (typeof(T) == typeof(byte)) + { + return vector; + } + + return SByte(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(Vector128 vector) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + return AdvSimd.Abs(vector.AsSByte()).As(); +#endif +#if SSE + return Ssse3.Abs(vector.AsSByte()).As(); +#endif + } + + return UInt16(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(Vector128 vector) + { + if (typeof(T) == typeof(ushort)) + { + return vector; + } + + return Int16(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(Vector128 vector) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + return AdvSimd.Abs(vector.AsInt16()).As(); +#endif +#if SSE + return Ssse3.Abs(vector.AsInt16()).As(); +#endif + } + + return UInt32(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(Vector128 vector) + { + if (typeof(T) == typeof(uint)) + { + return vector; + } + + return Int32(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(Vector128 vector) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + return AdvSimd.Abs(vector.AsInt32()).As(); +#endif +#if SSE + return Ssse3.Abs(vector.AsInt32()).As(); +#endif + } + + return UInt64(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(Vector128 vector) + { + if (typeof(T) == typeof(ulong)) + { + return vector; + } + + return Single(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 vector) + { + if (typeof(T) == typeof(float)) + { + return Simd128.And(vector.AsSingle(), Vector128.Create(0x7FFF_FFFFu).AsSingle()).As(); + } + + return Double(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 vector) + { + if (typeof(T) == typeof(double)) + { + return Simd128.And(vector.AsDouble(), Vector128.Create(0x7FFF_FFFF_FFFF_FFFFul).AsDouble()).As(); + } + + return Other(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 vector) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Abs(vector.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Add.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Add.cs new file mode 100644 index 0000000000..24e8abf1d7 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Add.cs @@ -0,0 +1,231 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Add on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Add(Vector128 left, Vector128 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsByte(), right.AsByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsSByte(), right.AsSByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsInt16(), right.AsInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsInt32(), right.AsInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ulong)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(long)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsSingle(), right.AsSingle()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(double)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Add(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 left, Vector128 right) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Add(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.And.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.And.cs new file mode 100644 index 0000000000..bdb0e4b640 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.And.cs @@ -0,0 +1,231 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated And on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 And(Vector128 left, Vector128 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsByte(), right.AsByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsSByte(), right.AsSByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsInt16(), right.AsInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsInt32(), right.AsInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ulong)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(long)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsSingle(), right.AsSingle()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(double)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.And(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 left, Vector128 right) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.And(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd128.Constants.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Constants.cs similarity index 77% rename from src/Maths/Silk.NET.Maths/Simd128.Constants.cs rename to src/Maths/Silk.NET.Maths/Simd/Simd128.Constants.cs index 6040cd45bd..8de6d1a7ec 100644 --- a/src/Maths/Silk.NET.Maths/Simd128.Constants.cs +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Constants.cs @@ -1,7 +1,5 @@ -// This file is part of Silk.NET. -// -// You may modify and distribute Silk.NET under the terms -// of the MIT license. See the LICENSE file for details. +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. #if INTRINSICS using System; @@ -10,8 +8,14 @@ namespace Silk.NET.Maths { + /// + /// Exposes bunch of methods for working with hardware accelerated operations. + /// public static class Simd128 where T : unmanaged { + /// + /// Indicates if the type is supported. + /// public static bool IsSupported => typeof(T) == typeof(sbyte) || typeof(T) == typeof(byte) || typeof(T) == typeof(ushort) @@ -98,6 +102,28 @@ public static class Simd128 where T : unmanaged /// public static readonly Vector128 Tau; + /// + /// Gets a new with all bits set to 1. + /// + public static readonly Vector128 AllBitsSet; + + /// + /// Indicates if there exists SIMD hardware acceleration + /// for the type . + /// + public static bool IsHardwareAccelerated => +#if SSE + System.Runtime.Intrinsics.X86.Sse2.IsSupported +#else + false +#endif + || +#if AdvSIMD + System.Runtime.Intrinsics.Arm.AdvSimd.IsSupported; +#else + false; +#endif + [MethodImpl(Scalar.MaxOpt)] static Simd128() { @@ -115,6 +141,15 @@ static Simd128() Pi = Simd128.Create(Scalar.Pi); PiOver2 = Simd128.Create(Scalar.PiOver2); Tau = Simd128.Create(Scalar.Tau); +#if NET5_0_OR_GREATER + AllBitsSet = Vector128.AllBitsSet; +#else + AllBitsSet = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + AllBitsSet.WithElement(i, Scalar.Not(Scalar.Zero)); + } +#endif } } } diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Create.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Create.cs new file mode 100644 index 0000000000..656a961879 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Create.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Create on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Create(T value) where T : unmanaged + { + return Byte(value); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(T value) + { + if (typeof(T) == typeof(byte)) + { + return (Vector128) (object) Vector128.Create((byte) (object) value); + } + + return SByte(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(T value) + { + if (typeof(T) == typeof(sbyte)) + { + return (Vector128) (object) Vector128.Create((sbyte) (object) value); + } + + return UInt16(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(T value) + { + if (typeof(T) == typeof(ushort)) + { + return (Vector128) (object) Vector128.Create((ushort) (object) value); + } + + return Int16(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(T value) + { + if (typeof(T) == typeof(short)) + { + return (Vector128) (object) Vector128.Create((short) (object) value); + } + + return UInt32(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(T value) + { + if (typeof(T) == typeof(uint)) + { + return (Vector128) (object) Vector128.Create((uint) (object) value); + } + + return Int32(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(T value) + { + if (typeof(T) == typeof(int)) + { + return (Vector128) (object) Vector128.Create((int) (object) value); + } + + return UInt64(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(T value) + { + if (typeof(T) == typeof(ulong)) + { + return (Vector128) (object) Vector128.Create((ulong) (object) value); + } + + return Int64(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int64(T value) + { + if (typeof(T) == typeof(long)) + { + return (Vector128) (object) Vector128.Create((long) (object) value); + } + + return Single(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(T value) + { + if (typeof(T) == typeof(float)) + { + return (Vector128) (object) Vector128.Create((float) (object) value); + } + + return Double(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(T value) + { + if (typeof(T) == typeof(double)) + { + return (Vector128) (object) Vector128.Create((double) (object) value); + } + + return Other(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(T value) + { + Scalar.ThrowUnsupportedType(); + return default; + + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Divide.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Divide.cs new file mode 100644 index 0000000000..71910dff96 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Divide.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Divide on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Divide(Vector128 left, Vector128 right) where T : unmanaged + { + return Single(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(float)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Divide(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(double)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Divide(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 left, Vector128 right) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Divide(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Load.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Load.cs new file mode 100644 index 0000000000..c0e3ef9f51 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Load.cs @@ -0,0 +1,244 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Load on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Load(T* ptr) where T : unmanaged + { + return Byte(ptr); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(T* ptr) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((byte*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((byte*) ptr); + } +#endif + } + + return SByte(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(T* ptr) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((sbyte*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((sbyte*) ptr); + } +#endif + } + + return UInt16(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(T* ptr) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((ushort*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((ushort*) ptr); + } +#endif + } + + return Int16(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(T* ptr) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((short*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((short*) ptr); + } +#endif + } + + return UInt32(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(T* ptr) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((uint*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((uint*) ptr); + } +#endif + } + + return Int32(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(T* ptr) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((int*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((int*) ptr); + } +#endif + } + + return UInt64(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(T* ptr) + { + if (typeof(T) == typeof(ulong)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((ulong*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((ulong*) ptr); + } +#endif + } + + return Int64(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int64(T* ptr) + { + if (typeof(T) == typeof(long)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((long*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((long*) ptr); + } +#endif + } + + return Single(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(T* ptr) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((float*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((float*) ptr); + } +#endif + } + + return Double(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(T* ptr) + { + if (typeof(T) == typeof(double)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector128) (object) AdvSimd.LoadVector128((double*) ptr); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return (Vector128) (object) Sse2.LoadVector128((double*) ptr); + } +#endif + } + + return Other(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(T* ptr) + { + return Unsafe.ReadUnaligned>(ptr); + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Multiply.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Multiply.cs new file mode 100644 index 0000000000..eabb65d712 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Multiply.cs @@ -0,0 +1,165 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Multiply on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Multiply(Vector128 left, Vector128 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsSingle(), right.AsSingle()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Multiply(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(double)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Multiply(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 left, Vector128 right) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Multiply(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Not.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Not.cs new file mode 100644 index 0000000000..61081b18cf --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Not.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Not on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Not(Vector128 vector) where T : unmanaged + { + if (Simd128.IsHardwareAccelerated) + return Simd128.Xor(vector, Simd128.AllBitsSet); + + return Other(vector); + + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 vector) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Not(vector.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Or.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Or.cs new file mode 100644 index 0000000000..30f9aa56e4 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Or.cs @@ -0,0 +1,231 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Or on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Or(Vector128 left, Vector128 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsByte(), right.AsByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsSByte(), right.AsSByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsInt16(), right.AsInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsInt32(), right.AsInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ulong)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(long)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsSingle(), right.AsSingle()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(double)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Or(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 left, Vector128 right) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Or(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Store.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Store.cs new file mode 100644 index 0000000000..fce0640103 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Store.cs @@ -0,0 +1,245 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Store on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static void Store(T* destination, Vector128 source) where T : unmanaged + { + Byte(destination, source); + [MethodImpl(Scalar.MaxOpt)] + static void Byte(T* destination, Vector128 source) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((byte*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((byte*) destination, (Vector128) (object) source); + } +#endif + } + + SByte(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void SByte(T* destination, Vector128 source) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((sbyte*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((sbyte*) destination, (Vector128) (object) source); + } +#endif + } + + UInt16(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt16(T* destination, Vector128 source) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((ushort*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((ushort*) destination, (Vector128) (object) source); + } +#endif + } + + Int16(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int16(T* destination, Vector128 source) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((short*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((short*) destination, (Vector128) (object) source); + } +#endif + } + + UInt32(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt32(T* destination, Vector128 source) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((uint*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((uint*) destination, (Vector128) (object) source); + } +#endif + } + + Int32(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int32(T* destination, Vector128 source) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((int*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((int*) destination, (Vector128) (object) source); + } +#endif + } + + UInt64(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt64(T* destination, Vector128 source) + { + if (typeof(T) == typeof(ulong)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((ulong*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((ulong*) destination, (Vector128) (object) source); + } +#endif + } + + Int64(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int64(T* destination, Vector128 source) + { + if (typeof(T) == typeof(long)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((long*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((long*) destination, (Vector128) (object) source); + } +#endif + } + + Single(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Single(T* destination, Vector128 source) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((float*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((float*) destination, (Vector128) (object) source); + } +#endif + } + + Double(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Double(T* destination, Vector128 source) + { + if (typeof(T) == typeof(double)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((double*) destination, (Vector128) (object) source); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + Sse2.Store((double*) destination, (Vector128) (object) source); + } +#endif + } + + Other(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Other(T* destination, Vector128 source) + { + Unsafe.WriteUnaligned>(destination, source); + + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Subtract.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Subtract.cs new file mode 100644 index 0000000000..e1661bbe66 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Subtract.cs @@ -0,0 +1,231 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Subtract on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Subtract(Vector128 left, Vector128 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsByte(), right.AsByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsSByte(), right.AsSByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsInt16(), right.AsInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsInt32(), right.AsInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ulong)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(long)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsSingle(), right.AsSingle()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(double)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Subtract(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 left, Vector128 right) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Subtract(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd128.Xor.cs b/src/Maths/Silk.NET.Maths/Simd/Simd128.Xor.cs new file mode 100644 index 0000000000..feb6d65db7 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd128.Xor.cs @@ -0,0 +1,231 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd128 + { + /// + /// Performs hardware-accelerated Xor on 128-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector128 Xor(Vector128 left, Vector128 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Byte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsByte(), right.AsByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 SByte(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsSByte(), right.AsSByte()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int16(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsInt16(), right.AsInt16()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int32(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsInt32(), right.AsInt32()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 UInt64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(ulong)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Int64(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(long)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Single(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsSingle(), right.AsSingle()).As(); + } +#endif +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Double(Vector128 left, Vector128 right) + { + if (typeof(T) == typeof(double)) + { +#if SSE + if (Sse2.IsSupported) + { + return Sse2.Xor(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector128 Other(Vector128 left, Vector128 right) + { + var vec = Vector128.Zero; + for (int i = 0; i < Vector128.Count; i++) + { + vec.WithElement(i, Scalar.Xor(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Abs.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Abs.cs new file mode 100644 index 0000000000..a6efc24148 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Abs.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Abs on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Abs(Vector256 vector) where T : unmanaged + { + return Byte(vector); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(Vector256 vector) + { + if (typeof(T) == typeof(byte)) + { + return vector; + } + + return SByte(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(Vector256 vector) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + return Avx2.Abs(vector.AsSByte()).As(); +#endif + } + + return UInt16(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(Vector256 vector) + { + if (typeof(T) == typeof(ushort)) + { + return vector; + } + + return Int16(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(Vector256 vector) + { + if (typeof(T) == typeof(short)) + { +#if AVX + return Avx2.Abs(vector.AsInt16()).As(); +#endif + } + + return UInt32(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(Vector256 vector) + { + if (typeof(T) == typeof(uint)) + { + return vector; + } + + return Int32(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(Vector256 vector) + { + if (typeof(T) == typeof(int)) + { +#if AVX + return Avx2.Abs(vector.AsInt32()).As(); +#endif + } + + return UInt64(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(Vector256 vector) + { + if (typeof(T) == typeof(ulong)) + { + return vector; + } + + return Single(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 vector) + { + if (typeof(T) == typeof(float)) + { + return Simd256.And(vector.AsSingle(), Vector256.Create(0x7FFF_FFFFu).AsSingle()).As(); + } + + return Double(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 vector) + { + if (typeof(T) == typeof(double)) + { + return Simd256.And(vector.AsDouble(), Vector256.Create(0x7FFF_FFFF_FFFF_FFFFul).AsDouble()).As(); + } + + return Other(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 vector) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Abs(vector.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Add.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Add.cs new file mode 100644 index 0000000000..e1a20bce2a --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Add.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Add on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Add(Vector256 left, Vector256 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(byte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(short)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(uint)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(int)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ulong)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(long)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Add(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 left, Vector256 right) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Add(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.And.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.And.cs new file mode 100644 index 0000000000..387de57ff1 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.And.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated And on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 And(Vector256 left, Vector256 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(byte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(short)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(uint)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(int)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ulong)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(long)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.And(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 left, Vector256 right) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.And(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Constants.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Constants.cs new file mode 100644 index 0000000000..8282657982 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Constants.cs @@ -0,0 +1,146 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace Silk.NET.Maths +{ + /// + /// Exposes bunch of methods for working with hardware accelerated operations. + /// + public static class Simd256 where T : unmanaged + { + /// + /// Indicates if the type is supported. + /// + public static bool IsSupported => typeof(T) == typeof(sbyte) + || typeof(T) == typeof(byte) + || typeof(T) == typeof(ushort) + || typeof(T) == typeof(short) + || typeof(T) == typeof(uint) + || typeof(T) == typeof(int) + || typeof(T) == typeof(ulong) + || typeof(T) == typeof(long) + || typeof(T) == typeof(float) + || typeof(T) == typeof(double); + + /// + /// Represents the smallest positive value that is greater than zero. Zero for non-floating point numbers. + /// + public static readonly Vector256 Epsilon; + + /// + /// Represents the largest possible value. + /// + public static readonly Vector256 MaxValue; + + /// + /// Represents the smallest possible value. + /// + public static readonly Vector256 MinValue; + + /// + /// Represents not a number (NaN). Zero for non-floating point numbers. + /// + public static readonly Vector256 NaN; + + /// + /// Represents negative infinity. Zero for non-floating point numbers. + /// + public static readonly Vector256 NegativeInfinity; + + /// + /// Represents positive infinity. Zero for non-floating point numbers. + /// + public static readonly Vector256 PositiveInfinity; + + /// + /// Represents zero. + /// + public static readonly Vector256 Zero = Vector256.Zero; + + /// + /// Represents one. + /// + public static readonly Vector256 One; + + /// + /// Represents two. + /// + public static readonly Vector256 Two; + + /// + /// Represents negative one. + /// + public static readonly Vector256 MinusOne; + + /// + /// Represents negative two. + /// + public static readonly Vector256 MinusTwo; + + /// + /// Represents the natural logarithmic base, specified by the constant, e. + /// + public static readonly Vector256 E; + + /// + /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π. + /// + public static readonly Vector256 Pi; + + /// + /// Represents Pi divided by two. + /// + public static readonly Vector256 PiOver2; + + /// + /// Represents the number of radians in one turn, specified by the constant, τ. + /// + public static readonly Vector256 Tau; + + /// + /// Gets a new with all bits set to 1. + /// + public static readonly Vector256 AllBitsSet; + + /// + /// Indicates if there exists SIMD hardware acceleration + /// for the type . + /// + public static bool IsHardwareAccelerated => Avx2.IsSupported; + + [MethodImpl(Scalar.MaxOpt)] + static Simd256() + { + Epsilon = Simd256.Create(Scalar.Epsilon); + MaxValue = Simd256.Create(Scalar.MaxValue); + MinValue = Simd256.Create(Scalar.MinValue); + NaN = Simd256.Create(Scalar.NaN); + NegativeInfinity = Simd256.Create(Scalar.NegativeInfinity); + PositiveInfinity = Simd256.Create(Scalar.PositiveInfinity); + One = Simd256.Create(Scalar.One); + Two = Simd256.Create(Scalar.Two); + MinusOne = Simd256.Create(Scalar.MinusOne); + MinusTwo = Simd256.Create(Scalar.MinusTwo); + E = Simd256.Create(Scalar.E); + Pi = Simd256.Create(Scalar.Pi); + PiOver2 = Simd256.Create(Scalar.PiOver2); + Tau = Simd256.Create(Scalar.Tau); +#if NET5_0_OR_GREATER + AllBitsSet = Vector256.AllBitsSet; +#else + AllBitsSet = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + AllBitsSet.WithElement(i, Scalar.Not(Scalar.Zero)); + } +#endif + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Create.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Create.cs new file mode 100644 index 0000000000..7f95a4dd21 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Create.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Create on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Create(T value) where T : unmanaged + { + return Byte(value); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(T value) + { + if (typeof(T) == typeof(byte)) + { + return (Vector256) (object) Vector256.Create((byte) (object) value); + } + + return SByte(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(T value) + { + if (typeof(T) == typeof(sbyte)) + { + return (Vector256) (object) Vector256.Create((sbyte) (object) value); + } + + return UInt16(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(T value) + { + if (typeof(T) == typeof(ushort)) + { + return (Vector256) (object) Vector256.Create((ushort) (object) value); + } + + return Int16(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(T value) + { + if (typeof(T) == typeof(short)) + { + return (Vector256) (object) Vector256.Create((short) (object) value); + } + + return UInt32(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(T value) + { + if (typeof(T) == typeof(uint)) + { + return (Vector256) (object) Vector256.Create((uint) (object) value); + } + + return Int32(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(T value) + { + if (typeof(T) == typeof(int)) + { + return (Vector256) (object) Vector256.Create((int) (object) value); + } + + return UInt64(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(T value) + { + if (typeof(T) == typeof(ulong)) + { + return (Vector256) (object) Vector256.Create((ulong) (object) value); + } + + return Int64(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int64(T value) + { + if (typeof(T) == typeof(long)) + { + return (Vector256) (object) Vector256.Create((long) (object) value); + } + + return Single(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(T value) + { + if (typeof(T) == typeof(float)) + { + return (Vector256) (object) Vector256.Create((float) (object) value); + } + + return Double(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(T value) + { + if (typeof(T) == typeof(double)) + { + return (Vector256) (object) Vector256.Create((double) (object) value); + } + + return Other(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(T value) + { + Scalar.ThrowUnsupportedType(); + return default; + + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Divide.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Divide.cs new file mode 100644 index 0000000000..d8da736b24 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Divide.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Divide on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Divide(Vector256 left, Vector256 right) where T : unmanaged + { + return Single(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Divide(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Divide(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 left, Vector256 right) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Divide(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Load.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Load.cs new file mode 100644 index 0000000000..c051c4659b --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Load.cs @@ -0,0 +1,184 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Load on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Load(T* ptr) where T : unmanaged + { + return Byte(ptr); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(T* ptr) + { + if (typeof(T) == typeof(byte)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((byte*) ptr); + } +#endif + } + + return SByte(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(T* ptr) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((sbyte*) ptr); + } +#endif + } + + return UInt16(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(T* ptr) + { + if (typeof(T) == typeof(ushort)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((ushort*) ptr); + } +#endif + } + + return Int16(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(T* ptr) + { + if (typeof(T) == typeof(short)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((short*) ptr); + } +#endif + } + + return UInt32(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(T* ptr) + { + if (typeof(T) == typeof(uint)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((uint*) ptr); + } +#endif + } + + return Int32(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(T* ptr) + { + if (typeof(T) == typeof(int)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((int*) ptr); + } +#endif + } + + return UInt64(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(T* ptr) + { + if (typeof(T) == typeof(ulong)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((ulong*) ptr); + } +#endif + } + + return Int64(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int64(T* ptr) + { + if (typeof(T) == typeof(long)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((long*) ptr); + } +#endif + } + + return Single(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(T* ptr) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((float*) ptr); + } +#endif + } + + return Double(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(T* ptr) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return (Vector256) (object) Avx2.LoadVector256((double*) ptr); + } +#endif + } + + return Other(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(T* ptr) + { + return Unsafe.ReadUnaligned>(ptr); + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Multiply.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Multiply.cs new file mode 100644 index 0000000000..063589c43b --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Multiply.cs @@ -0,0 +1,69 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Multiply on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Multiply(Vector256 left, Vector256 right) where T : unmanaged + { + return Single(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Multiply(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Multiply(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 left, Vector256 right) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Multiply(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Not.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Not.cs new file mode 100644 index 0000000000..25625edb08 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Not.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Not on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Not(Vector256 vector) where T : unmanaged + { + if (Simd256.IsHardwareAccelerated) + return Simd256.Xor(vector, Simd256.AllBitsSet); + + return Other(vector); + + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 vector) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Not(vector.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Or.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Or.cs new file mode 100644 index 0000000000..266e7ae3a1 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Or.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Or on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Or(Vector256 left, Vector256 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(byte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(short)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(uint)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(int)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ulong)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(long)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Or(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 left, Vector256 right) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Or(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Store.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Store.cs new file mode 100644 index 0000000000..83cbde8dd1 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Store.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Store on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static void Store(T* destination, Vector256 source) where T : unmanaged + { + Byte(destination, source); + [MethodImpl(Scalar.MaxOpt)] + static void Byte(T* destination, Vector256 source) + { + if (typeof(T) == typeof(byte)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((byte*) destination, (Vector256) (object) source); + } +#endif + } + + SByte(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void SByte(T* destination, Vector256 source) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((sbyte*) destination, (Vector256) (object) source); + } +#endif + } + + UInt16(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt16(T* destination, Vector256 source) + { + if (typeof(T) == typeof(ushort)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((ushort*) destination, (Vector256) (object) source); + } +#endif + } + + Int16(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int16(T* destination, Vector256 source) + { + if (typeof(T) == typeof(short)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((short*) destination, (Vector256) (object) source); + } +#endif + } + + UInt32(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt32(T* destination, Vector256 source) + { + if (typeof(T) == typeof(uint)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((uint*) destination, (Vector256) (object) source); + } +#endif + } + + Int32(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int32(T* destination, Vector256 source) + { + if (typeof(T) == typeof(int)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((int*) destination, (Vector256) (object) source); + } +#endif + } + + UInt64(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt64(T* destination, Vector256 source) + { + if (typeof(T) == typeof(ulong)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((ulong*) destination, (Vector256) (object) source); + } +#endif + } + + Int64(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int64(T* destination, Vector256 source) + { + if (typeof(T) == typeof(long)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((long*) destination, (Vector256) (object) source); + } +#endif + } + + Single(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Single(T* destination, Vector256 source) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((float*) destination, (Vector256) (object) source); + } +#endif + } + + Double(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Double(T* destination, Vector256 source) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + Avx2.Store((double*) destination, (Vector256) (object) source); + } +#endif + } + + Other(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Other(T* destination, Vector256 source) + { + Unsafe.WriteUnaligned>(destination, source); + + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Subtract.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Subtract.cs new file mode 100644 index 0000000000..b775760738 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Subtract.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Subtract on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Subtract(Vector256 left, Vector256 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(byte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(short)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(uint)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(int)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ulong)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(long)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Subtract(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 left, Vector256 right) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Subtract(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd256.Xor.cs b/src/Maths/Silk.NET.Maths/Simd/Simd256.Xor.cs new file mode 100644 index 0000000000..16e7e04efb --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd256.Xor.cs @@ -0,0 +1,189 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd256 + { + /// + /// Performs hardware-accelerated Xor on 256-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector256 Xor(Vector256 left, Vector256 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Byte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(byte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 SByte(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int16(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(short)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(uint)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int32(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(int)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return UInt64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 UInt64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(ulong)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsUInt64(), right.AsUInt64()).As(); + } +#endif + } + + return Int64(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Int64(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(long)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsInt64(), right.AsInt64()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Single(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(float)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Double(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Double(Vector256 left, Vector256 right) + { + if (typeof(T) == typeof(double)) + { +#if AVX + if (Avx2.IsSupported) + { + return Avx2.Xor(left.AsDouble(), right.AsDouble()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector256 Other(Vector256 left, Vector256 right) + { + var vec = Vector256.Zero; + for (int i = 0; i < Vector256.Count; i++) + { + vec.WithElement(i, Scalar.Xor(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Abs.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Abs.cs new file mode 100644 index 0000000000..bb0974e715 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Abs.cs @@ -0,0 +1,135 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Abs on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Abs(Vector64 vector) where T : unmanaged + { + return Byte(vector); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(Vector64 vector) + { + if (typeof(T) == typeof(byte)) + { + return vector; + } + + return SByte(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(Vector64 vector) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + return AdvSimd.Abs(vector.AsSByte()).As(); +#endif + } + + return UInt16(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(Vector64 vector) + { + if (typeof(T) == typeof(ushort)) + { + return vector; + } + + return Int16(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(Vector64 vector) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + return AdvSimd.Abs(vector.AsInt16()).As(); +#endif + } + + return UInt32(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(Vector64 vector) + { + if (typeof(T) == typeof(uint)) + { + return vector; + } + + return Int32(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(Vector64 vector) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + return AdvSimd.Abs(vector.AsInt32()).As(); +#endif + } + + return UInt64(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt64(Vector64 vector) + { + if (typeof(T) == typeof(ulong)) + { + return vector; + } + + return Single(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(Vector64 vector) + { + if (typeof(T) == typeof(float)) + { + return Simd64.And(vector.AsSingle(), Vector64.Create(0x7FFF_FFFFu).AsSingle()).As(); + } + + return Double(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Double(Vector64 vector) + { + if (typeof(T) == typeof(double)) + { + return Simd64.And(vector.AsDouble(), Vector64.Create(0x7FFF_FFFF_FFFF_FFFFul).AsDouble()).As(); + } + + return Other(vector); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 vector) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Abs(vector.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Add.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Add.cs new file mode 100644 index 0000000000..00620a9cac --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Add.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Add on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Add(Vector64 left, Vector64 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Add(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 left, Vector64 right) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Add(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.And.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.And.cs new file mode 100644 index 0000000000..767b92c826 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.And.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated And on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 And(Vector64 left, Vector64 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.And(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 left, Vector64 right) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.And(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Constants.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Constants.cs new file mode 100644 index 0000000000..4f983bf087 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Constants.cs @@ -0,0 +1,150 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + +namespace Silk.NET.Maths +{ + /// + /// Exposes bunch of methods for working with hardware accelerated operations. + /// + public static class Simd64 where T : unmanaged + { + /// + /// Indicates if the type is supported. + /// + public static bool IsSupported => typeof(T) == typeof(sbyte) + || typeof(T) == typeof(byte) + || typeof(T) == typeof(ushort) + || typeof(T) == typeof(short) + || typeof(T) == typeof(uint) + || typeof(T) == typeof(int) + || typeof(T) == typeof(ulong) + || typeof(T) == typeof(long) + || typeof(T) == typeof(float) + || typeof(T) == typeof(double); + + /// + /// Represents the smallest positive value that is greater than zero. Zero for non-floating point numbers. + /// + public static readonly Vector64 Epsilon; + + /// + /// Represents the largest possible value. + /// + public static readonly Vector64 MaxValue; + + /// + /// Represents the smallest possible value. + /// + public static readonly Vector64 MinValue; + + /// + /// Represents not a number (NaN). Zero for non-floating point numbers. + /// + public static readonly Vector64 NaN; + + /// + /// Represents negative infinity. Zero for non-floating point numbers. + /// + public static readonly Vector64 NegativeInfinity; + + /// + /// Represents positive infinity. Zero for non-floating point numbers. + /// + public static readonly Vector64 PositiveInfinity; + + /// + /// Represents zero. + /// + public static readonly Vector64 Zero = Vector64.Zero; + + /// + /// Represents one. + /// + public static readonly Vector64 One; + + /// + /// Represents two. + /// + public static readonly Vector64 Two; + + /// + /// Represents negative one. + /// + public static readonly Vector64 MinusOne; + + /// + /// Represents negative two. + /// + public static readonly Vector64 MinusTwo; + + /// + /// Represents the natural logarithmic base, specified by the constant, e. + /// + public static readonly Vector64 E; + + /// + /// Represents the ratio of the circumference of a circle to its diameter, specified by the constant, π. + /// + public static readonly Vector64 Pi; + + /// + /// Represents Pi divided by two. + /// + public static readonly Vector64 PiOver2; + + /// + /// Represents the number of radians in one turn, specified by the constant, τ. + /// + public static readonly Vector64 Tau; + + /// + /// Gets a new with all bits set to 1. + /// + public static readonly Vector64 AllBitsSet; + + /// + /// Indicates if there exists SIMD hardware acceleration + /// for the type . + /// + public static bool IsHardwareAccelerated => +#if AdvSIMD + System.Runtime.Intrinsics.Arm.AdvSimd.IsSupported; +#else + false; +#endif + + [MethodImpl(Scalar.MaxOpt)] + static Simd64() + { + Epsilon = Simd64.Create(Scalar.Epsilon); + MaxValue = Simd64.Create(Scalar.MaxValue); + MinValue = Simd64.Create(Scalar.MinValue); + NaN = Simd64.Create(Scalar.NaN); + NegativeInfinity = Simd64.Create(Scalar.NegativeInfinity); + PositiveInfinity = Simd64.Create(Scalar.PositiveInfinity); + One = Simd64.Create(Scalar.One); + Two = Simd64.Create(Scalar.Two); + MinusOne = Simd64.Create(Scalar.MinusOne); + MinusTwo = Simd64.Create(Scalar.MinusTwo); + E = Simd64.Create(Scalar.E); + Pi = Simd64.Create(Scalar.Pi); + PiOver2 = Simd64.Create(Scalar.PiOver2); + Tau = Simd64.Create(Scalar.Tau); +#if NET5_0_OR_GREATER + AllBitsSet = Vector64.AllBitsSet; +#else + AllBitsSet = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + AllBitsSet.WithElement(i, Scalar.Not(Scalar.Zero)); + } +#endif + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Create.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Create.cs new file mode 100644 index 0000000000..acb644f225 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Create.cs @@ -0,0 +1,136 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Create on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Create(T value) where T : unmanaged + { + return Byte(value); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(T value) + { + if (typeof(T) == typeof(byte)) + { + return (Vector64) (object) Vector64.Create((byte) (object) value); + } + + return SByte(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(T value) + { + if (typeof(T) == typeof(sbyte)) + { + return (Vector64) (object) Vector64.Create((sbyte) (object) value); + } + + return UInt16(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(T value) + { + if (typeof(T) == typeof(ushort)) + { + return (Vector64) (object) Vector64.Create((ushort) (object) value); + } + + return Int16(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(T value) + { + if (typeof(T) == typeof(short)) + { + return (Vector64) (object) Vector64.Create((short) (object) value); + } + + return UInt32(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(T value) + { + if (typeof(T) == typeof(uint)) + { + return (Vector64) (object) Vector64.Create((uint) (object) value); + } + + return Int32(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(T value) + { + if (typeof(T) == typeof(int)) + { + return (Vector64) (object) Vector64.Create((int) (object) value); + } + + return UInt64(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt64(T value) + { + if (typeof(T) == typeof(ulong)) + { + return (Vector64) (object) Vector64.Create((ulong) (object) value); + } + + return Int64(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int64(T value) + { + if (typeof(T) == typeof(long)) + { + return (Vector64) (object) Vector64.Create((long) (object) value); + } + + return Single(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(T value) + { + if (typeof(T) == typeof(float)) + { + return (Vector64) (object) Vector64.Create((float) (object) value); + } + + return Double(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Double(T value) + { + if (typeof(T) == typeof(double)) + { + return (Vector64) (object) Vector64.Create((double) (object) value); + } + + return Other(value); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(T value) + { + Scalar.ThrowUnsupportedType(); + return default; + + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Divide.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Divide.cs new file mode 100644 index 0000000000..602513202c --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Divide.cs @@ -0,0 +1,41 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Divide on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Divide(Vector64 left, Vector64 right) where T : unmanaged + { + return Other(left, right); + + + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 left, Vector64 right) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Divide(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Load.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Load.cs new file mode 100644 index 0000000000..f68a7941e8 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Load.cs @@ -0,0 +1,184 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Load on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Load(T* ptr) where T : unmanaged + { + return Byte(ptr); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(T* ptr) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((byte*) ptr); + } +#endif + } + + return SByte(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(T* ptr) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((sbyte*) ptr); + } +#endif + } + + return UInt16(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(T* ptr) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((ushort*) ptr); + } +#endif + } + + return Int16(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(T* ptr) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((short*) ptr); + } +#endif + } + + return UInt32(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(T* ptr) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((uint*) ptr); + } +#endif + } + + return Int32(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(T* ptr) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((int*) ptr); + } +#endif + } + + return UInt64(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt64(T* ptr) + { + if (typeof(T) == typeof(ulong)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((ulong*) ptr); + } +#endif + } + + return Int64(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int64(T* ptr) + { + if (typeof(T) == typeof(long)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((long*) ptr); + } +#endif + } + + return Single(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(T* ptr) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((float*) ptr); + } +#endif + } + + return Double(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Double(T* ptr) + { + if (typeof(T) == typeof(double)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return (Vector64) (object) AdvSimd.LoadVector64((double*) ptr); + } +#endif + } + + return Other(ptr); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(T* ptr) + { + return Unsafe.ReadUnaligned>(ptr); + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Multiply.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Multiply.cs new file mode 100644 index 0000000000..ebd5c16b17 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Multiply.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Multiply on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Multiply(Vector64 left, Vector64 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Multiply(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 left, Vector64 right) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Multiply(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Not.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Not.cs new file mode 100644 index 0000000000..680f5f96d1 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Not.cs @@ -0,0 +1,43 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Not on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Not(Vector64 vector) where T : unmanaged + { + if (Simd64.IsHardwareAccelerated) + return Simd64.Xor(vector, Simd64.AllBitsSet); + + return Other(vector); + + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 vector) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Not(vector.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Or.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Or.cs new file mode 100644 index 0000000000..f842e74425 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Or.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Or on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Or(Vector64 left, Vector64 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Or(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 left, Vector64 right) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Or(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Store.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Store.cs new file mode 100644 index 0000000000..272edce62c --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Store.cs @@ -0,0 +1,185 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Store on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static void Store(T* destination, Vector64 source) where T : unmanaged + { + Byte(destination, source); + [MethodImpl(Scalar.MaxOpt)] + static void Byte(T* destination, Vector64 source) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((byte*) destination, (Vector64) (object) source); + } +#endif + } + + SByte(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void SByte(T* destination, Vector64 source) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((sbyte*) destination, (Vector64) (object) source); + } +#endif + } + + UInt16(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt16(T* destination, Vector64 source) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((ushort*) destination, (Vector64) (object) source); + } +#endif + } + + Int16(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int16(T* destination, Vector64 source) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((short*) destination, (Vector64) (object) source); + } +#endif + } + + UInt32(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt32(T* destination, Vector64 source) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((uint*) destination, (Vector64) (object) source); + } +#endif + } + + Int32(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int32(T* destination, Vector64 source) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((int*) destination, (Vector64) (object) source); + } +#endif + } + + UInt64(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void UInt64(T* destination, Vector64 source) + { + if (typeof(T) == typeof(ulong)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((ulong*) destination, (Vector64) (object) source); + } +#endif + } + + Int64(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Int64(T* destination, Vector64 source) + { + if (typeof(T) == typeof(long)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((long*) destination, (Vector64) (object) source); + } +#endif + } + + Single(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Single(T* destination, Vector64 source) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((float*) destination, (Vector64) (object) source); + } +#endif + } + + Double(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Double(T* destination, Vector64 source) + { + if (typeof(T) == typeof(double)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + AdvSimd.Store((double*) destination, (Vector64) (object) source); + } +#endif + } + + Other(destination, source); + } + [MethodImpl(Scalar.MaxOpt)] + static void Other(T* destination, Vector64 source) + { + Unsafe.WriteUnaligned>(destination, source); + + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Subtract.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Subtract.cs new file mode 100644 index 0000000000..341e6944eb --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Subtract.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Subtract on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Subtract(Vector64 left, Vector64 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Subtract(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 left, Vector64 right) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Subtract(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd/Simd64.Xor.cs b/src/Maths/Silk.NET.Maths/Simd/Simd64.Xor.cs new file mode 100644 index 0000000000..abf4793220 --- /dev/null +++ b/src/Maths/Silk.NET.Maths/Simd/Simd64.Xor.cs @@ -0,0 +1,144 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +#if INTRINSICS +using System; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +#if SSE +using System.Runtime.Intrinsics.X86; +#endif +#if AdvSIMD +using System.Runtime.Intrinsics.Arm; +#endif + +namespace Silk.NET.Maths +{ + public static unsafe partial class Simd64 + { + /// + /// Performs hardware-accelerated Xor on 64-bit vectors. + /// + [MethodImpl(Scalar.MaxOpt)] + public static Vector64 Xor(Vector64 left, Vector64 right) where T : unmanaged + { + return Byte(left, right); + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Byte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(byte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsByte(), right.AsByte()).As(); + } +#endif + } + + return SByte(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 SByte(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(sbyte)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsSByte(), right.AsSByte()).As(); + } +#endif + } + + return UInt16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(ushort)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsUInt16(), right.AsUInt16()).As(); + } +#endif + } + + return Int16(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int16(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(short)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsInt16(), right.AsInt16()).As(); + } +#endif + } + + return UInt32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 UInt32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(uint)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsUInt32(), right.AsUInt32()).As(); + } +#endif + } + + return Int32(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Int32(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(int)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsInt32(), right.AsInt32()).As(); + } +#endif + } + + return Single(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Single(Vector64 left, Vector64 right) + { + if (typeof(T) == typeof(float)) + { +#if AdvSIMD + if (AdvSimd.IsSupported) + { + return AdvSimd.Xor(left.AsSingle(), right.AsSingle()).As(); + } +#endif + } + + return Other(left, right); + } + [MethodImpl(Scalar.MaxOpt)] + static Vector64 Other(Vector64 left, Vector64 right) + { + var vec = Vector64.Zero; + for (int i = 0; i < Vector64.Count; i++) + { + vec.WithElement(i, Scalar.Xor(left.GetElement(i), right.GetElement(i))); + } + return vec; + } + } + } +} +#endif diff --git a/src/Maths/Silk.NET.Maths/Simd128.cs b/src/Maths/Silk.NET.Maths/Simd128.cs deleted file mode 100644 index 9b9b5054ab..0000000000 --- a/src/Maths/Silk.NET.Maths/Simd128.cs +++ /dev/null @@ -1,1038 +0,0 @@ -// This file is part of Silk.NET. -// -// You may modify and distribute Silk.NET under the terms -// of the MIT license. See the LICENSE file for details. - -#if INTRINSICS -using System; -using System.Runtime.CompilerServices; -using System.Runtime.Intrinsics; -#if SSE -using System.Runtime.Intrinsics.X86; -#endif -#if AdvSIMD -using System.Runtime.Intrinsics.Arm; -#endif - -namespace Silk.NET.Maths -{ - public static unsafe class Simd128 - { - [MethodImpl(Scalar.MaxOpt)] - public static Vector128 Load(T* ptr) where T : unmanaged - { - return Byte(ptr); - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Byte(T* ptr) - { - if (typeof(T) == typeof(byte)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((byte*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((byte*) ptr); - } -#endif - } - - return SByte(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 SByte(T* ptr) - { - if (typeof(T) == typeof(sbyte)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((sbyte*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((sbyte*) ptr); - } -#endif - } - - return UShort(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 UShort(T* ptr) - { - if (typeof(T) == typeof(ushort)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((ushort*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((ushort*) ptr); - } -#endif - } - - return Short(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Short(T* ptr) - { - if (typeof(T) == typeof(short)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((short*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((short*) ptr); - } -#endif - } - - return UInt(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 UInt(T* ptr) - { - if (typeof(T) == typeof(uint)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((uint*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((uint*) ptr); - } -#endif - } - - return Int(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Int(T* ptr) - { - if (typeof(T) == typeof(int)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((int*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((int*) ptr); - } -#endif - } - - return ULong(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 ULong(T* ptr) - { - if (typeof(T) == typeof(ulong)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((ulong*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((ulong*) ptr); - } -#endif - } - - return Long(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Long(T* ptr) - { - if (typeof(T) == typeof(long)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((long*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((long*) ptr); - } -#endif - } - - return Float(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Float(T* ptr) - { - if (typeof(T) == typeof(float)) - { -#if SSE - if (Sse.IsSupported) - { - return (Vector128) (object) Sse.LoadVector128((float*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((float*) ptr); - } -#endif - } - - return Double(ptr); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Double(T* ptr) - { - if (typeof(T) == typeof(double)) - { -#if SSE - if (Sse2.IsSupported) - { - return (Vector128) (object) Sse2.LoadVector128((double*) ptr); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return (Vector128) (object) AdvSimd.LoadVector128((double*) ptr); - } -#endif - } - - return Other(ptr); - } - - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Other(T* ptr) - { - return Unsafe.ReadUnaligned>(ptr); - } - } - - [MethodImpl(Scalar.MaxOpt)] - public static void Store(T* destination, Vector128 source) where T : unmanaged - { - Byte(destination, source); - return; - - [MethodImpl(Scalar.MaxOpt)] - static void Byte(T* destination, Vector128 source) - { - if (typeof(T) == typeof(byte)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((byte*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((byte*) destination, (Vector128) (object) source); - return; - } -#endif - } - - SByte(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void SByte(T* destination, Vector128 source) - { - if (typeof(T) == typeof(sbyte)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((sbyte*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((sbyte*) destination, (Vector128) (object) source); - return; - } -#endif - } - - UShort(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void UShort(T* destination, Vector128 source) - { - if (typeof(T) == typeof(ushort)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((ushort*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((ushort*) destination, (Vector128) (object) source); - return; - } -#endif - } - - Short(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void Short(T* destination, Vector128 source) - { - if (typeof(T) == typeof(short)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((short*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((short*) destination, (Vector128) (object) source); - return; - } -#endif - } - - UInt(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void UInt(T* destination, Vector128 source) - { - if (typeof(T) == typeof(uint)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((uint*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((uint*) destination, (Vector128) (object) source); - return; - } -#endif - } - - Int(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void Int(T* destination, Vector128 source) - { - if (typeof(T) == typeof(int)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((int*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((int*) destination, (Vector128) (object) source); - return; - } -#endif - } - - ULong(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void ULong(T* destination, Vector128 source) - { - if (typeof(T) == typeof(ulong)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((ulong*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((ulong*) destination, (Vector128) (object) source); - return; - } -#endif - } - - Long(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void Long(T* destination, Vector128 source) - { - if (typeof(T) == typeof(long)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((long*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((long*) destination, (Vector128) (object) source); - return; - } -#endif - } - - Float(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void Float(T* destination, Vector128 source) - { - if (typeof(T) == typeof(float)) - { -#if SSE - if (Sse.IsSupported) - { - Sse.Store((float*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((float*) destination, (Vector128) (object) source); - return; - } -#endif - } - - Double(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void Double(T* destination, Vector128 source) - { - if (typeof(T) == typeof(double)) - { -#if SSE - if (Sse2.IsSupported) - { - Sse2.Store((double*) destination, (Vector128) (object) source); - return; - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - AdvSimd.Store((double*) destination, (Vector128) (object) source); - return; - } -#endif - } - - Other(destination, source); - } - - [MethodImpl(Scalar.MaxOpt)] - static void Other(T* dest, Vector128 src) - { - Unsafe.WriteUnaligned(dest, src); - } - } - - [MethodImpl(Scalar.MaxOpt)] - public static Vector128 Create(T value) where T : unmanaged - { - return Byte(value); - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Byte(T value) - { - if (typeof(T) == typeof(byte)) - { - return (Vector128) (object) Vector128.Create((byte) (object) value); - } - - return SByte(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 SByte(T value) - { - if (typeof(T) == typeof(sbyte)) - { - return (Vector128) (object) Vector128.Create((sbyte) (object) value); - } - - return UInt(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 UInt(T value) - { - if (typeof(T) == typeof(uint)) - { - return (Vector128) (object) Vector128.Create((uint) (object) value); - } - - return Int(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Int(T value) - { - if (typeof(T) == typeof(int)) - { - return (Vector128) (object) Vector128.Create((int) (object) value); - } - - return ULong(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 ULong(T value) - { - if (typeof(T) == typeof(ulong)) - { - return (Vector128) (object) Vector128.Create((ulong) (object) value); - } - - return Long(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Long(T value) - { - if (typeof(T) == typeof(long)) - { - return (Vector128) (object) Vector128.Create((long) (object) value); - } - - return Float(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Float(T value) - { - if (typeof(T) == typeof(float)) - { - return (Vector128) (object) Vector128.Create((float) (object) value); - } - - return Double(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Double(T value) - { - if (typeof(T) == typeof(double)) - { - return (Vector128) (object) Vector128.Create((double) (object) value); - } - - return Other(value); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Other(T value) - { - Scalar.ThrowUnsupportedType(); - return default; // unreachable - } - } - - [MethodImpl(Scalar.MaxOpt)] - public static bool AllBitsSet(Vector128 vector) where T : unmanaged - { - return Equal(vector, Vector128.AllBitsSet); - } - - // these two should ONLY be used in the constant-sized unrolled loops. - // unfortunately there is an issue otherwise. See https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA0AXEBDAzgWwB8ABAJgEYBYAKGIAYACY8gOgCUBXAOwwEt8YLAJI8ovLrl5hcAbho1iAZiakGAYRoBvGg11MUDACoxcGABQBKHXu3U99hgDNoDM+IwNeDALwM6MzwYAHgYANRgwDGhyUgAOIMcAGwhsDAA+FjUIbgwA3gBqfKs7B1KAOQgAeQAHNws5Et0AX2tdVv0GCpq3Hk9i+1tS3V5HVzMOdwtAtN8AegAqccn52fDI6LiE5NSMrJyp2dnguDgGbkh8AV6wPAx2oaZyAE5LBvsW6iagA - [MethodImpl(Scalar.MaxOpt)] - private static Vector128 WithElement(Vector128 vector, int index, T value) where T : unmanaged - { - Vector128 result = vector; - ref T e0 = ref Unsafe.As, T>(ref result); - Unsafe.Add(ref e0, index) = value; - return result; - } - - [MethodImpl(Scalar.MaxOpt)] - private static T GetElement(Vector128 vector, int index) where T : unmanaged - { - ref T e0 = ref Unsafe.As, T>(ref vector); - return Unsafe.Add(ref e0, index); - } - - [MethodImpl(Scalar.MaxOpt)] - public static Vector128 Abs(Vector128 vector) where T : unmanaged - { - return Start(vector); - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Start(Vector128 vector) - { - if (typeof(T) == typeof(byte) || typeof(T) == typeof(ushort) || typeof(T) == typeof(uint) || typeof(T) == typeof(ulong)) - return vector; - - return SByte(vector); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 SByte(Vector128 vector) - { - if (typeof(T) == typeof(sbyte)) - { -#if SSE - if (Ssse3.IsSupported) - { - return Ssse3.Abs(vector.AsSByte()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Abs(vector.AsSByte()).As(); - } -#endif - } - - return Short(vector); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Short(Vector128 vector) - { - if (typeof(T) == typeof(short)) - { -#if SSE - if (Ssse3.IsSupported) - { - return Ssse3.Abs(vector.AsInt16()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Abs(vector.AsInt16()).As(); - } -#endif - } - - return Int(vector); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Int(Vector128 vector) - { - if (typeof(T) == typeof(int)) - { -#if SSE - if (Ssse3.IsSupported) - { - return Ssse3.Abs(vector.AsInt32()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Abs(vector.AsInt32()).As(); - } -#endif - } - - return Long(vector); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Long(Vector128 vector) - { - if (typeof(T) == typeof(long)) - { - // no intrinsic available - } - - return Float(vector); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Float(Vector128 vector) - { - if (typeof(T) == typeof(float)) - { -#if SSE - if (Sse.IsSupported) - { - return Sse.And(vector.AsSingle(), Vector128.Create((uint) 0x7FFF_FFFF).AsSingle()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.And(vector.AsSingle(), Vector128.Create((uint) 0x7FFF_FFFF).AsSingle()).As(); - } -#endif - } - - return Double(vector); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Double(Vector128 vector) - { - if (typeof(T) == typeof(double)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.And(vector.AsDouble(), Vector128.Create((ulong) 0x7FFF_FFFF_FFFF_FFF).AsDouble()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.And(vector.AsDouble(), Vector128.Create((ulong) 0x7FFF_FFFF_FFFF_FFF).AsDouble()).As(); - } -#endif - } - - return Other(vector); - } - - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Other(Vector128 vector) - { - for (int i = 0; i < Vector128.Count; i++) - vector = WithElement(vector, i, Scalar.Abs(GetElement(vector, i))); - return vector; - } - } - - [MethodImpl(Scalar.MaxOpt)] - public static Vector128 Acos(Vector128 vector) where T : unmanaged - { - // there are no acos intrinsics. - for (int i = 0; i < Vector128.Count; i++) - vector = WithElement(vector, i, Scalar.Acos(GetElement(vector, i))); - return vector; - } - - [MethodImpl(Scalar.MaxOpt)] - public static Vector128 Acosh(Vector128 vector) where T : unmanaged - { - // there are no acosh intrinsics. - for (int i = 0; i < Vector128.Count; i++) - vector = WithElement(vector, i, Scalar.Acosh(GetElement(vector, i))); - return vector; - } - - [MethodImpl(Scalar.MaxOpt)] - public static Vector128 Asin(Vector128 vector) where T : unmanaged - { - // there are no asin intrinsics. - for (int i = 0; i < Vector128.Count; i++) - vector = WithElement(vector, i, Scalar.Asin(GetElement(vector, i))); - return vector; - } - - - [MethodImpl(Scalar.MaxOpt)] - public static Vector128 Add(Vector128 left, Vector128 right) where T : unmanaged - { - return Byte(left, right); - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Byte(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(byte)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsByte(), right.AsByte()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsByte(), right.AsByte()).As(); - } -#endif - } - - return SByte(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 SByte(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(sbyte)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsSByte(), right.AsSByte()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsSByte(), right.AsSByte()).As(); - } -#endif - } - - return UShort(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 UShort(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(ushort)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsUInt16(), right.AsUInt16()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsUInt16(), right.AsUInt16()).As(); - } -#endif - } - - return Short(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Short(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(short)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsInt16(), right.AsInt16()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsInt16(), right.AsInt16()).As(); - } -#endif - } - - return UInt(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 UInt(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(uint)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsUInt32(), right.AsUInt32()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsUInt32(), right.AsUInt32()).As(); - } -#endif - } - - return Int(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Int(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(int)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsInt32(), right.AsInt32()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsInt32(), right.AsInt32()).As(); - } -#endif - } - - return ULong(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 ULong(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(ulong)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsUInt64(), right.AsUInt64()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsUInt64(), right.AsUInt64()).As(); - } -#endif - } - - return Long(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Long(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(long)) - { -#if SSE - if (Sse2.IsSupported) - { - return Sse2.Add(left.AsInt64(), right.AsInt64()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsInt64(), right.AsInt64()).As(); - } -#endif - } - - return Float(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Float(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(float)) - { -#if SSE - if (Sse.IsSupported) - { - return Sse.Add(left.AsSingle(), right.AsSingle()).As(); - } -#endif -#if AdvSIMD - if (AdvSimd.IsSupported) - { - return AdvSimd.Add(left.AsSingle(), right.AsSingle()).As(); - } -#endif - } - - return Double(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Double(Vector128 left, Vector128 right) - { - if (typeof(T) == typeof(double)) - { -#if SSE - if (Sse.IsSupported) - { - return Sse2.Add(left.AsDouble(), right.AsDouble()).As(); - } -#endif - } - - return Other(left, right); - } - - [MethodImpl(Scalar.MaxOpt)] - static Vector128 Other(Vector128 left, Vector128 right) - { - var vec = Vector128.Zero; - for (int i = 0; i < Vector128.Count; i++) - { - WithElement(vec, i, Scalar.Add(GetElement(left, i), GetElement(right, i))); - } - - return vec; - } - } - } -} -#endif