summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFei Peng <feipeng.compiler@gmail.com>2019-01-16 15:13:06 -0800
committerFei Peng <feipeng.compiler@gmail.com>2019-01-16 15:13:06 -0800
commit0c803eadcc58bf2b0d0179ca330b2b0eca7c05c8 (patch)
tree2509a3670ebffff4520c877ae210a2b93f46036f
parent55b0d2790c75efe2b4a29a561127599668658e05 (diff)
downloadcoreclr-0c803eadcc58bf2b0d0179ca330b2b0eca7c05c8.tar.gz
coreclr-0c803eadcc58bf2b0d0179ca330b2b0eca7c05c8.tar.bz2
coreclr-0c803eadcc58bf2b0d0179ca330b2b0eca7c05c8.zip
Re-enable Avx.PermuteVar tests
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj2
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj2
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Double.cs412
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Single.cs412
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs2
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_r.csproj2
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_ro.csproj2
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Double.cs412
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Single.cs412
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Program.Avx_Vector128.cs2
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx4
11 files changed, 1664 insertions, 0 deletions
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj
index 37b883b2fa..39b42f4fc4 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj
@@ -127,6 +127,8 @@
<Compile Include="Permute2x128.UInt64.2.cs" />
<Compile Include="Permute2x128.Single.2.cs" />
<Compile Include="Permute2x128.Double.2.cs" />
+ <Compile Include="PermuteVar.Single.cs" />
+ <Compile Include="PermuteVar.Double.cs" />
<Compile Include="RoundCurrentDirection.Double.cs" />
<Compile Include="RoundCurrentDirection.Single.cs" />
<Compile Include="RoundToNearestInteger.Double.cs" />
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj
index 4e0f665924..25775560d5 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj
@@ -127,6 +127,8 @@
<Compile Include="Permute2x128.UInt64.2.cs" />
<Compile Include="Permute2x128.Single.2.cs" />
<Compile Include="Permute2x128.Double.2.cs" />
+ <Compile Include="PermuteVar.Single.cs" />
+ <Compile Include="PermuteVar.Double.cs" />
<Compile Include="RoundCurrentDirection.Double.cs" />
<Compile Include="RoundCurrentDirection.Single.cs" />
<Compile Include="RoundToNearestInteger.Double.cs" />
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Double.cs
new file mode 100644
index 0000000000..4ad02f2e44
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Double.cs
@@ -0,0 +1,412 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public static partial class Program
+ {
+ private static void PermuteVarDouble()
+ {
+ var test = new SimpleBinaryOpTest__PermuteVarDouble();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+
+ // Validates basic functionality works, using LoadAligned
+ test.RunBasicScenario_LoadAligned();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+
+ // Validates calling via reflection works, using LoadAligned
+ test.RunReflectionScenario_LoadAligned();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+
+ // Validates passing a local works, using LoadAligned
+ test.RunLclVarScenario_LoadAligned();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class SimpleBinaryOpTest__PermuteVarDouble
+ {
+ private struct TestStruct
+ {
+ public Vector256<Double> _fld1;
+ public Vector256<Int64> _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref testStruct._fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref testStruct._fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int64>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__PermuteVarDouble testClass)
+ {
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 32;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int64>>() / sizeof(Int64);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Double>>() / sizeof(Double);
+
+ private static Double[] _data1 = new Double[Op1ElementCount];
+ private static Int64[] _data2 = new Int64[Op2ElementCount];
+
+ private static Vector256<Double> _clsVar1;
+ private static Vector256<Int64> _clsVar2;
+
+ private Vector256<Double> _fld1;
+ private Vector256<Int64> _fld2;
+
+ private SimpleBinaryOpTest__DataTable<Double, Double, Int64> _dataTable;
+
+ static SimpleBinaryOpTest__PermuteVarDouble()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int64>>());
+ }
+
+ public SimpleBinaryOpTest__PermuteVarDouble()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Double>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int64>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ _dataTable = new SimpleBinaryOpTest__DataTable<Double, Double, Int64>(_data1, _data2, new Double[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Avx.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Avx.PermuteVar(
+ Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Int64>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Int64>) })
+ .Invoke(null, new object[] {
+ Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Int64>) })
+ .Invoke(null, new object[] {
+ Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Avx.PermuteVar(
+ _clsVar1,
+ _clsVar2
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var left = Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr);
+ var right = Unsafe.Read<Vector256<Int64>>(_dataTable.inArray2Ptr);
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var left = Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadVector256((Int64*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var left = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadAlignedVector256((Int64*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleBinaryOpTest__PermuteVarDouble();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Vector256<Double> left, Vector256<Int64> right, void* result, [CallerMemberName] string method = "")
+ {
+ Double[] inArray1 = new Double[Op1ElementCount];
+ Int64[] inArray2 = new Int64[Op2ElementCount];
+ Double[] outArray = new Double[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), left);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), right);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Double>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+ {
+ Double[] inArray1 = new Double[Op1ElementCount];
+ Int64[] inArray2 = new Int64[Op2ElementCount];
+ Double[] outArray = new Double[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Double>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Double>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(Double[] left, Int64[] right, Double[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[0]))
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (i > 1 ? (BitConverter.DoubleToInt64Bits(left[2]) != BitConverter.DoubleToInt64Bits(result[i])) : (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[i])))
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Avx)}.{nameof(Avx.PermuteVar)}<Double>(Vector256<Double>, Vector256<Int64>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})");
+ TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Single.cs
new file mode 100644
index 0000000000..a38bd9ffec
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/PermuteVar.Single.cs
@@ -0,0 +1,412 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public static partial class Program
+ {
+ private static void PermuteVarSingle()
+ {
+ var test = new SimpleBinaryOpTest__PermuteVarSingle();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+
+ // Validates basic functionality works, using LoadAligned
+ test.RunBasicScenario_LoadAligned();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+
+ // Validates calling via reflection works, using LoadAligned
+ test.RunReflectionScenario_LoadAligned();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+
+ // Validates passing a local works, using LoadAligned
+ test.RunLclVarScenario_LoadAligned();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class SimpleBinaryOpTest__PermuteVarSingle
+ {
+ private struct TestStruct
+ {
+ public Vector256<Single> _fld1;
+ public Vector256<Int32> _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref testStruct._fld1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Single>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref testStruct._fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__PermuteVarSingle testClass)
+ {
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 32;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector256<Single>>() / sizeof(Single);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector256<Int32>>() / sizeof(Int32);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector256<Single>>() / sizeof(Single);
+
+ private static Single[] _data1 = new Single[Op1ElementCount];
+ private static Int32[] _data2 = new Int32[Op2ElementCount];
+
+ private static Vector256<Single> _clsVar1;
+ private static Vector256<Int32> _clsVar2;
+
+ private Vector256<Single> _fld1;
+ private Vector256<Int32> _fld2;
+
+ private SimpleBinaryOpTest__DataTable<Single, Single, Int32> _dataTable;
+
+ static SimpleBinaryOpTest__PermuteVarSingle()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Single>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>());
+ }
+
+ public SimpleBinaryOpTest__PermuteVarSingle()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector256<Single>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector256<Int32>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ _dataTable = new SimpleBinaryOpTest__DataTable<Single, Single, Int32>(_data1, _data2, new Single[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Avx.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Avx.PermuteVar(
+ Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Int32>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Int32>) })
+ .Invoke(null, new object[] {
+ Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Int32>) })
+ .Invoke(null, new object[] {
+ Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Avx.PermuteVar(
+ _clsVar1,
+ _clsVar2
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var left = Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr);
+ var right = Unsafe.Read<Vector256<Int32>>(_dataTable.inArray2Ptr);
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var left = Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadVector256((Int32*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var left = Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadAlignedVector256((Int32*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleBinaryOpTest__PermuteVarSingle();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Vector256<Single> left, Vector256<Int32> right, void* result, [CallerMemberName] string method = "")
+ {
+ Single[] inArray1 = new Single[Op1ElementCount];
+ Int32[] inArray2 = new Int32[Op2ElementCount];
+ Single[] outArray = new Single[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), left);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), right);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Single>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+ {
+ Single[] inArray1 = new Single[Op1ElementCount];
+ Int32[] inArray2 = new Int32[Op2ElementCount];
+ Single[] outArray = new Single[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector256<Single>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector256<Int32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector256<Single>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(Single[] left, Int32[] right, Single[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[0]))
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (i > 3 ? (BitConverter.SingleToInt32Bits(left[5]) != BitConverter.SingleToInt32Bits(result[i])) : (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[i])))
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Avx)}.{nameof(Avx.PermuteVar)}<Single>(Vector256<Single>, Vector256<Int32>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})");
+ TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs
index 65fb994dcb..01555f3556 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs
@@ -112,6 +112,8 @@ namespace JIT.HardwareIntrinsics.X86
["Permute2x128.UInt32.2"] = Permute2x128UInt322,
["Permute2x128.Int64.2"] = Permute2x128Int642,
["Permute2x128.UInt64.2"] = Permute2x128UInt642,
+ ["PermuteVar.Single"] = PermuteVarSingle,
+ ["PermuteVar.Double"] = PermuteVarDouble,
["RoundCurrentDirection.Double"] = RoundCurrentDirectionDouble,
["RoundCurrentDirection.Single"] = RoundCurrentDirectionSingle,
["RoundToNearestInteger.Double"] = RoundToNearestIntegerDouble,
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_r.csproj
index 0c01a676c2..e8d1670c25 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_r.csproj
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_r.csproj
@@ -31,6 +31,8 @@
<Compile Include="MaskLoad.Single.cs" />
<Compile Include="MaskStore.Double.cs" />
<Compile Include="MaskStore.Single.cs" />
+ <Compile Include="PermuteVar.Single.cs" />
+ <Compile Include="PermuteVar.Double.cs" />
<Compile Include="Program.Avx_Vector128.cs" />
<Compile Include="..\Shared\Program.cs" />
<Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" />
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_ro.csproj
index ab44c158a8..27cf3a5384 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_ro.csproj
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Avx_ro.csproj
@@ -31,6 +31,8 @@
<Compile Include="MaskLoad.Single.cs" />
<Compile Include="MaskStore.Double.cs" />
<Compile Include="MaskStore.Single.cs" />
+ <Compile Include="PermuteVar.Single.cs" />
+ <Compile Include="PermuteVar.Double.cs" />
<Compile Include="Program.Avx_Vector128.cs" />
<Compile Include="..\Shared\Program.cs" />
<Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" />
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Double.cs
new file mode 100644
index 0000000000..858f0f3e14
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Double.cs
@@ -0,0 +1,412 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public static partial class Program
+ {
+ private static void PermuteVarDouble()
+ {
+ var test = new SimpleBinaryOpTest__PermuteVarDouble();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+
+ // Validates basic functionality works, using LoadAligned
+ test.RunBasicScenario_LoadAligned();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+
+ // Validates calling via reflection works, using LoadAligned
+ test.RunReflectionScenario_LoadAligned();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+
+ // Validates passing a local works, using LoadAligned
+ test.RunLclVarScenario_LoadAligned();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class SimpleBinaryOpTest__PermuteVarDouble
+ {
+ private struct TestStruct
+ {
+ public Vector128<Double> _fld1;
+ public Vector128<Int64> _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref testStruct._fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Double>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref testStruct._fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__PermuteVarDouble testClass)
+ {
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Double>>() / sizeof(Double);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Int64>>() / sizeof(Int64);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<Double>>() / sizeof(Double);
+
+ private static Double[] _data1 = new Double[Op1ElementCount];
+ private static Int64[] _data2 = new Int64[Op2ElementCount];
+
+ private static Vector128<Double> _clsVar1;
+ private static Vector128<Int64> _clsVar2;
+
+ private Vector128<Double> _fld1;
+ private Vector128<Int64> _fld2;
+
+ private SimpleBinaryOpTest__DataTable<Double, Double, Int64> _dataTable;
+
+ static SimpleBinaryOpTest__PermuteVarDouble()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Double>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ }
+
+ public SimpleBinaryOpTest__PermuteVarDouble()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Double>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (long)1; }
+ _dataTable = new SimpleBinaryOpTest__DataTable<Double, Double, Int64>(_data1, _data2, new Double[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Avx.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Avx.PermuteVar(
+ Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadVector128((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector128((Int64*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Int64>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Int64>) })
+ .Invoke(null, new object[] {
+ Avx.LoadVector128((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector128((Int64*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Int64>) })
+ .Invoke(null, new object[] {
+ Avx.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Avx.PermuteVar(
+ _clsVar1,
+ _clsVar2
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr);
+ var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr);
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var left = Avx.LoadVector128((Double*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadVector128((Int64*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var left = Avx.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleBinaryOpTest__PermuteVarDouble();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Vector128<Double> left, Vector128<Int64> right, void* result, [CallerMemberName] string method = "")
+ {
+ Double[] inArray1 = new Double[Op1ElementCount];
+ Int64[] inArray2 = new Int64[Op2ElementCount];
+ Double[] outArray = new Double[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), left);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), right);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Double>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+ {
+ Double[] inArray1 = new Double[Op1ElementCount];
+ Int64[] inArray2 = new Int64[Op2ElementCount];
+ Double[] outArray = new Double[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector128<Double>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Double>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(Double[] left, Int64[] right, Double[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[0]))
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[i]))
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Avx)}.{nameof(Avx.PermuteVar)}<Double>(Vector128<Double>, Vector128<Int64>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})");
+ TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Single.cs
new file mode 100644
index 0000000000..8f7426782d
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/PermuteVar.Single.cs
@@ -0,0 +1,412 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public static partial class Program
+ {
+ private static void PermuteVarSingle()
+ {
+ var test = new SimpleBinaryOpTest__PermuteVarSingle();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+
+ // Validates basic functionality works, using LoadAligned
+ test.RunBasicScenario_LoadAligned();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+
+ // Validates calling via reflection works, using LoadAligned
+ test.RunReflectionScenario_LoadAligned();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (Avx.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+
+ // Validates passing a local works, using LoadAligned
+ test.RunLclVarScenario_LoadAligned();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class SimpleBinaryOpTest__PermuteVarSingle
+ {
+ private struct TestStruct
+ {
+ public Vector128<Single> _fld1;
+ public Vector128<Int32> _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Single>, byte>(ref testStruct._fld1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Single>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref testStruct._fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__PermuteVarSingle testClass)
+ {
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Single>>() / sizeof(Single);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Int32>>() / sizeof(Int32);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<Single>>() / sizeof(Single);
+
+ private static Single[] _data1 = new Single[Op1ElementCount];
+ private static Int32[] _data2 = new Int32[Op2ElementCount];
+
+ private static Vector128<Single> _clsVar1;
+ private static Vector128<Int32> _clsVar2;
+
+ private Vector128<Single> _fld1;
+ private Vector128<Int32> _fld2;
+
+ private SimpleBinaryOpTest__DataTable<Single, Single, Int32> _dataTable;
+
+ static SimpleBinaryOpTest__PermuteVarSingle()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Single>, byte>(ref _clsVar1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Single>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ }
+
+ public SimpleBinaryOpTest__PermuteVarSingle()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Single>, byte>(ref _fld1), ref Unsafe.As<Single, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Single>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = 1; }
+ _dataTable = new SimpleBinaryOpTest__DataTable<Single, Single, Int32>(_data1, _data2, new Single[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Avx.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Avx.PermuteVar(
+ Unsafe.Read<Vector128<Single>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadVector128((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector128((Int32*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Avx.PermuteVar(
+ Avx.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector128<Single>), typeof(Vector128<Int32>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<Single>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector128<Single>), typeof(Vector128<Int32>) })
+ .Invoke(null, new object[] {
+ Avx.LoadVector128((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadVector128((Int32*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Avx).GetMethod(nameof(Avx.PermuteVar), new Type[] { typeof(Vector128<Single>), typeof(Vector128<Int32>) })
+ .Invoke(null, new object[] {
+ Avx.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)),
+ Avx.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Avx.PermuteVar(
+ _clsVar1,
+ _clsVar2
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var left = Unsafe.Read<Vector128<Single>>(_dataTable.inArray1Ptr);
+ var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr);
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var left = Avx.LoadVector128((Single*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadVector128((Int32*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var left = Avx.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr));
+ var right = Avx.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr));
+ var result = Avx.PermuteVar(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleBinaryOpTest__PermuteVarSingle();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Avx.PermuteVar(_fld1, _fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Avx.PermuteVar(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ bool succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ succeeded = true;
+ }
+
+ if (!succeeded)
+ {
+ Succeeded = false;
+ }
+ }
+
+ private void ValidateResult(Vector128<Single> left, Vector128<Int32> right, void* result, [CallerMemberName] string method = "")
+ {
+ Single[] inArray1 = new Single[Op1ElementCount];
+ Int32[] inArray2 = new Int32[Op2ElementCount];
+ Single[] outArray = new Single[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), left);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), right);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Single>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+ {
+ Single[] inArray1 = new Single[Op1ElementCount];
+ Int32[] inArray2 = new Int32[Op2ElementCount];
+ Single[] outArray = new Single[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector128<Single>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Single>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(Single[] left, Int32[] right, Single[] result, [CallerMemberName] string method = "")
+ {
+ bool succeeded = true;
+
+ if (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[0]))
+ {
+ succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[i]))
+ {
+ succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Avx)}.{nameof(Avx.PermuteVar)}<Single>(Vector128<Single>, Vector128<Int32>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})");
+ TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+
+ Succeeded = false;
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Program.Avx_Vector128.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Program.Avx_Vector128.cs
index cdeba98559..5b89f26fad 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Program.Avx_Vector128.cs
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx_Vector128/Program.Avx_Vector128.cs
@@ -16,6 +16,8 @@ namespace JIT.HardwareIntrinsics.X86
["MaskLoad.Single"] = MaskLoadSingle,
["MaskStore.Double"] = MaskStoreDouble,
["MaskStore.Single"] = MaskStoreSingle,
+ ["PermuteVar.Single"] = PermuteVarSingle,
+ ["PermuteVar.Double"] = PermuteVarDouble,
};
}
}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx
index 2b5ecfa1f8..0786381e92 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx
@@ -626,6 +626,8 @@ private static readonly (string templateFileName, Dictionary<string, string> tem
("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Permute2x128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt32", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt32", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt32", ["Imm"] = "2", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateFirstResult"] = "result[0] != right[0]", ["ValidateRemainingResults"] = "result[i] != (i < 4 ? right[i] : left[i-4])"}),
("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Permute2x128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int64", ["Imm"] = "2", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "result[0] != right[0]", ["ValidateRemainingResults"] = "result[i] != (i < 2 ? right[i] : left[i-2])"}),
("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Permute2x128", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "UInt64", ["Imm"] = "2", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "result[0] != right[0]", ["ValidateRemainingResults"] = "result[i] != (i < 2 ? right[i] : left[i-2])"}),
+ ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "PermuteVar", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "1", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "i > 3 ? (BitConverter.SingleToInt32Bits(left[5]) != BitConverter.SingleToInt32Bits(result[i])) : (BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[i]))"}),
+ ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "PermuteVar", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "(long)1", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "i > 1 ? (BitConverter.DoubleToInt64Bits(left[2]) != BitConverter.DoubleToInt64Bits(result[i])) : (BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[i]))"}),
("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundCurrentDirection", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i]))"}),
("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundCurrentDirection", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[i]))"}),
("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundToNearestInteger", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "32", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0], MidpointRounding.AwayFromZero))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i], MidpointRounding.AwayFromZero))"}),
@@ -674,6 +676,8 @@ private static readonly (string templateFileName, Dictionary<string, string> tem
("LoadBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "MaskLoad", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits((BitConverter.SingleToInt32Bits(right[0]) < 0) ? left[0] : 0)", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits((BitConverter.SingleToInt32Bits(right[i]) < 0) ? left[i] : 0)"}),
("StoreBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "MaskStore", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits((BitConverter.DoubleToInt64Bits(left[0]) < 0) ? right[0] : BitConverter.DoubleToInt64Bits(result[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits((BitConverter.DoubleToInt64Bits(left[i]) < 0) ? right[i] : BitConverter.DoubleToInt64Bits(result[i]))"}),
("StoreBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "MaskStore", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits((BitConverter.SingleToInt32Bits(left[0]) < 0) ? right[0] : BitConverter.SingleToInt32Bits(result[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits((BitConverter.SingleToInt32Bits(left[i]) < 0) ? right[i] : BitConverter.SingleToInt32Bits(result[i]))"}),
+ ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "PermuteVar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int32", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["NextValueOp2"] = "1", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(left[1]) != BitConverter.SingleToInt32Bits(result[i])"}),
+ ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "PermuteVar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "(long)1", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[0]) != BitConverter.DoubleToInt64Bits(result[i])"}),
};
private static readonly (string templateFileName, Dictionary<string, string> templateData)[] Avx2Inputs = new []