Change Vector<T> to use more compact code using S.R.CS.Unsafe (#26637)
[mono-project.git] / netcore / System.Private.CoreLib / shared / System / Numerics / Vector.tt
blob3d75adbfe3f0a6e1ce2ceef2b5c7b5b4d9af5e00
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;
14 using System.Text;
16 using Internal.Runtime.CompilerServices;
18 #pragma warning disable SA1121 // explicitly using type aliases instead of built-in types
19 #if BIT64
20 using nint = System.Int64;
21 #else
22 using nint = System.Int32;
23 #endif
25 namespace System.Numerics
27     /* Note: The following patterns are used throughout the code here and are described here
28     *
29     * PATTERN:
30     *    if (typeof(T) == typeof(int)) { ... }
31     *    else if (typeof(T) == typeof(float)) { ... }
32     * EXPLANATION:
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.
36     *
37     * PATTERN:
38     *    if (Vector.IsHardwareAccelerated) { ... }
39     *    else { ... }
40     * EXPLANATION
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.)
48     *
49     * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
51     /// <summary>
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.
55     /// </summary>
56     [Intrinsic]
57     public struct Vector<T> : IEquatable<Vector<T>>, IFormattable where T : struct
58     {
59         #region Fields
60         private Register register;
61         #endregion Fields
63         #region Static Members
64         /// <summary>
65         /// Returns the number of elements stored in the vector. This value is hardware dependent.
66         /// </summary>
67         public static int Count
68         {
69             [Intrinsic]
70             get
71             {
72                 ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
73                 return Unsafe.SizeOf<Vector<T>>() / Unsafe.SizeOf<T>();
74             }
75         }
77         /// <summary>
78         /// Returns a vector containing all zeroes.
79         /// </summary>
80         public static Vector<T> Zero
81         {
82             [Intrinsic]
83             get => s_zero;
84         }
85         private static readonly Vector<T> s_zero = new Vector<T>();
87         /// <summary>
88         /// Returns a vector containing all ones.
89         /// </summary>
90         public static Vector<T> One
91         {
92             [Intrinsic]
93             get => s_one;
94         }
95         private static readonly Vector<T> s_one = new Vector<T>(GetOneValue());
97         internal static Vector<T> AllOnes
98         {
99             [Intrinsic]
100             get => s_allOnes;
101         }
102         private static readonly Vector<T> s_allOnes = new Vector<T>(GetAllBitsSetValue());
103         #endregion Static Members
105         #region Constructors
106         /// <summary>
107         /// Constructs a vector whose components are all <code>value</code>
108         /// </summary>
109         [Intrinsic]
110         public unsafe Vector(T value)
111             : this()
112         {
113             if (Vector.IsHardwareAccelerated)
114             {
116     foreach (Type type in supportedTypes)
117     {
119                 <#=GenerateIfStatementHeader(type)#>
120                 {
121                     fixed (<#=typeAliases[type]#>* basePtr = &this.<#=GetRegisterFieldName(type, 0)#>)
122                     {
123                         for (nint g = 0; g < Count; g++)
124                         {
125                             *(basePtr + g) = (<#=typeAliases[type]#>)(object)value;
126                         }
127                     }
128                 }
130     }
132             }
133             else
134             {
136     foreach (Type type in supportedTypes)
137     {
139                 <#=GenerateIfStatementHeader(type)#>
140                 {
142         for (int g = 0; g < totalSize / Marshal.SizeOf(type); g++)
143         {
145                     <#=GetRegisterFieldName(type, g)#> = (<#=typeAliases[type]#>)(object)value;
147         }
149                 }
151     }
153             }
154         }
156         /// <summary>
157         /// Constructs a vector from the given array. The size of the given array must be at least Vector'T.Count.
158         /// </summary>
159         [Intrinsic]
160         public unsafe Vector(T[] values) : this(values, 0) { }
162         /// <summary>
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.
165         /// </summary>
166         [Intrinsic]
167         public unsafe Vector(T[] values, int index)
168         {
169             if (values == null)
170             {
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);
173             }
174             if (index < 0 || (values.Length - index) < Count)
175             {
176                 Vector.ThrowInsufficientNumberOfElementsException(Vector<T>.Count);
177             }
178             this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref values[index]));
179         }
181         internal unsafe Vector(void* dataPointer)
182         {
183             ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
184             this = Unsafe.ReadUnaligned<Vector<T>>(dataPointer);
185         }
187         private Vector(ref Register existingRegister)
188         {
189             this.register = existingRegister;
190         }
192         /// <summary>
193         /// Constructs a vector from the given <see cref="ReadOnlySpan{Byte}"/>. The span must contain at least <see cref="Vector{Byte}.Count"/> elements.
194         /// </summary>
195         [MethodImpl(MethodImplOptions.AggressiveInlining)]
196         public Vector(ReadOnlySpan<byte> values)
197         {
198             ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
199             if (values.Length < Vector<byte>.Count)
200             {
201                 Vector.ThrowInsufficientNumberOfElementsException(Vector<byte>.Count);
202             }
203             this = Unsafe.ReadUnaligned<Vector<T>>(ref MemoryMarshal.GetReference(values));
204         }
206         /// <summary>
207         /// Constructs a vector from the given <see cref="ReadOnlySpan{T}"/>. The span must contain at least <see cref="Vector{T}.Count"/> elements.
208         /// </summary>
209         [MethodImpl(MethodImplOptions.AggressiveInlining)]
210         public Vector(ReadOnlySpan<T> values)
211         {
212             if (values.Length < Count)
213             {
214                 Vector.ThrowInsufficientNumberOfElementsException(Vector<T>.Count);
215             }
216             this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)));
217         }
219         /// <summary>
220         /// Constructs a vector from the given <see cref="Span{T}"/>. The span must contain at least <see cref="Vector{T}.Count"/> elements.
221         /// </summary>
222         [MethodImpl(MethodImplOptions.AggressiveInlining)]
223         public Vector(Span<T> values)
224         {
225             if (values.Length < Count)
226             {
227                 Vector.ThrowInsufficientNumberOfElementsException(Vector<T>.Count);
228             }
229             this = Unsafe.ReadUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(values)));
230         }
231         #endregion Constructors
233         #region Public Instance Methods
234         /// <summary>
235         /// Copies the vector to the given <see cref="Span{Byte}"/>. The destination span must be at least size <see cref="Vector{Byte}.Count"/>.
236         /// </summary>
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)
240         {
241             ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
242             if ((uint)destination.Length < (uint)Vector<byte>.Count)
243             {
244                 ThrowHelper.ThrowArgumentException_DestinationTooShort();
245             }
247             Unsafe.WriteUnaligned<Vector<T>>(ref MemoryMarshal.GetReference(destination), this);
248         }
250         /// <summary>
251         /// Copies the vector to the given <see cref="Span{T}"/>. The destination span must be at least size <see cref="Vector{T}.Count"/>.
252         /// </summary>
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)
256         {
257             if ((uint)destination.Length < (uint)Count)
258             {
259                 ThrowHelper.ThrowArgumentException_DestinationTooShort();
260             }
262             Unsafe.WriteUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(destination)), this);
263         }
265         /// <summary>
266         /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count.
267         /// </summary>
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>
271         [Intrinsic]
272         public readonly void CopyTo(T[] destination)
273         {
274             CopyTo(destination, 0);
275         }
277         /// <summary>
278         /// Copies the vector to the given destination array. The destination array must be at least size Vector'T.Count.
279         /// </summary>
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>
285         [Intrinsic]
286         public readonly unsafe void CopyTo(T[] destination, int startIndex)
287         {
288             if (destination == null)
289             {
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);
292             }
293             if ((uint)startIndex >= (uint)destination.Length)
294             {
295                 throw new ArgumentOutOfRangeException(nameof(startIndex), SR.Format(SR.Arg_ArgumentOutOfRangeException, startIndex));
296             }
297             if ((destination.Length - startIndex) < Count)
298             {
299                 throw new ArgumentException(SR.Format(SR.Arg_ElementsInSourceIsGreaterThanDestination, startIndex));
300             }
302             Unsafe.WriteUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref destination[startIndex]), this);
303         }
305         /// <summary>
306         /// Returns the element at the given index.
307         /// </summary>
308         public readonly unsafe T this[int index]
309         {
310             [Intrinsic]
311             get
312             {
313                 if ((uint)index >= (uint)Count)
314                 {
315                     throw new IndexOutOfRangeException(SR.Format(SR.Arg_ArgumentOutOfRangeException, index));
316                 }
318                 return Unsafe.Add(ref Unsafe.As<Vector<T>, T>(ref Unsafe.AsRef<Vector<T>>(in this)), index);
319             }
320         }
322         /// <summary>
323         /// Returns a boolean indicating whether the given Object is equal to this vector instance.
324         /// </summary>
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)
329         {
330             if (!(obj is Vector<T>))
331             {
332                 return false;
333             }
334             return Equals((Vector<T>)obj);
335         }
337         /// <summary>
338         /// Returns a boolean indicating whether the given vector is equal to this vector instance.
339         /// </summary>
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>
342         [Intrinsic]
343         public readonly bool Equals(Vector<T> other)
344         {
345             if (Vector.IsHardwareAccelerated)
346             {
347                 for (int g = 0; g < Count; g++)
348                 {
349                     if (!ScalarEquals(this[g], other[g]))
350                     {
351                         return false;
352                     }
353                 }
354                 return true;
355             }
356             else
357             {
359     foreach (Type type in supportedTypes)
360     {
362                 <#=GenerateIfStatementHeader(type)#>
363                 {
364                     return
366         for (int g = 0; g < GetNumFields(type, totalSize); g++)
367         {
370             if (g == 0)
371             {
373                         this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#>
375             }
376             else
377             {
379                         && this.<#=GetRegisterFieldName(type, g)#> == other.<#=GetRegisterFieldName(type, g)#><#=(g == (GetNumFields(type, totalSize) -1)) ? ";" : ""#>
381             }
384         }
386                 }
388     }
390                 else
391                 {
392                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
393                 }
394             }
395         }
397         /// <summary>
398         /// Returns the hash code for this instance.
399         /// </summary>
400         /// <returns>The hash code.</returns>
401         public override readonly int GetHashCode()
402         {
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))
413             {
414                 for (nint g = 0; g < Vector<int>.Count; g++)
415                 {
416                     hashCode.Add(Unsafe.Add(ref Unsafe.As<Vector<T>, int>(ref Unsafe.AsRef<Vector<T>>(in this)), (IntPtr)g));
417                 }
418             }
419             else if (typeof(T) == typeof(float))
420             {
421                 for (nint g = 0; g < Count; g++)
422                 {
423                     hashCode.Add(Unsafe.Add(ref Unsafe.As<Vector<T>, float>(ref Unsafe.AsRef<Vector<T>>(in this)), (IntPtr)g));
424                 }
425             }
426             else if (typeof(T) == typeof(double))
427             {
428                 for (nint g = 0; g < Count; g++)
429                 {
430                     hashCode.Add(Unsafe.Add(ref Unsafe.As<Vector<T>, double>(ref Unsafe.AsRef<Vector<T>>(in this)), (IntPtr)g));
431                 }
432             }
433             else
434             {
435                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
436             }
438             return hashCode.ToHashCode();
439         }
441         /// <summary>
442         /// Returns a String representing this vector.
443         /// </summary>
444         /// <returns>The string representation.</returns>
445         public override readonly string ToString()
446         {
447             return ToString("G", CultureInfo.CurrentCulture);
448         }
450         /// <summary>
451         /// Returns a String representing this vector, using the specified format string to format individual elements.
452         /// </summary>
453         /// <param name="format">The format of individual elements.</param>
454         /// <returns>The string representation.</returns>
455         public readonly string ToString(string? format)
456         {
457             return ToString(format, CultureInfo.CurrentCulture);
458         }
460         /// <summary>
461         /// Returns a String representing this vector, using the specified format string to format individual elements
462         /// and the given IFormatProvider.
463         /// </summary>
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)
468         {
469             StringBuilder sb = new StringBuilder();
470             string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
471             sb.Append('<');
472             for (int g = 0; g < Count - 1; g++)
473             {
474                 sb.Append(((IFormattable)this[g]).ToString(format, formatProvider));
475                 sb.Append(separator);
476                 sb.Append(' ');
477             }
478             // Append last element w/out separator
479             sb.Append(((IFormattable)this[Count - 1]).ToString(format, formatProvider));
480             sb.Append('>');
481             return sb.ToString();
482         }
484         /// <summary>
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"/>.
486         /// </summary>
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)
491         {
492             ThrowHelper.ThrowForUnsupportedVectorBaseType<T>();
493             if ((uint)destination.Length < (uint)Vector<byte>.Count)
494             {
495                 return false;
496             }
498             Unsafe.WriteUnaligned<Vector<T>>(ref MemoryMarshal.GetReference(destination), this);
499             return true;
500         }
502         /// <summary>
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"/>.
504         /// </summary>
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)
509         {
510             if ((uint)destination.Length < (uint)Count)
511             {
512                 return false;
513             }
515             Unsafe.WriteUnaligned<Vector<T>>(ref Unsafe.As<T, byte>(ref MemoryMarshal.GetReference(destination)), this);
516             return true;
517         }
518         #endregion Public Instance Methods
520         #region Arithmetic Operators
521         /// <summary>
522         /// Adds two vectors together.
523         /// </summary>
524         /// <param name="left">The first source vector.</param>
525         /// <param name="right">The second source vector.</param>
526         /// <returns>The summed vector.</returns>
527         [Intrinsic]
528         public static unsafe Vector<T> operator +(Vector<T> left, Vector<T> right)
529         {
530             unchecked
531             {
532                 if (Vector.IsHardwareAccelerated)
533                 {
535     foreach (Type type in supportedTypes)
536     {
538                     <#=GenerateIfStatementHeader(type)#>
539                     {
540                         <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
541                         for (int g = 0; g < Count; g++)
542                         {
543                             dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarAdd(left[g], right[g]);
544                         }
545                         return new Vector<T>(dataPtr);
546                     }
548     }
550                     else
551                     {
552                         throw new NotSupportedException(SR.Arg_TypeNotSupported);
553                     }
554                 }
555                 else
556                 {
557                     Vector<T> sum = new Vector<T>();
559     foreach (Type type in supportedTypes)
560     {
562                     <#=GenerateIfStatementHeader(type)#>
563                     {
565                 for (int g = 0; g < GetNumFields(type, totalSize); g++)
566                 {
568                         sum.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> + right.<#= GetRegisterFieldName(type, g) #>);
570                 }
572                     }
574     }
576                     return sum;
577                 }
578             }
579         }
581         /// <summary>
582         /// Subtracts the second vector from the first.
583         /// </summary>
584         /// <param name="left">The first source vector.</param>
585         /// <param name="right">The second source vector.</param>
586         /// <returns>The difference vector.</returns>
587         [Intrinsic]
588         public static unsafe Vector<T> operator -(Vector<T> left, Vector<T> right)
589         {
590             unchecked
591             {
592                 if (Vector.IsHardwareAccelerated)
593                 {
595     foreach (Type type in supportedTypes)
596     {
598                     <#=GenerateIfStatementHeader(type)#>
599                     {
600                         <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
601                         for (int g = 0; g < Count; g++)
602                         {
603                             dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarSubtract(left[g], right[g]);
604                         }
605                         return new Vector<T>(dataPtr);
606                     }
608     }
610                     else
611                     {
612                         throw new NotSupportedException(SR.Arg_TypeNotSupported);
613                     }
614                 }
615                 else
616                 {
617                     Vector<T> difference = new Vector<T>();
619     foreach (Type type in supportedTypes)
620     {
622                     <#=GenerateIfStatementHeader(type)#>
623                     {
625         for (int g = 0; g < GetNumFields(type, totalSize); g++)
626         {
628                         difference.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> - right.<#= GetRegisterFieldName(type, g) #>);
630         }
632                     }
634     }
636                     return difference;
637                 }
638             }
639         }
641         // This method is intrinsic only for certain types. It cannot access fields directly unless we are sure the context is unaccelerated.
642         /// <summary>
643         /// Multiplies two vectors together.
644         /// </summary>
645         /// <param name="left">The first source vector.</param>
646         /// <param name="right">The second source vector.</param>
647         /// <returns>The product vector.</returns>
648         [Intrinsic]
649         public static unsafe Vector<T> operator *(Vector<T> left, Vector<T> right)
650         {
651             unchecked
652             {
653                 if (Vector.IsHardwareAccelerated)
654                 {
656     foreach (Type type in supportedTypes)
657     {
659                     <#=GenerateIfStatementHeader(type)#>
660                     {
661                         <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
662                         for (int g = 0; g < Count; g++)
663                         {
664                             dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarMultiply(left[g], right[g]);
665                         }
666                         return new Vector<T>(dataPtr);
667                     }
669     }
671                     else
672                     {
673                         throw new NotSupportedException(SR.Arg_TypeNotSupported);
674                     }
675                 }
676                 else
677                 {
678                     Vector<T> product = new Vector<T>();
680     foreach (Type type in supportedTypes)
681     {
683                     <#=GenerateIfStatementHeader(type)#>
684                     {
686         for (int g = 0; g < GetNumFields(type, totalSize); g++)
687         {
689                         product.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> * right.<#= GetRegisterFieldName(type, g) #>);
691         }
693                     }
695     }
697                     return product;
698                 }
699             }
700         }
702         /// <summary>
703         /// Multiplies a vector by the given scalar.
704         /// </summary>
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;
712         /// <summary>
713         /// Multiplies a vector by the given scalar.
714         /// </summary>
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.
723         /// <summary>
724         /// Divides the first vector by the second.
725         /// </summary>
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>
729         [Intrinsic]
730         public static unsafe Vector<T> operator /(Vector<T> left, Vector<T> right)
731         {
732             unchecked
733             {
734                 if (Vector.IsHardwareAccelerated)
735                 {
737     foreach (Type type in supportedTypes)
738     {
740                     <#=GenerateIfStatementHeader(type)#>
741                     {
742                         <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
743                         for (int g = 0; g < Count; g++)
744                         {
745                             dataPtr[g] = (<#=typeAliases[type]#>)(object)ScalarDivide(left[g], right[g]);
746                         }
747                         return new Vector<T>(dataPtr);
748                     }
750     }
752                     else
753                     {
754                         throw new NotSupportedException(SR.Arg_TypeNotSupported);
755                     }
756                 }
757                 else
758                 {
759                     Vector<T> quotient = new Vector<T>();
761     foreach (Type type in supportedTypes)
762     {
764                     <#=GenerateIfStatementHeader(type)#>
765                     {
767         for (int g = 0; g < GetNumFields(type, totalSize); g++)
768         {
770                         quotient.<#= GetRegisterFieldName(type, g) #> = (<#=typeAliases[type]#>)(left.<#= GetRegisterFieldName(type, g) #> / right.<#= GetRegisterFieldName(type, g) #>);
772         }
774                     }
776     }
778                     return quotient;
779                 }
780             }
781         }
783         /// <summary>
784         /// Negates a given vector.
785         /// </summary>
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
792         /// <summary>
793         /// Returns a new vector by performing a bitwise-and operation on each of the elements in the given vectors.
794         /// </summary>
795         /// <param name="left">The first source vector.</param>
796         /// <param name="right">The second source vector.</param>
797         /// <returns>The resultant vector.</returns>
798         [Intrinsic]
799         public static unsafe Vector<T> operator &(Vector<T> left, Vector<T> right)
800         {
801             Vector<T> result = new Vector<T>();
802             unchecked
803             {
804                 if (Vector.IsHardwareAccelerated)
805                 {
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++)
810                     {
811                         resultBase[g] = leftBase[g] & rightBase[g];
812                     }
813                 }
814                 else
815                 {
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)#>;
818                 }
819             }
820             return result;
821         }
823         /// <summary>
824         /// Returns a new vector by performing a bitwise-or operation on each of the elements in the given vectors.
825         /// </summary>
826         /// <param name="left">The first source vector.</param>
827         /// <param name="right">The second source vector.</param>
828         /// <returns>The resultant vector.</returns>
829         [Intrinsic]
830         public static unsafe Vector<T> operator |(Vector<T> left, Vector<T> right)
831         {
832             Vector<T> result = new Vector<T>();
833             unchecked
834             {
835                 if (Vector.IsHardwareAccelerated)
836                 {
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++)
841                     {
842                         resultBase[g] = leftBase[g] | rightBase[g];
843                     }
844                 }
845                 else
846                 {
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)#>;
849                 }
850             }
851             return result;
852         }
854         /// <summary>
855         /// Returns a new vector by performing a bitwise-exclusive-or operation on each of the elements in the given vectors.
856         /// </summary>
857         /// <param name="left">The first source vector.</param>
858         /// <param name="right">The second source vector.</param>
859         /// <returns>The resultant vector.</returns>
860         [Intrinsic]
861         public static unsafe Vector<T> operator ^(Vector<T> left, Vector<T> right)
862         {
863             Vector<T> result = new Vector<T>();
864             unchecked
865             {
866                 if (Vector.IsHardwareAccelerated)
867                 {
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++)
872                     {
873                         resultBase[g] = leftBase[g] ^ rightBase[g];
874                     }
875                 }
876                 else
877                 {
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)#>;
880                 }
881             }
882             return result;
883         }
885         /// <summary>
886         /// Returns a new vector whose elements are obtained by taking the one's complement of the given vector's elements.
887         /// </summary>
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) =>
892             s_allOnes ^ value;
893         #endregion Bitwise Operators
895         #region Logical Operators
896         /// <summary>
897         /// Returns a boolean indicating whether each pair of elements in the given vectors are equal.
898         /// </summary>
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>
902         [Intrinsic]
903         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
904         public static bool operator ==(Vector<T> left, Vector<T> right) =>
905             left.Equals(right);
907         /// <summary>
908         /// Returns a boolean indicating whether any single pair of elements in the given vectors are not equal.
909         /// </summary>
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>
913         [Intrinsic]
914         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
915         public static bool operator !=(Vector<T> left, Vector<T> right) => !(left == right);
916         #endregion Logical Operators
918         #region Conversions
920     foreach (Type type in supportedTypes)
921     {
923         /// <summary>
924         /// Reinterprets the bits of the given vector into those of another type.
925         /// </summary>
926         /// <param name="value">The source vector</param>
927         /// <returns>The reinterpreted vector.</returns>
929         if (nonClsCompliantTypes.Contains(type))
930         {
932         [CLSCompliant(false)]
934         }
936         [Intrinsic]
937         public static explicit operator Vector<<#=typeAliases[type]#>>(Vector<T> value) =>
938             new Vector<<#=typeAliases[type]#>>(ref value.register);
941     }
943         #endregion Conversions
945         #region Internal Comparison Methods
946         [Intrinsic]
947         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
948         internal static unsafe Vector<T> Equals(Vector<T> left, Vector<T> right)
949         {
950             if (Vector.IsHardwareAccelerated)
951             {
953     foreach (Type type in supportedTypes)
954     {
956                 <#=GenerateIfStatementHeader(type)#>
957                 {
958                     <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
959                     for (int g = 0; g < Count; g++)
960                     {
961                         dataPtr[g] = ScalarEquals(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
962                     }
963                     return new Vector<T>(dataPtr);
964                 }
966     }
968                 else
969                 {
970                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
971                 }
972             }
973             else
974             {
975                 Register register = new Register();
977     foreach (Type type in supportedTypes)
978     {
980                 <#=GenerateIfStatementHeader(type)#>
981                 {
983         for (int g = 0; g < GetNumFields(type, totalSize); g++)
984         {
986                     <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> == right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
988         }
990                     return new Vector<T>(ref register);
991                 }
993     }
995                 else
996                 {
997                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
998                 }
999             }
1000         }
1002         [Intrinsic]
1003         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1004         internal static unsafe Vector<T> LessThan(Vector<T> left, Vector<T> right)
1005         {
1006             if (Vector.IsHardwareAccelerated)
1007             {
1009     foreach (Type type in supportedTypes)
1010     {
1012                 <#=GenerateIfStatementHeader(type)#>
1013                 {
1014                     <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1015                     for (int g = 0; g < Count; g++)
1016                     {
1017                         dataPtr[g] = ScalarLessThan(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1018                     }
1019                     return new Vector<T>(dataPtr);
1020                 }
1022     }
1024                 else
1025                 {
1026                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1027                 }
1028             }
1029             else
1030             {
1031                 Register register = new Register();
1033     foreach (Type type in supportedTypes)
1034     {
1036                 <#=GenerateIfStatementHeader(type)#>
1037                 {
1039                 for (int g = 0; g < GetNumFields(type, totalSize); g++)
1040                 {
1042                     <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> < right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1044                 }
1046                     return new Vector<T>(ref register);
1047                 }
1049     }
1051                 else
1052                 {
1053                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1054                 }
1055             }
1056         }
1058         [Intrinsic]
1059         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1060         internal static unsafe Vector<T> GreaterThan(Vector<T> left, Vector<T> right)
1061         {
1062             if (Vector.IsHardwareAccelerated)
1063             {
1065     foreach (Type type in supportedTypes)
1066     {
1068                 <#=GenerateIfStatementHeader(type)#>
1069                 {
1070                     <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1071                     for (int g = 0; g < Count; g++)
1072                     {
1073                         dataPtr[g] = ScalarGreaterThan(left[g], right[g]) ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1074                     }
1075                     return new Vector<T>(dataPtr);
1076                 }
1078     }
1080                 else
1081                 {
1082                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1083                 }
1084             }
1085             else
1086             {
1087                 Register register = new Register();
1089     foreach (Type type in supportedTypes)
1090     {
1092                 <#=GenerateIfStatementHeader(type)#>
1093                 {
1095         for (int g = 0; g < GetNumFields(type, totalSize); g++)
1096         {
1098                     <#= GetRegisterFieldName(type, g) #> = left.<#= GetRegisterFieldName(type, g) #> > right.<#= GetRegisterFieldName(type, g) #> ? ConstantHelper.Get<#=type.Name#>WithAllBitsSet() : (<#=typeAliases[type]#>)0;
1100         }
1102                     return new Vector<T>(ref register);
1103                 }
1105     }
1107                 else
1108                 {
1109                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1110                 }
1111             }
1112         }
1114         [Intrinsic]
1115         internal static Vector<T> GreaterThanOrEqual(Vector<T> left, Vector<T> right)
1116         {
1117             return Equals(left, right) | GreaterThan(left, right);
1118         }
1120         [Intrinsic]
1121         internal static Vector<T> LessThanOrEqual(Vector<T> left, Vector<T> right)
1122         {
1123             return Equals(left, right) | LessThan(left, right);
1124         }
1126         [Intrinsic]
1127         internal static Vector<T> ConditionalSelect(Vector<T> condition, Vector<T> left, Vector<T> right)
1128         {
1129             return (left & condition) | (Vector.AndNot(right, condition));
1130         }
1131         #endregion Comparison Methods
1133         #region Internal Math Methods
1134         [Intrinsic]
1135         internal static unsafe Vector<T> Abs(Vector<T> value)
1136         {
1138     foreach (Type type in supportedTypes)
1139     {
1140         if (unsignedTypes.Contains(type))
1141         {
1143             <#=GenerateIfStatementHeader(type, unsignedTypes)#>
1144             {
1145                 return value;
1146             }
1148         }
1149     }
1151             if (Vector.IsHardwareAccelerated)
1152             {
1154     foreach (Type type in supportedTypes.Except(unsignedTypes))
1155     {
1157                 <#=GenerateIfStatementHeader(type, supportedTypes.Except(unsignedTypes))#>
1158                 {
1159                     <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1160                     for (int g = 0; g < Count; g++)
1161                     {
1162                         dataPtr[g] = (<#=typeAliases[type]#>)(object)(Math.Abs((<#=typeAliases[type]#>)(object)value[g]));
1163                     }
1164                     return new Vector<T>(dataPtr);
1165                 }
1167     }
1169                 else
1170                 {
1171                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1172                 }
1173             }
1174             else
1175             {
1177     foreach (Type type in supportedTypes.Except(unsignedTypes))
1178     {
1180                 <#=GenerateIfStatementHeader(type, supportedTypes.Except(unsignedTypes))#>
1181                 {
1183         for (int g = 0; g < GetNumFields(type, totalSize); g++)
1184         {
1186                     value.<#=GetRegisterFieldName(type, g)#> = (<#=typeAliases[type]#>)(Math.Abs(value.<#=GetRegisterFieldName(type, g)#>));
1188         }
1190                     return value;
1191                 }
1193     }
1195                 else
1196                 {
1197                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1198                 }
1199             }
1200         }
1202         [Intrinsic]
1203         internal static unsafe Vector<T> Min(Vector<T> left, Vector<T> right)
1204         {
1205             if (Vector.IsHardwareAccelerated)
1206             {
1208     foreach (Type type in supportedTypes)
1209     {
1211                 <#=GenerateIfStatementHeader(type)#>
1212                 {
1213                     <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1214                     for (int g = 0; g < Count; g++)
1215                     {
1216                         dataPtr[g] = ScalarLessThan(left[g], right[g]) ? (<#=typeAliases[type]#>)(object)left[g] : (<#=typeAliases[type]#>)(object)right[g];
1217                     }
1218                     return new Vector<T>(dataPtr);
1219                 }
1221     }
1223                 else
1224                 {
1225                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1226                 }
1227             }
1228             else
1229             {
1230                 Vector<T> vec = new Vector<T>();
1232     foreach (Type type in supportedTypes)
1233     {
1235                 <#=GenerateIfStatementHeader(type)#>
1236                 {
1238         for (int g = 0; g < GetNumFields(type, totalSize); g++)
1239         {
1241                     vec.<#=GetRegisterFieldName(type, g)#> = left.<#=GetRegisterFieldName(type, g)#> < right.<#=GetRegisterFieldName(type, g)#> ? left.<#=GetRegisterFieldName(type, g)#> : right.<#=GetRegisterFieldName(type, g)#>;
1243         }
1245                     return vec;
1246                 }
1248     }
1250                 else
1251                 {
1252                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1253                 }
1254             }
1255         }
1257         [Intrinsic]
1258         internal static unsafe Vector<T> Max(Vector<T> left, Vector<T> right)
1259         {
1260             if (Vector.IsHardwareAccelerated)
1261             {
1263     foreach (Type type in supportedTypes)
1264     {
1266                 <#=GenerateIfStatementHeader(type)#>
1267                 {
1268                     <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1269                     for (int g = 0; g < Count; g++)
1270                     {
1271                         dataPtr[g] = ScalarGreaterThan(left[g], right[g]) ? (<#=typeAliases[type]#>)(object)left[g] : (<#=typeAliases[type]#>)(object)right[g];
1272                     }
1273                     return new Vector<T>(dataPtr);
1274                 }
1276     }
1278                 else
1279                 {
1280                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1281                 }
1282             }
1283             else
1284             {
1285                 Vector<T> vec = new Vector<T>();
1287     foreach (Type type in supportedTypes)
1288     {
1290                 <#=GenerateIfStatementHeader(type)#>
1291                 {
1293         for (int g = 0; g < GetNumFields(type, totalSize); g++)
1294         {
1296                     vec.<#=GetRegisterFieldName(type, g)#> = left.<#=GetRegisterFieldName(type, g)#> > right.<#=GetRegisterFieldName(type, g)#> ? left.<#=GetRegisterFieldName(type, g)#> : right.<#=GetRegisterFieldName(type, g)#>;
1298         }
1300                     return vec;
1301                 }
1303     }
1305                 else
1306                 {
1307                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1308                 }
1309             }
1310         }
1312         [Intrinsic]
1313         internal static T Dot(Vector<T> left, Vector<T> right)
1314         {
1315             if (Vector.IsHardwareAccelerated)
1316             {
1317                 T product = default;
1318                 for (int g = 0; g < Count; g++)
1319                 {
1320                     product = ScalarAdd(product, ScalarMultiply(left[g], right[g]));
1321                 }
1322                 return product;
1323             }
1324             else
1325             {
1327     foreach (Type type in supportedTypes)
1328     {
1330                 <#=GenerateIfStatementHeader(type)#>
1331                 {
1332                     <#=typeAliases[type]#> product = 0;
1334         for (int g = 0; g < GetNumFields(type, totalSize); g++)
1335         {
1337                     product += (<#=typeAliases[type]#>)(left.<#=GetRegisterFieldName(type, g)#> * right.<#=GetRegisterFieldName(type, g)#>);
1339         }
1341                     return (T)(object)product;
1342                 }
1344     }
1346                 else
1347                 {
1348                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1349                 }
1350             }
1351         }
1353         [Intrinsic]
1354         internal static unsafe Vector<T> SquareRoot(Vector<T> value)
1355         {
1356             if (Vector.IsHardwareAccelerated)
1357             {
1359     foreach (Type type in supportedTypes)
1360     {
1362                 <#=GenerateIfStatementHeader(type)#>
1363                 {
1364                     <#=typeAliases[type]#>* dataPtr = stackalloc <#=typeAliases[type]#>[Count];
1365                     for (int g = 0; g < Count; g++)
1366                     {
1367                         dataPtr[g] = unchecked((<#=typeAliases[type]#>)Math.Sqrt((<#=typeAliases[type]#>)(object)value[g]));
1368                     }
1369                     return new Vector<T>(dataPtr);
1370                 }
1372     }
1374                 else
1375                 {
1376                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1377                 }
1378             }
1379             else
1380             {
1382     foreach (Type type in supportedTypes)
1383     {
1385                 <#=GenerateIfStatementHeader(type)#>
1386                 {
1388         for (int g = 0; g < GetNumFields(type, totalSize); g++)
1389         {
1391                     value.<#=GetRegisterFieldName(type, g)#> = (<#=typeAliases[type]#>)Math.Sqrt(value.<#=GetRegisterFieldName(type, g)#>);
1393         }
1395                     return value;
1396                 }
1398     }
1400                 else
1401                 {
1402                     throw new NotSupportedException(SR.Arg_TypeNotSupported);
1403                 }
1404             }
1405         }
1406         #endregion Internal Math Methods
1408         #region Helper Methods
1409         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1410         private static bool ScalarEquals(T left, T right)
1411         {
1413     foreach (Type type in supportedTypes)
1414     {
1416             <#=GenerateIfStatementHeader(type)#>
1417             {
1418                 return (<#=typeAliases[type]#>)(object)left == (<#=typeAliases[type]#>)(object)right;
1419             }
1421     }
1423             else
1424             {
1425                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1426             }
1427         }
1429         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1430         private static bool ScalarLessThan(T left, T right)
1431         {
1433     foreach (Type type in supportedTypes)
1434     {
1436             <#=GenerateIfStatementHeader(type)#>
1437             {
1438                 return (<#=typeAliases[type]#>)(object)left < (<#=typeAliases[type]#>)(object)right;
1439             }
1441     }
1443             else
1444             {
1445                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1446             }
1447         }
1449         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1450         private static bool ScalarGreaterThan(T left, T right)
1451         {
1453     foreach (Type type in supportedTypes)
1454     {
1456             <#=GenerateIfStatementHeader(type)#>
1457             {
1458                 return (<#=typeAliases[type]#>)(object)left > (<#=typeAliases[type]#>)(object)right;
1459             }
1461     }
1463             else
1464             {
1465                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1466             }
1467         }
1469         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1470         private static T ScalarAdd(T left, T right)
1471         {
1473     foreach (Type type in supportedTypes)
1474     {
1476             <#=GenerateIfStatementHeader(type)#>
1477             {
1478                 return (T)(object)unchecked((<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left + (<#=typeAliases[type]#>)(object)right));
1479             }
1481     }
1483             else
1484             {
1485                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1486             }
1487         }
1489         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1490         private static T ScalarSubtract(T left, T right)
1491         {
1493     foreach (Type type in supportedTypes)
1494     {
1496             <#=GenerateIfStatementHeader(type)#>
1497             {
1498                 return (T)(object)(<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left - (<#=typeAliases[type]#>)(object)right);
1499             }
1501     }
1503             else
1504             {
1505                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1506             }
1507         }
1509         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1510         private static T ScalarMultiply(T left, T right)
1511         {
1513     foreach (Type type in supportedTypes)
1514     {
1516             <#=GenerateIfStatementHeader(type)#>
1517             {
1518                 return (T)(object)unchecked((<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left * (<#=typeAliases[type]#>)(object)right));
1519             }
1521     }
1523             else
1524             {
1525                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1526             }
1527         }
1529         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1530         private static T ScalarDivide(T left, T right)
1531         {
1533     foreach (Type type in supportedTypes)
1534     {
1536             <#=GenerateIfStatementHeader(type)#>
1537             {
1538                 return (T)(object)(<#=typeAliases[type]#>)((<#=typeAliases[type]#>)(object)left / (<#=typeAliases[type]#>)(object)right);
1539             }
1541     }
1543             else
1544             {
1545                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1546             }
1547         }
1549         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1550         private static T GetOneValue()
1551         {
1553     foreach (Type type in supportedTypes)
1554     {
1556             <#=GenerateIfStatementHeader(type)#>
1557             {
1558                 <#=typeAliases[type]#> value = 1;
1559                 return (T)(object)value;
1560             }
1562     }
1564             else
1565             {
1566                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1567             }
1568         }
1570         [MethodImplAttribute(MethodImplOptions.AggressiveInlining)]
1571         private static T GetAllBitsSetValue()
1572         {
1574     foreach (Type type in supportedTypes)
1575     {
1577             <#=GenerateIfStatementHeader(type)#>
1578             {
1579                 return (T)(object)ConstantHelper.Get<#=type.Name#>WithAllBitsSet();
1580             }
1582     }
1584             else
1585             {
1586                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
1587             }
1588         }
1589         #endregion
1590     }
1592     [Intrinsic]
1593     public static partial class Vector
1594     {
1595         #region Widen/Narrow
1597     foreach (Type type in WidenableTypes)
1598     {
1599         Type widenTarget = GetWidenTarget(type);
1601         /// <summary>
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>
1606         /// </summary>
1608         if (nonClsCompliantTypes.Contains(type) || nonClsCompliantTypes.Contains(widenTarget))
1609         {
1611         [CLSCompliant(false)]
1613         }
1615         [Intrinsic]
1616         public static unsafe void Widen(Vector<<#=typeAliases[type]#>> source, out Vector<<#=typeAliases[widenTarget]#>> low, out Vector<<#=typeAliases[widenTarget]#>> high)
1617         {
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++)
1621             {
1622                 lowPtr[i] = (<#=typeAliases[widenTarget]#>)source[i];
1623             }
1624             <#=typeAliases[widenTarget]#>* highPtr = stackalloc <#=typeAliases[widenTarget]#>[elements / 2];
1625             for (int i = 0; i < elements / 2; i++)
1626             {
1627                 highPtr[i] = (<#=typeAliases[widenTarget]#>)source[i + (elements / 2)];
1628             }
1630             low = new Vector<<#=typeAliases[widenTarget]#>>(lowPtr);
1631             high = new Vector<<#=typeAliases[widenTarget]#>>(highPtr);
1632         }
1635     }
1637     foreach (Type narrowSource in NarrowableTypes)
1638     {
1639         Type narrowTarget = GetNarrowTarget(narrowSource);
1641         /// <summary>
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>
1646         /// </summary>
1648         if (nonClsCompliantTypes.Contains(narrowSource) || nonClsCompliantTypes.Contains(narrowTarget))
1649         {
1651         [CLSCompliant(false)]
1653         }
1655         [Intrinsic]
1656         public static unsafe Vector<<#=typeAliases[narrowTarget]#>> Narrow(Vector<<#=typeAliases[narrowSource]#>> low, Vector<<#=typeAliases[narrowSource]#>> high)
1657         {
1658             unchecked
1659             {
1660                 int elements = Vector<<#=typeAliases[narrowTarget]#>>.Count;
1661                 <#=typeAliases[narrowTarget]#>* retPtr = stackalloc <#=typeAliases[narrowTarget]#>[elements];
1662                 for (int i = 0; i < elements / 2; i++)
1663                 {
1664                     retPtr[i] = (<#=typeAliases[narrowTarget]#>)low[i];
1665                 }
1666                 for (int i = 0; i < elements / 2; i++)
1667                 {
1668                     retPtr[i + (elements / 2)] = (<#=typeAliases[narrowTarget]#>)high[i];
1669                 }
1671                 return new Vector<<#=typeAliases[narrowTarget]#>>(retPtr);
1672             }
1673         }
1676     }
1678         #endregion Widen/Narrow
1680         #region Same-Size Conversion
1682     foreach (var pair in SameSizeConversionPairs)
1683     {
1685         /// <summary>
1686         /// Converts a Vector{<#=pair.Key.Name#>} to a Vector{<#=pair.Value.Name#>}.
1687         /// </summary>
1688         /// <param name="value">The source vector.</param>
1689         /// <returns>The converted vector.</returns>
1691         if (nonClsCompliantTypes.Contains(pair.Key) || nonClsCompliantTypes.Contains(pair.Value))
1692         {
1694         [CLSCompliant(false)]
1696         }
1698         [Intrinsic]
1699         public static unsafe Vector<<#=typeAliases[pair.Value]#>> ConvertTo<#=pair.Value.Name#>(Vector<<#=typeAliases[pair.Key]#>> value)
1700         {
1701             unchecked
1702             {
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++)
1706                 {
1707                     retPtr[i] = (<#=typeAliases[pair.Value]#>)value[i];
1708                 }
1710                 return new Vector<<#=typeAliases[pair.Value]#>>(retPtr);
1711             }
1712         }
1715     }
1717         #endregion Same-Size Conversion
1719         #region Throw Helpers
1720         [DoesNotReturn]
1721         internal static void ThrowInsufficientNumberOfElementsException(int requiredElementCount)
1722         {
1723             throw new IndexOutOfRangeException(SR.Format(SR.Arg_InsufficientNumberOfElements, requiredElementCount, "values"));
1724         }
1725         #endregion
1726     }