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.Runtime.CompilerServices;
7 using System.Runtime.InteropServices;
8 using Internal.Runtime.CompilerServices;
10 namespace System.Runtime.Intrinsics
13 [DebuggerDisplay("{DisplayString,nq}")]
14 [DebuggerTypeProxy(typeof(Vector128DebugView<>))]
15 [StructLayout(LayoutKind.Sequential, Size = Vector128.Size)]
16 public readonly struct Vector128<T> where T : struct
18 // These fields exist to ensure the alignment is 8, rather than 1.
19 // This also allows the debug view to work https://github.com/dotnet/coreclr/issues/15694)
20 private readonly ulong _00;
21 private readonly ulong _01;
23 /// <summary>Gets a new <see cref="Vector128{T}" /> with all elements initialized to zero.</summary>
24 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
25 public static Vector128<T> Zero
30 ThrowIfUnsupportedType();
35 internal unsafe string DisplayString
41 var items = new T[ElementCount];
42 Unsafe.WriteUnaligned(ref Unsafe.As<T, byte>(ref items[0]), this);
43 return $"({string.Join(", ", items)})";
47 return SR.NotSupported_Type;
52 internal static int ElementCount
56 ThrowIfUnsupportedType();
57 return Vector128.Size / Unsafe.SizeOf<T>();
61 internal static bool IsSupported
63 [MethodImpl(MethodImplOptions.AggressiveInlining)]
66 return (typeof(T) == typeof(byte)) ||
67 (typeof(T) == typeof(sbyte)) ||
68 (typeof(T) == typeof(short)) ||
69 (typeof(T) == typeof(ushort)) ||
70 (typeof(T) == typeof(int)) ||
71 (typeof(T) == typeof(uint)) ||
72 (typeof(T) == typeof(long)) ||
73 (typeof(T) == typeof(ulong)) ||
74 (typeof(T) == typeof(float)) ||
75 (typeof(T) == typeof(double));
79 [MethodImpl(MethodImplOptions.AggressiveInlining)]
80 internal static void ThrowIfUnsupportedType()
84 throw new NotSupportedException(SR.Arg_TypeNotSupported);
88 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{U}" />.</summary>
89 /// <typeparam name="U">The type of the vector the current instance should be reinterpreted as.</typeparam>
90 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{U}" />.</returns>
91 /// <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>
93 [MethodImpl(MethodImplOptions.AggressiveInlining)]
94 public Vector128<U> As<U>() where U : struct
96 ThrowIfUnsupportedType();
97 Vector128<U>.ThrowIfUnsupportedType();
98 return Unsafe.As<Vector128<T>, Vector128<U>>(ref Unsafe.AsRef(in this));
101 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{byte}" />.</summary>
102 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{byte}" />.</returns>
103 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
105 public Vector128<byte> AsByte() => As<byte>();
107 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{double}" />.</summary>
108 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{double}" />.</returns>
109 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
111 public Vector128<double> AsDouble() => As<double>();
113 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{short}" />.</summary>
114 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{short}" />.</returns>
115 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
117 public Vector128<short> AsInt16() => As<short>();
119 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{int}" />.</summary>
120 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{int}" />.</returns>
121 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
123 public Vector128<int> AsInt32() => As<int>();
125 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{long}" />.</summary>
126 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{long}" />.</returns>
127 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
129 public Vector128<long> AsInt64() => As<long>();
131 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{sbyte}" />.</summary>
132 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{sbyte}" />.</returns>
133 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
135 [CLSCompliant(false)]
136 public Vector128<sbyte> AsSByte() => As<sbyte>();
138 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{float}" />.</summary>
139 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{float}" />.</returns>
140 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
142 public Vector128<float> AsSingle() => As<float>();
144 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{ushort}" />.</summary>
145 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{ushort}" />.</returns>
146 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
148 [CLSCompliant(false)]
149 public Vector128<ushort> AsUInt16() => As<ushort>();
151 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{uint}" />.</summary>
152 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{uint}" />.</returns>
153 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
155 [CLSCompliant(false)]
156 public Vector128<uint> AsUInt32() => As<uint>();
158 /// <summary>Reinterprets the current instance as a new <see cref="Vector128{ulong}" />.</summary>
159 /// <returns>The current instance reinterpreted as a new <see cref="Vector128{ulong}" />.</returns>
160 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
162 [CLSCompliant(false)]
163 public Vector128<ulong> AsUInt64() => As<ulong>();
165 /// <summary>Gets the element at the specified index.</summary>
166 /// <param name="index">The index of the element to get.</param>
167 /// <returns>The value of the element at <paramref name="index" />.</returns>
168 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
169 /// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> was less than zero or greater than the number of elements.</exception>
170 public T GetElement(int index)
172 ThrowIfUnsupportedType();
174 if ((uint)(index) >= (uint)(ElementCount))
176 throw new ArgumentOutOfRangeException(nameof(index));
179 ref T e0 = ref Unsafe.As<Vector128<T>, T>(ref Unsafe.AsRef(in this));
180 return Unsafe.Add(ref e0, index);
183 /// <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>
184 /// <param name="index">The index of the element to set.</param>
185 /// <param name="value">The value to set the value to.</param>
186 /// <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>
187 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
188 /// <exception cref="ArgumentOutOfRangeException"><paramref name="index" /> was less than zero or greater than the number of elements.</exception>
189 public Vector128<T> WithElement(int index, T value)
191 ThrowIfUnsupportedType();
193 if ((uint)(index) >= (uint)(ElementCount))
195 throw new ArgumentOutOfRangeException(nameof(index));
198 Vector128<T> result = this;
199 ref T e0 = ref Unsafe.As<Vector128<T>, T>(ref result);
200 Unsafe.Add(ref e0, index) = value;
204 /// <summary>Gets the value of the lower 64-bits as a new <see cref="Vector64{T}" />.</summary>
205 /// <returns>The value of the lower 64-bits as a new <see cref="Vector64{T}" />.</returns>
206 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
207 public Vector64<T> GetLower()
209 ThrowIfUnsupportedType();
210 Vector64<T>.ThrowIfUnsupportedType();
211 return Unsafe.As<Vector128<T>, Vector64<T>>(ref Unsafe.AsRef(in this));
214 /// <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>
215 /// <param name="value">The value of the lower 64-bits as a <see cref="Vector64{T}" />.</param>
216 /// <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>
217 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
218 public Vector128<T> WithLower(Vector64<T> value)
220 ThrowIfUnsupportedType();
221 Vector64<T>.ThrowIfUnsupportedType();
223 Vector128<T> result = this;
224 Unsafe.As<Vector128<T>, Vector64<T>>(ref result) = value;
228 /// <summary>Gets the value of the upper 64-bits as a new <see cref="Vector64{T}" />.</summary>
229 /// <returns>The value of the upper 64-bits as a new <see cref="Vector64{T}" />.</returns>
230 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
231 public Vector64<T> GetUpper()
233 ThrowIfUnsupportedType();
234 Vector64<T>.ThrowIfUnsupportedType();
236 ref Vector64<T> lower = ref Unsafe.As<Vector128<T>, Vector64<T>>(ref Unsafe.AsRef(in this));
237 return Unsafe.Add(ref lower, 1);
240 /// <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>
241 /// <param name="value">The value of the upper 64-bits as a <see cref="Vector64{T}" />.</param>
242 /// <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>
243 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
244 public Vector128<T> WithUpper(Vector64<T> value)
246 ThrowIfUnsupportedType();
247 Vector64<T>.ThrowIfUnsupportedType();
249 Vector128<T> result = this;
250 ref Vector64<T> lower = ref Unsafe.As<Vector128<T>, Vector64<T>>(ref result);
251 Unsafe.Add(ref lower, 1) = value;
255 /// <summary>Converts the current instance to a scalar containing the value of the first element.</summary>
256 /// <returns>A scalar <typeparamref name="T" /> containing the value of the first element.</returns>
257 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
260 ThrowIfUnsupportedType();
261 return Unsafe.As<Vector128<T>, T>(ref Unsafe.AsRef(in this));
264 /// <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>
265 /// <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>
266 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
267 public Vector256<T> ToVector256()
269 ThrowIfUnsupportedType();
270 Vector256<T>.ThrowIfUnsupportedType();
272 Vector256<T> result = Vector256<T>.Zero;
273 Unsafe.As<Vector256<T>, Vector128<T>>(ref result) = this;
277 /// <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>
278 /// <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>
279 /// <exception cref="NotSupportedException">The type of the current instance (<typeparamref name="T" />) is not supported.</exception>
280 public unsafe Vector256<T> ToVector256Unsafe()
282 ThrowIfUnsupportedType();
283 Vector256<T>.ThrowIfUnsupportedType();
285 // This relies on us stripping the "init" flag from the ".locals"
286 // declaration to let the upper bits be uninitialized.
288 var pResult = stackalloc byte[Vector256.Size];
289 Unsafe.AsRef<Vector128<T>>(pResult) = this;
290 return Unsafe.AsRef<Vector256<T>>(pResult);