10b42ad94a6a56e09a03dbc3a8d8400a60ffdf71
[platform/upstream/coreclr.git] / tests / src / JIT / HardwareIntrinsics / X86 / Fma_Vector256 / MultiplySubtractNegated.Double.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 /******************************************************************************
6  * This file is auto-generated from a template file by the GenerateTests.csx  *
7  * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make    *
8  * changes, please update the corresponding template and run according to the *
9  * directions listed in the file.                                             *
10  ******************************************************************************/
11
12 using System;
13 using System.Runtime.CompilerServices;
14 using System.Runtime.InteropServices;
15 using System.Runtime.Intrinsics;
16 using System.Runtime.Intrinsics.X86;
17
18 namespace JIT.HardwareIntrinsics.X86
19 {
20     public static partial class Program
21     {
22         private static void MultiplySubtractNegatedDouble()
23         {
24             var test = new SimpleTernaryOpTest__MultiplySubtractNegatedDouble();
25
26             if (test.IsSupported)
27             {
28                 // Validates basic functionality works, using Unsafe.Read
29                 test.RunBasicScenario_UnsafeRead();
30
31                 if (Avx.IsSupported)
32                 {
33                     // Validates basic functionality works, using Load
34                     test.RunBasicScenario_Load();
35
36                     // Validates basic functionality works, using LoadAligned
37                     test.RunBasicScenario_LoadAligned();
38                 }
39
40                 // Validates calling via reflection works, using Unsafe.Read
41                 test.RunReflectionScenario_UnsafeRead();
42
43                 if (Avx.IsSupported)
44                 {
45                     // Validates calling via reflection works, using Load
46                     test.RunReflectionScenario_Load();
47
48                     // Validates calling via reflection works, using LoadAligned
49                     test.RunReflectionScenario_LoadAligned();
50                 }
51
52                 // Validates passing a static member works
53                 test.RunClsVarScenario();
54
55                 // Validates passing a local works, using Unsafe.Read
56                 test.RunLclVarScenario_UnsafeRead();
57
58                 if (Avx.IsSupported)
59                 {
60                     // Validates passing a local works, using Load
61                     test.RunLclVarScenario_Load();
62
63                     // Validates passing a local works, using LoadAligned
64                     test.RunLclVarScenario_LoadAligned();
65                 }
66
67                 // Validates passing the field of a local class works
68                 test.RunClassLclFldScenario();
69
70                 // Validates passing an instance member of a class works
71                 test.RunClassFldScenario();
72
73                 // Validates passing the field of a local struct works
74                 test.RunStructLclFldScenario();
75
76                 // Validates passing an instance member of a struct works
77                 test.RunStructFldScenario();
78             }
79             else
80             {
81                 // Validates we throw on unsupported hardware
82                 test.RunUnsupportedScenario();
83             }
84
85             if (!test.Succeeded)
86             {
87                 throw new Exception("One or more scenarios did not complete as expected.");
88             }
89         }
90     }
91
92     public sealed unsafe class SimpleTernaryOpTest__MultiplySubtractNegatedDouble
93     {
94         private struct TestStruct
95         {
96             public Vector256<Double> _fld1;
97             public Vector256<Double> _fld2;
98             public Vector256<Double> _fld3;
99
100             public static TestStruct Create()
101             {
102                 var testStruct = new TestStruct();
103                 var random = new Random();
104
105                 for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); }
106                 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref testStruct._fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
107                 for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); }
108                 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref testStruct._fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
109                 for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (double)(random.NextDouble()); }
110                 Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar3), ref Unsafe.As<Double, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
111
112                 return testStruct;
113             }
114
115             public void RunStructFldScenario(SimpleTernaryOpTest__MultiplySubtractNegatedDouble testClass)
116             {
117                 var result = Fma.MultiplySubtractNegated(_fld1, _fld2, _fld3);
118
119                 Unsafe.Write(testClass._dataTable.outArrayPtr, result);
120                 testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr);
121             }
122         }
123
124         private static readonly int LargestVectorSize = 32;
125
126         private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double);
127         private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double);
128         private static readonly int Op3ElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double);
129         private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double);
130
131         private static Double[] _data1 = new Double[Op1ElementCount];
132         private static Double[] _data2 = new Double[Op2ElementCount];
133         private static Double[] _data3 = new Double[Op3ElementCount];
134
135         private static Vector256<Double> _clsVar1;
136         private static Vector256<Double> _clsVar2;
137         private static Vector256<Double> _clsVar3;
138
139         private Vector256<Double> _fld1;
140         private Vector256<Double> _fld2;
141         private Vector256<Double> _fld3;
142
143         private SimpleTernaryOpTest__DataTable<Double, Double, Double, Double> _dataTable;
144
145         static SimpleTernaryOpTest__MultiplySubtractNegatedDouble()
146         {
147             var random = new Random();
148
149             for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); }
150             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
151             for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); }
152             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
153             for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (double)(random.NextDouble()); }
154             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar3), ref Unsafe.As<Double, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
155         }
156
157         public SimpleTernaryOpTest__MultiplySubtractNegatedDouble()
158         {
159             Succeeded = true;
160
161             var random = new Random();
162
163             for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); }
164             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
165             for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); }
166             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
167             for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (double)(random.NextDouble()); }
168             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld3), ref Unsafe.As<Double, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
169
170             for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); }
171             for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); }
172             for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (double)(random.NextDouble()); }
173             _dataTable = new SimpleTernaryOpTest__DataTable<Double, Double, Double, Double>(_data1, _data2, _data3, new Double[RetElementCount], LargestVectorSize);
174         }
175
176         public bool IsSupported => Fma.IsSupported;
177
178         public bool Succeeded { get; set; }
179
180         public void RunBasicScenario_UnsafeRead()
181         {
182             var result = Fma.MultiplySubtractNegated(
183                 Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr),
184                 Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr),
185                 Unsafe.Read<Vector256<Double>>(_dataTable.inArray3Ptr)
186             );
187
188             Unsafe.Write(_dataTable.outArrayPtr, result);
189             ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
190         }
191
192         public void RunBasicScenario_Load()
193         {
194             var result = Fma.MultiplySubtractNegated(
195                 Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)),
196                 Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)),
197                 Avx.LoadVector256((Double*)(_dataTable.inArray3Ptr))
198             );
199
200             Unsafe.Write(_dataTable.outArrayPtr, result);
201             ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
202         }
203
204         public void RunBasicScenario_LoadAligned()
205         {
206             var result = Fma.MultiplySubtractNegated(
207                 Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)),
208                 Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)),
209                 Avx.LoadAlignedVector256((Double*)(_dataTable.inArray3Ptr))
210             );
211
212             Unsafe.Write(_dataTable.outArrayPtr, result);
213             ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
214         }
215
216         public void RunReflectionScenario_UnsafeRead()
217         {
218             var result = typeof(Fma).GetMethod(nameof(Fma.MultiplySubtractNegated), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>), typeof(Vector256<Double>) })
219                                      .Invoke(null, new object[] {
220                                         Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr),
221                                         Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr),
222                                         Unsafe.Read<Vector256<Double>>(_dataTable.inArray3Ptr)
223                                      });
224
225             Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result));
226             ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
227         }
228
229         public void RunReflectionScenario_Load()
230         {
231             var result = typeof(Fma).GetMethod(nameof(Fma.MultiplySubtractNegated), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>), typeof(Vector256<Double>) })
232                                      .Invoke(null, new object[] {
233                                         Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)),
234                                         Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)),
235                                         Avx.LoadVector256((Double*)(_dataTable.inArray3Ptr))
236                                      });
237
238             Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result));
239             ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
240         }
241
242         public void RunReflectionScenario_LoadAligned()
243         {
244             var result = typeof(Fma).GetMethod(nameof(Fma.MultiplySubtractNegated), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>), typeof(Vector256<Double>) })
245                                      .Invoke(null, new object[] {
246                                         Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)),
247                                         Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)),
248                                         Avx.LoadAlignedVector256((Double*)(_dataTable.inArray3Ptr))
249                                      });
250
251             Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result));
252             ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
253         }
254
255         public void RunClsVarScenario()
256         {
257             var result = Fma.MultiplySubtractNegated(
258                 _clsVar1,
259                 _clsVar2,
260                 _clsVar3
261             );
262
263             Unsafe.Write(_dataTable.outArrayPtr, result);
264             ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
265         }
266
267         public void RunLclVarScenario_UnsafeRead()
268         {
269             var firstOp = Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr);
270             var secondOp = Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr);
271             var thirdOp = Unsafe.Read<Vector256<Double>>(_dataTable.inArray3Ptr);
272             var result = Fma.MultiplySubtractNegated(firstOp, secondOp, thirdOp);
273
274             Unsafe.Write(_dataTable.outArrayPtr, result);
275             ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
276         }
277
278         public void RunLclVarScenario_Load()
279         {
280             var firstOp = Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr));
281             var secondOp = Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr));
282             var thirdOp = Avx.LoadVector256((Double*)(_dataTable.inArray3Ptr));
283             var result = Fma.MultiplySubtractNegated(firstOp, secondOp, thirdOp);
284
285             Unsafe.Write(_dataTable.outArrayPtr, result);
286             ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
287         }
288
289         public void RunLclVarScenario_LoadAligned()
290         {
291             var firstOp = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr));
292             var secondOp = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr));
293             var thirdOp = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray3Ptr));
294             var result = Fma.MultiplySubtractNegated(firstOp, secondOp, thirdOp);
295
296             Unsafe.Write(_dataTable.outArrayPtr, result);
297             ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
298         }
299
300         public void RunClassLclFldScenario()
301         {
302             var test = new SimpleTernaryOpTest__MultiplySubtractNegatedDouble();
303             var result = Fma.MultiplySubtractNegated(test._fld1, test._fld2, test._fld3);
304
305             Unsafe.Write(_dataTable.outArrayPtr, result);
306             ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
307         }
308
309         public void RunClassFldScenario()
310         {
311             var result = Fma.MultiplySubtractNegated(_fld1, _fld2, _fld3);
312
313             Unsafe.Write(_dataTable.outArrayPtr, result);
314             ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
315         }
316
317         public void RunStructLclFldScenario()
318         {
319             var test = TestStruct.Create();
320             var result = Fma.MultiplySubtractNegated(test._fld1, test._fld2, test._fld3);
321
322             Unsafe.Write(_dataTable.outArrayPtr, result);
323             ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
324         }
325
326         public void RunStructFldScenario()
327         {
328             var test = TestStruct.Create();
329             test.RunStructFldScenario(this);
330         }
331
332         public void RunUnsupportedScenario()
333         {
334             Succeeded = false;
335
336             try
337             {
338                 RunBasicScenario_UnsafeRead();
339             }
340             catch (PlatformNotSupportedException)
341             {
342                 Succeeded = true;
343             }
344         }
345
346         private void ValidateResult(Vector256<Double> firstOp, Vector256<Double> secondOp, Vector256<Double> thirdOp, void* result, [CallerMemberName] string method = "")
347         {
348             Double[] inArray1 = new Double[Op1ElementCount];
349             Double[] inArray2 = new Double[Op2ElementCount];
350             Double[] inArray3 = new Double[Op3ElementCount];
351             Double[] outArray = new Double[RetElementCount];
352
353             Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), firstOp);
354             Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), secondOp);
355             Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray3[0]), thirdOp);
356             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Double>>());
357
358             ValidateResult(inArray1, inArray2, inArray3, outArray, method);
359         }
360
361         private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
362         {
363             Double[] inArray1 = new Double[Op1ElementCount];
364             Double[] inArray2 = new Double[Op2ElementCount];
365             Double[] inArray3 = new Double[Op3ElementCount];
366             Double[] outArray = new Double[RetElementCount];
367
368             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), (uint)Unsafe.SizeOf<Vector256<Double>>());
369             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), (uint)Unsafe.SizeOf<Vector256<Double>>());
370             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), (uint)Unsafe.SizeOf<Vector256<Double>>());
371             Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Double>>());
372
373             ValidateResult(inArray1, inArray2, inArray3, outArray, method);
374         }
375
376         private void ValidateResult(Double[] firstOp, Double[] secondOp, Double[] thirdOp, Double[] result, [CallerMemberName] string method = "")
377         {
378             if (BitConverter.DoubleToInt64Bits(Math.Round(-(firstOp[0] * secondOp[0]) - thirdOp[0], 9)) != BitConverter.DoubleToInt64Bits(Math.Round(result[0], 9)))
379             {
380                 Succeeded = false;
381             }
382             else
383             {
384                 for (var i = 1; i < RetElementCount; i++)
385                 {
386                     if (BitConverter.DoubleToInt64Bits(Math.Round(-(firstOp[i] * secondOp[i]) - thirdOp[i], 9)) != BitConverter.DoubleToInt64Bits(Math.Round(result[i], 9)))
387                     {
388                         Succeeded = false;
389                         break;
390                     }
391                 }
392             }
393
394             if (!Succeeded)
395             {
396                 Console.WriteLine($"{nameof(Fma)}.{nameof(Fma.MultiplySubtractNegated)}<Double>(Vector256<Double>, Vector256<Double>, Vector256<Double>): {method} failed:");
397                 Console.WriteLine($"   firstOp: ({string.Join(", ", firstOp)})");
398                 Console.WriteLine($"  secondOp: ({string.Join(", ", secondOp)})");
399                 Console.WriteLine($"   thirdOp: ({string.Join(", ", thirdOp)})");
400                 Console.WriteLine($"    result: ({string.Join(", ", result)})");
401                 Console.WriteLine();
402             }
403         }
404     }
405 }