f3599a98422d0f8496080e863157f59e45fee7b2
[platform/upstream/coreclr.git] / src / System.Private.CoreLib / shared / System / Runtime / Intrinsics / Vector128_1.cs
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.
4
5 using System.Diagnostics;
6 using System.Runtime.CompilerServices;
7 using System.Runtime.InteropServices;
8 using Internal.Runtime.CompilerServices;
9
10 namespace System.Runtime.Intrinsics
11 {
12     [Intrinsic]
13     [DebuggerDisplay("{DisplayString,nq}")]
14     [DebuggerTypeProxy(typeof(Vector128DebugView<>))]
15     [StructLayout(LayoutKind.Sequential, Size = Vector128.Size)]
16     public readonly struct Vector128<T> where T : struct
17     {
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;
22
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
26         {
27             [Intrinsic]
28             get
29             {
30                 ThrowIfUnsupportedType();
31                 return default;
32             }
33         }
34
35         internal unsafe string DisplayString
36         {
37             get
38             {
39                 if (IsSupported)
40                 {
41                     var items = new T[ElementCount];
42                     Unsafe.WriteUnaligned(ref Unsafe.As<T, byte>(ref items[0]), this);
43                     return $"({string.Join(", ", items)})";
44                 }
45                 else
46                 {
47                     return SR.NotSupported_Type;
48                 }
49             }
50         }
51
52         internal static int ElementCount
53         {
54             get
55             {
56                 ThrowIfUnsupportedType();
57                 return Vector128.Size / Unsafe.SizeOf<T>();
58             }
59         }
60
61         internal static bool IsSupported
62         {
63             [MethodImpl(MethodImplOptions.AggressiveInlining)]
64             get
65             {
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));
76             }
77         }
78
79         [MethodImpl(MethodImplOptions.AggressiveInlining)]
80         internal static void ThrowIfUnsupportedType()
81         {
82             if (!IsSupported)
83             {
84                 throw new NotSupportedException(SR.Arg_TypeNotSupported);
85             }
86         }
87
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>
92         [Intrinsic]
93         [MethodImpl(MethodImplOptions.AggressiveInlining)]
94         public Vector128<U> As<U>() where U : struct
95         {
96             ThrowIfUnsupportedType();
97             Vector128<U>.ThrowIfUnsupportedType();
98             return Unsafe.As<Vector128<T>, Vector128<U>>(ref Unsafe.AsRef(in this));
99         }
100
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>
104         [Intrinsic]
105         public Vector128<byte> AsByte() => As<byte>();
106
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>
110         [Intrinsic]
111         public Vector128<double> AsDouble() => As<double>();
112
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>
116         [Intrinsic]
117         public Vector128<short> AsInt16() => As<short>();
118
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>
122         [Intrinsic]
123         public Vector128<int> AsInt32() => As<int>();
124
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>
128         [Intrinsic]
129         public Vector128<long> AsInt64() => As<long>();
130
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>
134         [Intrinsic]
135         [CLSCompliant(false)]
136         public Vector128<sbyte> AsSByte() => As<sbyte>();
137
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>
141         [Intrinsic]
142         public Vector128<float> AsSingle() => As<float>();
143
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>
147         [Intrinsic]
148         [CLSCompliant(false)]
149         public Vector128<ushort> AsUInt16() => As<ushort>();
150
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>
154         [Intrinsic]
155         [CLSCompliant(false)]
156         public Vector128<uint> AsUInt32() => As<uint>();
157
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>
161         [Intrinsic]
162         [CLSCompliant(false)]
163         public Vector128<ulong> AsUInt64() => As<ulong>();
164
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)
171         {
172             ThrowIfUnsupportedType();
173
174             if ((uint)(index) >= (uint)(ElementCount))
175             {
176                 throw new ArgumentOutOfRangeException(nameof(index));
177             }
178
179             ref T e0 = ref Unsafe.As<Vector128<T>, T>(ref Unsafe.AsRef(in this));
180             return Unsafe.Add(ref e0, index);
181         }
182
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)
190         {
191             ThrowIfUnsupportedType();
192
193             if ((uint)(index) >= (uint)(ElementCount))
194             {
195                 throw new ArgumentOutOfRangeException(nameof(index));
196             }
197
198             Vector128<T> result = this;
199             ref T e0 = ref Unsafe.As<Vector128<T>, T>(ref result);
200             Unsafe.Add(ref e0, index) = value;
201             return result;
202         }
203
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()
208         {
209             ThrowIfUnsupportedType();
210             Vector64<T>.ThrowIfUnsupportedType();
211             return Unsafe.As<Vector128<T>, Vector64<T>>(ref Unsafe.AsRef(in this));
212         }
213
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)
219         {
220             ThrowIfUnsupportedType();
221             Vector64<T>.ThrowIfUnsupportedType();
222
223             Vector128<T> result = this;
224             Unsafe.As<Vector128<T>, Vector64<T>>(ref result) = value;
225             return result;
226         }
227
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()
232         {
233             ThrowIfUnsupportedType();
234             Vector64<T>.ThrowIfUnsupportedType();
235
236             ref Vector64<T> lower = ref Unsafe.As<Vector128<T>, Vector64<T>>(ref Unsafe.AsRef(in this));
237             return Unsafe.Add(ref lower, 1);
238         }
239
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)
245         {
246             ThrowIfUnsupportedType();
247             Vector64<T>.ThrowIfUnsupportedType();
248
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;
252             return result;
253         }
254
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>
258         public T ToScalar()
259         {
260             ThrowIfUnsupportedType();
261             return Unsafe.As<Vector128<T>, T>(ref Unsafe.AsRef(in this));
262         }
263
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()
268         {
269             ThrowIfUnsupportedType();
270             Vector256<T>.ThrowIfUnsupportedType();
271
272             Vector256<T> result = Vector256<T>.Zero;
273             Unsafe.As<Vector256<T>, Vector128<T>>(ref result) = this;
274             return result;
275         }
276
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()
281         {
282             ThrowIfUnsupportedType();
283             Vector256<T>.ThrowIfUnsupportedType();
284
285             // This relies on us stripping the "init" flag from the ".locals"
286             // declaration to let the upper bits be uninitialized.
287
288             var pResult = stackalloc byte[Vector256.Size];
289             Unsafe.AsRef<Vector128<T>>(pResult) = this;
290             return Unsafe.AsRef<Vector256<T>>(pResult);
291         }
292     }
293 }