1 <#@ template debug="true" hostSpecific="true" #>
2 <#@ output extension=".cs" #>
3 <#@ Assembly Name="System.Core.dll" #>
4 <#@ Assembly Name="System.Xml.dll" #>
5 <#@ import namespace="System" #>
6 <#@ import namespace="System.Linq" #>
7 <#@ import namespace="System.Runtime.InteropServices" #>
8 <#@ include file="GenerationConfig.ttinclude" #><# GenerateCopyrightHeader(); #>
10 using System.Diagnostics.CodeAnalysis;
11 using System.Globalization;
12 using System.Runtime.CompilerServices;
13 using System.Runtime.InteropServices;
16 using Internal.Runtime.CompilerServices;
18 #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
20 using nint = System.Int64;
22 using nint = System.Int32;
25 namespace System.Numerics
27 /* Note: The following patterns are used throughout the code here and are described here
30 * if (typeof(T) == typeof(int)) { ... }
31 * else if (typeof(T) == typeof(float)) { ... }
33 * At runtime, each instantiation of Vector<T> will be type-specific, and each of these typeof blocks will be eliminated,
34 * as typeof(T) is a (JIT) compile-time constant for each instantiation. This design was chosen to eliminate any overhead from
35 * delegates and other patterns.
38 * if (Vector.IsHardwareAccelerated) { ... }
41 * This pattern solves two problems:
42 * 1. Allows us to unroll loops when we know the size (when no hardware acceleration is present)
43 * 2. Allows reflection to work:
44 * - If a method is called via reflection, it will not be "intrinsified", which would cause issues if we did
45 * not provide an implementation for that case (i.e. if it only included a case which assumed 16-byte registers)
46 * (NOTE: It is assumed that Vector.IsHardwareAccelerated will be a compile-time constant, eliminating these checks
47 * from the JIT'd code.)
49 * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
52 /// A structure that represents a single Vector. The count of this Vector is fixed but CPU register dependent.
53 /// This struct only supports numerical types. This type is intended to be used as a building block for vectorizing
54 /// large algorithms. This type is immutable, individual elements cannot be modified.
57 public struct Vector<T> : IEquatable<Vector<T>>, IFormattable where T : struct
60 private Register register;
63 #region Static Members
65 /// Returns the number of elements stored in the vector. This value is hardware dependent.
67 public static int Count
72 ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
73 return Unsafe.SizeOf<Vector<T>>() / Unsafe.SizeOf<T>();
78 /// Returns a vector containing all zeroes.
80 public static Vector<T> Zero
85 private static readonly Vector<T> s_zero = new Vector<T>();
88 /// Returns a vector containing all ones.
90 public static Vector<T> One
95 private static readonly Vector<T> s_one = new Vector<T>(GetOneValue());
97 internal static Vector<T> AllOnes
102 private static readonly Vector<T> s_allOnes = new Vector<T>(GetAllBitsSetValue());
103 #endregion Static Members
107 /// Constructs a vector whose components are all <code>value</code>
110 public unsafe Vector(T value)
113 if (Vector.IsHardwareAccelerated)
116 foreach (Type type in supportedTypes)
119 <#=GenerateIfStatementHeader(type)#>
121 fixed (<#=typeAliases[type]#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>)
123 for (nint g = 0; g < Count; g++)
125 *(basePtr + g) = (<#=typeAliases[type]#>)(object)value;
136 foreach (Type type in supportedTypes)
139 <#=GenerateIfStatementHeader(type)#>
142 for (int g = 0; g < totalSize / Marshal.SizeOf(type); g++)
145 <#=GetRegisterFieldName(type, g)#> = (<#=typeAliases[type]#>)(object)value;
157 /// Constructs a vector from the given array. The size of the given array must be at least Vector'T.Count.
160 public unsafe Vector(T[] values) : this(values, 0) { }
163 /// Constructs a vector from the given array, starting from the given index.
164 /// The array must contain at least Vector'T.Count from the given index.
167 public unsafe Vector(T[] values, int index)
171 // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
172 throw new NullReferenceException(SR.Arg_NullArgumentNullRef);
174 if (index < 0 || (values.Length - index) < Count)
176 Vector.ThrowInsufficientNumberOfElementsException(Vector<T>.Count);
178 this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref values[index]));
181 internal unsafe Vector(void* dataPointer)
183 ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
184 this = Unsafe.ReadUnaligned<Vector<T>>(dataPointer);
187 private Vector(ref Register existingRegister)
189 this.register = existingRegister;
193 /// Constructs a vector from the given <see cref="ReadOnlySpan{Byte}"/>. The span must contain at least <see cref="Vector{Byte}.Count"/> elements.
195 [MethodImpl(MethodImplOptions.AggressiveInlining)]
196 public Vector(ReadOnlySpan<byte> values)
198 ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
199 if (values.Length < Vector<byte>.Count)
201 Vector.ThrowInsufficientNumberOfElementsException(Vector<byte>.Count);
203 this = Unsafe.ReadUnaligned<Vector<T>>(ref MemoryMarshal.GetReference(values));
207 /// Constructs a vector from the given <see cref="ReadOnlySpan{T}"/>. The span must contain at least <see cref="Vector{T}.Count"/> elements.
209 [MethodImpl(MethodImplOptions.AggressiveInlining)]
210 public Vector(ReadOnlySpan<T> values)
212 if (values.Length < Count)
214 Vector.ThrowInsufficientNumberOfElementsException(Vector<T>.Count);
216 this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)));
220 /// Constructs a vector from the given <see cref="Span{T}"/>. The span must contain at least <see cref="Vector{T}.Count"/> elements.
222 [MethodImpl(MethodImplOptions.AggressiveInlining)]
223 public Vector(Span<T> values)
225 if (values.Length < Count)
227 Vector.ThrowInsufficientNumberOfElementsException(Vector<T>.Count);
229 this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)));
231 #endregion Constructors
233 #region Public Instance Methods
235 /// Copies the vector to the given <see cref="Span{Byte}"/>. The destination span must be at least size <see cref="Vector{Byte}.Count"/>.
237 /// <param name="destination">The destination span which the values are copied into</param>
238 /// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination span</exception>
239 public readonly void CopyTo(Span<byte> destination)
241 ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
242 if ((uint)destination.Length < (uint)Vector<byte>.Count)
244 ThrowHelper.ThrowArgumentException_DestinationTooShort();
247 Unsafe.WriteUnaligned<Vector<T>>(ref MemoryMarshal.GetReference(destination), this);
251 /// Copies the vector to the given <see cref="Span{T}"/>. The destination span must be at least size <see cref="Vector{T}.Count"/>.
253 /// <param name="destination">The destination span which the values are copied into</param>
254 /// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination span</exception>
255 public readonly void CopyTo(Span<T> destination)
257 if ((uint)destination.Length < (uint)Count)
259 ThrowHelper.ThrowArgumentException_DestinationTooShort();
262 Unsafe.WriteUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(destination)), this);
266 /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count.
268 /// <param name="destination">The destination array which the values are copied into</param>
269 /// <exception cref="ArgumentNullException">If the destination array is null</exception>
270 /// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array</exception>
272 public readonly void CopyTo(T[] destination)
274 CopyTo(destination, 0);
278 /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count.
280 /// <param name="destination">The destination array which the values are copied into</param>
281 /// <param name="startIndex">The index to start copying to</param>
282 /// <exception cref="ArgumentNullException">If the destination array is null</exception>
283 /// <exception cref="ArgumentOutOfRangeException">If index is greater than end of the array or index is less than zero</exception>
284 /// <exception cref="ArgumentException">If number of elements in source vector is greater than those available in destination array</exception>
286 public readonly unsafe void CopyTo(T[] destination, int startIndex)
288 if (destination == null)
290 // Match the JIT's exception type here. For perf, a NullReference is thrown instead of an ArgumentNull.
291 throw new NullReferenceException(SR.Arg_NullArgumentNullRef);
293 if ((uint)startIndex >= (uint)destination.Length)
295 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.Format(SR.Arg_ArgumentOutOfRangeException, startIndex));
297 if ((destination.Length - startIndex) < Count)
299 throw new ArgumentException(SR.Format(SR.Arg_ElementsInSourceIsGreaterThanDestination, startIndex));
302 Unsafe.WriteUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref destination[startIndex]), this);
306 /// Returns the element at the given index.
308 public readonly unsafe T this[int index]
313 if ((uint)index >= (uint)Count)
315 throw new IndexOutOfRangeException(SR.Format(SR.Arg_ArgumentOutOfRangeException, index));
318 return Unsafe.Add(ref Unsafe.As<Vector<T>, T>(ref Unsafe.AsRef<Vector<T>>(in this)), index);
323 /// Returns a boolean indicating whether the given Object is equal to this vector instance.
325 /// <param name="obj">The Object to compare against.</param>
326 /// <returns>True if the Object is equal to this vector; False otherwise.</returns>
327 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
328 public override readonly bool Equals(object? obj)
330 if (!(obj is Vector<T>))
334 return Equals((Vector<T>)obj);
338 /// Returns a boolean indicating whether the given vector is equal to this vector instance.
340 /// <param name="other">The vector to compare this instance to.</param>
341 /// <returns>True if the other vector is equal to this instance; False otherwise.</returns>
343 public readonly bool Equals(Vector<T> other)
345 if (Vector.IsHardwareAccelerated)
347 for (int g = 0; g < Count; g++)
349 if (!ScalarEquals(this[g], other[g]))
359 foreach (Type type in supportedTypes)
362 <#=GenerateIfStatementHeader(type)#>
366 for (int g = 0; g < GetNumFields(type, totalSize); g++)
373 this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#>
379 && this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#><#=(g == (GetNumFields(type, totalSize) -1)) ? ";" : ""#>
392 throw new NotSupportedException(SR.Arg_TypeNotSupported);
398 /// Returns the hash code for this instance.
400 /// <returns>The hash code.</returns>
401 public override readonly int GetHashCode()
403 HashCode hashCode = new HashCode();
405 if (typeof(T) == typeof(byte) ||
406 typeof(T) == typeof(sbyte) ||
407 typeof(T) == typeof(ushort) ||
408 typeof(T) == typeof(short) ||
409 typeof(T) == typeof(int) ||
410 typeof(T) == typeof(uint) ||
411 typeof(T) == typeof(long) ||
412 typeof(T) == typeof(ulong))
414 for (nint g = 0; g < Vector<int>.Count; g++)
416 hashCode.Add(Unsafe.Add(ref Unsafe.As<Vector<T>, int>(ref Unsafe.AsRef<Vector<T>>(in this)), (IntPtr)g));
419 else if (typeof(T) == typeof(float))
421 for (nint g = 0; g < Count; g++)
423 hashCode.Add(Unsafe.Add(ref Unsafe.As<Vector<T>, float>(ref Unsafe.AsRef<Vector<T>>(in this)), (IntPtr)g));
426 else if (typeof(T) == typeof(double))
428 for (nint g = 0; g < Count; g++)
430 hashCode.Add(Unsafe.Add(ref Unsafe.As<Vector<T>, double>(ref Unsafe.AsRef<Vector<T>>(in this)), (IntPtr)g));
435 throw new NotSupportedException(SR.Arg_TypeNotSupported);
438 return hashCode.ToHashCode();
442 /// Returns a String representing this vector.
444 /// <returns>The string representation.</returns>
445 public override readonly string ToString()
447 return ToString("G", CultureInfo.CurrentCulture);
451 /// Returns a String representing this vector, using the specified format string to format individual elements.
453 /// <param name="format">The format of individual elements.</param>
454 /// <returns>The string representation.</returns>
455 public readonly string ToString(string? format)
457 return ToString(format, CultureInfo.CurrentCulture);
461 /// Returns a String representing this vector, using the specified format string to format individual elements
462 /// and the given IFormatProvider.
464 /// <param name="format">The format of individual elements.</param>
465 /// <param name="formatProvider">The format provider to use when formatting elements.</param>
466 /// <returns>The string representation.</returns>
467 public readonly string ToString(string? format, IFormatProvider? formatProvider)
469 StringBuilder sb = new StringBuilder();
470 string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
472 for (int g = 0; g < Count - 1; g++)
474 sb.Append(((IFormattable)this[g]).ToString(format, formatProvider));
475 sb.Append(separator);
478 // Append last element w/out separator
479 sb.Append(((IFormattable)this[Count - 1]).ToString(format, formatProvider));
481 return sb.ToString();
485 /// Attempts to copy the vector to the given <see cref="Span{Byte}"/>. The destination span must be at least size <see cref="Vector{Byte}.Count"/>.
487 /// <param name="destination">The destination span which the values are copied into</param>
488 /// <returns>True if the source vector was successfully copied to <paramref name="destination"/>. False if
489 /// <paramref name="destination"/> is not large enough to hold the source vector.</returns>
490 public readonly bool TryCopyTo(Span<byte> destination)
492 ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
493 if ((uint)destination.Length < (uint)Vector<byte>.Count)
498 Unsafe.WriteUnaligned<Vector<T>>(ref MemoryMarshal.GetReference(destination), this);
503 /// Attempts to copy the vector to the given <see cref="Span{T}"/>. The destination span must be at least size <see cref="Vector{T}.Count"/>.
505 /// <param name="destination">The destination span which the values are copied into</param>
506 /// <returns>True if the source vector was successfully copied to <paramref name="destination"/>. False if
507 /// <paramref name="destination"/> is not large enough to hold the source vector.</returns>
508 public readonly bool TryCopyTo(Span<T> destination)
510 if ((uint)destination.Length < (uint)Count)
515 Unsafe.WriteUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(destination)), this);
518 #endregion Public Instance Methods
520 #region Arithmetic Operators
522 /// Adds two vectors together.
524 /// <param name="left">The first source vector.</param>
525 /// <param name="right">The second source vector.</param>
526 /// <returns>The summed vector.</returns>
528 public static unsafe Vector<T> operator +(Vector<T> left, Vector<T> right)
532 if (Vector.IsHardwareAccelerated)
535 foreach (Type type in supportedTypes)
538 <#=GenerateIfStatementHeader(type)#>
540 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
541 for (int g = 0; g < Count; g++)
543 dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarAdd(left[g], right[g]);
545 return new Vector<T>(dataPtr);
552 throw new NotSupportedException(SR.Arg_TypeNotSupported);
557 Vector<T> sum = new Vector<T>();
559 foreach (Type type in supportedTypes)
562 <#=GenerateIfStatementHeader(type)#>
565 for (int g = 0; g < GetNumFields(type, totalSize); g++)
568 sum.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> + right.<#= GetRegisterFieldName(type, g) #>);
582 /// Subtracts the second vector from the first.
584 /// <param name="left">The first source vector.</param>
585 /// <param name="right">The second source vector.</param>
586 /// <returns>The difference vector.</returns>
588 public static unsafe Vector<T> operator -(Vector<T> left, Vector<T> right)
592 if (Vector.IsHardwareAccelerated)
595 foreach (Type type in supportedTypes)
598 <#=GenerateIfStatementHeader(type)#>
600 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
601 for (int g = 0; g < Count; g++)
603 dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarSubtract(left[g], right[g]);
605 return new Vector<T>(dataPtr);
612 throw new NotSupportedException(SR.Arg_TypeNotSupported);
617 Vector<T> difference = new Vector<T>();
619 foreach (Type type in supportedTypes)
622 <#=GenerateIfStatementHeader(type)#>
625 for (int g = 0; g < GetNumFields(type, totalSize); g++)
628 difference.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> - right.<#= GetRegisterFieldName(type, g) #>);
641 // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated.
643 /// Multiplies two vectors together.
645 /// <param name="left">The first source vector.</param>
646 /// <param name="right">The second source vector.</param>
647 /// <returns>The product vector.</returns>
649 public static unsafe Vector<T> operator *(Vector<T> left, Vector<T> right)
653 if (Vector.IsHardwareAccelerated)
656 foreach (Type type in supportedTypes)
659 <#=GenerateIfStatementHeader(type)#>
661 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
662 for (int g = 0; g < Count; g++)
664 dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarMultiply(left[g], right[g]);
666 return new Vector<T>(dataPtr);
673 throw new NotSupportedException(SR.Arg_TypeNotSupported);
678 Vector<T> product = new Vector<T>();
680 foreach (Type type in supportedTypes)
683 <#=GenerateIfStatementHeader(type)#>
686 for (int g = 0; g < GetNumFields(type, totalSize); g++)
689 product.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> * right.<#= GetRegisterFieldName(type, g) #>);
703 /// Multiplies a vector by the given scalar.
705 /// <param name="value">The source vector.</param>
706 /// <param name="factor">The scalar value.</param>
707 /// <returns>The scaled vector.</returns>
708 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
709 public static Vector<T> operator *(Vector<T> value, T factor) =>
710 new Vector<T>(factor) * value;
713 /// Multiplies a vector by the given scalar.
715 /// <param name="factor">The scalar value.</param>
716 /// <param name="value">The source vector.</param>
717 /// <returns>The scaled vector.</returns>
718 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
719 public static Vector<T> operator *(T factor, Vector<T> value) =>
720 new Vector<T>(factor) * value;
722 // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated.
724 /// Divides the first vector by the second.
726 /// <param name="left">The first source vector.</param>
727 /// <param name="right">The second source vector.</param>
728 /// <returns>The vector resulting from the division.</returns>
730 public static unsafe Vector<T> operator /(Vector<T> left, Vector<T> right)
734 if (Vector.IsHardwareAccelerated)
737 foreach (Type type in supportedTypes)
740 <#=GenerateIfStatementHeader(type)#>
742 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
743 for (int g = 0; g < Count; g++)
745 dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarDivide(left[g], right[g]);
747 return new Vector<T>(dataPtr);
754 throw new NotSupportedException(SR.Arg_TypeNotSupported);
759 Vector<T> quotient = new Vector<T>();
761 foreach (Type type in supportedTypes)
764 <#=GenerateIfStatementHeader(type)#>
767 for (int g = 0; g < GetNumFields(type, totalSize); g++)
770 quotient.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> / right.<#= GetRegisterFieldName(type, g) #>);
784 /// Negates a given vector.
786 /// <param name="value">The source vector.</param>
787 /// <returns>The negated vector.</returns>
788 public static Vector<T> operator -(Vector<T> value) => Zero - value;
789 #endregion Arithmetic Operators
791 #region Bitwise Operators
793 /// Returns a new vector by performing a bitwise-and operation on each of the elements in the given vectors.
795 /// <param name="left">The first source vector.</param>
796 /// <param name="right">The second source vector.</param>
797 /// <returns>The resultant vector.</returns>
799 public static unsafe Vector<T> operator &(Vector<T> left, Vector<T> right)
801 Vector<T> result = new Vector<T>();
804 if (Vector.IsHardwareAccelerated)
806 long* resultBase = &result.register.int64_0;
807 long* leftBase = &left.register.int64_0;
808 long* rightBase = &right.register.int64_0;
809 for (int g = 0; g < Vector<long>.Count; g++)
811 resultBase[g] = leftBase[g] & rightBase[g];
816 result.<#=GetRegisterFieldName(typeof(long), 0)#> = left.<#=GetRegisterFieldName(typeof(long), 0)#> & right.<#=GetRegisterFieldName(typeof(long), 0)#>;
817 result.<#=GetRegisterFieldName(typeof(long), 1)#> = left.<#=GetRegisterFieldName(typeof(long), 1)#> & right.<#=GetRegisterFieldName(typeof(long), 1)#>;
824 /// Returns a new vector by performing a bitwise-or operation on each of the elements in the given vectors.
826 /// <param name="left">The first source vector.</param>
827 /// <param name="right">The second source vector.</param>
828 /// <returns>The resultant vector.</returns>
830 public static unsafe Vector<T> operator |(Vector<T> left, Vector<T> right)
832 Vector<T> result = new Vector<T>();
835 if (Vector.IsHardwareAccelerated)
837 long* resultBase = &result.register.int64_0;
838 long* leftBase = &left.register.int64_0;
839 long* rightBase = &right.register.int64_0;
840 for (int g = 0; g < Vector<long>.Count; g++)
842 resultBase[g] = leftBase[g] | rightBase[g];
847 result.<#=GetRegisterFieldName(typeof(long), 0)#> = left.<#=GetRegisterFieldName(typeof(long), 0)#> | right.<#=GetRegisterFieldName(typeof(long), 0)#>;
848 result.<#=GetRegisterFieldName(typeof(long), 1)#> = left.<#=GetRegisterFieldName(typeof(long), 1)#> | right.<#=GetRegisterFieldName(typeof(long), 1)#>;
855 /// Returns a new vector by performing a bitwise-exclusive-or operation on each of the elements in the given vectors.
857 /// <param name="left">The first source vector.</param>
858 /// <param name="right">The second source vector.</param>
859 /// <returns>The resultant vector.</returns>
861 public static unsafe Vector<T> operator ^(Vector<T> left, Vector<T> right)
863 Vector<T> result = new Vector<T>();
866 if (Vector.IsHardwareAccelerated)
868 long* resultBase = &result.register.int64_0;
869 long* leftBase = &left.register.int64_0;
870 long* rightBase = &right.register.int64_0;
871 for (int g = 0; g < Vector<long>.Count; g++)
873 resultBase[g] = leftBase[g] ^ rightBase[g];
878 result.<#=GetRegisterFieldName(typeof(long), 0)#> = left.<#=GetRegisterFieldName(typeof(long), 0)#> ^ right.<#=GetRegisterFieldName(typeof(long), 0)#>;
879 result.<#=GetRegisterFieldName(typeof(long), 1)#> = left.<#=GetRegisterFieldName(typeof(long), 1)#> ^ right.<#=GetRegisterFieldName(typeof(long), 1)#>;
886 /// Returns a new vector whose elements are obtained by taking the one's complement of the given vector's elements.
888 /// <param name="value">The source vector.</param>
889 /// <returns>The one's complement vector.</returns>
890 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
891 public static Vector<T> operator ~(Vector<T> value) =>
893 #endregion Bitwise Operators
895 #region Logical Operators
897 /// Returns a boolean indicating whether each pair of elements in the given vectors are equal.
899 /// <param name="left">The first vector to compare.</param>
900 /// <param name="right">The first vector to compare.</param>
901 /// <returns>True if all elements are equal; False otherwise.</returns>
903 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
904 public static bool operator ==(Vector<T> left, Vector<T> right) =>
908 /// Returns a boolean indicating whether any single pair of elements in the given vectors are not equal.
910 /// <param name="left">The first vector to compare.</param>
911 /// <param name="right">The second vector to compare.</param>
912 /// <returns>True if left and right are not equal; False otherwise.</returns>
914 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
915 public static bool operator !=(Vector<T> left, Vector<T> right) => !(left == right);
916 #endregion Logical Operators
920 foreach (Type type in supportedTypes)
924 /// Reinterprets the bits of the given vector into those of another type.
926 /// <param name="value">The source vector</param>
927 /// <returns>The reinterpreted vector.</returns>
929 if (nonClsCompliantTypes.Contains(type))
932 [CLSCompliant(false)]
937 public static explicit operator Vector<<#=typeAliases[type]#>>(Vector<T> value) =>
938 new Vector<<#=typeAliases[type]#>>(ref value.register);
943 #endregion Conversions
945 #region Internal Comparison Methods
947 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
948 internal static unsafe Vector<T> Equals(Vector<T> left, Vector<T> right)
950 if (Vector.IsHardwareAccelerated)
953 foreach (Type type in supportedTypes)
956 <#=GenerateIfStatementHeader(type)#>
958 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
959 for (int g = 0; g < Count; g++)
961 dataPtr[g] = ScalarEquals(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
963 return new Vector<T>(dataPtr);
970 throw new NotSupportedException(SR.Arg_TypeNotSupported);
975 Register register = new Register();
977 foreach (Type type in supportedTypes)
980 <#=GenerateIfStatementHeader(type)#>
983 for (int g = 0; g < GetNumFields(type, totalSize); g++)
986 <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> == right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
990 return new Vector<T>(ref register);
997 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1003 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1004 internal static unsafe Vector<T> LessThan(Vector<T> left, Vector<T> right)
1006 if (Vector.IsHardwareAccelerated)
1009 foreach (Type type in supportedTypes)
1012 <#=GenerateIfStatementHeader(type)#>
1014 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1015 for (int g = 0; g < Count; g++)
1017 dataPtr[g] = ScalarLessThan(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1019 return new Vector<T>(dataPtr);
1026 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1031 Register register = new Register();
1033 foreach (Type type in supportedTypes)
1036 <#=GenerateIfStatementHeader(type)#>
1039 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1042 <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> < right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1046 return new Vector<T>(ref register);
1053 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1059 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1060 internal static unsafe Vector<T> GreaterThan(Vector<T> left, Vector<T> right)
1062 if (Vector.IsHardwareAccelerated)
1065 foreach (Type type in supportedTypes)
1068 <#=GenerateIfStatementHeader(type)#>
1070 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1071 for (int g = 0; g < Count; g++)
1073 dataPtr[g] = ScalarGreaterThan(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1075 return new Vector<T>(dataPtr);
1082 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1087 Register register = new Register();
1089 foreach (Type type in supportedTypes)
1092 <#=GenerateIfStatementHeader(type)#>
1095 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1098 <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> > right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1102 return new Vector<T>(ref register);
1109 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1115 internal static Vector<T> GreaterThanOrEqual(Vector<T> left, Vector<T> right)
1117 return Equals(left, right) | GreaterThan(left, right);
1121 internal static Vector<T> LessThanOrEqual(Vector<T> left, Vector<T> right)
1123 return Equals(left, right) | LessThan(left, right);
1127 internal static Vector<T> ConditionalSelect(Vector<T> condition, Vector<T> left, Vector<T> right)
1129 return (left & condition) | (Vector.AndNot(right, condition));
1131 #endregion Comparison Methods
1133 #region Internal Math Methods
1135 internal static unsafe Vector<T> Abs(Vector<T> value)
1138 foreach (Type type in supportedTypes)
1140 if (unsignedTypes.Contains(type))
1143 <#=GenerateIfStatementHeader(type, unsignedTypes)#>
1151 if (Vector.IsHardwareAccelerated)
1154 foreach (Type type in supportedTypes.Except(unsignedTypes))
1157 <#=GenerateIfStatementHeader(type, supportedTypes.Except(unsignedTypes))#>
1159 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1160 for (int g = 0; g < Count; g++)
1162 dataPtr[g] = (<#=typeAliases[type]#>)(object)(Math.Abs((<#=typeAliases[type]#>)(object)value[g]));
1164 return new Vector<T>(dataPtr);
1171 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1177 foreach (Type type in supportedTypes.Except(unsignedTypes))
1180 <#=GenerateIfStatementHeader(type, supportedTypes.Except(unsignedTypes))#>
1183 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1186 value.<#=GetRegisterFieldName(type, g)#> = (<#=typeAliases[type]#>)(Math.Abs(value.<#=GetRegisterFieldName(type, g)#>));
1197 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1203 internal static unsafe Vector<T> Min(Vector<T> left, Vector<T> right)
1205 if (Vector.IsHardwareAccelerated)
1208 foreach (Type type in supportedTypes)
1211 <#=GenerateIfStatementHeader(type)#>
1213 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1214 for (int g = 0; g < Count; g++)
1216 dataPtr[g] = ScalarLessThan(left[g], right[g]) ? (<#=typeAliases[type]#>)(object)left[g] : (<#=typeAliases[type]#>)(object)right[g];
1218 return new Vector<T>(dataPtr);
1225 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1230 Vector<T> vec = new Vector<T>();
1232 foreach (Type type in supportedTypes)
1235 <#=GenerateIfStatementHeader(type)#>
1238 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1241 vec.<#=GetRegisterFieldName(type, g)#> = left.<#=GetRegisterFieldName(type, g)#> < right.<#=GetRegisterFieldName(type, g)#> ? left.<#=GetRegisterFieldName(type, g)#> : right.<#=GetRegisterFieldName(type, g)#>;
1252 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1258 internal static unsafe Vector<T> Max(Vector<T> left, Vector<T> right)
1260 if (Vector.IsHardwareAccelerated)
1263 foreach (Type type in supportedTypes)
1266 <#=GenerateIfStatementHeader(type)#>
1268 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1269 for (int g = 0; g < Count; g++)
1271 dataPtr[g] = ScalarGreaterThan(left[g], right[g]) ? (<#=typeAliases[type]#>)(object)left[g] : (<#=typeAliases[type]#>)(object)right[g];
1273 return new Vector<T>(dataPtr);
1280 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1285 Vector<T> vec = new Vector<T>();
1287 foreach (Type type in supportedTypes)
1290 <#=GenerateIfStatementHeader(type)#>
1293 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1296 vec.<#=GetRegisterFieldName(type, g)#> = left.<#=GetRegisterFieldName(type, g)#> > right.<#=GetRegisterFieldName(type, g)#> ? left.<#=GetRegisterFieldName(type, g)#> : right.<#=GetRegisterFieldName(type, g)#>;
1307 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1313 internal static T Dot(Vector<T> left, Vector<T> right)
1315 if (Vector.IsHardwareAccelerated)
1317 T product = default;
1318 for (int g = 0; g < Count; g++)
1320 product = ScalarAdd(product, ScalarMultiply(left[g], right[g]));
1327 foreach (Type type in supportedTypes)
1330 <#=GenerateIfStatementHeader(type)#>
1332 <#=typeAliases[type]#> product = 0;
1334 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1337 product += (<#=typeAliases[type]#>)(left.<#=GetRegisterFieldName(type, g)#> * right.<#=GetRegisterFieldName(type, g)#>);
1341 return (T)(object)product;
1348 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1354 internal static unsafe Vector<T> SquareRoot(Vector<T> value)
1356 if (Vector.IsHardwareAccelerated)
1359 foreach (Type type in supportedTypes)
1362 <#=GenerateIfStatementHeader(type)#>
1364 <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1365 for (int g = 0; g < Count; g++)
1367 dataPtr[g] = unchecked((<#=typeAliases[type]#>)Math.Sqrt((<#=typeAliases[type]#>)(object)value[g]));
1369 return new Vector<T>(dataPtr);
1376 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1382 foreach (Type type in supportedTypes)
1385 <#=GenerateIfStatementHeader(type)#>
1388 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1391 value.<#=GetRegisterFieldName(type, g)#> = (<#=typeAliases[type]#>)Math.Sqrt(value.<#=GetRegisterFieldName(type, g)#>);
1402 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1406 #endregion Internal Math Methods
1408 #region Helper Methods
1409 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1410 private static bool ScalarEquals(T left, T right)
1413 foreach (Type type in supportedTypes)
1416 <#=GenerateIfStatementHeader(type)#>
1418 return (<#=typeAliases[type]#>)(object)left == (<#=typeAliases[type]#>)(object)right;
1425 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1429 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1430 private static bool ScalarLessThan(T left, T right)
1433 foreach (Type type in supportedTypes)
1436 <#=GenerateIfStatementHeader(type)#>
1438 return (<#=typeAliases[type]#>)(object)left < (<#=typeAliases[type]#>)(object)right;
1445 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1449 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1450 private static bool ScalarGreaterThan(T left, T right)
1453 foreach (Type type in supportedTypes)
1456 <#=GenerateIfStatementHeader(type)#>
1458 return (<#=typeAliases[type]#>)(object)left > (<#=typeAliases[type]#>)(object)right;
1465 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1469 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1470 private static T ScalarAdd(T left, T right)
1473 foreach (Type type in supportedTypes)
1476 <#=GenerateIfStatementHeader(type)#>
1478 return (T)(object)unchecked((<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left + (<#=typeAliases[type]#>)(object)right));
1485 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1489 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1490 private static T ScalarSubtract(T left, T right)
1493 foreach (Type type in supportedTypes)
1496 <#=GenerateIfStatementHeader(type)#>
1498 return (T)(object)(<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left - (<#=typeAliases[type]#>)(object)right);
1505 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1509 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1510 private static T ScalarMultiply(T left, T right)
1513 foreach (Type type in supportedTypes)
1516 <#=GenerateIfStatementHeader(type)#>
1518 return (T)(object)unchecked((<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left * (<#=typeAliases[type]#>)(object)right));
1525 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1529 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1530 private static T ScalarDivide(T left, T right)
1533 foreach (Type type in supportedTypes)
1536 <#=GenerateIfStatementHeader(type)#>
1538 return (T)(object)(<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left / (<#=typeAliases[type]#>)(object)right);
1545 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1549 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1550 private static T GetOneValue()
1553 foreach (Type type in supportedTypes)
1556 <#=GenerateIfStatementHeader(type)#>
1558 <#=typeAliases[type]#> value = 1;
1559 return (T)(object)value;
1566 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1570 [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1571 private static T GetAllBitsSetValue()
1574 foreach (Type type in supportedTypes)
1577 <#=GenerateIfStatementHeader(type)#>
1579 return (T)(object)ConstantHelper.Get<#=type.Name#>WithAllBitsSet();
1586 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1593 public static partial class Vector
1595 #region Widen/Narrow
1597 foreach (Type type in WidenableTypes)
1599 Type widenTarget = GetWidenTarget(type);
1602 /// Widens a Vector{<#=type.Name#>} into two Vector{<#=widenTarget.Name#>}'s.
1603 /// <param name="source">The source vector whose elements are widened into the outputs.</param>
1604 /// <param name="low">The first output vector, whose elements will contain the widened elements from lower indices in the source vector.</param>
1605 /// <param name="high">The second output vector, whose elements will contain the widened elements from higher indices in the source vector.</param>
1608 if (nonClsCompliantTypes.Contains(type) || nonClsCompliantTypes.Contains(widenTarget))
1611 [CLSCompliant(false)]
1616 public static unsafe void Widen(Vector<<#=typeAliases[type]#>> source, out Vector<<#=typeAliases[widenTarget]#>> low, out Vector<<#=typeAliases[widenTarget]#>> high)
1618 int elements = Vector<<#=typeAliases[type]#>>.Count;
1619 <#=typeAliases[widenTarget]#>* lowPtr = stackalloc <#=typeAliases[widenTarget]#>[elements / 2];
1620 for (int i = 0; i < elements / 2; i++)
1622 lowPtr[i] = (<#=typeAliases[widenTarget]#>)source[i];
1624 <#=typeAliases[widenTarget]#>* highPtr = stackalloc <#=typeAliases[widenTarget]#>[elements / 2];
1625 for (int i = 0; i < elements / 2; i++)
1627 highPtr[i] = (<#=typeAliases[widenTarget]#>)source[i + (elements / 2)];
1630 low = new Vector<<#=typeAliases[widenTarget]#>>(lowPtr);
1631 high = new Vector<<#=typeAliases[widenTarget]#>>(highPtr);
1637 foreach (Type narrowSource in NarrowableTypes)
1639 Type narrowTarget = GetNarrowTarget(narrowSource);
1642 /// Narrows two Vector{<#=narrowSource.Name#>}'s into one Vector{<#=narrowTarget.Name#>}.
1643 /// <param name="low">The first source vector, whose elements become the lower-index elements of the return value.</param>
1644 /// <param name="high">The second source vector, whose elements become the higher-index elements of the return value.</param>
1645 /// <returns>A Vector{<#=narrowTarget.Name#>} containing elements narrowed from the source vectors.</returns>
1648 if (nonClsCompliantTypes.Contains(narrowSource) || nonClsCompliantTypes.Contains(narrowTarget))
1651 [CLSCompliant(false)]
1656 public static unsafe Vector<<#=typeAliases[narrowTarget]#>> Narrow(Vector<<#=typeAliases[narrowSource]#>> low, Vector<<#=typeAliases[narrowSource]#>> high)
1660 int elements = Vector<<#=typeAliases[narrowTarget]#>>.Count;
1661 <#=typeAliases[narrowTarget]#>* retPtr = stackalloc <#=typeAliases[narrowTarget]#>[elements];
1662 for (int i = 0; i < elements / 2; i++)
1664 retPtr[i] = (<#=typeAliases[narrowTarget]#>)low[i];
1666 for (int i = 0; i < elements / 2; i++)
1668 retPtr[i + (elements / 2)] = (<#=typeAliases[narrowTarget]#>)high[i];
1671 return new Vector<<#=typeAliases[narrowTarget]#>>(retPtr);
1678 #endregion Widen/Narrow
1680 #region Same-Size Conversion
1682 foreach (var pair in SameSizeConversionPairs)
1686 /// Converts a Vector{<#=pair.Key.Name#>} to a Vector{<#=pair.Value.Name#>}.
1688 /// <param name="value">The source vector.</param>
1689 /// <returns>The converted vector.</returns>
1691 if (nonClsCompliantTypes.Contains(pair.Key) || nonClsCompliantTypes.Contains(pair.Value))
1694 [CLSCompliant(false)]
1699 public static unsafe Vector<<#=typeAliases[pair.Value]#>> ConvertTo<#=pair.Value.Name#>(Vector<<#=typeAliases[pair.Key]#>> value)
1703 int elements = Vector<<#=typeAliases[pair.Value]#>>.Count;
1704 <#=typeAliases[pair.Value]#>* retPtr = stackalloc <#=typeAliases[pair.Value]#>[elements];
1705 for (int i = 0; i < elements; i++)
1707 retPtr[i] = (<#=typeAliases[pair.Value]#>)value[i];
1710 return new Vector<<#=typeAliases[pair.Value]#>>(retPtr);
1717 #endregion Same-Size Conversion
1719 #region Throw Helpers
1721 internal static void ThrowInsufficientNumberOfElementsException(int requiredElementCount)
1723 throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, requiredElementCount, "values"));