1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
5 using System.Diagnostics;
6 using System.Globalization;
7 using System.Runtime.CompilerServices;
8 using System.Runtime.InteropServices;
10 using Internal.Runtime.CompilerServices;
12 namespace System.Runtime.Intrinsics
15 [DebuggerDisplay("{DisplayString,nq}")]
16 [DebuggerTypeProxy(typeof(Vector128DebugView<>))]
17 [StructLayout(LayoutKind.Sequential, Size = Vector128.Size)]
18 public readonly struct Vector128<T> : IEquatable<Vector128<T>>, IFormattable
21 // These fields exist to ensure the alignment is 8, rather than 1.
22 // This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694)
23 private readonly ulong _00;
24 private readonly ulong _01;
26 /// <summary>Gets the number of <typeparamref name="T" /> that are in a <see cref="Vector128{T}" />.</summary>
27 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
28 public static int Count
32 ThrowIfUnsupportedType();
33 return Vector128.Size / Unsafe.SizeOf<T>();
37 /// <summary>Gets a new <see cref="Vector128{T}" /> with all elements initialized to zero.</summary>
38 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
39 public static Vector128<T> Zero
44 ThrowIfUnsupportedType();
49 internal unsafe string DisplayString
59 return SR.NotSupported_Type;
64 internal static bool IsSupported
66 [MethodImpl(MethodImplOptions.AggressiveInlining)]
69 return (typeof(T) == typeof(byte)) ||
70 (typeof(T) == typeof(sbyte)) ||
71 (typeof(T) == typeof(short)) ||
72 (typeof(T) == typeof(ushort)) ||
73 (typeof(T) == typeof(int)) ||
74 (typeof(T) == typeof(uint)) ||
75 (typeof(T) == typeof(long)) ||
76 (typeof(T) == typeof(ulong)) ||
77 (typeof(T) == typeof(float)) ||
78 (typeof(T) == typeof(double));
82 [MethodImpl(MethodImplOptions.AggressiveInlining)]
83 internal static void ThrowIfUnsupportedType()
87 throw new NotSupportedException(SR.Arg_TypeNotSupported);
91 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{U}" />.</summary>
92 /// <typeparam name="U">The type of the vector the current instance should be reinterpreted as.</typeparam>
93 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{U}" />.</returns>
94 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) or the type of the target (<typeparamref name="U" />) is not supported.</exception>
96 [MethodImpl(MethodImplOptions.AggressiveInlining)]
97 public Vector128<U> As<U>() where U : struct
99 ThrowIfUnsupportedType();
100 Vector128<U>.ThrowIfUnsupportedType();
101 return Unsafe.As<Vector128<T>, Vector128<U>>(ref Unsafe.AsRef(in this));
104 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{byte}" />.</summary>
105 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{byte}" />.</returns>
106 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
108 public Vector128<byte> AsByte() => As<byte>();
110 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{double}" />.</summary>
111 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{double}" />.</returns>
112 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
114 public Vector128<double> AsDouble() => As<double>();
116 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{short}" />.</summary>
117 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{short}" />.</returns>
118 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
120 public Vector128<short> AsInt16() => As<short>();
122 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{int}" />.</summary>
123 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{int}" />.</returns>
124 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
126 public Vector128<int> AsInt32() => As<int>();
128 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{long}" />.</summary>
129 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{long}" />.</returns>
130 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
132 public Vector128<long> AsInt64() => As<long>();
134 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{sbyte}" />.</summary>
135 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{sbyte}" />.</returns>
136 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
138 [CLSCompliant(false)]
139 public Vector128<sbyte> AsSByte() => As<sbyte>();
141 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{float}" />.</summary>
142 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{float}" />.</returns>
143 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
145 public Vector128<float> AsSingle() => As<float>();
147 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{ushort}" />.</summary>
148 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{ushort}" />.</returns>
149 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
151 [CLSCompliant(false)]
152 public Vector128<ushort> AsUInt16() => As<ushort>();
154 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{uint}" />.</summary>
155 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{uint}" />.</returns>
156 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
158 [CLSCompliant(false)]
159 public Vector128<uint> AsUInt32() => As<uint>();
161 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{ulong}" />.</summary>
162 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{ulong}" />.</returns>
163 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
165 [CLSCompliant(false)]
166 public Vector128<ulong> AsUInt64() => As<ulong>();
168 /// <summary>Determines whether the specified <see cref="Vector128{T}" /> is equal to the current instance.</summary>
169 /// <param name="other">The <see cref="Vector128{T}" /> to compare with the current instance.</param>
170 /// <returns><c>true</c> if <paramref name="other" /> is equal to the current instance; otherwise, <c>false</c>.</returns>
171 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
172 public bool Equals(Vector128<T> other)
174 ThrowIfUnsupportedType();
176 for (int i = 0; i < Count; i++)
178 if (!((IEquatable<T>)(GetElement(i))).Equals(other.GetElement(i)))
187 /// <summary>Determines whether the specified object is equal to the current instance.</summary>
188 /// <param name="obj">The object to compare with the current instance.</param>
189 /// <returns><c>true</c> if <paramref name="obj" /> is a <see cref="Vector128{T}" /> and is equal to the current instance; otherwise, <c>false</c>.</returns>
190 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
191 public override bool Equals(object obj)
193 return (obj is Vector128<T>) && Equals((Vector128<T>)(obj));
196 /// <summary>Gets the element at the specified index.</summary>
197 /// <param name="index">The index of the element to get.</param>
198 /// <returns>The value of the element at <paramref name="index" />.</returns>
199 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
200 /// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> was less than zero or greater than the number of elements.</exception>
201 public T GetElement(int index)
203 ThrowIfUnsupportedType();
205 if ((uint)(index) >= (uint)(Count))
207 throw new ArgumentOutOfRangeException(nameof(index));
210 ref T e0 = ref Unsafe.As<Vector128<T>, T>(ref Unsafe.AsRef(in this));
211 return Unsafe.Add(ref e0, index);
214 /// <summary>Creates a new <see cref="Vector128{T}" /> with the element at the specified index set to the specified value and the remaining elements set to the same value as that in the current instance.</summary>
215 /// <param name="index">The index of the element to set.</param>
216 /// <param name="value">The value to set the value to.</param>
217 /// <returns>A <see cref="Vector128{T}" /> with the value of the element at <paramref name="index" /> set to <paramref name="value" /> and the remaining elements set to the same value as that in the current instance.</returns>
218 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
219 /// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> was less than zero or greater than the number of elements.</exception>
220 public Vector128<T> WithElement(int index, T value)
222 ThrowIfUnsupportedType();
224 if ((uint)(index) >= (uint)(Count))
226 throw new ArgumentOutOfRangeException(nameof(index));
229 Vector128<T> result = this;
230 ref T e0 = ref Unsafe.As<Vector128<T>, T>(ref result);
231 Unsafe.Add(ref e0, index) = value;
235 /// <summary>Gets the hash code for the instance.</summary>
236 /// <returns>The hash code for the instance.</returns>
237 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
238 public override int GetHashCode()
240 ThrowIfUnsupportedType();
244 for (int i = 0; i < Count; i++)
246 hashCode = HashCode.Combine(hashCode, GetElement(i).GetHashCode());
252 /// <summary>Gets the value of the lower 64-bits as a new <see cref="Vector64{T}" />.</summary>
253 /// <returns>The value of the lower 64-bits as a new <see cref="Vector64{T}" />.</returns>
254 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
255 public Vector64<T> GetLower()
257 ThrowIfUnsupportedType();
258 Vector64<T>.ThrowIfUnsupportedType();
259 return Unsafe.As<Vector128<T>, Vector64<T>>(ref Unsafe.AsRef(in this));
262 /// <summary>Creates a new <see cref="Vector128{T}" /> with the lower 64-bits set to the specified value and the upper 64-bits set to the same value as that in the current instance.</summary>
263 /// <param name="value">The value of the lower 64-bits as a <see cref="Vector64{T}" />.</param>
264 /// <returns>A new <see cref="Vector128{T}" /> with the lower 64-bits set to the specified value and the upper 64-bits set to the same value as that in the current instance.</returns>
265 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
266 public Vector128<T> WithLower(Vector64<T> value)
268 ThrowIfUnsupportedType();
269 Vector64<T>.ThrowIfUnsupportedType();
271 Vector128<T> result = this;
272 Unsafe.As<Vector128<T>, Vector64<T>>(ref result) = value;
276 /// <summary>Gets the value of the upper 64-bits as a new <see cref="Vector64{T}" />.</summary>
277 /// <returns>The value of the upper 64-bits as a new <see cref="Vector64{T}" />.</returns>
278 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
279 public Vector64<T> GetUpper()
281 ThrowIfUnsupportedType();
282 Vector64<T>.ThrowIfUnsupportedType();
284 ref Vector64<T> lower = ref Unsafe.As<Vector128<T>, Vector64<T>>(ref Unsafe.AsRef(in this));
285 return Unsafe.Add(ref lower, 1);
288 /// <summary>Creates a new <see cref="Vector128{T}" /> with the upper 64-bits set to the specified value and the upper 64-bits set to the same value as that in the current instance.</summary>
289 /// <param name="value">The value of the upper 64-bits as a <see cref="Vector64{T}" />.</param>
290 /// <returns>A new <see cref="Vector128{T}" /> with the upper 64-bits set to the specified value and the upper 64-bits set to the same value as that in the current instance.</returns>
291 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
292 public Vector128<T> WithUpper(Vector64<T> value)
294 ThrowIfUnsupportedType();
295 Vector64<T>.ThrowIfUnsupportedType();
297 Vector128<T> result = this;
298 ref Vector64<T> lower = ref Unsafe.As<Vector128<T>, Vector64<T>>(ref result);
299 Unsafe.Add(ref lower, 1) = value;
303 /// <summary>Converts the current instance to a scalar containing the value of the first element.</summary>
304 /// <returns>A scalar <typeparamref name="T" /> containing the value of the first element.</returns>
305 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
308 ThrowIfUnsupportedType();
309 return Unsafe.As<Vector128<T>, T>(ref Unsafe.AsRef(in this));
312 /// <summary>Converts the current instance to an equivalent string representation.</summary>
313 /// <returns>An equivalent string representation of the current instance.</returns>
314 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
315 public override string ToString()
317 return ToString("G");
320 /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
321 /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
322 /// <returns>An equivalent string representation of the current instance.</returns>
323 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
324 public string ToString(string format)
326 return ToString(format, CultureInfo.CurrentCulture);
329 /// <summary>Converts the current instance to an equivalent string representation using the specified format.</summary>
330 /// <param name="format">The format specifier used to format the individual elements of the current instance.</param>
331 /// <param name="formatProvider">The format provider used to format the individual elements of the current instance.</param>
332 /// <returns>An equivalent string representation of the current instance.</returns>
333 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
334 public string ToString(string format, IFormatProvider formatProvider)
336 ThrowIfUnsupportedType();
338 string separator = NumberFormatInfo.GetInstance(formatProvider).NumberGroupSeparator;
339 int lastElement = Count - 1;
341 var sb = StringBuilderCache.Acquire();
344 for (int i = 0; i < lastElement; i++)
346 sb.Append(((IFormattable)(GetElement(i))).ToString(format, formatProvider));
347 sb.Append(separator);
350 sb.Append(((IFormattable)(GetElement(lastElement))).ToString(format, formatProvider));
353 return StringBuilderCache.GetStringAndRelease(sb);
356 /// <summary>Converts the current instance to a new <see cref="Vector256{T}" /> with the lower 128-bits set to the value of the current instance and the upper 128-bits initialized to zero.</summary>
357 /// <returns>A new <see cref="Vector256{T}" /> with the lower 128-bits set to the value of the current instance and the upper 128-bits initialized to zero.</returns>
358 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
359 public Vector256<T> ToVector256()
361 ThrowIfUnsupportedType();
362 Vector256<T>.ThrowIfUnsupportedType();
364 Vector256<T> result = Vector256<T>.Zero;
365 Unsafe.As<Vector256<T>, Vector128<T>>(ref result) = this;
369 /// <summary>Converts the current instance to a new <see cref="Vector256{T}" /> with the lower 128-bits set to the value of the current instance and the upper 128-bits left uninitialized.</summary>
370 /// <returns>A new <see cref="Vector256{T}" /> with the lower 128-bits set to the value of the current instance and the upper 128-bits left uninitialized.</returns>
371 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
372 public unsafe Vector256<T> ToVector256Unsafe()
374 ThrowIfUnsupportedType();
375 Vector256<T>.ThrowIfUnsupportedType();
377 // This relies on us stripping the "init" flag from the ".locals"
378 // declaration to let the upper bits be uninitialized.
380 var pResult = stackalloc byte[Vector256.Size];
381 Unsafe.AsRef<Vector128<T>>(pResult) = this;
382 return Unsafe.AsRef<Vector256<T>>(pResult);